mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
@@ -1,5 +1,9 @@
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { createVar, style } from '@vanilla-extract/css';
|
||||
|
||||
export const thumbSize = createVar();
|
||||
|
||||
export const root = style({});
|
||||
|
||||
export const trackStyle = style({
|
||||
width: '100%',
|
||||
@@ -11,7 +15,8 @@ export const trackStyle = style({
|
||||
cursor: 'pointer',
|
||||
});
|
||||
export const fakeTrackStyle = style({
|
||||
width: '100%',
|
||||
width: `calc(100% - ${thumbSize})`,
|
||||
transform: `translateX(calc(${thumbSize} * 0.5))`,
|
||||
height: '1px',
|
||||
backgroundColor: cssVarV2('layer/insideBorder/border'),
|
||||
position: 'relative',
|
||||
@@ -29,8 +34,8 @@ export const filledTrackStyle = style({
|
||||
});
|
||||
|
||||
export const thumbStyle = style({
|
||||
width: '14px',
|
||||
height: '14px',
|
||||
width: thumbSize,
|
||||
height: thumbSize,
|
||||
backgroundColor: cssVarV2('icon/primary'),
|
||||
borderRadius: '50%',
|
||||
position: 'absolute',
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import * as Sliders from '@radix-ui/react-slider';
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import { clamp } from 'lodash-es';
|
||||
import { useRef } from 'react';
|
||||
|
||||
import * as styles from './index.css';
|
||||
|
||||
export interface SliderProps extends Sliders.SliderProps {
|
||||
width?: number;
|
||||
thumbSize?: number;
|
||||
containerStyle?: React.CSSProperties;
|
||||
rootStyle?: React.CSSProperties;
|
||||
trackStyle?: React.CSSProperties;
|
||||
@@ -14,6 +17,46 @@ export interface SliderProps extends Sliders.SliderProps {
|
||||
nodes?: number[]; // The values where the nodes should be placed
|
||||
}
|
||||
|
||||
// migrate https://github.com/radix-ui/primitives/blob/660060a765634e9cc7bf4513f41e8dabc9824d74/packages/react/slider/src/Slider.tsx#L708 to align step markers with thumbs
|
||||
function calcStepMarkOffset(
|
||||
index: number,
|
||||
maxIndex: number,
|
||||
thumbSize: number
|
||||
) {
|
||||
const percent = convertValueToPercentage(index, 0, maxIndex);
|
||||
const thumbInBoundsOffset = getThumbInBoundsOffset(thumbSize, percent, 1);
|
||||
return `calc(${percent}% + ${thumbInBoundsOffset}px)`;
|
||||
|
||||
function convertValueToPercentage(value: number, min: number, max: number) {
|
||||
const maxSteps = max - min;
|
||||
const percentPerStep = 100 / maxSteps;
|
||||
const percentage = percentPerStep * (value - min);
|
||||
return clamp(percentage, 0, 100);
|
||||
}
|
||||
|
||||
function getThumbInBoundsOffset(
|
||||
width: number,
|
||||
left: number,
|
||||
direction: number
|
||||
) {
|
||||
const halfWidth = width / 2;
|
||||
const halfPercent = 50;
|
||||
const offset = linearScale([0, halfPercent], [0, halfWidth]);
|
||||
return (halfWidth - offset(left) * direction) * direction;
|
||||
}
|
||||
|
||||
function linearScale(
|
||||
input: readonly [number, number],
|
||||
output: readonly [number, number]
|
||||
) {
|
||||
return (value: number) => {
|
||||
if (input[0] === input[1] || output[0] === output[1]) return output[0];
|
||||
const ratio = (output[1] - output[0]) / (input[1] - input[0]);
|
||||
return output[0] + ratio * (value - input[0]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const Slider = ({
|
||||
value,
|
||||
min = 0,
|
||||
@@ -27,18 +70,28 @@ export const Slider = ({
|
||||
rangeStyle,
|
||||
thumbStyle,
|
||||
noteStyle,
|
||||
thumbSize = 14,
|
||||
...props
|
||||
}: SliderProps) => {
|
||||
const sliderRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
return (
|
||||
<div style={{ ...containerStyle, width: width ? `${width}px` : undefined }}>
|
||||
<div
|
||||
style={{
|
||||
...containerStyle,
|
||||
...assignInlineVars({
|
||||
[styles.thumbSize]: thumbSize ? `${thumbSize}px` : undefined,
|
||||
}),
|
||||
width: width ? `${width}px` : undefined,
|
||||
}}
|
||||
>
|
||||
<Sliders.Root
|
||||
value={value}
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
style={rootStyle}
|
||||
className={styles.root}
|
||||
{...props}
|
||||
>
|
||||
<Sliders.Track className={styles.trackStyle} ref={sliderRef}>
|
||||
@@ -56,7 +109,11 @@ export const Slider = ({
|
||||
className={styles.nodeStyle}
|
||||
data-active={value && value[0] >= nodeValue}
|
||||
style={{
|
||||
left: `${((nodeValue - (min !== undefined ? min : 0)) / (max !== undefined ? max - (min !== undefined ? min : 0) : 1)) * 100}%`,
|
||||
left: calcStepMarkOffset(
|
||||
index,
|
||||
nodes.length - 1,
|
||||
thumbSize / 2
|
||||
),
|
||||
transform:
|
||||
index === 0
|
||||
? 'translateY(-50%)'
|
||||
|
||||
Reference in New Issue
Block a user