Skip to content

Commit 9ba1136

Browse files
authored
Prevent <input> element re-rendering if tooltip visibility is changed (#12)
* docs: Add example of changing tooltip visibility during user interaction (currently buggy) * fix: Ensure <input> element only re-renders when absolutely necessary
1 parent 36f2451 commit 9ba1136

File tree

6 files changed

+420
-261
lines changed

6 files changed

+420
-261
lines changed

dist/index.js

Lines changed: 100 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -191,91 +191,121 @@ function _nonIterableRest() {
191191
}
192192

193193
var DEFAULT_CLASS_PREFIX = 'range-slider';
194-
var RangeSlider = /*#__PURE__*/React__default.forwardRef(function (_ref, ref) {
195-
var size = _ref.size,
196-
_ref$disabled = _ref.disabled,
197-
disabled = _ref$disabled === void 0 ? false : _ref$disabled,
198-
value = _ref.value,
199-
_ref$onChange = _ref.onChange,
200-
_onChange = _ref$onChange === void 0 ? function () {} : _ref$onChange,
201-
_ref$onAfterChange = _ref.onAfterChange,
202-
onAfterChange = _ref$onAfterChange === void 0 ? function () {} : _ref$onAfterChange,
203-
_ref$min = _ref.min,
204-
min = _ref$min === void 0 ? 0 : _ref$min,
205-
_ref$max = _ref.max,
206-
max = _ref$max === void 0 ? 100 : _ref$max,
207-
step = _ref.step,
208-
_ref$variant = _ref.variant,
209-
variant = _ref$variant === void 0 ? 'primary' : _ref$variant,
210-
_ref$inputProps = _ref.inputProps,
211-
inputProps = _ref$inputProps === void 0 ? {} : _ref$inputProps,
212-
_ref$tooltip = _ref.tooltip,
213-
tooltip = _ref$tooltip === void 0 ? 'auto' : _ref$tooltip,
214-
_ref$tooltipPlacement = _ref.tooltipPlacement,
215-
tooltipPlacement = _ref$tooltipPlacement === void 0 ? 'bottom' : _ref$tooltipPlacement,
216-
tooltipLabel = _ref.tooltipLabel,
217-
_ref$tooltipStyle = _ref.tooltipStyle,
218-
tooltipStyle = _ref$tooltipStyle === void 0 ? {} : _ref$tooltipStyle,
219-
_ref$tooltipProps = _ref.tooltipProps,
220-
tooltipProps = _ref$tooltipProps === void 0 ? {} : _ref$tooltipProps,
221-
bsPrefix = _ref.bsPrefix,
222-
className = _ref.className;
194+
195+
var Input = function Input(_ref) {
196+
var classes = _ref.classes,
197+
_onChange = _ref.onChange,
198+
onMouseUpOrTouchEnd = _ref.onMouseUpOrTouchEnd,
199+
_onTouchEnd = _ref.onTouchEnd,
200+
_onMouseUp = _ref.onMouseUp,
201+
rest = _objectWithoutProperties(_ref, ["classes", "onChange", "onMouseUpOrTouchEnd", "onTouchEnd", "onMouseUp"]);
202+
203+
return /*#__PURE__*/React__default.createElement("input", _extends({
204+
type: "range",
205+
onChange: function onChange(ev) {
206+
return _onChange(ev, ev.target.valueAsNumber);
207+
},
208+
onMouseUp: function onMouseUp(ev) {
209+
onMouseUpOrTouchEnd(ev);
210+
if (_onMouseUp) _onMouseUp(ev);
211+
},
212+
onTouchEnd: function onTouchEnd(ev) {
213+
onMouseUpOrTouchEnd(ev);
214+
if (_onTouchEnd) _onTouchEnd(ev);
215+
},
216+
className: classes
217+
}, rest));
218+
};
219+
220+
Input.propTypes = {
221+
classes: PropTypes.string.isRequired,
222+
onChange: PropTypes.func.isRequired,
223+
onMouseUpOrTouchEnd: PropTypes.func.isRequired,
224+
onTouchEnd: PropTypes.func,
225+
onMouseUp: PropTypes.func
226+
};
227+
var InputMemo = /*#__PURE__*/React__default.memo(Input);
228+
var RangeSlider = /*#__PURE__*/React__default.forwardRef(function (_ref2, ref) {
229+
var size = _ref2.size,
230+
_ref2$disabled = _ref2.disabled,
231+
disabled = _ref2$disabled === void 0 ? false : _ref2$disabled,
232+
value = _ref2.value,
233+
_ref2$onChange = _ref2.onChange,
234+
onChange = _ref2$onChange === void 0 ? function () {} : _ref2$onChange,
235+
_ref2$onAfterChange = _ref2.onAfterChange,
236+
onAfterChange = _ref2$onAfterChange === void 0 ? function () {} : _ref2$onAfterChange,
237+
_ref2$min = _ref2.min,
238+
min = _ref2$min === void 0 ? 0 : _ref2$min,
239+
_ref2$max = _ref2.max,
240+
max = _ref2$max === void 0 ? 100 : _ref2$max,
241+
step = _ref2.step,
242+
_ref2$variant = _ref2.variant,
243+
variant = _ref2$variant === void 0 ? 'primary' : _ref2$variant,
244+
_ref2$inputProps = _ref2.inputProps,
245+
inputProps = _ref2$inputProps === void 0 ? {} : _ref2$inputProps,
246+
_ref2$tooltip = _ref2.tooltip,
247+
tooltip = _ref2$tooltip === void 0 ? 'auto' : _ref2$tooltip,
248+
_ref2$tooltipPlacemen = _ref2.tooltipPlacement,
249+
tooltipPlacement = _ref2$tooltipPlacemen === void 0 ? 'bottom' : _ref2$tooltipPlacemen,
250+
tooltipLabel = _ref2.tooltipLabel,
251+
_ref2$tooltipStyle = _ref2.tooltipStyle,
252+
tooltipStyle = _ref2$tooltipStyle === void 0 ? {} : _ref2$tooltipStyle,
253+
_ref2$tooltipProps = _ref2.tooltipProps,
254+
tooltipProps = _ref2$tooltipProps === void 0 ? {} : _ref2$tooltipProps,
255+
bsPrefix = _ref2.bsPrefix,
256+
className = _ref2.className;
223257

224258
var _useState = React.useState(),
225259
_useState2 = _slicedToArray(_useState, 2),
226-
prevValue = _useState2[0],
227260
setPrevValue = _useState2[1];
228261

229262
var prefix = bsPrefix || DEFAULT_CLASS_PREFIX;
230263
var isTooltip = tooltip === 'auto' || tooltip === 'on';
231264
var classes = classNames(className, prefix, size && "".concat(prefix, "--").concat(size), disabled && 'disabled', variant && "".concat(prefix, "--").concat(variant));
232265

233-
var inputPropsOnMouseUp = inputProps.inputPropsOnMouseUp,
234-
restInputProps = _objectWithoutProperties(inputProps, ["inputPropsOnMouseUp"]);
266+
var onMouseUp = inputProps.onMouseUp,
267+
onTouchEnd = inputProps.onTouchEnd,
268+
restInputProps = _objectWithoutProperties(inputProps, ["onMouseUp", "onTouchEnd"]);
235269

236-
var inputEl = /*#__PURE__*/React__default.createElement("input", _extends({
237-
type: "range",
238-
className: classes,
270+
var onMouseUpOrTouchEnd = React.useCallback(function (ev) {
271+
setPrevValue(function (prevValue) {
272+
if (prevValue !== ev.target.value) onAfterChange(ev, ev.target.valueAsNumber);
273+
return ev.target.value;
274+
});
275+
}, [setPrevValue, onAfterChange]);
276+
var inputEl = /*#__PURE__*/React__default.createElement(InputMemo, _objectSpread2({
277+
disabled: disabled,
239278
value: value,
240279
min: min,
241280
max: max,
281+
ref: ref,
242282
step: step,
243-
onChange: function onChange(ev) {
244-
return _onChange(ev, ev.target.valueAsNumber);
245-
},
246-
onMouseUp: function onMouseUp(ev) {
247-
if (ev.target.value !== prevValue) onAfterChange(ev, ev.target.valueAsNumber);
248-
setPrevValue(ev.target.value);
249-
if (inputPropsOnMouseUp) inputPropsOnMouseUp(ev);
250-
},
251-
disabled: disabled,
252-
ref: ref
283+
classes: classes,
284+
onMouseUpOrTouchEnd: onMouseUpOrTouchEnd,
285+
onTouchEnd: onTouchEnd,
286+
onMouseUp: onMouseUp,
287+
onChange: onChange
253288
}, restInputProps));
254-
255-
if (isTooltip) {
256-
var wrapClasses = classNames("".concat(prefix, "__wrap"), size && "".concat(prefix, "__wrap--").concat(size));
257-
var tooltipClasses = classNames("".concat(prefix, "__tooltip"), isTooltip && "".concat(prefix, "__tooltip--").concat(tooltip), tooltipPlacement && "".concat(prefix, "__tooltip--").concat(tooltipPlacement), disabled && "".concat(prefix, "__tooltip--disabled"));
258-
var thumbRadius = size === 'sm' ? 8 : size === 'lg' ? 12 : 10;
259-
var fract = (value - min) / (max - min);
260-
var percentLeft = fract * 100;
261-
var fractFromCentre = (fract - 0.5) * 2;
262-
var adjustment = fractFromCentre * -thumbRadius; // Half thumb width
263-
264-
return /*#__PURE__*/React__default.createElement("span", {
265-
className: wrapClasses
266-
}, inputEl, /*#__PURE__*/React__default.createElement("div", _extends({
267-
className: tooltipClasses,
268-
style: _objectSpread2(_objectSpread2({}, tooltipStyle || {}), {}, {
269-
left: "calc(".concat(percentLeft, "% + ").concat(adjustment, "px)")
270-
})
271-
}, tooltipProps), /*#__PURE__*/React__default.createElement("div", {
272-
className: "".concat(prefix, "__tooltip__label")
273-
}, tooltipLabel ? tooltipLabel(value) : value), /*#__PURE__*/React__default.createElement("div", {
274-
className: "".concat(prefix, "__tooltip__arrow")
275-
})));
276-
} else {
277-
return inputEl;
278-
}
289+
var wrapClasses = classNames("".concat(prefix, "__wrap"), size && "".concat(prefix, "__wrap--").concat(size));
290+
var tooltipClasses = classNames("".concat(prefix, "__tooltip"), isTooltip && "".concat(prefix, "__tooltip--").concat(tooltip), tooltipPlacement && "".concat(prefix, "__tooltip--").concat(tooltipPlacement), disabled && "".concat(prefix, "__tooltip--disabled"));
291+
var thumbRadius = size === 'sm' ? 8 : size === 'lg' ? 12 : 10;
292+
var fract = (value - min) / (max - min);
293+
var percentLeft = fract * 100;
294+
var fractFromCentre = (fract - 0.5) * 2;
295+
var adjustment = fractFromCentre * -thumbRadius; // Half thumb width
296+
297+
return /*#__PURE__*/React__default.createElement("span", {
298+
className: wrapClasses
299+
}, inputEl, isTooltip && /*#__PURE__*/React__default.createElement("div", _extends({
300+
className: tooltipClasses,
301+
style: _objectSpread2(_objectSpread2({}, tooltipStyle || {}), {}, {
302+
left: "calc(".concat(percentLeft, "% + ").concat(adjustment, "px)")
303+
})
304+
}, tooltipProps), /*#__PURE__*/React__default.createElement("div", {
305+
className: "".concat(prefix, "__tooltip__label")
306+
}, tooltipLabel ? tooltipLabel(value) : value), /*#__PURE__*/React__default.createElement("div", {
307+
className: "".concat(prefix, "__tooltip__arrow")
308+
})));
279309
}); // Fix: https://github.com/jaywilz/react-bootstrap-range-slider/issues/3
280310

281311
var Element = typeof Element === 'undefined' ? function () {} : Element;

0 commit comments

Comments
 (0)