@react-md/form
Version:
This package is for creating all the different form input types.
367 lines • 14.3 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
import { useCallback, useEffect, useRef, useState } from "react";
import { applyRef, useDir, useIsomorphicLayoutEffect } from "@react-md/utils";
import { DEFAULT_SLIDER_ANIMATION_TIME } from "./constants";
import { getDragPercentage, getDragValue, isMouseEvent, isRangeSlider, isTouchEvent, } from "./utils";
var VALID_KEYS = [
"ArrowDown",
"ArrowUp",
"ArrowLeft",
"ArrowRight",
"Home",
"End",
"PageUp",
"PageDown",
];
/**
* This hook provides all the logic for updating the slider's when the user
* interacts with the slider.
*
* @internal
* @remarks \@since 2.5.0
*/
export function useSliderControls(_a) {
var _b, _c;
var ref = _a.ref, propThumb1Ref = _a.thumb1Ref, propThumb2Ref = _a.thumb2Ref, min = _a.min, max = _a.max, step = _a.step, _d = _a.disabled, disabled = _d === void 0 ? false : _d, _e = _a.vertical, vertical = _e === void 0 ? false : _e, onBlur = _a.onBlur, onKeyDown = _a.onKeyDown, onMouseDown = _a.onMouseDown, onTouchStart = _a.onTouchStart, _f = _a.animationDuration, animationDuration = _f === void 0 ? DEFAULT_SLIDER_ANIMATION_TIME : _f, controls = __rest(_a, ["ref", "thumb1Ref", "thumb2Ref", "min", "max", "step", "disabled", "vertical", "onBlur", "onKeyDown", "onMouseDown", "onTouchStart", "animationDuration"]);
var trackRef = useRef(null);
var thumb1Ref = useRef(null);
var thumb2Ref = useRef(null);
var _g = __read(useState(false), 2), dragging = _g[0], setDragging = _g[1];
var _h = __read(useState(min), 2), dragValue = _h[0], setDragValue = _h[1];
var _j = __read(useState(null), 2), draggingBy = _j[0], setDraggingBy = _j[1];
var _k = __read(useState(null), 2), draggingIndex = _k[0], setDraggingIndex = _k[1];
var controlsRef = useRef(controls);
useIsomorphicLayoutEffect(function () {
controlsRef.current = controls;
});
var dir = useDir().dir;
var isRtl = dir === "rtl";
var thumb1Value;
var thumb1Percentage;
var thumb2Value;
var thumb2Percentage;
if (isRangeSlider(controls)) {
_b = __read(controls.value, 2), thumb1Value = _b[0], thumb2Value = _b[1];
(_c = getDragPercentage({
min: min,
max: max,
thumb1Value: thumb1Value,
thumb2Value: thumb2Value,
dragging: dragging,
dragValue: dragValue,
draggingIndex: draggingIndex,
}), thumb1Percentage = _c.thumb1Percentage, thumb2Percentage = _c.thumb2Percentage);
}
else {
thumb1Value = controls.value;
(thumb1Percentage = getDragPercentage({
min: min,
max: max,
thumb1Value: thumb1Value,
dragging: dragging,
dragValue: dragValue,
draggingIndex: draggingIndex,
}).thumb1Percentage);
}
/**
* The main handler for updating the value of the slider. To help keep the
* drag experience smooth, some values are stored in refs to prevent the
* `useEffect` from being run during renders which adds and removes the move
* event handlers
*/
var drag = useCallback(function (event) {
var track = trackRef.current;
var slider1 = thumb1Ref.current;
var slider2 = thumb2Ref.current;
var altKey = event.altKey, ctrlKey = event.ctrlKey, metaKey = event.metaKey, shiftKey = event.shiftKey;
if (altKey ||
ctrlKey ||
metaKey ||
shiftKey ||
disabled ||
!track ||
!slider1 ||
(isMouseEvent(event) && event.button !== 0) ||
(isTouchEvent(event) && event.changedTouches.length !== 1) ||
(!isMouseEvent(event) && !isTouchEvent(event))) {
return;
}
// prevent text from being highlighted on desktop or the page from
// scrolling on mobile while dragging
if (!isTouchEvent(event) || event.type === "touchmove") {
event.preventDefault();
}
event.stopPropagation();
// get the current mouse/touch position to help determine hwo far the
// slider is being dragged
var clientX;
var clientY;
if (isMouseEvent(event)) {
(clientX = event.clientX, clientY = event.clientY);
}
else {
var touch = event.changedTouches[0];
(clientX = touch.clientX, clientY = touch.clientY);
}
var index = 0;
var slider = slider1;
if (slider2) {
// if we aren't dragging yet, try to find the slider closest to the
// mouse/touch position and use that one
if (draggingIndex === null) {
var x1 = slider1.getBoundingClientRect().x;
var x2 = slider2.getBoundingClientRect().x;
var y1 = slider1.getBoundingClientRect().y;
var y2 = slider2.getBoundingClientRect().y;
if (vertical) {
index = Math.abs(clientY - y1) < Math.abs(clientY - y2) ? 0 : 1;
}
else {
index = Math.abs(clientX - x1) < Math.abs(clientX - x2) ? 0 : 1;
}
}
else {
index = draggingIndex;
}
slider = index === 0 ? slider1 : slider2;
}
// if we aren't dragging yet, want to focus the slider element to make it
// easier to switch between mouse dragging and keyboard "dragging"
if (draggingIndex !== index) {
slider.focus();
setDraggingIndex(index);
}
setDraggingBy(isMouseEvent(event) ? "mouse" : "touch");
var _a = track.getBoundingClientRect(), left = _a.left, top = _a.top, height = _a.height, width = _a.width;
var options = {
min: min,
max: max,
step: step,
vertical: vertical,
clientX: clientX,
clientY: clientY,
left: left,
top: top,
height: height,
width: width,
isRtl: isRtl,
minValue: min,
maxValue: max,
};
var controls = controlsRef.current;
if (isRangeSlider(controls)) {
var _b = __read(controls.value, 2), thumb1Value_1 = _b[0], thumb2Value_1 = _b[1];
var _c = getDragValue(__assign(__assign({}, options), { minValue: index === 0 ? min : thumb1Value_1 + step, maxValue: index === 1 ? max : thumb2Value_1 - step })), value = _c.value, current = _c.current;
setDragValue(current);
controls.setValue(index === 0 ? [value, thumb2Value_1] : [thumb1Value_1, value]);
}
else {
var _d = getDragValue(options), value = _d.value, current = _d.current;
setDragValue(current);
controls.setValue(value);
}
}, [disabled, isRtl, draggingIndex, max, min, step, vertical]);
var stop = useCallback(function () {
controlsRef.current.persist();
setDragging(false);
setDraggingIndex(null);
setDraggingBy(null);
}, []);
useEffect(function () {
if (draggingBy === null) {
return;
}
if (draggingBy === "mouse") {
window.addEventListener("mousemove", drag);
window.addEventListener("mouseup", stop);
}
else {
window.addEventListener("touchmove", drag, { passive: false });
window.addEventListener("touchend", stop);
}
return function () {
if (draggingBy === "mouse") {
window.removeEventListener("mousemove", drag);
window.removeEventListener("mouseup", stop);
}
else {
window.removeEventListener("touchmove", drag);
window.removeEventListener("touchend", stop);
}
};
}, [draggingBy, drag, stop]);
useEffect(function () {
if (draggingIndex === null && draggingBy === null) {
return;
}
// I don't know how to reach this flow.. so maybe can be removed?
/* istanbul ignore if */
if (draggingIndex === null) {
setDragging(false);
return;
}
var timeout = window.setTimeout(function () {
setDragging(true);
}, animationDuration);
return function () {
window.clearTimeout(timeout);
};
}, [draggingIndex, draggingBy, animationDuration]);
var handleBlur = useCallback(function (event) {
if (onBlur) {
onBlur(event);
}
controlsRef.current.persist();
}, [onBlur]);
/**
* Note: this should be attached to the `SliderTrack` component.
*/
var handleMouseDown = useCallback(function (event) {
if (onMouseDown) {
onMouseDown(event);
}
// only call drag again when the dragging by isn't null since it can cause
// the "drag" events to be re-started if the mouse appears over the slider
// thumb again
if (draggingBy === null) {
drag(event);
}
}, [drag, draggingBy, onMouseDown]);
/**
* Note: this should be attached to the `SliderTrack` component.
*/
var handleTouchStart = useCallback(function (event) {
if (onTouchStart) {
onTouchStart(event);
}
// only call drag again when the dragging by isn't null since it can cause
// the "drag" events to be re-started if the user's finger appears over
// the slider thumb again
if (draggingBy === null) {
drag(event);
}
}, [drag, draggingBy, onTouchStart]);
/**
* Note: this should be attached to each `SliderThumb` component.
*/
var handleKeyDown = useCallback(function (event) {
if (onKeyDown) {
onKeyDown(event);
}
var key = event.key, altKey = event.altKey, ctrlKey = event.ctrlKey, metaKey = event.metaKey, shiftKey = event.shiftKey;
if (altKey ||
ctrlKey ||
metaKey ||
shiftKey ||
disabled ||
!VALID_KEYS.includes(key)) {
return;
}
var controls;
if (isRangeSlider(controlsRef.current)) {
var _a = controlsRef.current, increment_1 = _a.increment, incrementJump_1 = _a.incrementJump, decrement_1 = _a.decrement, decrementJump_1 = _a.decrementJump, minimum_1 = _a.minimum, maximum_1 = _a.maximum;
var index = event.currentTarget === thumb2Ref.current ? 1 : 0;
controls = {
increment: increment_1.bind(null, index),
incrementJump: incrementJump_1.bind(null, index),
decrement: decrement_1.bind(null, index),
decrementJump: decrementJump_1.bind(null, index),
minimum: minimum_1.bind(null, index),
maximum: maximum_1.bind(null, index),
};
}
else {
controls = controlsRef.current;
}
var increment = controls.increment, incrementJump = controls.incrementJump, decrement = controls.decrement, decrementJump = controls.decrementJump, minimum = controls.minimum, maximum = controls.maximum;
event.preventDefault();
event.stopPropagation();
switch (key) {
case "ArrowUp":
case "ArrowRight":
increment();
break;
case "ArrowDown":
case "ArrowLeft":
decrement();
break;
case "Home":
minimum();
break;
case "End":
maximum();
break;
case "PageUp":
incrementJump();
break;
case "PageDown":
decrementJump();
break;
}
}, [onKeyDown, disabled]);
var trackRefHandler = useCallback(function (instance) {
applyRef(instance, ref);
trackRef.current = instance;
}, [ref]);
var thumb1RefHandler = useCallback(function (instance) {
applyRef(instance, propThumb1Ref);
thumb1Ref.current = instance;
}, [propThumb1Ref]);
var thumb2RefHandler = useCallback(function (instance) {
applyRef(instance, propThumb2Ref);
thumb2Ref.current = instance;
}, [propThumb2Ref]);
return {
thumb1Ref: thumb1RefHandler,
thumb1Value: thumb1Value,
thumb1Percentage: thumb1Percentage,
thumb2Ref: thumb2RefHandler,
thumb2Value: thumb2Value,
thumb2Percentage: thumb2Percentage,
dragging: dragging,
draggingIndex: draggingIndex,
ref: trackRefHandler,
onBlur: handleBlur,
onKeyDown: handleKeyDown,
onMouseDown: handleMouseDown,
onTouchStart: handleTouchStart,
};
}
//# sourceMappingURL=useSliderControls.js.map