1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | import { __assign, __extends } from "tslib";
|
17 | import classNames from "classnames";
|
18 | import * as React from "react";
|
19 | import { AbstractPureComponent, Classes, DISPLAYNAME_PREFIX, Intent, Utils } from "../../common";
|
20 | import * as Errors from "../../common/errors";
|
21 | import { Handle } from "./handle";
|
22 | import { HandleInteractionKind, HandleType } from "./handleProps";
|
23 | import { argMin, fillValues, formatPercentage } from "./sliderUtils";
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | var MultiSliderHandle = function () { return null; };
|
29 | MultiSliderHandle.displayName = "".concat(DISPLAYNAME_PREFIX, ".MultiSliderHandle");
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | var MultiSlider = (function (_super) {
|
36 | __extends(MultiSlider, _super);
|
37 | function MultiSlider() {
|
38 | var _this = _super !== null && _super.apply(this, arguments) || this;
|
39 | _this.state = {
|
40 | labelPrecision: getLabelPrecision(_this.props),
|
41 | tickSize: 0,
|
42 | tickSizeRatio: 0,
|
43 | };
|
44 | _this.handleElements = [];
|
45 | _this.trackElement = null;
|
46 | _this.addHandleRef = function (ref) {
|
47 | if (ref != null) {
|
48 | _this.handleElements.push(ref);
|
49 | }
|
50 | };
|
51 | _this.maybeHandleTrackClick = function (event) {
|
52 | if (_this.canHandleTrackEvent(event)) {
|
53 | var foundHandle = _this.nearestHandleForValue(_this.handleElements, function (handle) {
|
54 | return handle.mouseEventClientOffset(event);
|
55 | });
|
56 | if (foundHandle) {
|
57 | foundHandle.beginHandleMovement(event);
|
58 | }
|
59 | }
|
60 | };
|
61 | _this.maybeHandleTrackTouch = function (event) {
|
62 | if (_this.canHandleTrackEvent(event)) {
|
63 | var foundHandle = _this.nearestHandleForValue(_this.handleElements, function (handle) {
|
64 | return handle.touchEventClientOffset(event);
|
65 | });
|
66 | if (foundHandle) {
|
67 | foundHandle.beginHandleTouchMovement(event);
|
68 | }
|
69 | }
|
70 | };
|
71 | _this.canHandleTrackEvent = function (event) {
|
72 | var target = event.target;
|
73 |
|
74 | return !_this.props.disabled && target.closest(".".concat(Classes.SLIDER_HANDLE)) == null;
|
75 | };
|
76 | _this.getHandlerForIndex = function (index, callback) {
|
77 | return function (newValue) {
|
78 | callback === null || callback === void 0 ? void 0 : callback(_this.getNewHandleValues(newValue, index));
|
79 | };
|
80 | };
|
81 | _this.handleChange = function (newValues) {
|
82 | var _a, _b;
|
83 | var handleProps = getSortedInteractiveHandleProps(_this.props);
|
84 | var oldValues = handleProps.map(function (handle) { return handle.value; });
|
85 | if (!Utils.arraysEqual(newValues, oldValues)) {
|
86 | (_b = (_a = _this.props).onChange) === null || _b === void 0 ? void 0 : _b.call(_a, newValues);
|
87 | handleProps.forEach(function (handle, index) {
|
88 | var _a;
|
89 | if (oldValues[index] !== newValues[index]) {
|
90 | (_a = handle.onChange) === null || _a === void 0 ? void 0 : _a.call(handle, newValues[index]);
|
91 | }
|
92 | });
|
93 | }
|
94 | };
|
95 | _this.handleRelease = function (newValues) {
|
96 | var _a, _b;
|
97 | var handleProps = getSortedInteractiveHandleProps(_this.props);
|
98 | (_b = (_a = _this.props).onRelease) === null || _b === void 0 ? void 0 : _b.call(_a, newValues);
|
99 | handleProps.forEach(function (handle, index) {
|
100 | var _a;
|
101 | (_a = handle.onRelease) === null || _a === void 0 ? void 0 : _a.call(handle, newValues[index]);
|
102 | });
|
103 | };
|
104 | return _this;
|
105 | }
|
106 | MultiSlider.getDerivedStateFromProps = function (props) {
|
107 | return { labelPrecision: MultiSlider.getLabelPrecision(props) };
|
108 | };
|
109 | MultiSlider.getLabelPrecision = function (_a) {
|
110 | var labelPrecision = _a.labelPrecision, stepSize = _a.stepSize;
|
111 |
|
112 | return labelPrecision == null ? Utils.countDecimalPlaces(stepSize) : labelPrecision;
|
113 | };
|
114 | MultiSlider.prototype.getSnapshotBeforeUpdate = function (prevProps) {
|
115 | var prevHandleProps = getSortedInteractiveHandleProps(prevProps);
|
116 | var newHandleProps = getSortedInteractiveHandleProps(this.props);
|
117 | if (newHandleProps.length !== prevHandleProps.length) {
|
118 |
|
119 | this.handleElements = [];
|
120 | }
|
121 | return null;
|
122 | };
|
123 | MultiSlider.prototype.render = function () {
|
124 | var _a;
|
125 | var _this = this;
|
126 | var classes = classNames(Classes.SLIDER, (_a = {},
|
127 | _a[Classes.DISABLED] = this.props.disabled,
|
128 | _a["".concat(Classes.SLIDER, "-unlabeled")] = this.props.labelRenderer === false,
|
129 | _a[Classes.VERTICAL] = this.props.vertical,
|
130 | _a), this.props.className);
|
131 | return (React.createElement("div", { className: classes, onMouseDown: this.maybeHandleTrackClick, onTouchStart: this.maybeHandleTrackTouch },
|
132 | React.createElement("div", { className: Classes.SLIDER_TRACK, ref: function (ref) { return (_this.trackElement = ref); } }, this.renderTracks()),
|
133 | React.createElement("div", { className: Classes.SLIDER_AXIS }, this.renderLabels()),
|
134 | this.renderHandles()));
|
135 | };
|
136 | MultiSlider.prototype.componentDidMount = function () {
|
137 | this.updateTickSize();
|
138 | };
|
139 | MultiSlider.prototype.componentDidUpdate = function (prevProps, prevState) {
|
140 | _super.prototype.componentDidUpdate.call(this, prevProps, prevState);
|
141 | this.updateTickSize();
|
142 | };
|
143 | MultiSlider.prototype.validateProps = function (props) {
|
144 | if (props.stepSize <= 0) {
|
145 | throw new Error(Errors.SLIDER_ZERO_STEP);
|
146 | }
|
147 | if (props.labelStepSize !== undefined && props.labelValues !== undefined) {
|
148 | throw new Error(Errors.MULTISLIDER_WARN_LABEL_STEP_SIZE_LABEL_VALUES_MUTEX);
|
149 | }
|
150 | if (props.labelStepSize !== undefined && props.labelStepSize <= 0) {
|
151 | throw new Error(Errors.SLIDER_ZERO_LABEL_STEP);
|
152 | }
|
153 | if (props.min !== undefined && !isFinite(props.min)) {
|
154 | throw new Error(Errors.SLIDER_MIN);
|
155 | }
|
156 | if (props.max !== undefined && !isFinite(props.max)) {
|
157 | throw new Error(Errors.SLIDER_MAX);
|
158 | }
|
159 | var anyInvalidChildren = false;
|
160 | React.Children.forEach(props.children, function (child) {
|
161 |
|
162 | if (child && !Utils.isElementOfType(child, MultiSlider.Handle)) {
|
163 | anyInvalidChildren = true;
|
164 | }
|
165 | });
|
166 | if (anyInvalidChildren) {
|
167 | throw new Error(Errors.MULTISLIDER_INVALID_CHILD);
|
168 | }
|
169 | };
|
170 | MultiSlider.prototype.formatLabel = function (value, isHandleTooltip) {
|
171 | if (isHandleTooltip === void 0) { isHandleTooltip = false; }
|
172 | var labelRenderer = this.props.labelRenderer;
|
173 | if (labelRenderer === false) {
|
174 | return undefined;
|
175 | }
|
176 | else if (Utils.isFunction(labelRenderer)) {
|
177 | return labelRenderer(value, { isHandleTooltip: isHandleTooltip });
|
178 | }
|
179 | else {
|
180 | return value.toFixed(this.state.labelPrecision);
|
181 | }
|
182 | };
|
183 | MultiSlider.prototype.renderLabels = function () {
|
184 | var _this = this;
|
185 | if (this.props.labelRenderer === false) {
|
186 | return null;
|
187 | }
|
188 | var values = this.getLabelValues();
|
189 | var _a = this.props, max = _a.max, min = _a.min;
|
190 | var labels = values.map(function (step, i) {
|
191 | var offsetPercentage = formatPercentage((step - min) / (max - min));
|
192 | var style = _this.props.vertical ? { bottom: offsetPercentage } : { left: offsetPercentage };
|
193 | return (React.createElement("div", { className: Classes.SLIDER_LABEL, key: i, style: style }, _this.formatLabel(step)));
|
194 | });
|
195 | return labels;
|
196 | };
|
197 | MultiSlider.prototype.renderTracks = function () {
|
198 | var trackStops = getSortedHandleProps(this.props);
|
199 | trackStops.push({ value: this.props.max });
|
200 |
|
201 | var previous = { value: this.props.min };
|
202 | var handles = [];
|
203 | for (var index = 0; index < trackStops.length; index++) {
|
204 | var current = trackStops[index];
|
205 | handles.push(this.renderTrackFill(index, previous, current));
|
206 | previous = current;
|
207 | }
|
208 | return handles;
|
209 | };
|
210 | MultiSlider.prototype.renderTrackFill = function (index, start, end) {
|
211 |
|
212 | var _a = [this.getOffsetRatio(start.value), this.getOffsetRatio(end.value)].sort(function (left, right) { return left - right; }), startRatio = _a[0], endRatio = _a[1];
|
213 | var startOffset = formatPercentage(startRatio);
|
214 | var endOffset = formatPercentage(1 - endRatio);
|
215 | var orientationStyle = this.props.vertical
|
216 | ? { bottom: startOffset, top: endOffset, left: 0 }
|
217 | : { left: startOffset, right: endOffset, top: 0 };
|
218 | var style = __assign(__assign({}, orientationStyle), (start.trackStyleAfter || end.trackStyleBefore || {}));
|
219 | var classes = classNames(Classes.SLIDER_PROGRESS, Classes.intentClass(this.getTrackIntent(start, end)));
|
220 | return React.createElement("div", { key: "track-".concat(index), className: classes, style: style });
|
221 | };
|
222 | MultiSlider.prototype.renderHandles = function () {
|
223 | var _this = this;
|
224 | var _a = this.props, disabled = _a.disabled, max = _a.max, min = _a.min, stepSize = _a.stepSize, vertical = _a.vertical;
|
225 | var handleProps = getSortedInteractiveHandleProps(this.props);
|
226 | if (handleProps.length === 0) {
|
227 | return null;
|
228 | }
|
229 | return handleProps.map(function (_a, index) {
|
230 | var _b;
|
231 | var value = _a.value, type = _a.type, className = _a.className, htmlProps = _a.htmlProps;
|
232 | return (React.createElement(Handle, { htmlProps: htmlProps, className: classNames((_b = {},
|
233 | _b[Classes.START] = type === HandleType.START,
|
234 | _b[Classes.END] = type === HandleType.END,
|
235 | _b), className), disabled: disabled, key: "".concat(index, "-").concat(handleProps.length), label: _this.formatLabel(value, true), max: max, min: min, onChange: _this.getHandlerForIndex(index, _this.handleChange), onRelease: _this.getHandlerForIndex(index, _this.handleRelease), ref: _this.addHandleRef, stepSize: stepSize, tickSize: _this.state.tickSize, tickSizeRatio: _this.state.tickSizeRatio, value: value, vertical: vertical }));
|
236 | });
|
237 | };
|
238 | MultiSlider.prototype.nearestHandleForValue = function (handles, getOffset) {
|
239 | return argMin(handles, function (handle) {
|
240 | var offset = getOffset(handle);
|
241 | var offsetValue = handle.clientToValue(offset);
|
242 | var handleValue = handle.props.value;
|
243 | return Math.abs(offsetValue - handleValue);
|
244 | });
|
245 | };
|
246 | MultiSlider.prototype.getNewHandleValues = function (newValue, oldIndex) {
|
247 | var handleProps = getSortedInteractiveHandleProps(this.props);
|
248 | var oldValues = handleProps.map(function (handle) { return handle.value; });
|
249 | var newValues = oldValues.slice();
|
250 | newValues[oldIndex] = newValue;
|
251 | newValues.sort(function (left, right) { return left - right; });
|
252 | var newIndex = newValues.indexOf(newValue);
|
253 | var lockIndex = this.findFirstLockedHandleIndex(oldIndex, newIndex);
|
254 | if (lockIndex === -1) {
|
255 | fillValues(newValues, oldIndex, newIndex, newValue);
|
256 | }
|
257 | else {
|
258 |
|
259 | var lockValue = oldValues[lockIndex];
|
260 | fillValues(oldValues, oldIndex, lockIndex, lockValue);
|
261 | return oldValues;
|
262 | }
|
263 | return newValues;
|
264 | };
|
265 | MultiSlider.prototype.findFirstLockedHandleIndex = function (startIndex, endIndex) {
|
266 | var inc = startIndex < endIndex ? 1 : -1;
|
267 | var handleProps = getSortedInteractiveHandleProps(this.props);
|
268 | for (var index = startIndex + inc; index !== endIndex + inc; index += inc) {
|
269 | if (handleProps[index].interactionKind !== HandleInteractionKind.PUSH) {
|
270 | return index;
|
271 | }
|
272 | }
|
273 | return -1;
|
274 | };
|
275 | MultiSlider.prototype.getLabelValues = function () {
|
276 | var _a = this.props, labelStepSize = _a.labelStepSize, labelValues = _a.labelValues, min = _a.min, max = _a.max;
|
277 | var values = [];
|
278 | if (labelValues !== undefined) {
|
279 | values = labelValues.slice();
|
280 | }
|
281 | else {
|
282 | for (var i = min; i < max || Utils.approxEqual(i, max); i += labelStepSize !== null && labelStepSize !== void 0 ? labelStepSize : 1) {
|
283 | values.push(i);
|
284 | }
|
285 | }
|
286 | return values;
|
287 | };
|
288 | MultiSlider.prototype.getOffsetRatio = function (value) {
|
289 | return Utils.clamp((value - this.props.min) * this.state.tickSizeRatio, 0, 1);
|
290 | };
|
291 | MultiSlider.prototype.getTrackIntent = function (start, end) {
|
292 | if (!this.props.showTrackFill) {
|
293 | return Intent.NONE;
|
294 | }
|
295 | if (start.intentAfter !== undefined) {
|
296 | return start.intentAfter;
|
297 | }
|
298 | else if (end !== undefined && end.intentBefore !== undefined) {
|
299 | return end.intentBefore;
|
300 | }
|
301 | return this.props.defaultTrackIntent;
|
302 | };
|
303 | MultiSlider.prototype.updateTickSize = function () {
|
304 | if (this.trackElement != null) {
|
305 | var trackSize = this.props.vertical ? this.trackElement.clientHeight : this.trackElement.clientWidth;
|
306 | var tickSizeRatio = 1 / (this.props.max - this.props.min);
|
307 | var tickSize = trackSize * tickSizeRatio;
|
308 | this.setState({ tickSize: tickSize, tickSizeRatio: tickSizeRatio });
|
309 | }
|
310 | };
|
311 | MultiSlider.defaultSliderProps = {
|
312 | disabled: false,
|
313 | max: 10,
|
314 | min: 0,
|
315 | showTrackFill: true,
|
316 | stepSize: 1,
|
317 | vertical: false,
|
318 | };
|
319 | MultiSlider.defaultProps = __assign(__assign({}, MultiSlider.defaultSliderProps), { defaultTrackIntent: Intent.NONE });
|
320 | MultiSlider.displayName = "".concat(DISPLAYNAME_PREFIX, ".MultiSlider");
|
321 | MultiSlider.Handle = MultiSliderHandle;
|
322 | return MultiSlider;
|
323 | }(AbstractPureComponent));
|
324 | export { MultiSlider };
|
325 | function getLabelPrecision(_a) {
|
326 | var labelPrecision = _a.labelPrecision, _b = _a.stepSize, stepSize = _b === void 0 ? MultiSlider.defaultSliderProps.stepSize : _b;
|
327 |
|
328 | return labelPrecision == null ? Utils.countDecimalPlaces(stepSize) : labelPrecision;
|
329 | }
|
330 | function getSortedInteractiveHandleProps(props) {
|
331 | return getSortedHandleProps(props, function (childProps) { return childProps.interactionKind !== HandleInteractionKind.NONE; });
|
332 | }
|
333 | function getSortedHandleProps(_a, predicate) {
|
334 | var children = _a.children;
|
335 | if (predicate === void 0) { predicate = function () { return true; }; }
|
336 | var maybeHandles = React.Children.map(children, function (child) {
|
337 | return Utils.isElementOfType(child, MultiSlider.Handle) && predicate(child.props) ? child.props : null;
|
338 | });
|
339 | var handles = maybeHandles != null ? maybeHandles : [];
|
340 | handles = handles.filter(function (handle) { return handle !== null; });
|
341 | handles.sort(function (left, right) { return left.value - right.value; });
|
342 | return handles;
|
343 | }
|
344 |
|
\ | No newline at end of file |