mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-22 19:53:48 +08:00
@@ -1,5 +1,9 @@
|
|||||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
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({
|
export const trackStyle = style({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
@@ -11,7 +15,8 @@ export const trackStyle = style({
|
|||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
});
|
});
|
||||||
export const fakeTrackStyle = style({
|
export const fakeTrackStyle = style({
|
||||||
width: '100%',
|
width: `calc(100% - ${thumbSize})`,
|
||||||
|
transform: `translateX(calc(${thumbSize} * 0.5))`,
|
||||||
height: '1px',
|
height: '1px',
|
||||||
backgroundColor: cssVarV2('layer/insideBorder/border'),
|
backgroundColor: cssVarV2('layer/insideBorder/border'),
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@@ -29,8 +34,8 @@ export const filledTrackStyle = style({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const thumbStyle = style({
|
export const thumbStyle = style({
|
||||||
width: '14px',
|
width: thumbSize,
|
||||||
height: '14px',
|
height: thumbSize,
|
||||||
backgroundColor: cssVarV2('icon/primary'),
|
backgroundColor: cssVarV2('icon/primary'),
|
||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import * as Sliders from '@radix-ui/react-slider';
|
import * as Sliders from '@radix-ui/react-slider';
|
||||||
|
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||||
|
import { clamp } from 'lodash-es';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
|
|
||||||
import * as styles from './index.css';
|
import * as styles from './index.css';
|
||||||
|
|
||||||
export interface SliderProps extends Sliders.SliderProps {
|
export interface SliderProps extends Sliders.SliderProps {
|
||||||
width?: number;
|
width?: number;
|
||||||
|
thumbSize?: number;
|
||||||
containerStyle?: React.CSSProperties;
|
containerStyle?: React.CSSProperties;
|
||||||
rootStyle?: React.CSSProperties;
|
rootStyle?: React.CSSProperties;
|
||||||
trackStyle?: 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
|
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 = ({
|
export const Slider = ({
|
||||||
value,
|
value,
|
||||||
min = 0,
|
min = 0,
|
||||||
@@ -27,18 +70,28 @@ export const Slider = ({
|
|||||||
rangeStyle,
|
rangeStyle,
|
||||||
thumbStyle,
|
thumbStyle,
|
||||||
noteStyle,
|
noteStyle,
|
||||||
|
thumbSize = 14,
|
||||||
...props
|
...props
|
||||||
}: SliderProps) => {
|
}: SliderProps) => {
|
||||||
const sliderRef = useRef<HTMLDivElement>(null);
|
const sliderRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
return (
|
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
|
<Sliders.Root
|
||||||
value={value}
|
value={value}
|
||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
step={step}
|
step={step}
|
||||||
style={rootStyle}
|
style={rootStyle}
|
||||||
|
className={styles.root}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<Sliders.Track className={styles.trackStyle} ref={sliderRef}>
|
<Sliders.Track className={styles.trackStyle} ref={sliderRef}>
|
||||||
@@ -56,7 +109,11 @@ export const Slider = ({
|
|||||||
className={styles.nodeStyle}
|
className={styles.nodeStyle}
|
||||||
data-active={value && value[0] >= nodeValue}
|
data-active={value && value[0] >= nodeValue}
|
||||||
style={{
|
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:
|
transform:
|
||||||
index === 0
|
index === 0
|
||||||
? 'translateY(-50%)'
|
? 'translateY(-50%)'
|
||||||
|
|||||||
Reference in New Issue
Block a user