@toptal/picasso-slider 5.0.2 → 5.0.3-alpha-pf-fix-alpha-release-ea13b5aca.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-package/src/Slider/Slider.d.ts.map +1 -1
- package/dist-package/src/Slider/Slider.js +52 -34
- package/dist-package/src/Slider/Slider.js.map +1 -1
- package/dist-package/src/SliderMark/SliderMark.d.ts +2 -4
- package/dist-package/src/SliderMark/SliderMark.d.ts.map +1 -1
- package/dist-package/src/SliderMark/SliderMark.js +2 -2
- package/dist-package/src/SliderMark/SliderMark.js.map +1 -1
- package/dist-package/src/SliderValueLabel/SliderValueLabel.d.ts +8 -5
- package/dist-package/src/SliderValueLabel/SliderValueLabel.d.ts.map +1 -1
- package/dist-package/src/SliderValueLabel/SliderValueLabel.js +1 -1
- package/dist-package/src/SliderValueLabel/SliderValueLabel.js.map +1 -1
- package/package.json +11 -11
- package/src/Slider/Slider.tsx +139 -53
- package/src/Slider/__snapshots__/test.tsx.snap +98 -74
- package/src/Slider/story/ControlledWithLabel.example.tsx +3 -1
- package/src/SliderMark/SliderMark.tsx +4 -4
- package/src/SliderValueLabel/SliderValueLabel.tsx +14 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../../src/Slider/Slider.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../../src/Slider/Slider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAA;AAIvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAMvD,MAAM,WAAW,KAAM,SAAQ,SAAS;IACtC,2BAA2B;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,2BAA2B;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACzB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAChC,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qCAAqC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;MAIE;IACF,OAAO,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,KAAK,CAAA;IAC/B,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC,CAAA;IAC5E,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EACxB,WAAW,EAAE,MAAM,KAChB,IAAI,CAAA;IACT,gCAAgC;IAChC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAA;IACxD,+BAA+B;IAC/B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAA;IACvD,+FAA+F;IAC/F,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,+BAA+B;IAC/B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAA;CACZ;AAkBD,eAAO,MAAM,MAAM,2EAkLjB,CAAA;AAIF,eAAe,MAAM,CAAA"}
|
|
@@ -9,19 +9,28 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
import { Slider as MUIBaseSlider } from '@mui/base/Slider';
|
|
12
|
+
import React, { forwardRef, useCallback, useMemo, useRef } from 'react';
|
|
13
|
+
import { Slider as BaseUISlider } from '@base-ui/react/slider';
|
|
15
14
|
import { useCombinedRefs, useOnScreen } from '@toptal/picasso-utils';
|
|
16
15
|
import { twJoin, twMerge } from '@toptal/picasso-tailwind-merge';
|
|
17
16
|
import SliderMark from '../SliderMark';
|
|
18
17
|
import SliderValueLabel from '../SliderValueLabel';
|
|
19
18
|
import { useLabelOverlap } from './hooks';
|
|
19
|
+
const formatTooltipValue = (value, index, tooltipFormat) => {
|
|
20
|
+
if (typeof tooltipFormat === 'function') {
|
|
21
|
+
return tooltipFormat(value, index);
|
|
22
|
+
}
|
|
23
|
+
if (typeof tooltipFormat === 'string') {
|
|
24
|
+
return tooltipFormat;
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
};
|
|
20
28
|
export const Slider = forwardRef(function Slider(_a, ref) {
|
|
21
|
-
var { defaultValue = 0, min = 0, max = 100, tooltip = 'off' } = _a, props = __rest(_a, ["defaultValue", "min", "max", "tooltip"]);
|
|
22
|
-
const { marks, value, tooltipFormat,
|
|
29
|
+
var { defaultValue = 0, min = 0, max = 100, step = 1, tooltip = 'off' } = _a, props = __rest(_a, ["defaultValue", "min", "max", "step", "tooltip"]);
|
|
30
|
+
const { marks, value, tooltipFormat, disabled, onChange, onBlur, onFocus, hideThumbOnEmpty, disableTrackHighlight, className, style, name, id, 'data-private': dataPrivate, 'data-testid': dataTestid, } = props;
|
|
23
31
|
const containerRef = useRef(null);
|
|
24
32
|
const sliderRef = useCombinedRefs(ref, useRef(null));
|
|
33
|
+
const baseUiSliderRef = sliderRef;
|
|
25
34
|
// The rootMargin is not working correctly in the storybooks iframe
|
|
26
35
|
// To test properly we can open the iframe in new window
|
|
27
36
|
const { isOnScreen, isObserved } = useOnScreen({
|
|
@@ -35,35 +44,44 @@ export const Slider = forwardRef(function Slider(_a, ref) {
|
|
|
35
44
|
isTooltipRendered: isObserved,
|
|
36
45
|
});
|
|
37
46
|
const isThumbHidden = hideThumbOnEmpty && (typeof value === 'undefined' || value === null);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
47
|
+
const handleValueChange = useCallback((newValue, eventDetails) => {
|
|
48
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(eventDetails.event, newValue, eventDetails.activeThumbIndex);
|
|
49
|
+
}, [onChange]);
|
|
50
|
+
const marksList = useMemo(() => {
|
|
51
|
+
if (!marks) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
const list = [];
|
|
55
|
+
for (let markValue = min; markValue <= max; markValue += step) {
|
|
56
|
+
list.push(markValue);
|
|
57
|
+
}
|
|
58
|
+
return list;
|
|
59
|
+
}, [marks, min, max, step]);
|
|
60
|
+
// Derive active state from the live value (`state.values`), not from
|
|
61
|
+
// `value ?? defaultValue`, which would freeze marks/labels in uncontrolled mode.
|
|
62
|
+
const isMarkActive = (markValue, values) => {
|
|
63
|
+
var _a;
|
|
64
|
+
if (values.length > 1) {
|
|
65
|
+
const [start, end] = values;
|
|
66
|
+
return (markValue >= Math.min(start, end) && markValue <= Math.max(start, end));
|
|
67
|
+
}
|
|
68
|
+
return markValue <= ((_a = values[0]) !== null && _a !== void 0 ? _a : min);
|
|
69
|
+
};
|
|
70
|
+
const thumbClassName = twJoin('group/thumb flex justify-center items-center w-[19px] h-[19px]', 'rounded-[50%] bg-blue-500 border-[2px] border-solid border-white', 'outline-0 transition-shadow cursor-pointer', isThumbHidden && 'hidden');
|
|
71
|
+
const handleThumbFocus = onFocus;
|
|
72
|
+
const handleThumbBlur = onBlur;
|
|
73
|
+
const renderThumb = (thumbValue, index) => (React.createElement(BaseUISlider.Thumb, { key: index, index: index, className: thumbClassName, onFocus: handleThumbFocus, onBlur: handleThumbBlur, role: 'slider' },
|
|
74
|
+
React.createElement(SliderValueLabel, { index: index, value: thumbValue, tooltip: isObserved ? tooltip : 'off', onRender: handleValueLabelOnRender, yPlacement: isOnScreen ? 'top' : 'bottom', isOverlaped: isPartiallyOverlapped }, formatTooltipValue(thumbValue, index, tooltipFormat))));
|
|
75
|
+
return (React.createElement("div", { ref: containerRef, className: twMerge('mb-[4px] mt-[5px] mx-0 h-[15px]', className), style: style },
|
|
76
|
+
React.createElement(BaseUISlider.Root, { ref: baseUiSliderRef, defaultValue: defaultValue, value: value, min: min, max: max, step: step, thumbCollisionBehavior: 'swap', disabled: disabled, "data-testid": dataTestid, "data-private": dataPrivate, onValueChange: handleValueChange, name: name, id: id, className: 'block cursor-pointer width-full relative' },
|
|
77
|
+
React.createElement(BaseUISlider.Control, { className: 'block absolute inset-0 h-[15px]' },
|
|
78
|
+
React.createElement(BaseUISlider.Track, { className: 'block w-full h-[1px] top-[7px] rounded-none bg-gray-500', render: (trackProps, { values }) => (React.createElement("div", Object.assign({}, trackProps),
|
|
79
|
+
React.createElement(BaseUISlider.Indicator, { className: twJoin('block h-[1px]', disableTrackHighlight ? 'bg-gray-500' : 'bg-blue-500') }),
|
|
80
|
+
marksList.map((markValue, idx) => {
|
|
81
|
+
const percent = ((markValue - min) / (max - min)) * 100;
|
|
82
|
+
return (React.createElement(SliderMark, { key: markValue, markActive: isMarkActive(markValue, values), value: values[0], style: { left: `${percent}%` }, forceInactive: Boolean(disableTrackHighlight), "data-index": idx }));
|
|
83
|
+
}),
|
|
84
|
+
values.map((thumbValue, index) => renderThumb(thumbValue, index)))) })))));
|
|
67
85
|
});
|
|
68
86
|
Slider.displayName = 'Slider';
|
|
69
87
|
export default Slider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Slider.js","sourceRoot":"","sources":["../../../src/Slider/Slider.tsx"],"names":[],"mappings":";;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"Slider.js","sourceRoot":"","sources":["../../../src/Slider/Slider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
export type SliderMarkProps = {
|
|
3
3
|
markActive: boolean;
|
|
4
|
-
|
|
5
|
-
value: number;
|
|
6
|
-
};
|
|
4
|
+
value?: number;
|
|
7
5
|
style: React.CSSProperties;
|
|
8
6
|
'data-index': number;
|
|
9
7
|
forceInactive: boolean;
|
|
10
8
|
};
|
|
11
|
-
declare const SliderMark: ({ markActive,
|
|
9
|
+
declare const SliderMark: ({ markActive, value, "data-index": dataIndex, style, forceInactive, }: SliderMarkProps) => JSX.Element;
|
|
12
10
|
export default SliderMark;
|
|
13
11
|
//# sourceMappingURL=SliderMark.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SliderMark.d.ts","sourceRoot":"","sources":["../../../src/SliderMark/SliderMark.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,OAAO,CAAA;IACnB,
|
|
1
|
+
{"version":3,"file":"SliderMark.d.ts","sourceRoot":"","sources":["../../../src/SliderMark/SliderMark.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,OAAO,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,KAAK,CAAC,aAAa,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,OAAO,CAAA;CACvB,CAAA;AAID,QAAA,MAAM,UAAU,0EAMb,eAAe,gBAWjB,CAAA;AAED,eAAe,UAAU,CAAA"}
|
|
@@ -3,8 +3,8 @@ import { twJoin } from '@toptal/picasso-tailwind-merge';
|
|
|
3
3
|
import { getBgColor } from '../utils';
|
|
4
4
|
// We need custom Mark component because we have
|
|
5
5
|
// different bg color based on value of the Slider
|
|
6
|
-
const SliderMark = ({ markActive,
|
|
7
|
-
return (React.createElement("span", { "data-index": dataIndex, style: style, className: twJoin('absolute w-[
|
|
6
|
+
const SliderMark = ({ markActive, value, 'data-index': dataIndex, style, forceInactive, }) => {
|
|
7
|
+
return (React.createElement("span", { "data-index": dataIndex, style: style, className: twJoin('absolute w-[9px] h-[9px] top-1/2 rounded-[50%] -translate-x-2/4 -translate-y-2/4 box-content', getBgColor({ markActive, forceInactive, value })) }));
|
|
8
8
|
};
|
|
9
9
|
export default SliderMark;
|
|
10
10
|
//# sourceMappingURL=SliderMark.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SliderMark.js","sourceRoot":"","sources":["../../../src/SliderMark/SliderMark.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAA;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAUrC,gDAAgD;AAChD,kDAAkD;AAClD,MAAM,UAAU,GAAG,CAAC,EAClB,UAAU,EACV,
|
|
1
|
+
{"version":3,"file":"SliderMark.js","sourceRoot":"","sources":["../../../src/SliderMark/SliderMark.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAA;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAUrC,gDAAgD;AAChD,kDAAkD;AAClD,MAAM,UAAU,GAAG,CAAC,EAClB,UAAU,EACV,KAAK,EACL,YAAY,EAAE,SAAS,EACvB,KAAK,EACL,aAAa,GACG,EAAE,EAAE;IACpB,OAAO,CACL,4CACc,SAAS,EACrB,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,MAAM,CACf,8FAA8F,EAC9F,UAAU,CAAC,EAAE,UAAU,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CACjD,GACD,CACH,CAAA;AACH,CAAC,CAAA;AAED,eAAe,UAAU,CAAA"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { RefObject } from 'react';
|
|
1
|
+
import type { ReactNode, RefObject } from 'react';
|
|
3
2
|
type ValueLabelDisplay = 'on' | 'auto' | 'off';
|
|
4
|
-
|
|
3
|
+
type SliderValueLabelProps = {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
index?: number;
|
|
6
|
+
value: number;
|
|
5
7
|
tooltip: ValueLabelDisplay;
|
|
6
|
-
yPlacement:
|
|
8
|
+
yPlacement: 'top' | 'bottom';
|
|
7
9
|
/** indicates if there are two SliderValueLabels that overlap each other */
|
|
8
10
|
isOverlaped: boolean;
|
|
9
11
|
onRender: (index: number, ref: RefObject<HTMLSpanElement>) => void;
|
|
10
|
-
}
|
|
12
|
+
};
|
|
13
|
+
declare const SliderValueLabel: ({ children, index, value, tooltip, onRender, yPlacement, isOverlaped, }: SliderValueLabelProps) => JSX.Element;
|
|
11
14
|
export default SliderValueLabel;
|
|
12
15
|
//# sourceMappingURL=SliderValueLabel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SliderValueLabel.d.ts","sourceRoot":"","sources":["../../../src/SliderValueLabel/SliderValueLabel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"SliderValueLabel.d.ts","sourceRoot":"","sources":["../../../src/SliderValueLabel/SliderValueLabel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMjD,KAAK,iBAAiB,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAA;AAE9C,KAAK,qBAAqB,GAAG;IAC3B,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,iBAAiB,CAAA;IAC1B,UAAU,EAAE,KAAK,GAAG,QAAQ,CAAA;IAC5B,2EAA2E;IAC3E,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAA;CACnE,CAAA;AAqBD,QAAA,MAAM,gBAAgB,4EAQnB,qBAAqB,gBAiDvB,CAAA;AAED,eAAe,gBAAgB,CAAA"}
|
|
@@ -17,7 +17,7 @@ const yPlacementClasses = {
|
|
|
17
17
|
bottom: 'top-[calc(100%+2px)]',
|
|
18
18
|
top: 'bottom-[calc(100%+2px)]',
|
|
19
19
|
};
|
|
20
|
-
const SliderValueLabel = ({ children, index = -1, tooltip = 'off', onRender, yPlacement, isOverlaped,
|
|
20
|
+
const SliderValueLabel = ({ children, index = -1, value, tooltip = 'off', onRender, yPlacement, isOverlaped, }) => {
|
|
21
21
|
const ref = useRef(null);
|
|
22
22
|
// we need to change the placement of the label if it is overlaped
|
|
23
23
|
// or if it is out of the viewport
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SliderValueLabel.js","sourceRoot":"","sources":["../../../src/SliderValueLabel/SliderValueLabel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SliderValueLabel.js","sourceRoot":"","sources":["../../../src/SliderValueLabel/SliderValueLabel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAA;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAexC,MAAM,gBAAgB,GAAsC;IAC1D,GAAG,EAAE,QAAQ;IACb,yEAAyE;IACzE,6CAA6C;IAC7C,IAAI,EAAE,sEAAsE;IAC5E,EAAE,EAAE,kCAAkC;CACvC,CAAA;AAED,MAAM,iBAAiB,GAAG;IACxB,IAAI,EAAE,yBAAyB;IAC/B,KAAK,EAAE,wBAAwB;IAC/B,MAAM,EAAE,EAAE;CACF,CAAA;AAEV,MAAM,iBAAiB,GAAG;IACxB,MAAM,EAAE,sBAAsB;IAC9B,GAAG,EAAE,yBAAyB;CACtB,CAAA;AAEV,MAAM,gBAAgB,GAAG,CAAC,EACxB,QAAQ,EACR,KAAK,GAAG,CAAC,CAAC,EACV,KAAK,EACL,OAAO,GAAG,KAAK,EACf,QAAQ,EACR,UAAU,EACV,WAAW,GACW,EAAE,EAAE;IAC1B,MAAM,GAAG,GAAG,MAAM,CAAkB,IAAI,CAAC,CAAA;IAEzC,kEAAkE;IAClE,kCAAkC;IAClC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAC1C,QAAQ,CACT,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACtB,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAA;IAErB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACjB,OAAM;QACR,CAAC;QAED,aAAa,CACX,aAAa,CAAC;YACZ,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE;YACzC,WAAW,EAAE,WAAW;YACxB,YAAY,EAAE,KAAK,KAAK,CAAC;YACzB,gBAAgB,EAAE,UAAU;SAC7B,CAAC,CACH,CAAA;QACD,yDAAyD;IAC3D,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAA;IAEpD,OAAO,CACL,8BACE,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,MAAM,CACf,qDAAqD,EACrD,gBAAgB,CAAC,OAAO,CAAC,EACzB,iBAAiB,CAAC,UAAU,CAAC,EAC7B,iBAAiB,CAAC,UAAU,CAAC,CAC9B;QAED,8BACE,SAAS,EAAE,MAAM,CACf,6CAA6C,EAC7C,wDAAwD,CACzD,IAEA,QAAQ,CACJ,CACF,CACR,CAAA;AACH,CAAC,CAAA;AAED,eAAe,gBAAgB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toptal/picasso-slider",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.3-alpha-pf-fix-alpha-release-ea13b5aca.0",
|
|
4
4
|
"description": "Toptal UI components library - Slider",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -18,24 +18,24 @@
|
|
|
18
18
|
},
|
|
19
19
|
"homepage": "https://github.com/toptal/picasso/tree/master/packages/picasso#readme",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@
|
|
22
|
-
"@toptal/picasso-shared": "16.0.0",
|
|
23
|
-
"@toptal/picasso-tooltip": "2.0.
|
|
24
|
-
"@toptal/picasso-utils": "4.0.
|
|
21
|
+
"@base-ui/react": "^1.4.1",
|
|
22
|
+
"@toptal/picasso-shared": "16.0.1-alpha-pf-fix-alpha-release-ea13b5aca.0",
|
|
23
|
+
"@toptal/picasso-tooltip": "2.0.8-alpha-pf-fix-alpha-release-ea13b5aca.0",
|
|
24
|
+
"@toptal/picasso-utils": "4.0.2-alpha-pf-fix-alpha-release-ea13b5aca.0"
|
|
25
25
|
},
|
|
26
26
|
"sideEffects": false,
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@toptal/picasso-tailwind-merge": "
|
|
29
|
-
"@toptal/picasso-provider": "
|
|
30
|
-
"@toptal/picasso-tailwind": "
|
|
31
|
-
"react": ">=16.12.0
|
|
28
|
+
"@toptal/picasso-tailwind-merge": "2.0.6-alpha-pf-fix-alpha-release-ea13b5aca.0",
|
|
29
|
+
"@toptal/picasso-provider": "6.0.1-alpha-pf-fix-alpha-release-ea13b5aca.0",
|
|
30
|
+
"@toptal/picasso-tailwind": "4.0.1-alpha-pf-fix-alpha-release-ea13b5aca.0",
|
|
31
|
+
"react": ">=16.12.0"
|
|
32
32
|
},
|
|
33
33
|
"exports": {
|
|
34
34
|
".": "./dist-package/src/index.js"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@toptal/picasso-tailwind-merge": "2.0.
|
|
38
|
-
"@toptal/picasso-provider": "6.0.0"
|
|
37
|
+
"@toptal/picasso-tailwind-merge": "2.0.6-alpha-pf-fix-alpha-release-ea13b5aca.0",
|
|
38
|
+
"@toptal/picasso-provider": "6.0.1-alpha-pf-fix-alpha-release-ea13b5aca.0"
|
|
39
39
|
},
|
|
40
40
|
"files": [
|
|
41
41
|
"dist-package/**",
|
package/src/Slider/Slider.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import { Slider as MUIBaseSlider } from '@mui/base/Slider'
|
|
1
|
+
import React, { forwardRef, useCallback, useMemo, useRef } from 'react'
|
|
2
|
+
import { Slider as BaseUISlider } from '@base-ui/react/slider'
|
|
4
3
|
import { useCombinedRefs, useOnScreen } from '@toptal/picasso-utils'
|
|
5
4
|
import { twJoin, twMerge } from '@toptal/picasso-tailwind-merge'
|
|
6
5
|
import type { BaseProps } from '@toptal/picasso-shared'
|
|
@@ -56,15 +55,30 @@ export interface Props extends BaseProps {
|
|
|
56
55
|
id?: string
|
|
57
56
|
}
|
|
58
57
|
|
|
58
|
+
const formatTooltipValue = (
|
|
59
|
+
value: number,
|
|
60
|
+
index: number,
|
|
61
|
+
tooltipFormat?: Props['tooltipFormat']
|
|
62
|
+
): React.ReactNode => {
|
|
63
|
+
if (typeof tooltipFormat === 'function') {
|
|
64
|
+
return tooltipFormat(value, index)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (typeof tooltipFormat === 'string') {
|
|
68
|
+
return tooltipFormat
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return value
|
|
72
|
+
}
|
|
73
|
+
|
|
59
74
|
export const Slider = forwardRef<HTMLElement, Props>(function Slider(
|
|
60
|
-
{ defaultValue = 0, min = 0, max = 100, tooltip = 'off', ...props },
|
|
75
|
+
{ defaultValue = 0, min = 0, max = 100, step = 1, tooltip = 'off', ...props },
|
|
61
76
|
ref
|
|
62
77
|
) {
|
|
63
78
|
const {
|
|
64
79
|
marks,
|
|
65
80
|
value,
|
|
66
81
|
tooltipFormat,
|
|
67
|
-
step,
|
|
68
82
|
disabled,
|
|
69
83
|
onChange,
|
|
70
84
|
onBlur,
|
|
@@ -80,6 +94,7 @@ export const Slider = forwardRef<HTMLElement, Props>(function Slider(
|
|
|
80
94
|
} = props
|
|
81
95
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
82
96
|
const sliderRef = useCombinedRefs<HTMLElement>(ref, useRef<HTMLElement>(null))
|
|
97
|
+
const baseUiSliderRef = sliderRef as React.RefObject<HTMLDivElement>
|
|
83
98
|
|
|
84
99
|
// The rootMargin is not working correctly in the storybooks iframe
|
|
85
100
|
// To test properly we can open the iframe in new window
|
|
@@ -98,69 +113,140 @@ export const Slider = forwardRef<HTMLElement, Props>(function Slider(
|
|
|
98
113
|
const isThumbHidden =
|
|
99
114
|
hideThumbOnEmpty && (typeof value === 'undefined' || value === null)
|
|
100
115
|
|
|
116
|
+
const handleValueChange = useCallback(
|
|
117
|
+
(
|
|
118
|
+
newValue: number | number[],
|
|
119
|
+
eventDetails: { event: Event; activeThumbIndex: number }
|
|
120
|
+
) => {
|
|
121
|
+
onChange?.(eventDetails.event, newValue, eventDetails.activeThumbIndex)
|
|
122
|
+
},
|
|
123
|
+
[onChange]
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
const marksList = useMemo(() => {
|
|
127
|
+
if (!marks) {
|
|
128
|
+
return []
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const list: number[] = []
|
|
132
|
+
|
|
133
|
+
for (let markValue = min; markValue <= max; markValue += step) {
|
|
134
|
+
list.push(markValue)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return list
|
|
138
|
+
}, [marks, min, max, step])
|
|
139
|
+
|
|
140
|
+
// Derive active state from the live value (`state.values`), not from
|
|
141
|
+
// `value ?? defaultValue`, which would freeze marks/labels in uncontrolled mode.
|
|
142
|
+
const isMarkActive = (
|
|
143
|
+
markValue: number,
|
|
144
|
+
values: readonly number[]
|
|
145
|
+
): boolean => {
|
|
146
|
+
if (values.length > 1) {
|
|
147
|
+
const [start, end] = values
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
markValue >= Math.min(start, end) && markValue <= Math.max(start, end)
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return markValue <= (values[0] ?? min)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const thumbClassName = twJoin(
|
|
158
|
+
'group/thumb flex justify-center items-center w-[19px] h-[19px]',
|
|
159
|
+
'rounded-[50%] bg-blue-500 border-[2px] border-solid border-white',
|
|
160
|
+
'outline-0 transition-shadow cursor-pointer',
|
|
161
|
+
isThumbHidden && 'hidden'
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
const handleThumbFocus = onFocus as
|
|
165
|
+
| React.FocusEventHandler<HTMLInputElement>
|
|
166
|
+
| undefined
|
|
167
|
+
const handleThumbBlur = onBlur as
|
|
168
|
+
| React.FocusEventHandler<HTMLInputElement>
|
|
169
|
+
| undefined
|
|
170
|
+
|
|
171
|
+
const renderThumb = (thumbValue: number, index: number) => (
|
|
172
|
+
<BaseUISlider.Thumb
|
|
173
|
+
key={index}
|
|
174
|
+
index={index}
|
|
175
|
+
className={thumbClassName}
|
|
176
|
+
onFocus={handleThumbFocus}
|
|
177
|
+
onBlur={handleThumbBlur}
|
|
178
|
+
role='slider'
|
|
179
|
+
>
|
|
180
|
+
<SliderValueLabel
|
|
181
|
+
index={index}
|
|
182
|
+
value={thumbValue}
|
|
183
|
+
tooltip={isObserved ? tooltip : 'off'}
|
|
184
|
+
onRender={handleValueLabelOnRender}
|
|
185
|
+
yPlacement={isOnScreen ? 'top' : 'bottom'}
|
|
186
|
+
isOverlaped={isPartiallyOverlapped}
|
|
187
|
+
>
|
|
188
|
+
{formatTooltipValue(thumbValue, index, tooltipFormat)}
|
|
189
|
+
</SliderValueLabel>
|
|
190
|
+
</BaseUISlider.Thumb>
|
|
191
|
+
)
|
|
192
|
+
|
|
101
193
|
return (
|
|
102
194
|
<div
|
|
103
195
|
ref={containerRef}
|
|
104
|
-
className={twMerge('
|
|
196
|
+
className={twMerge('mb-[4px] mt-[5px] mx-0 h-[15px]', className)}
|
|
105
197
|
style={style}
|
|
106
198
|
>
|
|
107
|
-
<
|
|
108
|
-
ref={
|
|
199
|
+
<BaseUISlider.Root
|
|
200
|
+
ref={baseUiSliderRef}
|
|
109
201
|
defaultValue={defaultValue}
|
|
110
202
|
value={value}
|
|
111
203
|
min={min}
|
|
112
204
|
max={max}
|
|
113
205
|
step={step}
|
|
114
|
-
|
|
206
|
+
thumbCollisionBehavior='swap'
|
|
115
207
|
disabled={disabled}
|
|
116
208
|
data-testid={dataTestid}
|
|
117
209
|
data-private={dataPrivate}
|
|
118
|
-
|
|
119
|
-
onBlur={onBlur}
|
|
210
|
+
onValueChange={handleValueChange}
|
|
120
211
|
name={name}
|
|
121
212
|
id={id}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
},
|
|
160
|
-
}}
|
|
161
|
-
valueLabelFormat={tooltipFormat}
|
|
162
|
-
onChange={onChange}
|
|
163
|
-
/>
|
|
213
|
+
className='block cursor-pointer width-full relative'
|
|
214
|
+
>
|
|
215
|
+
<BaseUISlider.Control className='block absolute inset-0 h-[15px]'>
|
|
216
|
+
<BaseUISlider.Track
|
|
217
|
+
className='block w-full h-[1px] top-[7px] rounded-none bg-gray-500'
|
|
218
|
+
render={(trackProps, { values }) => (
|
|
219
|
+
<div {...trackProps}>
|
|
220
|
+
<BaseUISlider.Indicator
|
|
221
|
+
className={twJoin(
|
|
222
|
+
'block h-[1px]',
|
|
223
|
+
disableTrackHighlight ? 'bg-gray-500' : 'bg-blue-500'
|
|
224
|
+
)}
|
|
225
|
+
/>
|
|
226
|
+
|
|
227
|
+
{marksList.map((markValue, idx) => {
|
|
228
|
+
const percent = ((markValue - min) / (max - min)) * 100
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<SliderMark
|
|
232
|
+
key={markValue}
|
|
233
|
+
markActive={isMarkActive(markValue, values)}
|
|
234
|
+
value={values[0]}
|
|
235
|
+
style={{ left: `${percent}%` }}
|
|
236
|
+
forceInactive={Boolean(disableTrackHighlight)}
|
|
237
|
+
data-index={idx}
|
|
238
|
+
/>
|
|
239
|
+
)
|
|
240
|
+
})}
|
|
241
|
+
|
|
242
|
+
{values.map((thumbValue, index) =>
|
|
243
|
+
renderThumb(thumbValue, index)
|
|
244
|
+
)}
|
|
245
|
+
</div>
|
|
246
|
+
)}
|
|
247
|
+
/>
|
|
248
|
+
</BaseUISlider.Control>
|
|
249
|
+
</BaseUISlider.Root>
|
|
164
250
|
</div>
|
|
165
251
|
)
|
|
166
252
|
})
|
|
@@ -3,48 +3,60 @@
|
|
|
3
3
|
exports[`Slider renders 1`] = `
|
|
4
4
|
<div>
|
|
5
5
|
<div
|
|
6
|
-
class="
|
|
6
|
+
class="mb-[4px] mt-[5px] mx-0 h-[15px]"
|
|
7
7
|
>
|
|
8
|
-
<
|
|
9
|
-
class="
|
|
8
|
+
<div
|
|
9
|
+
class="block cursor-pointer width-full relative"
|
|
10
|
+
data-orientation="horizontal"
|
|
11
|
+
id="base-ui-:r0:"
|
|
12
|
+
role="group"
|
|
10
13
|
>
|
|
11
|
-
<
|
|
12
|
-
class="
|
|
13
|
-
|
|
14
|
-
<span
|
|
15
|
-
class="base-Slider block absolute h-[1px] bg-blue"
|
|
16
|
-
style="left: 0%; width: 0%;"
|
|
17
|
-
/>
|
|
18
|
-
<span
|
|
19
|
-
class="base-Slider group/thumb flex justify-center items-center w-[15px] h-[15px] rounded-[50%] bg-blue border-[2px] border-solid border-white -mt -ml outline-0 absolute transition-shadow cursor-pointer"
|
|
20
|
-
data-index="0"
|
|
21
|
-
role="slider"
|
|
22
|
-
style="left: 0%;"
|
|
14
|
+
<div
|
|
15
|
+
class="block absolute inset-0 h-[15px]"
|
|
16
|
+
data-orientation="horizontal"
|
|
23
17
|
>
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
aria-valuenow="0"
|
|
29
|
-
data-index="0"
|
|
30
|
-
max="100"
|
|
31
|
-
min="0"
|
|
32
|
-
step="1"
|
|
33
|
-
style="border: 0px; height: 100%; margin: -1px; overflow: hidden; padding: 0px; position: absolute; white-space: nowrap; width: 100%; direction: ltr;"
|
|
34
|
-
type="range"
|
|
35
|
-
value="0"
|
|
36
|
-
/>
|
|
37
|
-
<span
|
|
38
|
-
class="absolute will-change transition-transform hidden bottom-[calc(100%+2px)] left-[calc(100%-13px)]"
|
|
18
|
+
<div
|
|
19
|
+
class="block w-full h-[1px] top-[7px] rounded-none bg-gray"
|
|
20
|
+
data-orientation="horizontal"
|
|
21
|
+
style="position: relative;"
|
|
39
22
|
>
|
|
40
|
-
<
|
|
41
|
-
class="
|
|
23
|
+
<div
|
|
24
|
+
class="block h-[1px] bg-blue"
|
|
25
|
+
data-orientation="horizontal"
|
|
26
|
+
style="position: relative; height: inherit; inset-inline-start: 0; width: 0%;"
|
|
27
|
+
/>
|
|
28
|
+
<div
|
|
29
|
+
class="group/thumb flex justify-center items-center w-[19px] h-[19px] rounded-[50%] bg-blue border-[2px] border-solid border-white outline-0 transition-shadow cursor-pointer"
|
|
30
|
+
data-index="0"
|
|
31
|
+
data-orientation="horizontal"
|
|
32
|
+
id="base-ui-:r1:"
|
|
33
|
+
role="slider"
|
|
34
|
+
style="position: absolute; inset-inline-start: 0%; top: 50%;"
|
|
42
35
|
>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
36
|
+
<span
|
|
37
|
+
class="absolute will-change transition-transform hidden bottom-[calc(100%+2px)] left-[calc(100%-13px)]"
|
|
38
|
+
>
|
|
39
|
+
<span
|
|
40
|
+
class="shadow-4 text-sm text-white bg-graphite m-1 rounded-sm py-[2px] px-2 max-w break-words"
|
|
41
|
+
>
|
|
42
|
+
0
|
|
43
|
+
</span>
|
|
44
|
+
</span>
|
|
45
|
+
<input
|
|
46
|
+
aria-orientation="horizontal"
|
|
47
|
+
aria-valuenow="0"
|
|
48
|
+
id="base-ui-:r3:"
|
|
49
|
+
max="100"
|
|
50
|
+
min="0"
|
|
51
|
+
step="1"
|
|
52
|
+
style="clip-path: inset(50%); overflow: hidden; white-space: nowrap; border: 0px; padding: 0px; width: 100%; height: 100%; margin: -1px; position: fixed; top: 0px; left: 0px;"
|
|
53
|
+
type="range"
|
|
54
|
+
value="0"
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
48
60
|
</div>
|
|
49
61
|
</div>
|
|
50
62
|
`;
|
|
@@ -52,48 +64,60 @@ exports[`Slider renders 1`] = `
|
|
|
52
64
|
exports[`Slider with initial value 1`] = `
|
|
53
65
|
<div>
|
|
54
66
|
<div
|
|
55
|
-
class="
|
|
67
|
+
class="mb-[4px] mt-[5px] mx-0 h-[15px]"
|
|
56
68
|
>
|
|
57
|
-
<
|
|
58
|
-
class="
|
|
69
|
+
<div
|
|
70
|
+
class="block cursor-pointer width-full relative"
|
|
71
|
+
data-orientation="horizontal"
|
|
72
|
+
id="base-ui-:r8:"
|
|
73
|
+
role="group"
|
|
59
74
|
>
|
|
60
|
-
<
|
|
61
|
-
class="
|
|
62
|
-
|
|
63
|
-
<span
|
|
64
|
-
class="base-Slider block absolute h-[1px] bg-blue"
|
|
65
|
-
style="left: 0%; width: 4%;"
|
|
66
|
-
/>
|
|
67
|
-
<span
|
|
68
|
-
class="base-Slider group/thumb flex justify-center items-center w-[15px] h-[15px] rounded-[50%] bg-blue border-[2px] border-solid border-white -mt -ml outline-0 absolute transition-shadow cursor-pointer"
|
|
69
|
-
data-index="0"
|
|
70
|
-
role="slider"
|
|
71
|
-
style="left: 4%;"
|
|
75
|
+
<div
|
|
76
|
+
class="block absolute inset-0 h-[15px]"
|
|
77
|
+
data-orientation="horizontal"
|
|
72
78
|
>
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
aria-valuenow="4"
|
|
78
|
-
data-index="0"
|
|
79
|
-
max="100"
|
|
80
|
-
min="0"
|
|
81
|
-
step="1"
|
|
82
|
-
style="border: 0px; height: 100%; margin: -1px; overflow: hidden; padding: 0px; position: absolute; white-space: nowrap; width: 100%; direction: ltr;"
|
|
83
|
-
type="range"
|
|
84
|
-
value="4"
|
|
85
|
-
/>
|
|
86
|
-
<span
|
|
87
|
-
class="absolute will-change transition-transform hidden bottom-[calc(100%+2px)] left-[calc(100%-13px)]"
|
|
79
|
+
<div
|
|
80
|
+
class="block w-full h-[1px] top-[7px] rounded-none bg-gray"
|
|
81
|
+
data-orientation="horizontal"
|
|
82
|
+
style="position: relative;"
|
|
88
83
|
>
|
|
89
|
-
<
|
|
90
|
-
class="
|
|
84
|
+
<div
|
|
85
|
+
class="block h-[1px] bg-blue"
|
|
86
|
+
data-orientation="horizontal"
|
|
87
|
+
style="position: relative; height: inherit; inset-inline-start: 0; width: 4%;"
|
|
88
|
+
/>
|
|
89
|
+
<div
|
|
90
|
+
class="group/thumb flex justify-center items-center w-[19px] h-[19px] rounded-[50%] bg-blue border-[2px] border-solid border-white outline-0 transition-shadow cursor-pointer"
|
|
91
|
+
data-index="0"
|
|
92
|
+
data-orientation="horizontal"
|
|
93
|
+
id="base-ui-:r9:"
|
|
94
|
+
role="slider"
|
|
95
|
+
style="position: absolute; inset-inline-start: 4%; top: 50%;"
|
|
91
96
|
>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
<span
|
|
98
|
+
class="absolute will-change transition-transform hidden bottom-[calc(100%+2px)] left-[calc(100%-13px)]"
|
|
99
|
+
>
|
|
100
|
+
<span
|
|
101
|
+
class="shadow-4 text-sm text-white bg-graphite m-1 rounded-sm py-[2px] px-2 max-w break-words"
|
|
102
|
+
>
|
|
103
|
+
4
|
|
104
|
+
</span>
|
|
105
|
+
</span>
|
|
106
|
+
<input
|
|
107
|
+
aria-orientation="horizontal"
|
|
108
|
+
aria-valuenow="4"
|
|
109
|
+
id="base-ui-:rb:"
|
|
110
|
+
max="100"
|
|
111
|
+
min="0"
|
|
112
|
+
step="1"
|
|
113
|
+
style="clip-path: inset(50%); overflow: hidden; white-space: nowrap; border: 0px; padding: 0px; width: 100%; height: 100%; margin: -1px; position: fixed; top: 0px; left: 0px;"
|
|
114
|
+
type="range"
|
|
115
|
+
value="4"
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
97
121
|
</div>
|
|
98
122
|
</div>
|
|
99
123
|
`;
|
|
@@ -17,7 +17,9 @@ const Example = () => {
|
|
|
17
17
|
<Slider value={value} onChange={handleChange} max={100} />
|
|
18
18
|
</Grid.Item>
|
|
19
19
|
<Grid.Item>
|
|
20
|
-
<Typography size='medium'>
|
|
20
|
+
<Typography size='medium' className='inline-block min-w-[2rem] text-right'>
|
|
21
|
+
{value}
|
|
22
|
+
</Typography>
|
|
21
23
|
</Grid.Item>
|
|
22
24
|
</Grid>
|
|
23
25
|
</Grid.Item>
|
|
@@ -5,7 +5,7 @@ import { getBgColor } from '../utils'
|
|
|
5
5
|
|
|
6
6
|
export type SliderMarkProps = {
|
|
7
7
|
markActive: boolean
|
|
8
|
-
|
|
8
|
+
value?: number
|
|
9
9
|
style: React.CSSProperties
|
|
10
10
|
'data-index': number
|
|
11
11
|
forceInactive: boolean
|
|
@@ -15,7 +15,7 @@ export type SliderMarkProps = {
|
|
|
15
15
|
// different bg color based on value of the Slider
|
|
16
16
|
const SliderMark = ({
|
|
17
17
|
markActive,
|
|
18
|
-
|
|
18
|
+
value,
|
|
19
19
|
'data-index': dataIndex,
|
|
20
20
|
style,
|
|
21
21
|
forceInactive,
|
|
@@ -25,8 +25,8 @@ const SliderMark = ({
|
|
|
25
25
|
data-index={dataIndex}
|
|
26
26
|
style={style}
|
|
27
27
|
className={twJoin(
|
|
28
|
-
'absolute w-[
|
|
29
|
-
getBgColor({ markActive, forceInactive, value
|
|
28
|
+
'absolute w-[9px] h-[9px] top-1/2 rounded-[50%] -translate-x-2/4 -translate-y-2/4 box-content',
|
|
29
|
+
getBgColor({ markActive, forceInactive, value })
|
|
30
30
|
)}
|
|
31
31
|
/>
|
|
32
32
|
)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { RefObject } from 'react'
|
|
1
|
+
import type { ReactNode, RefObject } from 'react'
|
|
3
2
|
import React, { useEffect, useRef, useState } from 'react'
|
|
4
3
|
import { twJoin } from '@toptal/picasso-tailwind-merge'
|
|
5
4
|
|
|
@@ -7,6 +6,17 @@ import { getXPlacement } from '../utils'
|
|
|
7
6
|
|
|
8
7
|
type ValueLabelDisplay = 'on' | 'auto' | 'off'
|
|
9
8
|
|
|
9
|
+
type SliderValueLabelProps = {
|
|
10
|
+
children?: ReactNode
|
|
11
|
+
index?: number
|
|
12
|
+
value: number
|
|
13
|
+
tooltip: ValueLabelDisplay
|
|
14
|
+
yPlacement: 'top' | 'bottom'
|
|
15
|
+
/** indicates if there are two SliderValueLabels that overlap each other */
|
|
16
|
+
isOverlaped: boolean
|
|
17
|
+
onRender: (index: number, ref: RefObject<HTMLSpanElement>) => void
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
const classesByTooltip: Record<ValueLabelDisplay, string> = {
|
|
11
21
|
off: 'hidden',
|
|
12
22
|
// We need to use visibility: hidden instead of display: none to keep the
|
|
@@ -29,18 +39,12 @@ const yPlacementClasses = {
|
|
|
29
39
|
const SliderValueLabel = ({
|
|
30
40
|
children,
|
|
31
41
|
index = -1,
|
|
42
|
+
value,
|
|
32
43
|
tooltip = 'off',
|
|
33
44
|
onRender,
|
|
34
45
|
yPlacement,
|
|
35
46
|
isOverlaped,
|
|
36
|
-
|
|
37
|
-
}: SliderValueLabelSlotProps & {
|
|
38
|
-
tooltip: ValueLabelDisplay
|
|
39
|
-
yPlacement: 'top' | 'bottom'
|
|
40
|
-
/** indicates if there are two SliderValueLabels that overlap each other */
|
|
41
|
-
isOverlaped: boolean
|
|
42
|
-
onRender: (index: number, ref: RefObject<HTMLSpanElement>) => void
|
|
43
|
-
}) => {
|
|
47
|
+
}: SliderValueLabelProps) => {
|
|
44
48
|
const ref = useRef<HTMLSpanElement>(null)
|
|
45
49
|
|
|
46
50
|
// we need to change the placement of the label if it is overlaped
|