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