etudes 0.28.0 → 0.32.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/lib/Slider.d.ts +4 -16
- package/lib/Slider.js +49 -74
- package/lib/Slider.js.map +1 -1
- package/lib/StepwiseSlider.d.ts +29 -0
- package/lib/StepwiseSlider.js +239 -0
- package/lib/StepwiseSlider.js.map +1 -0
- package/package.json +4 -2
package/lib/Slider.d.ts
CHANGED
|
@@ -1,36 +1,24 @@
|
|
|
1
1
|
import { CSSProperties } from 'react';
|
|
2
2
|
import { CSSProp } from 'styled-components';
|
|
3
3
|
import { Orientation } from './types';
|
|
4
|
-
export declare type GutterCSSProps = Readonly<{
|
|
5
|
-
orientation: Orientation;
|
|
6
|
-
}>;
|
|
7
|
-
export declare type LabelCSSProps = Readonly<{
|
|
8
|
-
knobHeight: number;
|
|
9
|
-
}>;
|
|
10
4
|
export declare type Props = {
|
|
11
5
|
id?: string;
|
|
12
6
|
className?: string;
|
|
13
7
|
style?: CSSProperties;
|
|
14
8
|
isInverted?: boolean;
|
|
15
9
|
onlyDispatchesOnDragEnd?: boolean;
|
|
16
|
-
|
|
17
|
-
labelProvider?: (position: number, index: number) => string;
|
|
10
|
+
labelProvider?: (position: number) => string;
|
|
18
11
|
gutterPadding?: number;
|
|
19
12
|
knobHeight?: number;
|
|
20
13
|
knobWidth?: number;
|
|
21
14
|
orientation?: Orientation;
|
|
22
|
-
|
|
15
|
+
position?: number;
|
|
16
|
+
onPositionChange?: (position: number, isDragging: boolean) => void;
|
|
23
17
|
onDragEnd?: () => void;
|
|
24
18
|
onDragStart?: () => void;
|
|
25
|
-
onPositionChange?: (position: number) => void;
|
|
26
19
|
startingGutterCSS?: CSSProp<any>;
|
|
27
20
|
endingGutterCSS?: CSSProp<any>;
|
|
28
21
|
knobCSS?: CSSProp<any>;
|
|
29
22
|
labelCSS?: CSSProp<any>;
|
|
30
|
-
breakpoints?: readonly number[];
|
|
31
|
-
autoSnap?: boolean;
|
|
32
|
-
defaultIndex?: number;
|
|
33
|
-
onIndexChange?: (index: number) => void;
|
|
34
23
|
};
|
|
35
|
-
export
|
|
36
|
-
export default function Slider({ id, className, style, isInverted, onlyDispatchesOnDragEnd, gutterPadding, knobHeight, knobWidth, orientation, defaultPosition, isLabelVisible, labelProvider, onDragEnd, onDragStart, onPositionChange, startingGutterCSS, endingGutterCSS, knobCSS, labelCSS, breakpoints, autoSnap, defaultIndex, onIndexChange, }: Props): JSX.Element;
|
|
24
|
+
export default function Slider({ id, className, style, isInverted, onlyDispatchesOnDragEnd, gutterPadding, knobHeight, knobWidth, orientation, position, labelProvider, onDragEnd, onDragStart, onPositionChange, startingGutterCSS, endingGutterCSS, knobCSS, labelCSS, }: Props): JSX.Element;
|
package/lib/Slider.js
CHANGED
|
@@ -53,64 +53,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
53
53
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
54
54
|
};
|
|
55
55
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
|
-
exports.generateBreakpoints = void 0;
|
|
57
56
|
var classnames_1 = __importDefault(require("classnames"));
|
|
58
57
|
var interactjs_1 = __importDefault(require("interactjs"));
|
|
59
58
|
var react_1 = __importStar(require("react"));
|
|
60
59
|
var spase_1 = require("spase");
|
|
61
60
|
var styled_components_1 = __importStar(require("styled-components"));
|
|
62
|
-
function
|
|
63
|
-
if (length <= 1)
|
|
64
|
-
throw new Error('`length` value must be greater than or equal to 2');
|
|
65
|
-
if (Math.round(length) !== length)
|
|
66
|
-
throw new Error('`length` value must be an integer');
|
|
67
|
-
var interval = 1 / (length - 1);
|
|
68
|
-
return Array(length).fill(null).map(function (v, i) {
|
|
69
|
-
var pos = interval * i;
|
|
70
|
-
return pos;
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
exports.generateBreakpoints = generateBreakpoints;
|
|
61
|
+
var debug = process.env.NODE_ENV === 'development' ? require('debug')('etudes:slider') : function () { };
|
|
74
62
|
function Slider(_a) {
|
|
75
|
-
var id = _a.id, className = _a.className, style = _a.style, _b = _a.isInverted, isInverted = _b === void 0 ? false : _b, _c = _a.onlyDispatchesOnDragEnd, onlyDispatchesOnDragEnd = _c === void 0 ? false : _c, _d = _a.gutterPadding, gutterPadding = _d === void 0 ? 0 : _d, _e = _a.knobHeight, knobHeight = _e === void 0 ? 30 : _e, _f = _a.knobWidth, knobWidth = _f === void 0 ? 30 : _f, _g = _a.orientation, orientation = _g === void 0 ? 'vertical' : _g, _h = _a.
|
|
76
|
-
function getPosition(natural) {
|
|
77
|
-
if (natural === void 0) { natural = false; }
|
|
78
|
-
if (natural)
|
|
79
|
-
return isInverted ? (1 - position.current) : position.current;
|
|
80
|
-
return position.current;
|
|
81
|
-
}
|
|
82
|
-
function setPosition(value) {
|
|
83
|
-
position.current = value;
|
|
84
|
-
if (onlyDispatchesOnDragEnd && isDragging)
|
|
85
|
-
return;
|
|
86
|
-
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(position.current);
|
|
87
|
-
if (breakpoints)
|
|
88
|
-
onIndexChange === null || onIndexChange === void 0 ? void 0 : onIndexChange(getClosestIndex());
|
|
89
|
-
}
|
|
90
|
-
function getClosestIndex() {
|
|
91
|
-
if (!breakpoints)
|
|
92
|
-
return -1;
|
|
93
|
-
var index = 0;
|
|
94
|
-
var minDelta = NaN;
|
|
95
|
-
for (var i = 0, n = breakpoints.length; i < n; i++) {
|
|
96
|
-
var breakpoint = getPositionByIndex(i);
|
|
97
|
-
var delta = Math.abs(getPosition() - breakpoint);
|
|
98
|
-
if (isNaN(minDelta) || (delta < minDelta)) {
|
|
99
|
-
minDelta = delta;
|
|
100
|
-
index = i;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return index;
|
|
104
|
-
}
|
|
105
|
-
function getPositionByIndex(index) {
|
|
106
|
-
if (!breakpoints)
|
|
107
|
-
return NaN;
|
|
108
|
-
return breakpoints[index];
|
|
109
|
-
}
|
|
63
|
+
var id = _a.id, className = _a.className, style = _a.style, _b = _a.isInverted, isInverted = _b === void 0 ? false : _b, _c = _a.onlyDispatchesOnDragEnd, onlyDispatchesOnDragEnd = _c === void 0 ? false : _c, _d = _a.gutterPadding, gutterPadding = _d === void 0 ? 0 : _d, _e = _a.knobHeight, knobHeight = _e === void 0 ? 30 : _e, _f = _a.knobWidth, knobWidth = _f === void 0 ? 30 : _f, _g = _a.orientation, orientation = _g === void 0 ? 'vertical' : _g, _h = _a.position, position = _h === void 0 ? 0 : _h, labelProvider = _a.labelProvider, onDragEnd = _a.onDragEnd, onDragStart = _a.onDragStart, onPositionChange = _a.onPositionChange, startingGutterCSS = _a.startingGutterCSS, endingGutterCSS = _a.endingGutterCSS, knobCSS = _a.knobCSS, labelCSS = _a.labelCSS;
|
|
110
64
|
function initInteractivity() {
|
|
111
65
|
var knob = knobRef.current;
|
|
112
66
|
if (!knob || interactjs_1.default.isSet(knob))
|
|
113
67
|
return;
|
|
68
|
+
debug('Initializing interactivity...', 'OK');
|
|
114
69
|
(0, interactjs_1.default)(knob).draggable({
|
|
115
70
|
inertia: true,
|
|
116
71
|
onstart: function () { return onKnobDragStart(); },
|
|
@@ -123,40 +78,44 @@ function Slider(_a) {
|
|
|
123
78
|
}
|
|
124
79
|
function deinitInteractivity() {
|
|
125
80
|
var knob = knobRef.current;
|
|
126
|
-
if (!knob)
|
|
81
|
+
if (!knob || !interactjs_1.default.isSet(knob))
|
|
127
82
|
return;
|
|
83
|
+
debug('Deinitializing interactivity...', 'OK');
|
|
128
84
|
(0, interactjs_1.default)(knob).unset();
|
|
129
85
|
}
|
|
130
86
|
function onKnobDragStart() {
|
|
87
|
+
debug('Handling drag start...', 'OK');
|
|
131
88
|
setIsDragging(true);
|
|
132
89
|
onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart();
|
|
133
90
|
}
|
|
134
91
|
function onKnobDragMove(delta) {
|
|
135
92
|
var _a;
|
|
136
93
|
var rect = (_a = spase_1.Rect.from(rootRef.current)) !== null && _a !== void 0 ? _a : new spase_1.Rect();
|
|
137
|
-
var naturalPosition =
|
|
94
|
+
var naturalPosition = isInverted ? 1 - livePosition.current : livePosition.current;
|
|
138
95
|
var naturalNewPositionX = naturalPosition * rect.width + delta;
|
|
139
96
|
var naturalNewPositionY = naturalPosition * rect.height + delta;
|
|
140
97
|
var naturalNewPosition = (orientation === 'vertical') ? Math.max(0, Math.min(1, naturalNewPositionY / rect.height)) : Math.max(0, Math.min(1, naturalNewPositionX / rect.width));
|
|
141
|
-
var newPosition = isInverted ?
|
|
98
|
+
var newPosition = isInverted ? 1 - naturalNewPosition : naturalNewPosition;
|
|
142
99
|
setIsDragging(true);
|
|
143
|
-
|
|
100
|
+
setLivePosition(newPosition);
|
|
144
101
|
}
|
|
145
102
|
function onKnobDragStop() {
|
|
103
|
+
debug('Handling drag stop...', 'OK');
|
|
146
104
|
setIsDragging(false);
|
|
147
|
-
snapToClosestBreakpointIfNeeded();
|
|
148
105
|
onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd();
|
|
149
106
|
}
|
|
150
|
-
function
|
|
151
|
-
if (
|
|
107
|
+
function setLivePosition(position) {
|
|
108
|
+
if (livePosition.current === position)
|
|
152
109
|
return;
|
|
153
|
-
|
|
154
|
-
|
|
110
|
+
livePosition.current = position;
|
|
111
|
+
_setPosition(position);
|
|
155
112
|
}
|
|
156
113
|
var rootRef = (0, react_1.useRef)(null);
|
|
157
114
|
var knobRef = (0, react_1.useRef)(null);
|
|
158
|
-
var
|
|
159
|
-
var
|
|
115
|
+
var livePosition = (0, react_1.useRef)(position);
|
|
116
|
+
var _j = __read((0, react_1.useState)(livePosition.current), 2), _position = _j[0], _setPosition = _j[1];
|
|
117
|
+
var _k = __read((0, react_1.useState)(undefined), 2), isDragging = _k[0], setIsDragging = _k[1];
|
|
118
|
+
var naturalPosition = isInverted ? 1 - _position : _position;
|
|
160
119
|
(0, react_1.useEffect)(function () {
|
|
161
120
|
initInteractivity();
|
|
162
121
|
return function () {
|
|
@@ -164,45 +123,61 @@ function Slider(_a) {
|
|
|
164
123
|
};
|
|
165
124
|
}, []);
|
|
166
125
|
(0, react_1.useEffect)(function () {
|
|
167
|
-
|
|
168
|
-
|
|
126
|
+
if (isDragging === true)
|
|
127
|
+
return;
|
|
128
|
+
if (position === _position)
|
|
129
|
+
return;
|
|
130
|
+
setIsDragging(undefined);
|
|
131
|
+
setLivePosition(position);
|
|
132
|
+
}, [position]);
|
|
133
|
+
(0, react_1.useEffect)(function () {
|
|
134
|
+
if (isDragging === true && onlyDispatchesOnDragEnd)
|
|
135
|
+
return;
|
|
136
|
+
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(_position, isDragging === true);
|
|
137
|
+
}, [_position]);
|
|
138
|
+
(0, react_1.useEffect)(function () {
|
|
139
|
+
if (isDragging === false && onlyDispatchesOnDragEnd) {
|
|
140
|
+
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(_position, false);
|
|
141
|
+
}
|
|
142
|
+
}, [isDragging]);
|
|
169
143
|
return (react_1.default.createElement(StyledRoot, { ref: rootRef, id: id, className: className, orientation: orientation, style: style },
|
|
170
144
|
react_1.default.createElement(StyledGutter, { orientation: orientation, css: startingGutterCSS, style: orientation === 'vertical' ? {
|
|
171
145
|
top: 0,
|
|
172
|
-
height: "calc(".concat(
|
|
146
|
+
height: "calc(".concat(naturalPosition * 100, "% - ").concat(knobHeight * .5, "px - ").concat(gutterPadding, "px)"),
|
|
173
147
|
} : {
|
|
174
148
|
left: 0,
|
|
175
|
-
width: "calc(".concat(
|
|
149
|
+
width: "calc(".concat(naturalPosition * 100, "% - ").concat(knobWidth * .5, "px - ").concat(gutterPadding, "px)"),
|
|
176
150
|
} }),
|
|
177
151
|
react_1.default.createElement(StyledKnobContainer, { ref: knobRef, style: __assign({ transform: 'translate3d(-50%, -50%, 0)' }, (orientation === 'vertical' ? {
|
|
178
|
-
|
|
152
|
+
left: '50%',
|
|
153
|
+
top: "".concat(naturalPosition * 100, "%"),
|
|
179
154
|
transition: isDragging === false ? 'top 100ms ease-out' : 'none',
|
|
180
155
|
} : {
|
|
181
|
-
left: "".concat(
|
|
156
|
+
left: "".concat(naturalPosition * 100, "%"),
|
|
157
|
+
top: '50%',
|
|
182
158
|
transition: isDragging === false ? 'left 100ms ease-out' : 'none',
|
|
183
159
|
})) },
|
|
184
160
|
react_1.default.createElement(StyledKnob, { className: (0, classnames_1.default)({
|
|
185
|
-
'at-end': isInverted ? (
|
|
186
|
-
'at-start': isInverted ? (
|
|
161
|
+
'at-end': isInverted ? (_position === 0) : (_position === 1),
|
|
162
|
+
'at-start': isInverted ? (_position === 1) : (_position === 0),
|
|
187
163
|
'dragging': isDragging === true,
|
|
188
|
-
'idle': isDragging === false,
|
|
189
164
|
}), css: knobCSS, style: {
|
|
190
165
|
height: "".concat(knobHeight, "px"),
|
|
191
166
|
width: "".concat(knobWidth, "px"),
|
|
192
|
-
} },
|
|
167
|
+
} }, labelProvider && (react_1.default.createElement(StyledLabel, { knobHeight: knobHeight, css: labelCSS }, labelProvider(_position))))),
|
|
193
168
|
react_1.default.createElement(StyledGutter, { orientation: orientation, css: endingGutterCSS, style: orientation === 'vertical' ? {
|
|
194
169
|
bottom: 0,
|
|
195
|
-
height: "calc(".concat((1 -
|
|
170
|
+
height: "calc(".concat((1 - naturalPosition) * 100, "% - ").concat(knobHeight * .5, "px - ").concat(gutterPadding, "px)"),
|
|
196
171
|
} : {
|
|
197
172
|
right: 0,
|
|
198
|
-
width: "calc(".concat((1 -
|
|
173
|
+
width: "calc(".concat((1 - naturalPosition) * 100, "% - ").concat(knobWidth * .5, "px - ").concat(gutterPadding, "px)"),
|
|
199
174
|
} })));
|
|
200
175
|
}
|
|
201
176
|
exports.default = Slider;
|
|
202
|
-
var StyledGutter = styled_components_1.default.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n background: #fff;\n position: absolute;\n\n ", "\n"], ["\n background: #fff;\n position: absolute;\n\n ", "\n"])), function (props) { return props.orientation === 'vertical' ? (0, styled_components_1.css)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n left: 0;\n margin: 0 auto;\n right: 0;\n width: 100%;\n "], ["\n left: 0;\n margin: 0 auto;\n right: 0;\n width: 100%;\n "]))) : (0, styled_components_1.css)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n bottom: 0;\n height: 100%;\n margin: auto 0;\n top: 0;\n "], ["\n bottom: 0;\n height: 100%;\n margin: auto 0;\n top: 0;\n "]))); });
|
|
203
|
-
var StyledLabel = styled_components_1.default.label(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n color: #000;\n font-size: ", "px;\n pointer-events: none;\n user-select: none;\n"], ["\n color: #000;\n font-size: ", "px;\n pointer-events: none;\n user-select: none;\n"])), function (props) { return props.knobHeight * .5; });
|
|
177
|
+
var StyledGutter = styled_components_1.default.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n background: #fff;\n position: absolute;\n\n ", "\n\n ", "\n"], ["\n background: #fff;\n position: absolute;\n\n ", "\n\n ", "\n"])), function (props) { return props.orientation === 'vertical' ? (0, styled_components_1.css)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n left: 0;\n margin: 0 auto;\n right: 0;\n width: 100%;\n "], ["\n left: 0;\n margin: 0 auto;\n right: 0;\n width: 100%;\n "]))) : (0, styled_components_1.css)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n bottom: 0;\n height: 100%;\n margin: auto 0;\n top: 0;\n "], ["\n bottom: 0;\n height: 100%;\n margin: auto 0;\n top: 0;\n "]))); }, function (props) { return props.css; });
|
|
178
|
+
var StyledLabel = styled_components_1.default.label(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n color: #000;\n font-size: ", "px;\n pointer-events: none;\n user-select: none;\n\n ", "\n"], ["\n color: #000;\n font-size: ", "px;\n pointer-events: none;\n user-select: none;\n\n ", "\n"])), function (props) { return props.knobHeight * .5; }, function (props) { return props.css; });
|
|
204
179
|
var StyledKnobContainer = styled_components_1.default.button(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n position: absolute;\n z-index: 1;\n transition-duration: 100ms;\n transition-property: top;\n transition-timing-function: ease-out;\n"], ["\n position: absolute;\n z-index: 1;\n transition-duration: 100ms;\n transition-property: top;\n transition-timing-function: ease-out;\n"])));
|
|
205
|
-
var StyledKnob = styled_components_1.default.div(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n align-items: center;\n background: #fff;\n box-sizing: border-box;\n
|
|
180
|
+
var StyledKnob = styled_components_1.default.div(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n align-items: center;\n background: #fff;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n justify-content: center;\n touch-action: none;\n transition-duration: 100ms;\n transition-property: background, color, opacity, transform;\n transition-timing-function: ease-out;\n\n ", "\n"], ["\n align-items: center;\n background: #fff;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n justify-content: center;\n touch-action: none;\n transition-duration: 100ms;\n transition-property: background, color, opacity, transform;\n transition-timing-function: ease-out;\n\n ", "\n"])), function (props) { return props.css; });
|
|
206
181
|
var StyledRoot = styled_components_1.default.div(templateObject_7 || (templateObject_7 = __makeTemplateObject(["\n box-sizing: border-box;\n display: block;\n height: ", ";\n position: relative;\n width: ", ";\n"], ["\n box-sizing: border-box;\n display: block;\n height: ", ";\n position: relative;\n width: ", ";\n"])), function (props) { return props.orientation === 'vertical' ? '300px' : '4px'; }, function (props) { return props.orientation === 'vertical' ? '4px' : '300px'; });
|
|
207
182
|
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7;
|
|
208
183
|
//# sourceMappingURL=Slider.js.map
|
package/lib/Slider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Slider.js","sourceRoot":"/","sources":["Slider.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,0DAAmC;AACnC,0DAAiC;AACjC,6CAAyE;AACzE,+BAA4B;AAC5B,qEAAwD;AAgKxD,SAAgB,mBAAmB,CAAC,MAAc;IAChD,IAAI,MAAM,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACrF,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;IAEvF,IAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAEjC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,UAAC,CAAC,EAAE,CAAC;QACvC,IAAM,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAA;QACxB,OAAO,GAAG,CAAA;IACZ,CAAC,CAAC,CAAA;AACJ,CAAC;AAVD,kDAUC;AAaD,SAAwB,MAAM,CAAC,EAwBvB;QAvBN,EAAE,QAAA,EACF,SAAS,eAAA,EACT,KAAK,WAAA,EACL,kBAAkB,EAAlB,UAAU,mBAAG,KAAK,KAAA,EAClB,+BAA+B,EAA/B,uBAAuB,mBAAG,KAAK,KAAA,EAC/B,qBAAiB,EAAjB,aAAa,mBAAG,CAAC,KAAA,EACjB,kBAAe,EAAf,UAAU,mBAAG,EAAE,KAAA,EACf,iBAAc,EAAd,SAAS,mBAAG,EAAE,KAAA,EACd,mBAAwB,EAAxB,WAAW,mBAAG,UAAU,KAAA,EACxB,uBAAmB,EAAnB,eAAe,mBAAG,CAAC,KAAA,EACnB,sBAAqB,EAArB,cAAc,mBAAG,IAAI,KAAA,EACrB,aAAa,mBAAA,EACb,SAAS,eAAA,EACT,WAAW,iBAAA,EACX,gBAAgB,sBAAA,EAChB,iBAAiB,uBAAA,EACjB,eAAe,qBAAA,EACf,OAAO,aAAA,EACP,QAAQ,cAAA,EACR,WAAW,iBAAA,EACX,gBAAe,EAAf,QAAQ,mBAAG,IAAI,KAAA,EACf,YAAY,kBAAA,EACZ,aAAa,mBAAA;IAWb,SAAS,WAAW,CAAC,OAAe;QAAf,wBAAA,EAAA,eAAe;QAClC,IAAI,OAAO;YAAE,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAA;QAC1E,OAAO,QAAQ,CAAC,OAAO,CAAA;IACzB,CAAC;IAQD,SAAS,WAAW,CAAC,KAAa;QAChC,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAA;QAExB,IAAI,uBAAuB,IAAI,UAAU;YAAE,OAAM;QACjD,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAG,QAAQ,CAAC,OAAO,CAAC,CAAA;QACpC,IAAI,WAAW;YAAE,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAG,eAAe,EAAE,CAAC,CAAA;IACrD,CAAC;IAQD,SAAS,eAAe;QACtB,IAAI,CAAC,WAAW;YAAE,OAAO,CAAC,CAAC,CAAA;QAE3B,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,IAAI,QAAQ,GAAG,GAAG,CAAA;QAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YAClD,IAAM,UAAU,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAA;YACxC,IAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,CAAA;YAElD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,EAAE;gBACzC,QAAQ,GAAG,KAAK,CAAA;gBAChB,KAAK,GAAG,CAAC,CAAA;aACV;SACF;QAED,OAAO,KAAK,CAAA;IACd,CAAC;IAUD,SAAS,kBAAkB,CAAC,KAAa;QACvC,IAAI,CAAC,WAAW;YAAE,OAAO,GAAG,CAAA;QAC5B,OAAO,WAAW,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC;IAKD,SAAS,iBAAiB;QACxB,IAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAA;QAC5B,IAAI,CAAC,IAAI,IAAI,oBAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAM;QAEzC,IAAA,oBAAQ,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC;YACvB,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,cAAM,OAAA,eAAe,EAAE,EAAjB,CAAiB;YAChC,MAAM,EAAE,UAAC,EAAU;oBAAR,EAAE,QAAA,EAAE,EAAE,QAAA;gBAAO,OAAA,cAAc,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAApD,CAAoD;YAC5E,KAAK,EAAE,cAAM,OAAA,cAAc,EAAE,EAAhB,CAAgB;SAC9B,CAAC,CAAA;IACJ,CAAC;IAKD,SAAS,mBAAmB;QAC1B,IAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAA;QAC5B,IAAI,CAAC,IAAI;YAAE,OAAM;QAEjB,IAAA,oBAAQ,EAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC;IAKD,SAAS,eAAe;QACtB,aAAa,CAAC,IAAI,CAAC,CAAA;QAEnB,WAAW,aAAX,WAAW,uBAAX,WAAW,EAAI,CAAA;IACjB,CAAC;IAOD,SAAS,cAAc,CAAC,KAAa;;QACnC,IAAM,IAAI,GAAG,MAAA,YAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,mCAAI,IAAI,YAAI,EAAE,CAAA;QACrD,IAAM,eAAe,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;QACzC,IAAM,mBAAmB,GAAG,eAAe,GAAG,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAChE,IAAM,mBAAmB,GAAG,eAAe,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;QACjE,IAAM,kBAAkB,GAAG,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;QAClL,IAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAA;QAE9E,aAAa,CAAC,IAAI,CAAC,CAAA;QACnB,WAAW,CAAC,WAAW,CAAC,CAAA;IAC1B,CAAC;IAKD,SAAS,cAAc;QACrB,aAAa,CAAC,KAAK,CAAC,CAAA;QACpB,+BAA+B,EAAE,CAAA;QAEjC,SAAS,aAAT,SAAS,uBAAT,SAAS,EAAI,CAAA;IACf,CAAC;IAMD,SAAS,+BAA+B;QACtC,IAAI,CAAC,QAAQ,IAAI,CAAC,WAAW;YAAE,OAAM;QACrC,IAAM,QAAQ,GAAG,kBAAkB,CAAC,eAAe,EAAE,CAAC,CAAA;QACtD,WAAW,CAAC,QAAQ,CAAC,CAAA;IACvB,CAAC;IAED,IAAM,OAAO,GAAG,IAAA,cAAM,EAAiB,IAAI,CAAC,CAAA;IAC5C,IAAM,OAAO,GAAG,IAAA,cAAM,EAAoB,IAAI,CAAC,CAAA;IAC/C,IAAM,QAAQ,GAAG,IAAA,cAAM,EAAC,CAAC,CAAC,WAAW,KAAK,SAAS,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAA;IAErI,IAAA,KAAA,OAA8B,IAAA,gBAAQ,EAAsB,SAAS,CAAC,IAAA,EAArE,UAAU,QAAA,EAAE,aAAa,QAA4C,CAAA;IAE5E,IAAA,iBAAS,EAAC;QACR,iBAAiB,EAAE,CAAA;QAEnB,OAAO;YACL,mBAAmB,EAAE,CAAA;QACvB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,IAAA,iBAAS,EAAC;QACR,+BAA+B,EAAE,CAAA;IACnC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,OAAO,CACL,8BAAC,UAAU,IAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;QAC5F,8BAAC,YAAY,IAAC,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,iBAAiB,EAC5D,KAAK,EAAE,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC;gBAClC,GAAG,EAAE,CAAC;gBACN,MAAM,EAAE,eAAQ,WAAW,CAAC,IAAI,CAAC,GAAC,GAAG,iBAAO,UAAU,GAAC,EAAE,kBAAQ,aAAa,QAAK;aACpF,CAAC,CAAC,CAAC;gBACF,IAAI,EAAE,CAAC;gBACP,KAAK,EAAE,eAAQ,WAAW,CAAC,IAAI,CAAC,GAAC,GAAG,iBAAO,SAAS,GAAC,EAAE,kBAAQ,aAAa,QAAK;aAClF,GACD;QACF,8BAAC,mBAAmB,IAAC,GAAG,EAAE,OAAO,EAAE,KAAK,aACtC,SAAS,EAAE,4BAA4B,IACpC,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC;gBAC/B,GAAG,EAAE,UAAG,QAAQ,CAAC,OAAO,GAAG,GAAG,MAAG;gBACjC,UAAU,EAAE,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,MAAM;aACjE,CAAC,CAAC,CAAC;gBACF,IAAI,EAAE,UAAG,QAAQ,CAAC,OAAO,GAAG,GAAG,MAAG;gBAClC,UAAU,EAAE,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,MAAM;aAClE,CAAC;YAEF,8BAAC,UAAU,IACT,SAAS,EAAE,IAAA,oBAAU,EAAC;oBACpB,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,KAAK,CAAC,CAAC;oBAC1E,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,KAAK,CAAC,CAAC;oBAC5E,UAAU,EAAE,UAAU,KAAK,IAAI;oBAC/B,MAAM,EAAE,UAAU,KAAK,KAAK;iBAC7B,CAAC,EACF,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE;oBACL,MAAM,EAAE,UAAG,UAAU,OAAI;oBACzB,KAAK,EAAE,UAAG,SAAS,OAAI;iBACxB,IAEA,WAAW,IAAI,cAAc,IAAI,aAAa,IAAI,CACjD,8BAAC,WAAW,IAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,IAAG,aAAa,CAAC,WAAW,EAAE,EAAE,eAAe,EAAE,CAAC,CAAe,CACpH,CACU,CACO;QACtB,8BAAC,YAAY,IAAC,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,eAAe,EAC1D,KAAK,EAAE,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC;gBAClC,MAAM,EAAE,CAAC;gBACT,MAAM,EAAE,eAAQ,CAAC,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,GAAC,GAAG,iBAAO,UAAU,GAAC,EAAE,kBAAQ,aAAa,QAAK;aAC1F,CAAC,CAAC,CAAC;gBACF,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE,eAAQ,CAAC,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,GAAC,GAAG,iBAAO,SAAS,GAAC,EAAE,kBAAQ,aAAa,QAAK;aACxF,GACD,CACS,CACd,CAAA;AACH,CAAC;AAtOD,yBAsOC;AAED,IAAM,YAAY,GAAG,2BAAM,CAAC,GAAG,6HAAgB,oDAI3C,EAUD,IACF,KAXG,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,KAAC,uBAAG,8IAAA,0EAKhD,KAAC,CAAC,KAAC,uBAAG,+IAAA,2EAKN,IAAA,EAVU,CAUV,CACF,CAAA;AAED,IAAM,WAAW,GAAG,2BAAM,CAAC,KAAK,4JAAe,iCAEhC,EAA8B,sDAG5C,KAHc,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,UAAU,GAAG,EAAE,EAArB,CAAqB,CAG5C,CAAA;AAED,IAAM,mBAAmB,GAAG,2BAAM,CAAC,MAAM,kNAAA,+IAMxC,IAAA,CAAA;AAED,IAAM,UAAU,GAAG,2BAAM,CAAC,GAAG,gnBAAA,6iBAuB5B,IAAA,CAAA;AAED,IAAM,UAAU,GAAG,2BAAM,CAAC,GAAG,6KAE3B,4DAGU,EAA2D,qCAE5D,EAA2D,KACrE,KAHW,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAlD,CAAkD,EAE5D,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAlD,CAAkD,CACrE,CAAA","sourcesContent":["import classNames from 'classnames'\nimport interact from 'interactjs'\nimport React, { CSSProperties, useEffect, useRef, useState } from 'react'\nimport { Rect } from 'spase'\nimport styled, { css, CSSProp } from 'styled-components'\nimport { Orientation } from './types'\n\nexport type GutterCSSProps = Readonly<{\n orientation: Orientation\n}>\n\nexport type LabelCSSProps = Readonly<{\n knobHeight: number\n}>\n\nexport type Props = {\n /**\n * ID attribute of the root element.\n */\n id?: string\n\n /**\n * Class attribute of the root element.\n */\n className?: string\n\n /**\n * Inline style attribute of the root element.\n */\n style?: CSSProperties\n\n /**\n * By default the position is a value from 0 - 1, 0 being the start of the slider and 1 being the\n * end. Switching on this flag inverts this behavior, where 0 becomes the end of the slider and 1\n * being the start.\n */\n isInverted?: boolean\n\n /**\n * Indicates if position/index change events are dispatched only when dragging ends. When\n * disabled, aforementioned events are fired repeatedly while dragging.\n */\n onlyDispatchesOnDragEnd?: boolean\n\n /**\n * Indicates if the label is visible by the knob. Note that this is only applicable if\n * `labelProvider` is set.\n */\n isLabelVisible?: boolean\n\n /**\n * A function that returns the label to be displayed (if `isLabelVisible` is `true`) at a given\n * slider position and cloest breakpoint index (if breakpoints are provided).\n *\n * @param position - The current slider position.\n * @praam index - The nearest breakpoint index (if breakpoints are provided), or -1 if no\n * breakpoints are provided.\n *\n * @returns The label.\n */\n labelProvider?: (position: number, index: number) => string\n\n /**\n * Padding between the gutter and the knob in pixels.\n */\n gutterPadding?: number\n\n /**\n * Height of the knob in pixels.\n */\n knobHeight?: number\n\n /**\n * Width of the knob in pixels.\n */\n knobWidth?: number\n\n /**\n * Orientation of the slider.\n */\n orientation?: Orientation\n\n /**\n * The default position. This is ignored if `defaultIndex` and breakpoints are provided.\n */\n defaultPosition?: number\n\n /**\n * Handler invoked when dragging ends.\n */\n onDragEnd?: () => void\n\n /**\n * Handler invoked when dragging begins.\n */\n onDragStart?: () => void\n\n /**\n * Handler invoked when position changes.\n *\n * @param position - The current slider position.\n */\n onPositionChange?: (position: number) => void\n\n /**\n * Custom CSS provided to the gutter before the knob.\n */\n startingGutterCSS?: CSSProp<any>\n\n /**\n * Custom CSS provided to the gutter after the knob.\n */\n endingGutterCSS?: CSSProp<any>\n\n /**\n * Custom CSS provided to the knob.\n */\n knobCSS?: CSSProp<any>\n\n /**\n * Custom CSS provided to the label inside the knob.\n */\n labelCSS?: CSSProp<any>\n\n // The following props are only used if `breakpoints` are provided.\n\n /**\n * An array of breakpoint descriptors. A breakpoint is a position (0 - 1 inclusive) on the gutter\n * where the knob should snap to if dragging stops near it. If breakpoints are to be specified,\n * ensure that there are at least two: one for the start of the gutter and one for the end.\n */\n breakpoints?: readonly number[]\n\n /**\n * Indicates whether the knob automatically snaps to the nearest breakpoint, if breakpoints are\n * provided.\n */\n autoSnap?: boolean\n\n /**\n * The default index. This is only used if breakpoints are provided. On the other hand, if\n * breakpoints are provided, the default position will be calculated based on this value, making\n * `defaultPosition` irrelevant.\n */\n defaultIndex?: number\n\n /**\n * Handler invoked when index changes. This happens simultaneously with `onPositionChange`. Note\n * that this is only invoked if breakpoints are provided, because otherwise there will be no\n * indexes.\n *\n * @param index - The current breakpoint index.\n */\n onIndexChange?: (index: number) => void\n}\n\n/**\n * Generates a set of breakpoints compatible with this component.\n *\n * @param length - The number of breakpoints. This must be at least 2 because you must include the\n * starting and ending points.\n *\n * @returns An array of breakpoints.\n */\nexport function generateBreakpoints(length: number): readonly number[] {\n if (length <= 1) throw new Error('`length` value must be greater than or equal to 2')\n if (Math.round(length) !== length) throw new Error('`length` value must be an integer')\n\n const interval = 1 / (length - 1)\n\n return Array(length).fill(null).map((v, i) => {\n const pos = interval * i\n return pos\n })\n}\n\n/**\n * A slider component that divides the scroll gutter into two different elements—one that is before\n * the knob and one that is after the knob. This allows for individual styling customizations. The\n * width and height of the root element of this component is taken from the aggregated rect of both\n * gutter parts. The dimension of the knob itself does not impact that of the root element. In\n * addition to the tranditional behavior of a scrollbar, this component allows you to provide\n * breakpoints along the gutter so the knob can automatically snap to them (if feature is enabled)\n * when dragging ends near the breakpoint positions. You can also supply a label to each breakpoint\n * and have it display on the knob when the current position is close to the breakpoint. This\n * component supports both horizontal and vertical orientations.\n */\nexport default function Slider({\n id,\n className,\n style,\n isInverted = false,\n onlyDispatchesOnDragEnd = false,\n gutterPadding = 0,\n knobHeight = 30,\n knobWidth = 30,\n orientation = 'vertical',\n defaultPosition = 0,\n isLabelVisible = true,\n labelProvider,\n onDragEnd,\n onDragStart,\n onPositionChange,\n startingGutterCSS,\n endingGutterCSS,\n knobCSS,\n labelCSS,\n breakpoints,\n autoSnap = true,\n defaultIndex,\n onIndexChange,\n}: Props) {\n /**\n * Gets the current position. If `natural` is `true`, the uninverted (if `isInverted` is set to\n * `true`) position will be returned.\n *\n * @param natural - Specifies if the natural position should be returned in case `isInverted` is\n * specified.\n *\n * @returns The current position.\n */\n function getPosition(natural = false): number {\n if (natural) return isInverted ? (1 - position.current) : position.current\n return position.current\n }\n\n /**\n * Sets the current position. The position should be normalized. That is, inversion should be\n * taken care of prior to passing the new value to this method if `isInverted` is `true`.\n *\n * @param value - The value to set the position to.\n */\n function setPosition(value: number) {\n position.current = value\n\n if (onlyDispatchesOnDragEnd && isDragging) return\n onPositionChange?.(position.current)\n if (breakpoints) onIndexChange?.(getClosestIndex())\n }\n\n /**\n * Gets the index of the breakpoint of which the current position is closest to. If for whatever\n * reason the index cannot be computed (i.e. no breakpoints were provided), -1 is returned.\n *\n * @returns The closest index.\n */\n function getClosestIndex(): number {\n if (!breakpoints) return -1\n\n let index = 0\n let minDelta = NaN\n\n for (let i = 0, n = breakpoints.length; i < n; i++) {\n const breakpoint = getPositionByIndex(i)\n const delta = Math.abs(getPosition() - breakpoint)\n\n if (isNaN(minDelta) || (delta < minDelta)) {\n minDelta = delta\n index = i\n }\n }\n\n return index\n }\n\n /**\n * Gets the position by breakpoint index. This value ranges between 0 - 1, inclusive.\n *\n * @param index - The breakpoint index.\n *\n * @returns The position. If for whatever reason the position cannot be determined, NaN is\n * returned.\n */\n function getPositionByIndex(index: number): number {\n if (!breakpoints) return NaN\n return breakpoints[index]\n }\n\n /**\n * Initializes input interactivity of the knob.\n */\n function initInteractivity() {\n const knob = knobRef.current\n if (!knob || interact.isSet(knob)) return\n\n interact(knob).draggable({\n inertia: true,\n onstart: () => onKnobDragStart(),\n onmove: ({ dx, dy }) => onKnobDragMove(orientation === 'vertical' ? dy : dx),\n onend: () => onKnobDragStop(),\n })\n }\n\n /**\n * Deinitializes input interactivity of the knob.\n */\n function deinitInteractivity() {\n const knob = knobRef.current\n if (!knob) return\n\n interact(knob).unset()\n }\n\n /**\n * Handler invoked when the knob starts dragging.\n */\n function onKnobDragStart() {\n setIsDragging(true)\n\n onDragStart?.()\n }\n\n /**\n * Handler invoked when the knob moves.\n *\n * @param delta - The distance traveled (in pixels) since the last invocation of this handler.\n */\n function onKnobDragMove(delta: number) {\n const rect = Rect.from(rootRef.current) ?? new Rect()\n const naturalPosition = getPosition(true)\n const naturalNewPositionX = naturalPosition * rect.width + delta\n const naturalNewPositionY = naturalPosition * rect.height + delta\n const naturalNewPosition = (orientation === 'vertical') ? Math.max(0, Math.min(1, naturalNewPositionY / rect.height)) : Math.max(0, Math.min(1, naturalNewPositionX / rect.width))\n const newPosition = isInverted ? (1 - naturalNewPosition) : naturalNewPosition\n\n setIsDragging(true)\n setPosition(newPosition)\n }\n\n /**\n * Handler invoked when the knob stops dragging.\n */\n function onKnobDragStop() {\n setIsDragging(false)\n snapToClosestBreakpointIfNeeded()\n\n onDragEnd?.()\n }\n\n /**\n * Snaps the knob to the closest breakpoint. Note that if there are no breakpoints or\n * auto-snapping feature is disabled, this method does nothing.\n */\n function snapToClosestBreakpointIfNeeded() {\n if (!autoSnap || !breakpoints) return\n const position = getPositionByIndex(getClosestIndex())\n setPosition(position)\n }\n\n const rootRef = useRef<HTMLDivElement>(null)\n const knobRef = useRef<HTMLButtonElement>(null)\n const position = useRef(((breakpoints !== undefined) && (defaultIndex !== undefined)) ? getPositionByIndex(defaultIndex) : defaultPosition)\n\n const [isDragging, setIsDragging] = useState<boolean | undefined>(undefined)\n\n useEffect(() => {\n initInteractivity()\n\n return () => {\n deinitInteractivity()\n }\n }, [])\n\n useEffect(() => {\n snapToClosestBreakpointIfNeeded()\n }, [autoSnap])\n\n return (\n <StyledRoot ref={rootRef} id={id} className={className} orientation={orientation} style={style}>\n <StyledGutter orientation={orientation} css={startingGutterCSS}\n style={orientation === 'vertical' ? {\n top: 0,\n height: `calc(${getPosition(true)*100}% - ${knobHeight*.5}px - ${gutterPadding}px)`,\n } : {\n left: 0,\n width: `calc(${getPosition(true)*100}% - ${knobWidth*.5}px - ${gutterPadding}px)`,\n }}\n />\n <StyledKnobContainer ref={knobRef} style={{\n transform: 'translate3d(-50%, -50%, 0)',\n ...(orientation === 'vertical' ? {\n top: `${position.current * 100}%`,\n transition: isDragging === false ? 'top 100ms ease-out' : 'none',\n } : {\n left: `${position.current * 100}%`,\n transition: isDragging === false ? 'left 100ms ease-out' : 'none',\n }),\n }}>\n <StyledKnob\n className={classNames({\n 'at-end': isInverted ? (position.current === 0) : (position.current === 1),\n 'at-start': isInverted ? (position.current === 1) : (position.current === 0),\n 'dragging': isDragging === true,\n 'idle': isDragging === false,\n })}\n css={knobCSS}\n style={{\n height: `${knobHeight}px`,\n width: `${knobWidth}px`,\n }}\n >\n {breakpoints && isLabelVisible && labelProvider && (\n <StyledLabel knobHeight={knobHeight} css={labelCSS}>{labelProvider(getPosition(), getClosestIndex())}</StyledLabel>\n )}\n </StyledKnob>\n </StyledKnobContainer>\n <StyledGutter orientation={orientation} css={endingGutterCSS}\n style={orientation === 'vertical' ? {\n bottom: 0,\n height: `calc(${(1 - getPosition(true))*100}% - ${knobHeight*.5}px - ${gutterPadding}px)`,\n } : {\n right: 0,\n width: `calc(${(1 - getPosition(true))*100}% - ${knobWidth*.5}px - ${gutterPadding}px)`,\n }}\n />\n </StyledRoot>\n )\n}\n\nconst StyledGutter = styled.div<GutterCSSProps>`\n background: #fff;\n position: absolute;\n\n ${props => props.orientation === 'vertical' ? css`\n left: 0;\n margin: 0 auto;\n right: 0;\n width: 100%;\n ` : css`\n bottom: 0;\n height: 100%;\n margin: auto 0;\n top: 0;\n `}\n`\n\nconst StyledLabel = styled.label<LabelCSSProps>`\n color: #000;\n font-size: ${props => props.knobHeight * .5}px;\n pointer-events: none;\n user-select: none;\n`\n\nconst StyledKnobContainer = styled.button`\n position: absolute;\n z-index: 1;\n transition-duration: 100ms;\n transition-property: top;\n transition-timing-function: ease-out;\n`\n\nconst StyledKnob = styled.div`\n align-items: center;\n background: #fff;\n box-sizing: border-box;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n justify-content: center;\n opacity: 1;\n touch-action: none;\n transition-duration: 100ms;\n transition-property: background, color, opacity, transform;\n transition-timing-function: ease-out;\n\n &.idle {\n opacity: 1;\n transition-property: background, color, opacity, margin, transform;\n }\n\n &.dragging {\n opacity: .6;\n transition-property: background, color, transform, opacity;\n }\n`\n\nconst StyledRoot = styled.div<{\n orientation: Orientation\n}>`\n box-sizing: border-box;\n display: block;\n height: ${props => props.orientation === 'vertical' ? '300px' : '4px'};\n position: relative;\n width: ${props => props.orientation === 'vertical' ? '4px' : '300px'};\n`\n"]}
|
|
1
|
+
{"version":3,"file":"Slider.js","sourceRoot":"/","sources":["Slider.tsx"],"names":[],"mappings":"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","sourcesContent":["import classNames from 'classnames'\nimport interact from 'interactjs'\nimport React, { CSSProperties, useEffect, useRef, useState } from 'react'\nimport { Rect } from 'spase'\nimport styled, { css, CSSProp } from 'styled-components'\nimport { Orientation } from './types'\n\nconst debug = process.env.NODE_ENV === 'development' ? require('debug')('etudes:slider') : () => {}\n\nexport type Props = {\n /**\n * ID attribute of the root element.\n */\n id?: string\n\n /**\n * Class attribute of the root element.\n */\n className?: string\n\n /**\n * Inline style attribute of the root element.\n */\n style?: CSSProperties\n\n /**\n * By default the position is a value from 0 - 1, 0 being the start of the slider and 1 being the\n * end. Switching on this flag inverts this behavior, where 0 becomes the end of the slider and 1\n * being the start.\n */\n isInverted?: boolean\n\n /**\n * Indicates if position change events are dispatched only when dragging ends. When disabled,\n * aforementioned events are fired repeatedly while dragging.\n */\n onlyDispatchesOnDragEnd?: boolean\n\n /**\n * A function that returns the label to be displayed at a given slider position.\n *\n * @param position - The current slider position.\n *\n * @returns The label.\n */\n labelProvider?: (position: number) => string\n\n /**\n * Padding between the gutter and the knob in pixels.\n */\n gutterPadding?: number\n\n /**\n * Height of the knob in pixels.\n */\n knobHeight?: number\n\n /**\n * Width of the knob in pixels.\n */\n knobWidth?: number\n\n /**\n * Orientation of the slider.\n */\n orientation?: Orientation\n\n /**\n * The current position.\n */\n position?: number\n\n /**\n * Handler invoked when position changes.\n *\n * @param position - The current slider position.\n * @param isDragging - Indicates if the position change is triggered by dragging the slider.\n */\n onPositionChange?: (position: number, isDragging: boolean) => void\n\n /**\n * Handler invoked when dragging ends.\n */\n onDragEnd?: () => void\n\n /**\n * Handler invoked when dragging begins.\n */\n onDragStart?: () => void\n\n /**\n * Custom CSS provided to the gutter before the knob.\n */\n startingGutterCSS?: CSSProp<any>\n\n /**\n * Custom CSS provided to the gutter after the knob.\n */\n endingGutterCSS?: CSSProp<any>\n\n /**\n * Custom CSS provided to the knob.\n */\n knobCSS?: CSSProp<any>\n\n /**\n * Custom CSS provided to the label inside the knob.\n */\n labelCSS?: CSSProp<any>\n}\n\n/**\n * A slider component that divides the scroll gutter into two different elements—one that is before\n * the knob and one that is after the knob. This allows for individual styling customizations. The\n * width and height of the root element of this component is inferred from CSS. The dimension of the\n * knob itself does not impact that of the root element. This component supports both horizontal and\n * vertical orientations.\n */\nexport default function Slider({\n id,\n className,\n style,\n isInverted = false,\n onlyDispatchesOnDragEnd = false,\n gutterPadding = 0,\n knobHeight = 30,\n knobWidth = 30,\n orientation = 'vertical',\n position = 0,\n labelProvider,\n onDragEnd,\n onDragStart,\n onPositionChange,\n startingGutterCSS,\n endingGutterCSS,\n knobCSS,\n labelCSS,\n}: Props) {\n /**\n * Initializes input interactivity of the knob.\n */\n function initInteractivity() {\n const knob = knobRef.current\n if (!knob || interact.isSet(knob)) return\n\n debug('Initializing interactivity...', 'OK')\n\n interact(knob).draggable({\n inertia: true,\n onstart: () => onKnobDragStart(),\n onmove: ({ dx, dy }) => onKnobDragMove(orientation === 'vertical' ? dy : dx),\n onend: () => onKnobDragStop(),\n })\n }\n\n /**\n * Deinitializes input interactivity of the knob.\n */\n function deinitInteractivity() {\n const knob = knobRef.current\n if (!knob || !interact.isSet(knob)) return\n\n debug('Deinitializing interactivity...', 'OK')\n\n interact(knob).unset()\n }\n\n /**\n * Handler invoked when the knob starts dragging. Note that this is an event listener and does not\n * have read access to component states.\n */\n function onKnobDragStart() {\n debug('Handling drag start...', 'OK')\n setIsDragging(true)\n onDragStart?.()\n }\n\n /**\n * Handler invoked when the knob moves. Note that this is an event listener and does not have read\n * access to component states.\n *\n * @param delta - The distance traveled (in pixels) since the last invocation of this handler.\n */\n function onKnobDragMove(delta: number) {\n const rect = Rect.from(rootRef.current) ?? new Rect()\n const naturalPosition = isInverted ? 1 - livePosition.current : livePosition.current\n const naturalNewPositionX = naturalPosition * rect.width + delta\n const naturalNewPositionY = naturalPosition * rect.height + delta\n const naturalNewPosition = (orientation === 'vertical') ? Math.max(0, Math.min(1, naturalNewPositionY / rect.height)) : Math.max(0, Math.min(1, naturalNewPositionX / rect.width))\n const newPosition = isInverted ? 1 - naturalNewPosition : naturalNewPosition\n\n setIsDragging(true)\n setLivePosition(newPosition)\n }\n\n /**\n * Handler invoked when the knob stops dragging. Note that this is an event listener and does not\n * have read access to component states.\n */\n function onKnobDragStop() {\n debug('Handling drag stop...', 'OK')\n setIsDragging(false)\n onDragEnd?.()\n }\n\n /**\n * Sets the current live position. The live position is different from the position state value.\n * Because states are asynchronous by nature, this live position value is used to record position\n * changes when drag event happens. This position should be normalized. That is, inversion should\n * be taken care of prior to passing the new value to this method if `isInverted` is `true`.\n *\n * @param position - The value to set the live position to.\n */\n function setLivePosition(position: number) {\n if (livePosition.current === position) return\n livePosition.current = position\n // debug('Updating live position...', 'OK', position)\n _setPosition(position)\n }\n\n const rootRef = useRef<HTMLDivElement>(null)\n const knobRef = useRef<HTMLButtonElement>(null)\n\n const livePosition = useRef(position)\n\n const [_position, _setPosition] = useState(livePosition.current)\n const [isDragging, setIsDragging] = useState<boolean | undefined>(undefined)\n\n const naturalPosition = isInverted ? 1 - _position : _position\n\n useEffect(() => {\n initInteractivity()\n\n return () => {\n deinitInteractivity()\n }\n }, [])\n\n useEffect(() => {\n if (isDragging === true) return\n if (position === _position) return\n setIsDragging(undefined)\n setLivePosition(position)\n }, [position])\n\n useEffect(() => {\n if (isDragging === true && onlyDispatchesOnDragEnd) return\n onPositionChange?.(_position, isDragging === true)\n }, [_position])\n\n useEffect(() => {\n if (isDragging === false && onlyDispatchesOnDragEnd) {\n onPositionChange?.(_position, false)\n }\n }, [isDragging])\n\n return (\n <StyledRoot ref={rootRef} id={id} className={className} orientation={orientation} style={style}>\n <StyledGutter orientation={orientation} css={startingGutterCSS}\n style={orientation === 'vertical' ? {\n top: 0,\n height: `calc(${naturalPosition*100}% - ${knobHeight*.5}px - ${gutterPadding}px)`,\n } : {\n left: 0,\n width: `calc(${naturalPosition*100}% - ${knobWidth*.5}px - ${gutterPadding}px)`,\n }}\n />\n <StyledKnobContainer ref={knobRef} style={{\n transform: 'translate3d(-50%, -50%, 0)',\n ...(orientation === 'vertical' ? {\n left: '50%',\n top: `${naturalPosition*100}%`,\n transition: isDragging === false ? 'top 100ms ease-out' : 'none',\n } : {\n left: `${naturalPosition*100}%`,\n top: '50%',\n transition: isDragging === false ? 'left 100ms ease-out' : 'none',\n }),\n }}>\n <StyledKnob\n className={classNames({\n 'at-end': isInverted ? (_position === 0) : (_position === 1),\n 'at-start': isInverted ? (_position === 1) : (_position === 0),\n 'dragging': isDragging === true,\n })}\n css={knobCSS}\n style={{\n height: `${knobHeight}px`,\n width: `${knobWidth}px`,\n }}\n >\n {labelProvider && (\n <StyledLabel knobHeight={knobHeight} css={labelCSS}>{labelProvider(_position)}</StyledLabel>\n )}\n </StyledKnob>\n </StyledKnobContainer>\n <StyledGutter orientation={orientation} css={endingGutterCSS}\n style={orientation === 'vertical' ? {\n bottom: 0,\n height: `calc(${(1 - naturalPosition)*100}% - ${knobHeight*.5}px - ${gutterPadding}px)`,\n } : {\n right: 0,\n width: `calc(${(1 - naturalPosition)*100}% - ${knobWidth*.5}px - ${gutterPadding}px)`,\n }}\n />\n </StyledRoot>\n )\n}\n\nconst StyledGutter = styled.div<{ orientation: NonNullable<Props['orientation']> }>`\n background: #fff;\n position: absolute;\n\n ${props => props.orientation === 'vertical' ? css`\n left: 0;\n margin: 0 auto;\n right: 0;\n width: 100%;\n ` : css`\n bottom: 0;\n height: 100%;\n margin: auto 0;\n top: 0;\n `}\n\n ${props => props.css}\n`\n\nconst StyledLabel = styled.label<{ knobHeight: NonNullable<Props['knobHeight']> }>`\n color: #000;\n font-size: ${props => props.knobHeight * .5}px;\n pointer-events: none;\n user-select: none;\n\n ${props => props.css}\n`\n\nconst StyledKnobContainer = styled.button`\n position: absolute;\n z-index: 1;\n transition-duration: 100ms;\n transition-property: top;\n transition-timing-function: ease-out;\n`\n\nconst StyledKnob = styled.div`\n align-items: center;\n background: #fff;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n justify-content: center;\n touch-action: none;\n transition-duration: 100ms;\n transition-property: background, color, opacity, transform;\n transition-timing-function: ease-out;\n\n ${props => props.css}\n`\n\nconst StyledRoot = styled.div<{\n orientation: Orientation\n}>`\n box-sizing: border-box;\n display: block;\n height: ${props => props.orientation === 'vertical' ? '300px' : '4px'};\n position: relative;\n width: ${props => props.orientation === 'vertical' ? '4px' : '300px'};\n`\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
import { CSSProp } from 'styled-components';
|
|
3
|
+
import { Orientation } from './types';
|
|
4
|
+
export declare type Props = {
|
|
5
|
+
id?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
style?: CSSProperties;
|
|
8
|
+
isInverted?: boolean;
|
|
9
|
+
onlyDispatchesOnDragEnd?: boolean;
|
|
10
|
+
labelProvider?: (position: number, index: number) => string;
|
|
11
|
+
gutterPadding?: number;
|
|
12
|
+
knobHeight?: number;
|
|
13
|
+
knobWidth?: number;
|
|
14
|
+
orientation?: Orientation;
|
|
15
|
+
steps?: readonly number[];
|
|
16
|
+
index?: number;
|
|
17
|
+
onIndexChange?: (index: number, isDragging: boolean) => void;
|
|
18
|
+
onPositionChange?: (position: number, isDragging: boolean) => void;
|
|
19
|
+
onDragEnd?: () => void;
|
|
20
|
+
onDragStart?: () => void;
|
|
21
|
+
startingGutterCSS?: CSSProp<any>;
|
|
22
|
+
endingGutterCSS?: CSSProp<any>;
|
|
23
|
+
knobCSS?: CSSProp<any>;
|
|
24
|
+
labelCSS?: CSSProp<any>;
|
|
25
|
+
};
|
|
26
|
+
export declare function generateSteps(length: number): readonly number[];
|
|
27
|
+
export declare function getNearestIndexByPosition(position: number, steps: readonly number[]): number;
|
|
28
|
+
export declare function getPositionAt(index: number, steps: readonly number[]): number;
|
|
29
|
+
export default function StepwiseSlider({ id, className, style, isInverted, onlyDispatchesOnDragEnd, gutterPadding, knobHeight, knobWidth, orientation, labelProvider, onDragEnd, onDragStart, onPositionChange, startingGutterCSS, endingGutterCSS, knobCSS, labelCSS, steps, index, onIndexChange, }: Props): JSX.Element;
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
|
|
3
|
+
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
|
|
4
|
+
return cooked;
|
|
5
|
+
};
|
|
6
|
+
var __assign = (this && this.__assign) || function () {
|
|
7
|
+
__assign = Object.assign || function(t) {
|
|
8
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
9
|
+
s = arguments[i];
|
|
10
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
11
|
+
t[p] = s[p];
|
|
12
|
+
}
|
|
13
|
+
return t;
|
|
14
|
+
};
|
|
15
|
+
return __assign.apply(this, arguments);
|
|
16
|
+
};
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
37
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
38
|
+
if (!m) return o;
|
|
39
|
+
var i = m.call(o), r, ar = [], e;
|
|
40
|
+
try {
|
|
41
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
42
|
+
}
|
|
43
|
+
catch (error) { e = { error: error }; }
|
|
44
|
+
finally {
|
|
45
|
+
try {
|
|
46
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
47
|
+
}
|
|
48
|
+
finally { if (e) throw e.error; }
|
|
49
|
+
}
|
|
50
|
+
return ar;
|
|
51
|
+
};
|
|
52
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
53
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
54
|
+
};
|
|
55
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
|
+
exports.getPositionAt = exports.getNearestIndexByPosition = exports.generateSteps = void 0;
|
|
57
|
+
var classnames_1 = __importDefault(require("classnames"));
|
|
58
|
+
var interactjs_1 = __importDefault(require("interactjs"));
|
|
59
|
+
var react_1 = __importStar(require("react"));
|
|
60
|
+
var spase_1 = require("spase");
|
|
61
|
+
var styled_components_1 = __importStar(require("styled-components"));
|
|
62
|
+
var debug = process.env.NODE_ENV === 'development' ? require('debug')('etudes:stepwise-slider') : function () { };
|
|
63
|
+
function generateSteps(length) {
|
|
64
|
+
if (length <= 1)
|
|
65
|
+
throw new Error('`length` value must be greater than or equal to 2');
|
|
66
|
+
if (Math.round(length) !== length)
|
|
67
|
+
throw new Error('`length` value must be an integer');
|
|
68
|
+
var interval = 1 / (length - 1);
|
|
69
|
+
return Array(length).fill(null).map(function (v, i) {
|
|
70
|
+
var position = interval * i;
|
|
71
|
+
return position;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
exports.generateSteps = generateSteps;
|
|
75
|
+
function getNearestIndexByPosition(position, steps) {
|
|
76
|
+
var index = -1;
|
|
77
|
+
var minDelta = NaN;
|
|
78
|
+
for (var i = 0, n = steps.length; i < n; i++) {
|
|
79
|
+
var step = getPositionAt(i, steps);
|
|
80
|
+
if (isNaN(step))
|
|
81
|
+
continue;
|
|
82
|
+
var delta = Math.abs(position - step);
|
|
83
|
+
if (isNaN(minDelta) || (delta < minDelta)) {
|
|
84
|
+
minDelta = delta;
|
|
85
|
+
index = i;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return index;
|
|
89
|
+
}
|
|
90
|
+
exports.getNearestIndexByPosition = getNearestIndexByPosition;
|
|
91
|
+
function getPositionAt(index, steps) {
|
|
92
|
+
if (index >= steps.length)
|
|
93
|
+
return NaN;
|
|
94
|
+
return steps[index];
|
|
95
|
+
}
|
|
96
|
+
exports.getPositionAt = getPositionAt;
|
|
97
|
+
function StepwiseSlider(_a) {
|
|
98
|
+
var id = _a.id, className = _a.className, style = _a.style, _b = _a.isInverted, isInverted = _b === void 0 ? false : _b, _c = _a.onlyDispatchesOnDragEnd, onlyDispatchesOnDragEnd = _c === void 0 ? false : _c, _d = _a.gutterPadding, gutterPadding = _d === void 0 ? 0 : _d, _e = _a.knobHeight, knobHeight = _e === void 0 ? 30 : _e, _f = _a.knobWidth, knobWidth = _f === void 0 ? 30 : _f, _g = _a.orientation, orientation = _g === void 0 ? 'vertical' : _g, labelProvider = _a.labelProvider, onDragEnd = _a.onDragEnd, onDragStart = _a.onDragStart, onPositionChange = _a.onPositionChange, startingGutterCSS = _a.startingGutterCSS, endingGutterCSS = _a.endingGutterCSS, knobCSS = _a.knobCSS, labelCSS = _a.labelCSS, _h = _a.steps, steps = _h === void 0 ? generateSteps(10) : _h, _j = _a.index, index = _j === void 0 ? 0 : _j, onIndexChange = _a.onIndexChange;
|
|
99
|
+
function initInteractivity() {
|
|
100
|
+
var knob = knobRef.current;
|
|
101
|
+
if (!knob || interactjs_1.default.isSet(knob))
|
|
102
|
+
return;
|
|
103
|
+
debug('Initializing interactivity...', 'OK');
|
|
104
|
+
(0, interactjs_1.default)(knob).draggable({
|
|
105
|
+
inertia: true,
|
|
106
|
+
onstart: function () { return onKnobDragStart(); },
|
|
107
|
+
onmove: function (_a) {
|
|
108
|
+
var dx = _a.dx, dy = _a.dy;
|
|
109
|
+
return onKnobDragMove(orientation === 'vertical' ? dy : dx);
|
|
110
|
+
},
|
|
111
|
+
onend: function () { return onKnobDragStop(); },
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function deinitInteractivity() {
|
|
115
|
+
var knob = knobRef.current;
|
|
116
|
+
if (!knob || !interactjs_1.default.isSet(knob))
|
|
117
|
+
return;
|
|
118
|
+
debug('Deinitializing interactivity...', 'OK');
|
|
119
|
+
(0, interactjs_1.default)(knob).unset();
|
|
120
|
+
}
|
|
121
|
+
function onKnobDragStart() {
|
|
122
|
+
debug('Handling drag start...', 'OK');
|
|
123
|
+
setIsDragging(true);
|
|
124
|
+
onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart();
|
|
125
|
+
}
|
|
126
|
+
function onKnobDragMove(delta) {
|
|
127
|
+
var _a;
|
|
128
|
+
var rect = (_a = spase_1.Rect.from(rootRef.current)) !== null && _a !== void 0 ? _a : new spase_1.Rect();
|
|
129
|
+
var naturalPosition = isInverted ? 1 - livePosition.current : livePosition.current;
|
|
130
|
+
var naturalNewPositionX = naturalPosition * rect.width + delta;
|
|
131
|
+
var naturalNewPositionY = naturalPosition * rect.height + delta;
|
|
132
|
+
var naturalNewPosition = (orientation === 'vertical') ? Math.max(0, Math.min(1, naturalNewPositionY / rect.height)) : Math.max(0, Math.min(1, naturalNewPositionX / rect.width));
|
|
133
|
+
var newPosition = isInverted ? 1 - naturalNewPosition : naturalNewPosition;
|
|
134
|
+
var newIndex = getNearestIndexByPosition(newPosition, steps);
|
|
135
|
+
setIsDragging(true);
|
|
136
|
+
setLivePosition(newPosition);
|
|
137
|
+
setLiveIndex(newIndex);
|
|
138
|
+
}
|
|
139
|
+
function onKnobDragStop() {
|
|
140
|
+
debug('Handling drag stop...', 'OK');
|
|
141
|
+
setIsDragging(false);
|
|
142
|
+
onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd();
|
|
143
|
+
}
|
|
144
|
+
function setLivePosition(position) {
|
|
145
|
+
if (livePosition.current === position)
|
|
146
|
+
return;
|
|
147
|
+
livePosition.current = position;
|
|
148
|
+
_setPosition(position);
|
|
149
|
+
}
|
|
150
|
+
function setLiveIndex(index) {
|
|
151
|
+
if (liveIndex.current === index)
|
|
152
|
+
return;
|
|
153
|
+
liveIndex.current = index;
|
|
154
|
+
_setIndex(index);
|
|
155
|
+
}
|
|
156
|
+
var rootRef = (0, react_1.useRef)(null);
|
|
157
|
+
var knobRef = (0, react_1.useRef)(null);
|
|
158
|
+
var livePosition = (0, react_1.useRef)(getPositionAt(index, steps));
|
|
159
|
+
var liveIndex = (0, react_1.useRef)(index);
|
|
160
|
+
var _k = __read((0, react_1.useState)(livePosition.current), 2), _position = _k[0], _setPosition = _k[1];
|
|
161
|
+
var _l = __read((0, react_1.useState)(liveIndex.current), 2), _index = _l[0], _setIndex = _l[1];
|
|
162
|
+
var _m = __read((0, react_1.useState)(undefined), 2), isDragging = _m[0], setIsDragging = _m[1];
|
|
163
|
+
var naturalPosition = isInverted ? 1 - _position : _position;
|
|
164
|
+
(0, react_1.useEffect)(function () {
|
|
165
|
+
initInteractivity();
|
|
166
|
+
return function () {
|
|
167
|
+
deinitInteractivity();
|
|
168
|
+
};
|
|
169
|
+
}, []);
|
|
170
|
+
(0, react_1.useEffect)(function () {
|
|
171
|
+
if (isDragging === true)
|
|
172
|
+
return;
|
|
173
|
+
if (index === _index)
|
|
174
|
+
return;
|
|
175
|
+
setIsDragging(undefined);
|
|
176
|
+
setLivePosition(getPositionAt(index, steps));
|
|
177
|
+
setLiveIndex(index);
|
|
178
|
+
}, [index]);
|
|
179
|
+
(0, react_1.useEffect)(function () {
|
|
180
|
+
if (isDragging === true && onlyDispatchesOnDragEnd)
|
|
181
|
+
return;
|
|
182
|
+
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(_position, isDragging !== undefined);
|
|
183
|
+
}, [_position]);
|
|
184
|
+
(0, react_1.useEffect)(function () {
|
|
185
|
+
if (isDragging === true && onlyDispatchesOnDragEnd)
|
|
186
|
+
return;
|
|
187
|
+
onIndexChange === null || onIndexChange === void 0 ? void 0 : onIndexChange(_index, isDragging !== undefined);
|
|
188
|
+
}, [_index]);
|
|
189
|
+
(0, react_1.useEffect)(function () {
|
|
190
|
+
if (isDragging !== false)
|
|
191
|
+
return;
|
|
192
|
+
var nearestIndex = getNearestIndexByPosition(_position, steps);
|
|
193
|
+
var nearestPosition = getPositionAt(nearestIndex, steps);
|
|
194
|
+
setLivePosition(nearestPosition);
|
|
195
|
+
if (onlyDispatchesOnDragEnd) {
|
|
196
|
+
onIndexChange === null || onIndexChange === void 0 ? void 0 : onIndexChange(_index, true);
|
|
197
|
+
}
|
|
198
|
+
}, [isDragging]);
|
|
199
|
+
return (react_1.default.createElement(StyledRoot, { ref: rootRef, id: id, className: className, orientation: orientation, style: style },
|
|
200
|
+
react_1.default.createElement(StyledGutter, { orientation: orientation, css: startingGutterCSS, style: orientation === 'vertical' ? {
|
|
201
|
+
top: 0,
|
|
202
|
+
height: "calc(".concat(naturalPosition * 100, "% - ").concat(knobHeight * .5, "px - ").concat(gutterPadding, "px)"),
|
|
203
|
+
} : {
|
|
204
|
+
left: 0,
|
|
205
|
+
width: "calc(".concat(naturalPosition * 100, "% - ").concat(knobWidth * .5, "px - ").concat(gutterPadding, "px)"),
|
|
206
|
+
} }),
|
|
207
|
+
react_1.default.createElement(StyledKnobContainer, { ref: knobRef, style: __assign({ transform: 'translate3d(-50%, -50%, 0)' }, (orientation === 'vertical' ? {
|
|
208
|
+
left: '50%',
|
|
209
|
+
top: "".concat(naturalPosition * 100, "%"),
|
|
210
|
+
transition: isDragging === false ? 'top 100ms ease-out' : 'none',
|
|
211
|
+
} : {
|
|
212
|
+
left: "".concat(naturalPosition * 100, "%"),
|
|
213
|
+
top: '50%',
|
|
214
|
+
transition: isDragging === false ? 'left 100ms ease-out' : 'none',
|
|
215
|
+
})) },
|
|
216
|
+
react_1.default.createElement(StyledKnob, { className: (0, classnames_1.default)({
|
|
217
|
+
'at-end': isInverted ? (_position === 0) : (_position === 1),
|
|
218
|
+
'at-start': isInverted ? (_position === 1) : (_position === 0),
|
|
219
|
+
'dragging': isDragging === true,
|
|
220
|
+
}), css: knobCSS, style: {
|
|
221
|
+
height: "".concat(knobHeight, "px"),
|
|
222
|
+
width: "".concat(knobWidth, "px"),
|
|
223
|
+
} }, steps && labelProvider && (react_1.default.createElement(StyledLabel, { knobHeight: knobHeight, css: labelCSS }, labelProvider(_position, getNearestIndexByPosition(_position, steps)))))),
|
|
224
|
+
react_1.default.createElement(StyledGutter, { orientation: orientation, css: endingGutterCSS, style: orientation === 'vertical' ? {
|
|
225
|
+
bottom: 0,
|
|
226
|
+
height: "calc(".concat((1 - naturalPosition) * 100, "% - ").concat(knobHeight * .5, "px - ").concat(gutterPadding, "px)"),
|
|
227
|
+
} : {
|
|
228
|
+
right: 0,
|
|
229
|
+
width: "calc(".concat((1 - naturalPosition) * 100, "% - ").concat(knobWidth * .5, "px - ").concat(gutterPadding, "px)"),
|
|
230
|
+
} })));
|
|
231
|
+
}
|
|
232
|
+
exports.default = StepwiseSlider;
|
|
233
|
+
var StyledGutter = styled_components_1.default.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n background: #fff;\n position: absolute;\n\n ", "\n\n ", "\n"], ["\n background: #fff;\n position: absolute;\n\n ", "\n\n ", "\n"])), function (props) { return props.orientation === 'vertical' ? (0, styled_components_1.css)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n left: 0;\n margin: 0 auto;\n right: 0;\n width: 100%;\n "], ["\n left: 0;\n margin: 0 auto;\n right: 0;\n width: 100%;\n "]))) : (0, styled_components_1.css)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n bottom: 0;\n height: 100%;\n margin: auto 0;\n top: 0;\n "], ["\n bottom: 0;\n height: 100%;\n margin: auto 0;\n top: 0;\n "]))); }, function (props) { return props.css; });
|
|
234
|
+
var StyledLabel = styled_components_1.default.label(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n color: #000;\n font-size: ", "px;\n pointer-events: none;\n user-select: none;\n\n ", "\n"], ["\n color: #000;\n font-size: ", "px;\n pointer-events: none;\n user-select: none;\n\n ", "\n"])), function (props) { return props.knobHeight * .5; }, function (props) { return props.css; });
|
|
235
|
+
var StyledKnobContainer = styled_components_1.default.button(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n position: absolute;\n z-index: 1;\n transition-duration: 100ms;\n transition-property: top;\n transition-timing-function: ease-out;\n"], ["\n position: absolute;\n z-index: 1;\n transition-duration: 100ms;\n transition-property: top;\n transition-timing-function: ease-out;\n"])));
|
|
236
|
+
var StyledKnob = styled_components_1.default.div(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n align-items: center;\n background: #fff;\n box-sizing: border-box;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n justify-content: center;\n opacity: 1;\n touch-action: none;\n transition-duration: 100ms;\n transition-property: background, color, opacity, transform;\n transition-timing-function: ease-out;\n\n ", "\n"], ["\n align-items: center;\n background: #fff;\n box-sizing: border-box;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n justify-content: center;\n opacity: 1;\n touch-action: none;\n transition-duration: 100ms;\n transition-property: background, color, opacity, transform;\n transition-timing-function: ease-out;\n\n ", "\n"])), function (props) { return props.css; });
|
|
237
|
+
var StyledRoot = styled_components_1.default.div(templateObject_7 || (templateObject_7 = __makeTemplateObject(["\n box-sizing: border-box;\n display: block;\n height: ", ";\n position: relative;\n width: ", ";\n"], ["\n box-sizing: border-box;\n display: block;\n height: ", ";\n position: relative;\n width: ", ";\n"])), function (props) { return props.orientation === 'vertical' ? '300px' : '4px'; }, function (props) { return props.orientation === 'vertical' ? '4px' : '300px'; });
|
|
238
|
+
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7;
|
|
239
|
+
//# sourceMappingURL=StepwiseSlider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StepwiseSlider.js","sourceRoot":"/","sources":["StepwiseSlider.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,0DAAmC;AACnC,0DAAiC;AACjC,6CAAyE;AACzE,+BAA4B;AAC5B,qEAAwD;AAGxD,IAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,cAAO,CAAC,CAAA;AAiI5G,SAAgB,aAAa,CAAC,MAAc;IAC1C,IAAI,MAAM,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACrF,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;IAEvF,IAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAEjC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,UAAC,CAAC,EAAE,CAAC;QACvC,IAAM,QAAQ,GAAG,QAAQ,GAAG,CAAC,CAAA;QAC7B,OAAO,QAAQ,CAAA;IACjB,CAAC,CAAC,CAAA;AACJ,CAAC;AAVD,sCAUC;AAWD,SAAgB,yBAAyB,CAAC,QAAgB,EAAE,KAAwB;IAClF,IAAI,KAAK,GAAG,CAAC,CAAC,CAAA;IACd,IAAI,QAAQ,GAAG,GAAG,CAAA;IAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;QAC5C,IAAM,IAAI,GAAG,aAAa,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;QAEpC,IAAI,KAAK,CAAC,IAAI,CAAC;YAAE,SAAQ;QAEzB,IAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;QAEvC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,EAAE;YACzC,QAAQ,GAAG,KAAK,CAAA;YAChB,KAAK,GAAG,CAAC,CAAA;SACV;KACF;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAlBD,8DAkBC;AAWD,SAAgB,aAAa,CAAC,KAAa,EAAE,KAAwB;IACnE,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,GAAG,CAAA;IACrC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAA;AACrB,CAAC;AAHD,sCAGC;AAUD,SAAwB,cAAc,CAAC,EAqB/B;QApBN,EAAE,QAAA,EACF,SAAS,eAAA,EACT,KAAK,WAAA,EACL,kBAAkB,EAAlB,UAAU,mBAAG,KAAK,KAAA,EAClB,+BAA+B,EAA/B,uBAAuB,mBAAG,KAAK,KAAA,EAC/B,qBAAiB,EAAjB,aAAa,mBAAG,CAAC,KAAA,EACjB,kBAAe,EAAf,UAAU,mBAAG,EAAE,KAAA,EACf,iBAAc,EAAd,SAAS,mBAAG,EAAE,KAAA,EACd,mBAAwB,EAAxB,WAAW,mBAAG,UAAU,KAAA,EACxB,aAAa,mBAAA,EACb,SAAS,eAAA,EACT,WAAW,iBAAA,EACX,gBAAgB,sBAAA,EAChB,iBAAiB,uBAAA,EACjB,eAAe,qBAAA,EACf,OAAO,aAAA,EACP,QAAQ,cAAA,EACR,aAAyB,EAAzB,KAAK,mBAAG,aAAa,CAAC,EAAE,CAAC,KAAA,EACzB,aAAS,EAAT,KAAK,mBAAG,CAAC,KAAA,EACT,aAAa,mBAAA;IAKb,SAAS,iBAAiB;QACxB,IAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAA;QAC5B,IAAI,CAAC,IAAI,IAAI,oBAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAM;QAEzC,KAAK,CAAC,+BAA+B,EAAE,IAAI,CAAC,CAAA;QAE5C,IAAA,oBAAQ,EAAC,IAAI,CAAC,CAAC,SAAS,CAAC;YACvB,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,cAAM,OAAA,eAAe,EAAE,EAAjB,CAAiB;YAChC,MAAM,EAAE,UAAC,EAAU;oBAAR,EAAE,QAAA,EAAE,EAAE,QAAA;gBAAO,OAAA,cAAc,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAApD,CAAoD;YAC5E,KAAK,EAAE,cAAM,OAAA,cAAc,EAAE,EAAhB,CAAgB;SAC9B,CAAC,CAAA;IACJ,CAAC;IAKD,SAAS,mBAAmB;QAC1B,IAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAA;QAC5B,IAAI,CAAC,IAAI,IAAI,CAAC,oBAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAM;QAE1C,KAAK,CAAC,iCAAiC,EAAE,IAAI,CAAC,CAAA;QAE9C,IAAA,oBAAQ,EAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC;IAMD,SAAS,eAAe;QACtB,KAAK,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAA;QACrC,aAAa,CAAC,IAAI,CAAC,CAAA;QACnB,WAAW,aAAX,WAAW,uBAAX,WAAW,EAAI,CAAA;IACjB,CAAC;IAQD,SAAS,cAAc,CAAC,KAAa;;QACnC,IAAM,IAAI,GAAG,MAAA,YAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,mCAAI,IAAI,YAAI,EAAE,CAAA;QACrD,IAAM,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAA;QACpF,IAAM,mBAAmB,GAAG,eAAe,GAAG,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAChE,IAAM,mBAAmB,GAAG,eAAe,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;QACjE,IAAM,kBAAkB,GAAG,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;QAClL,IAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,kBAAkB,CAAA;QAC5E,IAAM,QAAQ,GAAG,yBAAyB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAA;QAE9D,aAAa,CAAC,IAAI,CAAC,CAAA;QACnB,eAAe,CAAC,WAAW,CAAC,CAAA;QAC5B,YAAY,CAAC,QAAQ,CAAC,CAAA;IACxB,CAAC;IAMD,SAAS,cAAc;QACrB,KAAK,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAA;QACpC,aAAa,CAAC,KAAK,CAAC,CAAA;QACpB,SAAS,aAAT,SAAS,uBAAT,SAAS,EAAI,CAAA;IACf,CAAC;IAUD,SAAS,eAAe,CAAC,QAAgB;QACvC,IAAI,YAAY,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAM;QAC7C,YAAY,CAAC,OAAO,GAAG,QAAQ,CAAA;QAE/B,YAAY,CAAC,QAAQ,CAAC,CAAA;IACxB,CAAC;IASD,SAAS,YAAY,CAAC,KAAa;QACjC,IAAI,SAAS,CAAC,OAAO,KAAK,KAAK;YAAE,OAAM;QACvC,SAAS,CAAC,OAAO,GAAG,KAAK,CAAA;QAEzB,SAAS,CAAC,KAAK,CAAC,CAAA;IAClB,CAAC;IAED,IAAM,OAAO,GAAG,IAAA,cAAM,EAAiB,IAAI,CAAC,CAAA;IAC5C,IAAM,OAAO,GAAG,IAAA,cAAM,EAAoB,IAAI,CAAC,CAAA;IAE/C,IAAM,YAAY,GAAG,IAAA,cAAM,EAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;IACxD,IAAM,SAAS,GAAG,IAAA,cAAM,EAAC,KAAK,CAAC,CAAA;IAEzB,IAAA,KAAA,OAA4B,IAAA,gBAAQ,EAAC,YAAY,CAAC,OAAO,CAAC,IAAA,EAAzD,SAAS,QAAA,EAAE,YAAY,QAAkC,CAAA;IAC1D,IAAA,KAAA,OAAsB,IAAA,gBAAQ,EAAC,SAAS,CAAC,OAAO,CAAC,IAAA,EAAhD,MAAM,QAAA,EAAE,SAAS,QAA+B,CAAA;IACjD,IAAA,KAAA,OAA8B,IAAA,gBAAQ,EAAsB,SAAS,CAAC,IAAA,EAArE,UAAU,QAAA,EAAE,aAAa,QAA4C,CAAA;IAE5E,IAAM,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;IAE9D,IAAA,iBAAS,EAAC;QACR,iBAAiB,EAAE,CAAA;QAEnB,OAAO;YACL,mBAAmB,EAAE,CAAA;QACvB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,IAAA,iBAAS,EAAC;QACR,IAAI,UAAU,KAAK,IAAI;YAAE,OAAM;QAC/B,IAAI,KAAK,KAAK,MAAM;YAAE,OAAM;QAC5B,aAAa,CAAC,SAAS,CAAC,CAAA;QACxB,eAAe,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;QAC5C,YAAY,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,IAAA,iBAAS,EAAC;QACR,IAAI,UAAU,KAAK,IAAI,IAAI,uBAAuB;YAAE,OAAM;QAC1D,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAG,SAAS,EAAE,UAAU,KAAK,SAAS,CAAC,CAAA;IACzD,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;IAEf,IAAA,iBAAS,EAAC;QACR,IAAI,UAAU,KAAK,IAAI,IAAI,uBAAuB;YAAE,OAAM;QAC1D,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAG,MAAM,EAAE,UAAU,KAAK,SAAS,CAAC,CAAA;IACnD,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAEZ,IAAA,iBAAS,EAAC;QACR,IAAI,UAAU,KAAK,KAAK;YAAE,OAAM;QAEhC,IAAM,YAAY,GAAG,yBAAyB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;QAChE,IAAM,eAAe,GAAG,aAAa,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;QAC1D,eAAe,CAAC,eAAe,CAAC,CAAA;QAEhC,IAAI,uBAAuB,EAAE;YAC3B,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAG,MAAM,EAAE,IAAI,CAAC,CAAA;SAC9B;IACH,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAEhB,OAAO,CACL,8BAAC,UAAU,IAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;QAC5F,8BAAC,YAAY,IAAC,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,iBAAiB,EAC5D,KAAK,EAAE,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC;gBAClC,GAAG,EAAE,CAAC;gBACN,MAAM,EAAE,eAAQ,eAAe,GAAC,GAAG,iBAAO,UAAU,GAAC,EAAE,kBAAQ,aAAa,QAAK;aAClF,CAAC,CAAC,CAAC;gBACF,IAAI,EAAE,CAAC;gBACP,KAAK,EAAE,eAAQ,eAAe,GAAC,GAAG,iBAAO,SAAS,GAAC,EAAE,kBAAQ,aAAa,QAAK;aAChF,GACD;QACF,8BAAC,mBAAmB,IAAC,GAAG,EAAE,OAAO,EAAE,KAAK,aACtC,SAAS,EAAE,4BAA4B,IACpC,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC;gBAC/B,IAAI,EAAE,KAAK;gBACX,GAAG,EAAE,UAAG,eAAe,GAAC,GAAG,MAAG;gBAC9B,UAAU,EAAE,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,MAAM;aACjE,CAAC,CAAC,CAAC;gBACF,IAAI,EAAE,UAAG,eAAe,GAAC,GAAG,MAAG;gBAC/B,GAAG,EAAE,KAAK;gBACV,UAAU,EAAE,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,MAAM;aAClE,CAAC;YAEF,8BAAC,UAAU,IACT,SAAS,EAAE,IAAA,oBAAU,EAAC;oBACpB,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC;oBAC5D,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC;oBAC9D,UAAU,EAAE,UAAU,KAAK,IAAI;iBAChC,CAAC,EACF,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE;oBACL,MAAM,EAAE,UAAG,UAAU,OAAI;oBACzB,KAAK,EAAE,UAAG,SAAS,OAAI;iBACxB,IAEA,KAAK,IAAI,aAAa,IAAI,CACzB,8BAAC,WAAW,IAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,IAAG,aAAa,CAAC,SAAS,EAAE,yBAAyB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAe,CAC1I,CACU,CACO;QACtB,8BAAC,YAAY,IAAC,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,eAAe,EAC1D,KAAK,EAAE,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC;gBAClC,MAAM,EAAE,CAAC;gBACT,MAAM,EAAE,eAAQ,CAAC,CAAC,GAAG,eAAe,CAAC,GAAC,GAAG,iBAAO,UAAU,GAAC,EAAE,kBAAQ,aAAa,QAAK;aACxF,CAAC,CAAC,CAAC;gBACF,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE,eAAQ,CAAC,CAAC,GAAG,eAAe,CAAC,GAAC,GAAG,iBAAO,SAAS,GAAC,EAAE,kBAAQ,aAAa,QAAK;aACtF,GACD,CACS,CACd,CAAA;AACH,CAAC;AA7ND,iCA6NC;AAED,IAAM,YAAY,GAAG,2BAAM,CAAC,GAAG,uIAAoD,oDAI/E,EAUD,QAEC,EAAkB,IACrB,KAbG,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,KAAC,uBAAG,8IAAA,0EAKhD,KAAC,CAAC,KAAC,uBAAG,+IAAA,2EAKN,IAAA,EAVU,CAUV,EAEC,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,GAAG,EAAT,CAAS,CACrB,CAAA;AAED,IAAM,WAAW,GAAG,2BAAM,CAAC,KAAK,sKAAkD,iCAEnE,EAA8B,0DAIzC,EAAkB,IACrB,KALc,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,UAAU,GAAG,EAAE,EAArB,CAAqB,EAIzC,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,GAAG,EAAT,CAAS,CACrB,CAAA;AAED,IAAM,mBAAmB,GAAG,2BAAM,CAAC,MAAM,kNAAA,+IAMxC,IAAA,CAAA;AAED,IAAM,UAAU,GAAG,2BAAM,CAAC,GAAG,maAAA,0VAczB,EAAkB,IACrB,KADG,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,GAAG,EAAT,CAAS,CACrB,CAAA;AAED,IAAM,UAAU,GAAG,2BAAM,CAAC,GAAG,6KAE3B,4DAGU,EAA2D,qCAE5D,EAA2D,KACrE,KAHW,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAlD,CAAkD,EAE5D,UAAA,KAAK,IAAI,OAAA,KAAK,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAlD,CAAkD,CACrE,CAAA","sourcesContent":["import classNames from 'classnames'\nimport interact from 'interactjs'\nimport React, { CSSProperties, useEffect, useRef, useState } from 'react'\nimport { Rect } from 'spase'\nimport styled, { css, CSSProp } from 'styled-components'\nimport { Orientation } from './types'\n\nconst debug = process.env.NODE_ENV === 'development' ? require('debug')('etudes:stepwise-slider') : () => {}\n\nexport type Props = {\n /**\n * ID attribute of the root element.\n */\n id?: string\n\n /**\n * Class attribute of the root element.\n */\n className?: string\n\n /**\n * Inline style attribute of the root element.\n */\n style?: CSSProperties\n\n /**\n * By default the position is a value from 0 - 1, 0 being the start of the slider and 1 being the\n * end. Switching on this flag inverts this behavior, where 0 becomes the end of the slider and 1\n * being the start.\n */\n isInverted?: boolean\n\n /**\n * Indicates if position/index change events are dispatched only when dragging ends. When\n * disabled, aforementioned events are fired repeatedly while dragging.\n */\n onlyDispatchesOnDragEnd?: boolean\n\n /**\n * A function that returns the label to be displayed at a given slider position and closest step\n * index (if steps are provided).\n *\n * @param position - The current slider position.\n * @param index - The nearest step index (if steps are provided), or -1 if no steps are provided.\n *\n * @returns The label.\n */\n labelProvider?: (position: number, index: number) => string\n\n /**\n * Padding between the gutter and the knob in pixels.\n */\n gutterPadding?: number\n\n /**\n * Height of the knob in pixels.\n */\n knobHeight?: number\n\n /**\n * Width of the knob in pixels.\n */\n knobWidth?: number\n\n /**\n * Orientation of the slider.\n */\n orientation?: Orientation\n\n /**\n * An array of step descriptors. A step is a position (0 - 1 inclusive) on the gutter where the\n * knob should snap to if dragging stops near it. Ensure that there are at least two steps: one\n * for the start of the gutter and one for the end.\n */\n steps?: readonly number[]\n\n /**\n * The current index.\n */\n index?: number\n\n /**\n * Handler invoked when index changes. This happens simultaneously with `onPositionChange`.\n *\n * @param index - The current step index.\n * @param isDragging - Indicates if the index change is triggered by dragging the slider..\n */\n onIndexChange?: (index: number, isDragging: boolean) => void\n\n /**\n * Handler invoked when position changes.\n *\n * @param position - The current slider position.\n * @param isDragging - Indicates if the position change is triggered by dragging the slider.\n */\n onPositionChange?: (position: number, isDragging: boolean) => void\n\n /**\n * Handler invoked when dragging ends.\n */\n onDragEnd?: () => void\n\n /**\n * Handler invoked when dragging begins.\n */\n onDragStart?: () => void\n\n /**\n * Custom CSS provided to the gutter before the knob.\n */\n startingGutterCSS?: CSSProp<any>\n\n /**\n * Custom CSS provided to the gutter after the knob.\n */\n endingGutterCSS?: CSSProp<any>\n\n /**\n * Custom CSS provided to the knob.\n */\n knobCSS?: CSSProp<any>\n\n /**\n * Custom CSS provided to the label inside the knob.\n */\n labelCSS?: CSSProp<any>\n}\n\n/**\n * Generates a set of steps compatible with this component.\n *\n * @param length - The number of steps. This must be at least 2 because you must include the\n * starting and ending points.\n *\n * @returns An array of steps.\n */\nexport function generateSteps(length: number): readonly number[] {\n if (length <= 1) throw new Error('`length` value must be greater than or equal to 2')\n if (Math.round(length) !== length) throw new Error('`length` value must be an integer')\n\n const interval = 1 / (length - 1)\n\n return Array(length).fill(null).map((v, i) => {\n const position = interval * i\n return position\n })\n}\n\n/**\n * Gets the index of the step of which the specified position is closest to. If for whatever\n * reason the index cannot be computed, -1 is returned.\n *\n * @param position - The position (0 - 1, inclusive).\n * @param steps - The steps.\n *\n * @returns The nearest index.\n */\nexport function getNearestIndexByPosition(position: number, steps: readonly number[]): number {\n let index = -1\n let minDelta = NaN\n\n for (let i = 0, n = steps.length; i < n; i++) {\n const step = getPositionAt(i, steps)\n\n if (isNaN(step)) continue\n\n const delta = Math.abs(position - step)\n\n if (isNaN(minDelta) || (delta < minDelta)) {\n minDelta = delta\n index = i\n }\n }\n\n return index\n}\n\n/**\n * Gets the position by step index. This value ranges between 0 - 1, inclusive.\n *\n * @param index - The step index.\n * @param steps - The steps.\n *\n * @returns The position. If for whatever reason the position cannot be determined, `NaN` is\n * returned.\n */\nexport function getPositionAt(index: number, steps: readonly number[]): number {\n if (index >= steps.length) return NaN\n return steps[index]\n}\n\n/**\n * A \"stepwise\" slider component that automatically snaps to certain points on the slider. The\n * component divides the scroll gutter into two different elements—one that is before the knob and\n * one that is after the knob. This allows for individual styling customizations. The width and\n * height of the root element of this component is inferred from its CSS rules. The dimension of the\n * knob itself does not impact that of the root element. This component supports both horizontal and\n * vertical orientations.\n */\nexport default function StepwiseSlider({\n id,\n className,\n style,\n isInverted = false,\n onlyDispatchesOnDragEnd = false,\n gutterPadding = 0,\n knobHeight = 30,\n knobWidth = 30,\n orientation = 'vertical',\n labelProvider,\n onDragEnd,\n onDragStart,\n onPositionChange,\n startingGutterCSS,\n endingGutterCSS,\n knobCSS,\n labelCSS,\n steps = generateSteps(10),\n index = 0,\n onIndexChange,\n}: Props) {\n /**\n * Initializes input interactivity of the knob.\n */\n function initInteractivity() {\n const knob = knobRef.current\n if (!knob || interact.isSet(knob)) return\n\n debug('Initializing interactivity...', 'OK')\n\n interact(knob).draggable({\n inertia: true,\n onstart: () => onKnobDragStart(),\n onmove: ({ dx, dy }) => onKnobDragMove(orientation === 'vertical' ? dy : dx),\n onend: () => onKnobDragStop(),\n })\n }\n\n /**\n * Deinitializes input interactivity of the knob.\n */\n function deinitInteractivity() {\n const knob = knobRef.current\n if (!knob || !interact.isSet(knob)) return\n\n debug('Deinitializing interactivity...', 'OK')\n\n interact(knob).unset()\n }\n\n /**\n * Handler invoked when the knob starts dragging. Note that this is an event listener and does not\n * have read access to component states.\n */\n function onKnobDragStart() {\n debug('Handling drag start...', 'OK')\n setIsDragging(true)\n onDragStart?.()\n }\n\n /**\n * Handler invoked when the knob moves. Note that this is an event listener and does not have read\n * access to component states.\n *\n * @param delta - The distance traveled (in pixels) since the last invocation of this handler.\n */\n function onKnobDragMove(delta: number) {\n const rect = Rect.from(rootRef.current) ?? new Rect()\n const naturalPosition = isInverted ? 1 - livePosition.current : livePosition.current\n const naturalNewPositionX = naturalPosition * rect.width + delta\n const naturalNewPositionY = naturalPosition * rect.height + delta\n const naturalNewPosition = (orientation === 'vertical') ? Math.max(0, Math.min(1, naturalNewPositionY / rect.height)) : Math.max(0, Math.min(1, naturalNewPositionX / rect.width))\n const newPosition = isInverted ? 1 - naturalNewPosition : naturalNewPosition\n const newIndex = getNearestIndexByPosition(newPosition, steps)\n\n setIsDragging(true)\n setLivePosition(newPosition)\n setLiveIndex(newIndex)\n }\n\n /**\n * Handler invoked when the knob stops dragging. Note that this is an event listener and does not\n * have read access to component states.\n */\n function onKnobDragStop() {\n debug('Handling drag stop...', 'OK')\n setIsDragging(false)\n onDragEnd?.()\n }\n\n /**\n * Sets the current live position. The live position is different from the position state value.\n * Because states are asynchronous by nature, this live position value is used to record position\n * changes when drag event happens. This position should be normalized. That is, inversion should\n * be taken care of prior to passing the new value to this method if `isInverted` is `true`.\n *\n * @param position - The value to set the live position to.\n */\n function setLivePosition(position: number) {\n if (livePosition.current === position) return\n livePosition.current = position\n // debug('Updating live position...', 'OK', position)\n _setPosition(position)\n }\n\n /**\n * Sets the current live index. The live index is different from the index state value. Because\n * states are asynchronous by nature, this live index value is used to record index changes when\n * drag event happens.\n *\n * @param index - The value to set the live index to.\n */\n function setLiveIndex(index: number) {\n if (liveIndex.current === index) return\n liveIndex.current = index\n // debug('Updating live index...', 'OK', index)\n _setIndex(index)\n }\n\n const rootRef = useRef<HTMLDivElement>(null)\n const knobRef = useRef<HTMLButtonElement>(null)\n\n const livePosition = useRef(getPositionAt(index, steps))\n const liveIndex = useRef(index)\n\n const [_position, _setPosition] = useState(livePosition.current)\n const [_index, _setIndex] = useState(liveIndex.current)\n const [isDragging, setIsDragging] = useState<boolean | undefined>(undefined)\n\n const naturalPosition = isInverted ? 1 - _position : _position\n\n useEffect(() => {\n initInteractivity()\n\n return () => {\n deinitInteractivity()\n }\n }, [])\n\n useEffect(() => {\n if (isDragging === true) return\n if (index === _index) return\n setIsDragging(undefined)\n setLivePosition(getPositionAt(index, steps))\n setLiveIndex(index)\n }, [index])\n\n useEffect(() => {\n if (isDragging === true && onlyDispatchesOnDragEnd) return\n onPositionChange?.(_position, isDragging !== undefined)\n }, [_position])\n\n useEffect(() => {\n if (isDragging === true && onlyDispatchesOnDragEnd) return\n onIndexChange?.(_index, isDragging !== undefined)\n }, [_index])\n\n useEffect(() => {\n if (isDragging !== false) return\n\n const nearestIndex = getNearestIndexByPosition(_position, steps)\n const nearestPosition = getPositionAt(nearestIndex, steps)\n setLivePosition(nearestPosition)\n\n if (onlyDispatchesOnDragEnd) {\n onIndexChange?.(_index, true)\n }\n }, [isDragging])\n\n return (\n <StyledRoot ref={rootRef} id={id} className={className} orientation={orientation} style={style}>\n <StyledGutter orientation={orientation} css={startingGutterCSS}\n style={orientation === 'vertical' ? {\n top: 0,\n height: `calc(${naturalPosition*100}% - ${knobHeight*.5}px - ${gutterPadding}px)`,\n } : {\n left: 0,\n width: `calc(${naturalPosition*100}% - ${knobWidth*.5}px - ${gutterPadding}px)`,\n }}\n />\n <StyledKnobContainer ref={knobRef} style={{\n transform: 'translate3d(-50%, -50%, 0)',\n ...(orientation === 'vertical' ? {\n left: '50%',\n top: `${naturalPosition*100}%`,\n transition: isDragging === false ? 'top 100ms ease-out' : 'none',\n } : {\n left: `${naturalPosition*100}%`,\n top: '50%',\n transition: isDragging === false ? 'left 100ms ease-out' : 'none',\n }),\n }}>\n <StyledKnob\n className={classNames({\n 'at-end': isInverted ? (_position === 0) : (_position === 1),\n 'at-start': isInverted ? (_position === 1) : (_position === 0),\n 'dragging': isDragging === true,\n })}\n css={knobCSS}\n style={{\n height: `${knobHeight}px`,\n width: `${knobWidth}px`,\n }}\n >\n {steps && labelProvider && (\n <StyledLabel knobHeight={knobHeight} css={labelCSS}>{labelProvider(_position, getNearestIndexByPosition(_position, steps))}</StyledLabel>\n )}\n </StyledKnob>\n </StyledKnobContainer>\n <StyledGutter orientation={orientation} css={endingGutterCSS}\n style={orientation === 'vertical' ? {\n bottom: 0,\n height: `calc(${(1 - naturalPosition)*100}% - ${knobHeight*.5}px - ${gutterPadding}px)`,\n } : {\n right: 0,\n width: `calc(${(1 - naturalPosition)*100}% - ${knobWidth*.5}px - ${gutterPadding}px)`,\n }}\n />\n </StyledRoot>\n )\n}\n\nconst StyledGutter = styled.div<{ orientation: NonNullable<Props['orientation']> }>`\n background: #fff;\n position: absolute;\n\n ${props => props.orientation === 'vertical' ? css`\n left: 0;\n margin: 0 auto;\n right: 0;\n width: 100%;\n ` : css`\n bottom: 0;\n height: 100%;\n margin: auto 0;\n top: 0;\n `}\n\n ${props => props.css}\n`\n\nconst StyledLabel = styled.label<{ knobHeight: NonNullable<Props['knobHeight']> }>`\n color: #000;\n font-size: ${props => props.knobHeight * .5}px;\n pointer-events: none;\n user-select: none;\n\n ${props => props.css}\n`\n\nconst StyledKnobContainer = styled.button`\n position: absolute;\n z-index: 1;\n transition-duration: 100ms;\n transition-property: top;\n transition-timing-function: ease-out;\n`\n\nconst StyledKnob = styled.div`\n align-items: center;\n background: #fff;\n box-sizing: border-box;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n justify-content: center;\n opacity: 1;\n touch-action: none;\n transition-duration: 100ms;\n transition-property: background, color, opacity, transform;\n transition-timing-function: ease-out;\n\n ${props => props.css}\n`\n\nconst StyledRoot = styled.div<{\n orientation: Orientation\n}>`\n box-sizing: border-box;\n display: block;\n height: ${props => props.orientation === 'vertical' ? '300px' : '4px'};\n position: relative;\n width: ${props => props.orientation === 'vertical' ? '4px' : '300px'};\n`\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "etudes",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "A study of styled React components",
|
|
5
5
|
"main": "lib",
|
|
6
6
|
"scripts": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"prebuild": "npm run lint",
|
|
9
9
|
"build": "npm run clean && tsc -p tsconfig.json",
|
|
10
10
|
"pages": "rimraf .gh-pages && webpack --config demo/config/build.conf.ts",
|
|
11
|
-
"demo": "cross-env NODE_ENV=development webpack-cli serve --mode development --hot --config demo/config/build.conf.ts",
|
|
11
|
+
"demo": "npm run clean && concurrently \"npm run build -- --watch\" \"wait-on lib && cross-env NODE_ENV=development webpack-cli serve --mode development --hot --config demo/config/build.conf.ts\"",
|
|
12
12
|
"test": "echo \"No tests yet :)\"",
|
|
13
13
|
"lint": "eslint --ext .ts --ext .tsx src demo",
|
|
14
14
|
"lint:fix": "npm run lint -- --fix"
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"@typescript-eslint/parser": "^5.4.0",
|
|
49
49
|
"babel-loader": "^8.2.3",
|
|
50
50
|
"babel-plugin-styled-components": "^2.0.1",
|
|
51
|
+
"concurrently": "^6.4.0",
|
|
51
52
|
"cross-env": "^7.0.3",
|
|
52
53
|
"debug": "^4.3.2",
|
|
53
54
|
"dirty-dom": "^7.0.0",
|
|
@@ -67,6 +68,7 @@
|
|
|
67
68
|
"ts-node": "^10.4.0",
|
|
68
69
|
"typescript": "^4.5.2",
|
|
69
70
|
"url-loader": "^4.1.1",
|
|
71
|
+
"wait-on": "^6.0.0",
|
|
70
72
|
"webpack": "^5.64.3",
|
|
71
73
|
"webpack-cli": "^4.9.1",
|
|
72
74
|
"webpack-dev-server": "^4.5.0"
|