Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@react-aria/slider

Package Overview
Dependencies
Maintainers
1
Versions
792
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@react-aria/slider - npm Package Compare versions

Comparing version 3.0.0-alpha.2 to 3.0.0-alpha.3

311

dist/main.js

@@ -6,2 +6,10 @@ var {

var {
useMove
} = require("@react-aria/interactions");
var {
useLocale
} = require("@react-aria/i18n");
var {
useLabel

@@ -11,8 +19,2 @@ } = require("@react-aria/label");

var {
mergeProps,
useDrag1D,
focusWithoutScrolling
} = require("@react-aria/utils");
var {
useRef,

@@ -23,2 +25,9 @@ useCallback,

var {
clamp,
mergeProps,
useGlobalListeners,
focusWithoutScrolling
} = require("@react-aria/utils");
var _babelRuntimeHelpersExtends = $parcel$interopDefault(require("@babel/runtime/helpers/extends"));

@@ -45,44 +54,120 @@

const {
let {
labelProps,
fieldProps
} = useLabel(props);
const isSliderEditable = !(props.isDisabled || props.isReadOnly); // Attach id of the label to the state so it can be accessed by useSliderThumb.
let isVertical = props.orientation === 'vertical'; // Attach id of the label to the state so it can be accessed by useSliderThumb.
$dec1906781d9c7cb69245fc4d5344b$export$sliderIds.set(state, (_labelProps$id = labelProps.id) != null ? _labelProps$id : fieldProps.id); // When the user clicks or drags the track, we want the motion to set and drag the
// closest thumb. Hence we also need to install useDrag1D() on the track element.
$dec1906781d9c7cb69245fc4d5344b$export$sliderIds.set(state, (_labelProps$id = labelProps.id) != null ? _labelProps$id : fieldProps.id);
let {
direction
} = useLocale();
let {
addGlobalListener,
removeGlobalListener
} = useGlobalListeners(); // When the user clicks or drags the track, we want the motion to set and drag the
// closest thumb. Hence we also need to install useMove() on the track element.
// Here, we keep track of which index is the "closest" to the drag start point.
// It is set onMouseDown; see trackProps below.
// It is set onMouseDown/onTouchDown; see trackProps below.
const realTimeTrackDraggingIndex = useRef(undefined);
const isTrackDragging = useRef(false);
const realTimeTrackDraggingIndex = useRef(null);
const stateRef = useRef(null);
stateRef.current = state;
const reverseX = direction === 'rtl';
const currentPosition = useRef(null);
const {
onMouseDown,
onMouseEnter,
onMouseOut
} = useDrag1D({
containerRef: trackRef,
reverse: false,
orientation: 'horizontal',
onDrag: dragging => {
if (realTimeTrackDraggingIndex.current !== undefined) {
state.setThumbDragging(realTimeTrackDraggingIndex.current, dragging);
moveProps
} = useMove({
onMoveStart() {
currentPosition.current = null;
},
onMove(_ref) {
let {
deltaX,
deltaY
} = _ref;
let size = isVertical ? trackRef.current.offsetHeight : trackRef.current.offsetWidth;
if (currentPosition.current == null) {
currentPosition.current = stateRef.current.getThumbPercent(realTimeTrackDraggingIndex.current) * size;
}
isTrackDragging.current = dragging;
let delta = isVertical ? deltaY : deltaX;
if (isVertical || reverseX) {
delta = -delta;
}
currentPosition.current += delta;
if (realTimeTrackDraggingIndex.current != null && trackRef.current) {
const percent = clamp(currentPosition.current / size, 0, 1);
stateRef.current.setThumbPercent(realTimeTrackDraggingIndex.current, percent);
}
},
onPositionChange: position => {
if (realTimeTrackDraggingIndex.current !== undefined && trackRef.current) {
const percent = position / trackRef.current.offsetWidth;
state.setThumbPercent(realTimeTrackDraggingIndex.current, percent); // When track-dragging ends, onDrag is called before a final onPositionChange is
// called, so we can't reset realTimeTrackDraggingIndex until onPositionChange,
// as we still needed to update the thumb position one last time. Hence we
// track whether we're dragging, and the actual dragged index, separately.
if (!isTrackDragging.current) {
realTimeTrackDraggingIndex.current = undefined;
}
onMoveEnd() {
if (realTimeTrackDraggingIndex.current != null) {
stateRef.current.setThumbDragging(realTimeTrackDraggingIndex.current, false);
realTimeTrackDraggingIndex.current = null;
}
}
});
let currentPointer = useRef(undefined);
let onDownTrack = (e, id, clientX, clientY) => {
// We only trigger track-dragging if the user clicks on the track itself and nothing is currently being dragged.
if (trackRef.current && !props.isDisabled && state.values.every((_, i) => !state.isThumbDragging(i))) {
let size = isVertical ? trackRef.current.offsetHeight : trackRef.current.offsetWidth; // Find the closest thumb
const trackPosition = trackRef.current.getBoundingClientRect()[isVertical ? 'top' : 'left'];
const clickPosition = isVertical ? clientY : clientX;
const offset = clickPosition - trackPosition;
let percent = offset / size;
if (direction === 'rtl' || isVertical) {
percent = 1 - percent;
}
let value = state.getPercentValue(percent); // Only compute the diff for thumbs that are editable, as only they can be dragged
const minDiff = Math.min(...state.values.map((v, index) => state.isThumbEditable(index) ? Math.abs(v - value) : Number.POSITIVE_INFINITY));
const index = state.values.findIndex(v => Math.abs(v - value) === minDiff);
if (minDiff !== Number.POSITIVE_INFINITY && index >= 0) {
// Don't unfocus anything
e.preventDefault();
realTimeTrackDraggingIndex.current = index;
state.setFocusedThumb(index);
currentPointer.current = id;
state.setThumbDragging(realTimeTrackDraggingIndex.current, true);
state.setThumbValue(index, value);
addGlobalListener(window, 'mouseup', onUpTrack, false);
addGlobalListener(window, 'touchend', onUpTrack, false);
addGlobalListener(window, 'pointerup', onUpTrack, false);
} else {
realTimeTrackDraggingIndex.current = null;
}
}
};
let onUpTrack = e => {
var _e$pointerId, _e$changedTouches;
let id = (_e$pointerId = e.pointerId) != null ? _e$pointerId : (_e$changedTouches = e.changedTouches) == null ? void 0 : _e$changedTouches[0].identifier;
if (id === currentPointer.current) {
if (realTimeTrackDraggingIndex.current != null) {
state.setThumbDragging(realTimeTrackDraggingIndex.current, false);
realTimeTrackDraggingIndex.current = null;
}
removeGlobalListener(window, 'mouseup', onUpTrack, false);
removeGlobalListener(window, 'touchend', onUpTrack, false);
removeGlobalListener(window, 'pointerup', onUpTrack, false);
}
};
return {

@@ -97,38 +182,15 @@ labelProps,

trackProps: mergeProps({
onMouseDown: e => {
// We only trigger track-dragging if the user clicks on the track itself.
if (trackRef.current && isSliderEditable) {
// Find the closest thumb
const trackPosition = trackRef.current.getBoundingClientRect().left;
const clickPosition = e.clientX;
const offset = clickPosition - trackPosition;
const percent = offset / trackRef.current.offsetWidth;
const value = state.getPercentValue(percent); // Only compute the diff for thumbs that are editable, as only they can be dragged
onMouseDown(e) {
onDownTrack(e, undefined, e.clientX, e.clientY);
},
const minDiff = Math.min(...state.values.map((v, index) => state.isThumbEditable(index) ? Math.abs(v - value) : Number.POSITIVE_INFINITY));
const index = state.values.findIndex(v => Math.abs(v - value) === minDiff);
onPointerDown(e) {
onDownTrack(e, e.pointerId, e.clientX, e.clientY);
},
if (minDiff !== Number.POSITIVE_INFINITY && index >= 0) {
// Don't unfocus anything
e.preventDefault();
realTimeTrackDraggingIndex.current = index;
state.setFocusedThumb(index); // We immediately toggle state to dragging and set the value on mouse down.
// We set the value now, instead of waiting for onDrag, so that the thumb
// is updated while you're still holding the mouse button down. And we
// set dragging on now, so that onChangeEnd() won't fire yet when we set
// the value. Dragging state will be reset to false in onDrag above, even
// if no dragging actually occurs.
onTouchStart(e) {
onDownTrack(e, e.changedTouches[0].identifier, e.changedTouches[0].clientX, e.changedTouches[0].clientY);
}
state.setThumbDragging(realTimeTrackDraggingIndex.current, true);
state.setThumbValue(index, value);
} else {
realTimeTrackDraggingIndex.current = undefined;
}
}
}
}, {
onMouseDown,
onMouseEnter,
onMouseOut
})
}, moveProps)
};

@@ -148,7 +210,6 @@ }

const {
let {
index,
isRequired,
isDisabled,
isReadOnly,
validationState,

@@ -158,2 +219,10 @@ trackRef,

} = opts;
let isVertical = opts.orientation === 'vertical';
let {
direction
} = useLocale();
let {
addGlobalListener,
removeGlobalListener
} = useGlobalListeners();
let labelId = $dec1906781d9c7cb69245fc4d5344b$export$sliderIds.get(state);

@@ -167,3 +236,2 @@ const {

const value = state.values[index];
const isEditable = !(isDisabled || isReadOnly);
const focusInput = useCallback(() => {

@@ -180,17 +248,50 @@ if (inputRef.current) {

}, [isFocused, focusInput]);
const draggableProps = useDrag1D({
containerRef: trackRef,
reverse: false,
orientation: 'horizontal',
onDrag: dragging => {
state.setThumbDragging(index, dragging);
focusInput();
const stateRef = useRef(null);
stateRef.current = state;
let reverseX = direction === 'rtl';
let currentPosition = useRef(null);
let {
moveProps
} = useMove({
onMoveStart() {
currentPosition.current = null;
state.setThumbDragging(index, true);
},
onPositionChange: position => {
const percent = position / trackRef.current.offsetWidth;
state.setThumbPercent(index, percent);
onMove(_ref) {
let {
deltaX,
deltaY,
pointerType
} = _ref;
let size = isVertical ? trackRef.current.offsetHeight : trackRef.current.offsetWidth;
if (currentPosition.current == null) {
currentPosition.current = stateRef.current.getThumbPercent(index) * size;
}
if (pointerType === 'keyboard') {
// (invert left/right according to language direction) + (according to vertical)
let delta = ((reverseX ? -deltaX : deltaX) + (isVertical ? -deltaY : -deltaY)) * stateRef.current.step;
currentPosition.current += delta * size;
stateRef.current.setThumbValue(index, stateRef.current.getThumbValue(index) + delta);
} else {
let delta = isVertical ? deltaY : deltaX;
if (isVertical || reverseX) {
delta = -delta;
}
currentPosition.current += delta;
stateRef.current.setThumbPercent(index, clamp(currentPosition.current / size, 0, 1));
}
},
onMoveEnd() {
state.setThumbDragging(index, false);
}
}); // Immediately register editability with the state
state.setThumbEditable(index, isEditable);
state.setThumbEditable(index, !isDisabled);
const {

@@ -201,3 +302,27 @@ focusableProps

onBlur: () => state.setFocusedThumb(undefined)
}), inputRef); // We install mouse handlers for the drag motion on the thumb div, but
}), inputRef);
let currentPointer = useRef(undefined);
let onDown = id => {
focusInput();
currentPointer.current = id;
state.setThumbDragging(index, true);
addGlobalListener(window, 'mouseup', onUp, false);
addGlobalListener(window, 'touchend', onUp, false);
addGlobalListener(window, 'pointerup', onUp, false);
};
let onUp = e => {
var _e$pointerId, _e$changedTouches;
let id = (_e$pointerId = e.pointerId) != null ? _e$pointerId : (_e$changedTouches = e.changedTouches) == null ? void 0 : _e$changedTouches[0].identifier;
if (id === currentPointer.current) {
focusInput();
state.setThumbDragging(index, false);
removeGlobalListener(window, 'mouseup', onUp, false);
removeGlobalListener(window, 'touchend', onUp, false);
removeGlobalListener(window, 'pointerup', onUp, false);
}
}; // We install mouse handlers for the drag motion on the thumb div, but
// not the key handler for moving the thumb with the slider. Instead,

@@ -207,6 +332,7 @@ // we focus the range input, and let the browser handle the keyboard

return {
inputProps: mergeProps(focusableProps, fieldProps, {
type: 'range',
tabIndex: isEditable ? 0 : undefined,
tabIndex: !isDisabled ? 0 : undefined,
min: state.getThumbMinValue(index),

@@ -216,5 +342,4 @@ max: state.getThumbMaxValue(index),

value: value,
readOnly: isReadOnly,
disabled: isDisabled,
'aria-orientation': 'horizontal',
'aria-orientation': opts.orientation,
'aria-valuetext': state.getThumbValueLabel(index),

@@ -228,8 +353,12 @@ 'aria-required': isRequired || undefined,

}),
thumbProps: isEditable ? mergeProps({
onMouseDown: draggableProps.onMouseDown,
onMouseEnter: draggableProps.onMouseEnter,
onMouseOut: draggableProps.onMouseOut
}, {
onMouseDown: focusInput
thumbProps: !isDisabled ? mergeProps(moveProps, {
onMouseDown: () => {
onDown(null);
},
onPointerDown: e => {
onDown(e.pointerId);
},
onTouchStart: e => {
onDown(e.changedTouches[0].identifier);
}
}) : {},

@@ -236,0 +365,0 @@ labelProps

import { useFocusable } from "@react-aria/focus";
import { useMove } from "@react-aria/interactions";
import { useLocale } from "@react-aria/i18n";
import { useLabel } from "@react-aria/label";
import { mergeProps, useDrag1D, focusWithoutScrolling } from "@react-aria/utils";
import { useRef, useCallback, useEffect } from "react";
import { clamp, mergeProps, useGlobalListeners, focusWithoutScrolling } from "@react-aria/utils";
import _babelRuntimeHelpersEsmExtends from "@babel/runtime/helpers/esm/extends";

@@ -21,44 +23,120 @@ const $d20491ae7743da17cfa841ff6d87$export$sliderIds = new WeakMap();

const {
let {
labelProps,
fieldProps
} = useLabel(props);
const isSliderEditable = !(props.isDisabled || props.isReadOnly); // Attach id of the label to the state so it can be accessed by useSliderThumb.
let isVertical = props.orientation === 'vertical'; // Attach id of the label to the state so it can be accessed by useSliderThumb.
$d20491ae7743da17cfa841ff6d87$export$sliderIds.set(state, (_labelProps$id = labelProps.id) != null ? _labelProps$id : fieldProps.id); // When the user clicks or drags the track, we want the motion to set and drag the
// closest thumb. Hence we also need to install useDrag1D() on the track element.
$d20491ae7743da17cfa841ff6d87$export$sliderIds.set(state, (_labelProps$id = labelProps.id) != null ? _labelProps$id : fieldProps.id);
let {
direction
} = useLocale();
let {
addGlobalListener,
removeGlobalListener
} = useGlobalListeners(); // When the user clicks or drags the track, we want the motion to set and drag the
// closest thumb. Hence we also need to install useMove() on the track element.
// Here, we keep track of which index is the "closest" to the drag start point.
// It is set onMouseDown; see trackProps below.
// It is set onMouseDown/onTouchDown; see trackProps below.
const realTimeTrackDraggingIndex = useRef(undefined);
const isTrackDragging = useRef(false);
const realTimeTrackDraggingIndex = useRef(null);
const stateRef = useRef(null);
stateRef.current = state;
const reverseX = direction === 'rtl';
const currentPosition = useRef(null);
const {
onMouseDown,
onMouseEnter,
onMouseOut
} = useDrag1D({
containerRef: trackRef,
reverse: false,
orientation: 'horizontal',
onDrag: dragging => {
if (realTimeTrackDraggingIndex.current !== undefined) {
state.setThumbDragging(realTimeTrackDraggingIndex.current, dragging);
moveProps
} = useMove({
onMoveStart() {
currentPosition.current = null;
},
onMove(_ref) {
let {
deltaX,
deltaY
} = _ref;
let size = isVertical ? trackRef.current.offsetHeight : trackRef.current.offsetWidth;
if (currentPosition.current == null) {
currentPosition.current = stateRef.current.getThumbPercent(realTimeTrackDraggingIndex.current) * size;
}
isTrackDragging.current = dragging;
let delta = isVertical ? deltaY : deltaX;
if (isVertical || reverseX) {
delta = -delta;
}
currentPosition.current += delta;
if (realTimeTrackDraggingIndex.current != null && trackRef.current) {
const percent = clamp(currentPosition.current / size, 0, 1);
stateRef.current.setThumbPercent(realTimeTrackDraggingIndex.current, percent);
}
},
onPositionChange: position => {
if (realTimeTrackDraggingIndex.current !== undefined && trackRef.current) {
const percent = position / trackRef.current.offsetWidth;
state.setThumbPercent(realTimeTrackDraggingIndex.current, percent); // When track-dragging ends, onDrag is called before a final onPositionChange is
// called, so we can't reset realTimeTrackDraggingIndex until onPositionChange,
// as we still needed to update the thumb position one last time. Hence we
// track whether we're dragging, and the actual dragged index, separately.
if (!isTrackDragging.current) {
realTimeTrackDraggingIndex.current = undefined;
}
onMoveEnd() {
if (realTimeTrackDraggingIndex.current != null) {
stateRef.current.setThumbDragging(realTimeTrackDraggingIndex.current, false);
realTimeTrackDraggingIndex.current = null;
}
}
});
let currentPointer = useRef(undefined);
let onDownTrack = (e, id, clientX, clientY) => {
// We only trigger track-dragging if the user clicks on the track itself and nothing is currently being dragged.
if (trackRef.current && !props.isDisabled && state.values.every((_, i) => !state.isThumbDragging(i))) {
let size = isVertical ? trackRef.current.offsetHeight : trackRef.current.offsetWidth; // Find the closest thumb
const trackPosition = trackRef.current.getBoundingClientRect()[isVertical ? 'top' : 'left'];
const clickPosition = isVertical ? clientY : clientX;
const offset = clickPosition - trackPosition;
let percent = offset / size;
if (direction === 'rtl' || isVertical) {
percent = 1 - percent;
}
let value = state.getPercentValue(percent); // Only compute the diff for thumbs that are editable, as only they can be dragged
const minDiff = Math.min(...state.values.map((v, index) => state.isThumbEditable(index) ? Math.abs(v - value) : Number.POSITIVE_INFINITY));
const index = state.values.findIndex(v => Math.abs(v - value) === minDiff);
if (minDiff !== Number.POSITIVE_INFINITY && index >= 0) {
// Don't unfocus anything
e.preventDefault();
realTimeTrackDraggingIndex.current = index;
state.setFocusedThumb(index);
currentPointer.current = id;
state.setThumbDragging(realTimeTrackDraggingIndex.current, true);
state.setThumbValue(index, value);
addGlobalListener(window, 'mouseup', onUpTrack, false);
addGlobalListener(window, 'touchend', onUpTrack, false);
addGlobalListener(window, 'pointerup', onUpTrack, false);
} else {
realTimeTrackDraggingIndex.current = null;
}
}
};
let onUpTrack = e => {
var _e$pointerId, _e$changedTouches;
let id = (_e$pointerId = e.pointerId) != null ? _e$pointerId : (_e$changedTouches = e.changedTouches) == null ? void 0 : _e$changedTouches[0].identifier;
if (id === currentPointer.current) {
if (realTimeTrackDraggingIndex.current != null) {
state.setThumbDragging(realTimeTrackDraggingIndex.current, false);
realTimeTrackDraggingIndex.current = null;
}
removeGlobalListener(window, 'mouseup', onUpTrack, false);
removeGlobalListener(window, 'touchend', onUpTrack, false);
removeGlobalListener(window, 'pointerup', onUpTrack, false);
}
};
return {

@@ -73,38 +151,15 @@ labelProps,

trackProps: mergeProps({
onMouseDown: e => {
// We only trigger track-dragging if the user clicks on the track itself.
if (trackRef.current && isSliderEditable) {
// Find the closest thumb
const trackPosition = trackRef.current.getBoundingClientRect().left;
const clickPosition = e.clientX;
const offset = clickPosition - trackPosition;
const percent = offset / trackRef.current.offsetWidth;
const value = state.getPercentValue(percent); // Only compute the diff for thumbs that are editable, as only they can be dragged
onMouseDown(e) {
onDownTrack(e, undefined, e.clientX, e.clientY);
},
const minDiff = Math.min(...state.values.map((v, index) => state.isThumbEditable(index) ? Math.abs(v - value) : Number.POSITIVE_INFINITY));
const index = state.values.findIndex(v => Math.abs(v - value) === minDiff);
onPointerDown(e) {
onDownTrack(e, e.pointerId, e.clientX, e.clientY);
},
if (minDiff !== Number.POSITIVE_INFINITY && index >= 0) {
// Don't unfocus anything
e.preventDefault();
realTimeTrackDraggingIndex.current = index;
state.setFocusedThumb(index); // We immediately toggle state to dragging and set the value on mouse down.
// We set the value now, instead of waiting for onDrag, so that the thumb
// is updated while you're still holding the mouse button down. And we
// set dragging on now, so that onChangeEnd() won't fire yet when we set
// the value. Dragging state will be reset to false in onDrag above, even
// if no dragging actually occurs.
onTouchStart(e) {
onDownTrack(e, e.changedTouches[0].identifier, e.changedTouches[0].clientX, e.changedTouches[0].clientY);
}
state.setThumbDragging(realTimeTrackDraggingIndex.current, true);
state.setThumbValue(index, value);
} else {
realTimeTrackDraggingIndex.current = undefined;
}
}
}
}, {
onMouseDown,
onMouseEnter,
onMouseOut
})
}, moveProps)
};

@@ -122,7 +177,6 @@ }

const {
let {
index,
isRequired,
isDisabled,
isReadOnly,
validationState,

@@ -132,2 +186,10 @@ trackRef,

} = opts;
let isVertical = opts.orientation === 'vertical';
let {
direction
} = useLocale();
let {
addGlobalListener,
removeGlobalListener
} = useGlobalListeners();
let labelId = $d20491ae7743da17cfa841ff6d87$export$sliderIds.get(state);

@@ -141,3 +203,2 @@ const {

const value = state.values[index];
const isEditable = !(isDisabled || isReadOnly);
const focusInput = useCallback(() => {

@@ -154,17 +215,50 @@ if (inputRef.current) {

}, [isFocused, focusInput]);
const draggableProps = useDrag1D({
containerRef: trackRef,
reverse: false,
orientation: 'horizontal',
onDrag: dragging => {
state.setThumbDragging(index, dragging);
focusInput();
const stateRef = useRef(null);
stateRef.current = state;
let reverseX = direction === 'rtl';
let currentPosition = useRef(null);
let {
moveProps
} = useMove({
onMoveStart() {
currentPosition.current = null;
state.setThumbDragging(index, true);
},
onPositionChange: position => {
const percent = position / trackRef.current.offsetWidth;
state.setThumbPercent(index, percent);
onMove(_ref) {
let {
deltaX,
deltaY,
pointerType
} = _ref;
let size = isVertical ? trackRef.current.offsetHeight : trackRef.current.offsetWidth;
if (currentPosition.current == null) {
currentPosition.current = stateRef.current.getThumbPercent(index) * size;
}
if (pointerType === 'keyboard') {
// (invert left/right according to language direction) + (according to vertical)
let delta = ((reverseX ? -deltaX : deltaX) + (isVertical ? -deltaY : -deltaY)) * stateRef.current.step;
currentPosition.current += delta * size;
stateRef.current.setThumbValue(index, stateRef.current.getThumbValue(index) + delta);
} else {
let delta = isVertical ? deltaY : deltaX;
if (isVertical || reverseX) {
delta = -delta;
}
currentPosition.current += delta;
stateRef.current.setThumbPercent(index, clamp(currentPosition.current / size, 0, 1));
}
},
onMoveEnd() {
state.setThumbDragging(index, false);
}
}); // Immediately register editability with the state
state.setThumbEditable(index, isEditable);
state.setThumbEditable(index, !isDisabled);
const {

@@ -175,3 +269,27 @@ focusableProps

onBlur: () => state.setFocusedThumb(undefined)
}), inputRef); // We install mouse handlers for the drag motion on the thumb div, but
}), inputRef);
let currentPointer = useRef(undefined);
let onDown = id => {
focusInput();
currentPointer.current = id;
state.setThumbDragging(index, true);
addGlobalListener(window, 'mouseup', onUp, false);
addGlobalListener(window, 'touchend', onUp, false);
addGlobalListener(window, 'pointerup', onUp, false);
};
let onUp = e => {
var _e$pointerId, _e$changedTouches;
let id = (_e$pointerId = e.pointerId) != null ? _e$pointerId : (_e$changedTouches = e.changedTouches) == null ? void 0 : _e$changedTouches[0].identifier;
if (id === currentPointer.current) {
focusInput();
state.setThumbDragging(index, false);
removeGlobalListener(window, 'mouseup', onUp, false);
removeGlobalListener(window, 'touchend', onUp, false);
removeGlobalListener(window, 'pointerup', onUp, false);
}
}; // We install mouse handlers for the drag motion on the thumb div, but
// not the key handler for moving the thumb with the slider. Instead,

@@ -181,6 +299,7 @@ // we focus the range input, and let the browser handle the keyboard

return {
inputProps: mergeProps(focusableProps, fieldProps, {
type: 'range',
tabIndex: isEditable ? 0 : undefined,
tabIndex: !isDisabled ? 0 : undefined,
min: state.getThumbMinValue(index),

@@ -190,5 +309,4 @@ max: state.getThumbMaxValue(index),

value: value,
readOnly: isReadOnly,
disabled: isDisabled,
'aria-orientation': 'horizontal',
'aria-orientation': opts.orientation,
'aria-valuetext': state.getThumbValueLabel(index),

@@ -202,8 +320,12 @@ 'aria-required': isRequired || undefined,

}),
thumbProps: isEditable ? mergeProps({
onMouseDown: draggableProps.onMouseDown,
onMouseEnter: draggableProps.onMouseEnter,
onMouseOut: draggableProps.onMouseOut
}, {
onMouseDown: focusInput
thumbProps: !isDisabled ? mergeProps(moveProps, {
onMouseDown: () => {
onDown(null);
},
onPointerDown: e => {
onDown(e.pointerId);
},
onTouchStart: e => {
onDown(e.changedTouches[0].identifier);
}
}) : {},

@@ -210,0 +332,0 @@ labelProps

@@ -1,2 +0,2 @@

import { HTMLAttributes } from "react";
import React, { HTMLAttributes } from "react";
import { SliderProps, SliderThumbProps } from "@react-types/slider";

@@ -31,3 +31,3 @@ import { SliderState } from "@react-stately/slider";

}
interface SliderThumbOptions extends SliderThumbProps {
export interface SliderThumbOptions extends SliderThumbProps {
trackRef: React.RefObject<HTMLElement>;

@@ -34,0 +34,0 @@ inputRef: React.RefObject<HTMLInputElement>;

{
"name": "@react-aria/slider",
"version": "3.0.0-alpha.2",
"version": "3.0.0-alpha.3",
"description": "Slider",

@@ -21,11 +21,11 @@ "license": "Apache-2.0",

"@babel/runtime": "^7.6.2",
"@react-aria/focus": "^3.2.2",
"@react-aria/i18n": "^3.1.2",
"@react-aria/interactions": "^3.2.1",
"@react-aria/focus": "^3.2.3",
"@react-aria/i18n": "^3.1.3",
"@react-aria/interactions": "^3.3.0",
"@react-aria/label": "^3.1.1",
"@react-aria/utils": "^3.3.0",
"@react-aria/utils": "^3.4.0",
"@react-stately/radio": "^3.2.1",
"@react-stately/slider": "3.0.0-alpha.2",
"@react-stately/slider": "3.0.0-alpha.3",
"@react-types/radio": "^3.1.1",
"@react-types/slider": "3.0.0-alpha.1"
"@react-types/slider": "3.0.0-alpha.2"
},

@@ -38,3 +38,3 @@ "peerDependencies": {

},
"gitHead": "0778f71a3c13e1e24388a23b6d525e3b9f5b98f1"
"gitHead": "9f738a06ea4e256c8d975f00502b4b0bbabb8f65"
}

@@ -13,4 +13,4 @@ /*

import {HTMLAttributes, useRef} from 'react';
import {mergeProps, useDrag1D} from '@react-aria/utils';
import {clamp, mergeProps, useGlobalListeners} from '@react-aria/utils';
import React, {HTMLAttributes, useRef} from 'react';
import {sliderIds} from './utils';

@@ -20,2 +20,4 @@ import {SliderProps} from '@react-types/slider';

import {useLabel} from '@react-aria/label';
import {useLocale} from '@react-aria/i18n';
import {useMove} from '@react-aria/interactions';

@@ -48,5 +50,5 @@ interface SliderAria {

): SliderAria {
const {labelProps, fieldProps} = useLabel(props);
let {labelProps, fieldProps} = useLabel(props);
const isSliderEditable = !(props.isDisabled || props.isReadOnly);
let isVertical = props.orientation === 'vertical';

@@ -56,37 +58,101 @@ // Attach id of the label to the state so it can be accessed by useSliderThumb.

let {direction} = useLocale();
let {addGlobalListener, removeGlobalListener} = useGlobalListeners();
// When the user clicks or drags the track, we want the motion to set and drag the
// closest thumb. Hence we also need to install useDrag1D() on the track element.
// closest thumb. Hence we also need to install useMove() on the track element.
// Here, we keep track of which index is the "closest" to the drag start point.
// It is set onMouseDown; see trackProps below.
const realTimeTrackDraggingIndex = useRef<number | undefined>(undefined);
const isTrackDragging = useRef(false);
const {onMouseDown, onMouseEnter, onMouseOut} = useDrag1D({
containerRef: trackRef as any,
reverse: false,
orientation: 'horizontal',
onDrag: (dragging) => {
if (realTimeTrackDraggingIndex.current !== undefined) {
state.setThumbDragging(realTimeTrackDraggingIndex.current, dragging);
}
isTrackDragging.current = dragging;
// It is set onMouseDown/onTouchDown; see trackProps below.
const realTimeTrackDraggingIndex = useRef<number | null>(null);
const stateRef = useRef<SliderState>(null);
stateRef.current = state;
const reverseX = direction === 'rtl';
const currentPosition = useRef<number>(null);
const {moveProps} = useMove({
onMoveStart() {
currentPosition.current = null;
},
onPositionChange: (position) => {
if (realTimeTrackDraggingIndex.current !== undefined && trackRef.current) {
const percent = position / trackRef.current.offsetWidth;
state.setThumbPercent(realTimeTrackDraggingIndex.current, percent);
onMove({deltaX, deltaY}) {
let size = isVertical ? trackRef.current.offsetHeight : trackRef.current.offsetWidth;
// When track-dragging ends, onDrag is called before a final onPositionChange is
// called, so we can't reset realTimeTrackDraggingIndex until onPositionChange,
// as we still needed to update the thumb position one last time. Hence we
// track whether we're dragging, and the actual dragged index, separately.
if (!isTrackDragging.current) {
realTimeTrackDraggingIndex.current = undefined;
}
if (currentPosition.current == null) {
currentPosition.current = stateRef.current.getThumbPercent(realTimeTrackDraggingIndex.current) * size;
}
let delta = isVertical ? deltaY : deltaX;
if (isVertical || reverseX) {
delta = -delta;
}
currentPosition.current += delta;
if (realTimeTrackDraggingIndex.current != null && trackRef.current) {
const percent = clamp(currentPosition.current / size, 0, 1);
stateRef.current.setThumbPercent(realTimeTrackDraggingIndex.current, percent);
}
},
onMoveEnd() {
if (realTimeTrackDraggingIndex.current != null) {
stateRef.current.setThumbDragging(realTimeTrackDraggingIndex.current, false);
realTimeTrackDraggingIndex.current = null;
}
}
});
let currentPointer = useRef<number | null | undefined>(undefined);
let onDownTrack = (e: React.UIEvent, id: number, clientX: number, clientY: number) => {
// We only trigger track-dragging if the user clicks on the track itself and nothing is currently being dragged.
if (trackRef.current && !props.isDisabled && state.values.every((_, i) => !state.isThumbDragging(i))) {
let size = isVertical ? trackRef.current.offsetHeight : trackRef.current.offsetWidth;
// Find the closest thumb
const trackPosition = trackRef.current.getBoundingClientRect()[isVertical ? 'top' : 'left'];
const clickPosition = isVertical ? clientY : clientX;
const offset = clickPosition - trackPosition;
let percent = offset / size;
if (direction === 'rtl' || isVertical) {
percent = 1 - percent;
}
let value = state.getPercentValue(percent);
// Only compute the diff for thumbs that are editable, as only they can be dragged
const minDiff = Math.min(...state.values.map((v, index) => state.isThumbEditable(index) ? Math.abs(v - value) : Number.POSITIVE_INFINITY));
const index = state.values.findIndex(v => Math.abs(v - value) === minDiff);
if (minDiff !== Number.POSITIVE_INFINITY && index >= 0) {
// Don't unfocus anything
e.preventDefault();
realTimeTrackDraggingIndex.current = index;
state.setFocusedThumb(index);
currentPointer.current = id;
state.setThumbDragging(realTimeTrackDraggingIndex.current, true);
state.setThumbValue(index, value);
addGlobalListener(window, 'mouseup', onUpTrack, false);
addGlobalListener(window, 'touchend', onUpTrack, false);
addGlobalListener(window, 'pointerup', onUpTrack, false);
} else {
realTimeTrackDraggingIndex.current = null;
}
}
};
let onUpTrack = (e) => {
let id = e.pointerId ?? e.changedTouches?.[0].identifier;
if (id === currentPointer.current) {
if (realTimeTrackDraggingIndex.current != null) {
state.setThumbDragging(realTimeTrackDraggingIndex.current, false);
realTimeTrackDraggingIndex.current = null;
}
removeGlobalListener(window, 'mouseup', onUpTrack, false);
removeGlobalListener(window, 'touchend', onUpTrack, false);
removeGlobalListener(window, 'pointerup', onUpTrack, false);
}
};
return {
labelProps,
// The root element of the Slider will have role="group" to group together

@@ -100,39 +166,7 @@ // all the thumb inputs in the Slider. The label of the Slider will

trackProps: mergeProps({
onMouseDown: (e: React.MouseEvent<HTMLElement>) => {
// We only trigger track-dragging if the user clicks on the track itself.
if (trackRef.current && isSliderEditable) {
// Find the closest thumb
const trackPosition = trackRef.current.getBoundingClientRect().left;
const clickPosition = e.clientX;
const offset = clickPosition - trackPosition;
const percent = offset / trackRef.current.offsetWidth;
const value = state.getPercentValue(percent);
// Only compute the diff for thumbs that are editable, as only they can be dragged
const minDiff = Math.min(...state.values.map((v, index) => state.isThumbEditable(index) ? Math.abs(v - value) : Number.POSITIVE_INFINITY));
const index = state.values.findIndex(v => Math.abs(v - value) === minDiff);
if (minDiff !== Number.POSITIVE_INFINITY && index >= 0) {
// Don't unfocus anything
e.preventDefault();
realTimeTrackDraggingIndex.current = index;
state.setFocusedThumb(index);
// We immediately toggle state to dragging and set the value on mouse down.
// We set the value now, instead of waiting for onDrag, so that the thumb
// is updated while you're still holding the mouse button down. And we
// set dragging on now, so that onChangeEnd() won't fire yet when we set
// the value. Dragging state will be reset to false in onDrag above, even
// if no dragging actually occurs.
state.setThumbDragging(realTimeTrackDraggingIndex.current, true);
state.setThumbValue(index, value);
} else {
realTimeTrackDraggingIndex.current = undefined;
}
}
}
}, {
onMouseDown, onMouseEnter, onMouseOut
})
onMouseDown(e: React.MouseEvent<HTMLElement>) { onDownTrack(e, undefined, e.clientX, e.clientY); },
onPointerDown(e: React.PointerEvent<HTMLElement>) { onDownTrack(e, e.pointerId, e.clientX, e.clientY); },
onTouchStart(e: React.TouchEvent<HTMLElement>) { onDownTrack(e, e.changedTouches[0].identifier, e.changedTouches[0].clientX, e.changedTouches[0].clientY); }
}, moveProps)
};
}

@@ -1,3 +0,3 @@

import {ChangeEvent, HTMLAttributes, useCallback, useEffect} from 'react';
import {focusWithoutScrolling, mergeProps, useDrag1D} from '@react-aria/utils';
import {clamp, focusWithoutScrolling, mergeProps, useGlobalListeners} from '@react-aria/utils';
import React, {ChangeEvent, HTMLAttributes, useCallback, useEffect, useRef} from 'react';
import {sliderIds} from './utils';

@@ -8,2 +8,4 @@ import {SliderState} from '@react-stately/slider';

import {useLabel} from '@react-aria/label';
import {useLocale} from '@react-aria/i18n';
import {useMove} from '@react-aria/interactions';

@@ -21,3 +23,3 @@ interface SliderThumbAria {

interface SliderThumbOptions extends SliderThumbProps {
export interface SliderThumbOptions extends SliderThumbProps {
trackRef: React.RefObject<HTMLElement>,

@@ -35,9 +37,8 @@ inputRef: React.RefObject<HTMLInputElement>

opts: SliderThumbOptions,
state: SliderState,
state: SliderState
): SliderThumbAria {
const {
let {
index,
isRequired,
isDisabled,
isReadOnly,
validationState,

@@ -48,2 +49,7 @@ trackRef,

let isVertical = opts.orientation === 'vertical';
let {direction} = useLocale();
let {addGlobalListener, removeGlobalListener} = useGlobalListeners();
let labelId = sliderIds.get(state);

@@ -56,3 +62,2 @@ const {labelProps, fieldProps} = useLabel({

const value = state.values[index];
const isEditable = !(isDisabled || isReadOnly);

@@ -73,13 +78,34 @@ const focusInput = useCallback(() => {

const draggableProps = useDrag1D({
containerRef: trackRef as any,
reverse: false,
orientation: 'horizontal',
onDrag: (dragging) => {
state.setThumbDragging(index, dragging);
focusInput();
const stateRef = useRef<SliderState>(null);
stateRef.current = state;
let reverseX = direction === 'rtl';
let currentPosition = useRef<number>(null);
let {moveProps} = useMove({
onMoveStart() {
currentPosition.current = null;
state.setThumbDragging(index, true);
},
onPositionChange: (position) => {
const percent = position / trackRef.current.offsetWidth;
state.setThumbPercent(index, percent);
onMove({deltaX, deltaY, pointerType}) {
let size = isVertical ? trackRef.current.offsetHeight : trackRef.current.offsetWidth;
if (currentPosition.current == null) {
currentPosition.current = stateRef.current.getThumbPercent(index) * size;
}
if (pointerType === 'keyboard') {
// (invert left/right according to language direction) + (according to vertical)
let delta = ((reverseX ? -deltaX : deltaX) + (isVertical ? -deltaY : -deltaY)) * stateRef.current.step;
currentPosition.current += delta * size;
stateRef.current.setThumbValue(index, stateRef.current.getThumbValue(index) + delta);
} else {
let delta = isVertical ? deltaY : deltaX;
if (isVertical || reverseX) {
delta = -delta;
}
currentPosition.current += delta;
stateRef.current.setThumbPercent(index, clamp(currentPosition.current / size, 0, 1));
}
},
onMoveEnd() {
state.setThumbDragging(index, false);
}

@@ -89,3 +115,3 @@ });

// Immediately register editability with the state
state.setThumbEditable(index, isEditable);
state.setThumbEditable(index, !isDisabled);

@@ -100,2 +126,25 @@ const {focusableProps} = useFocusable(

let currentPointer = useRef<number | null | undefined>(undefined);
let onDown = (id: number | null) => {
focusInput();
currentPointer.current = id;
state.setThumbDragging(index, true);
addGlobalListener(window, 'mouseup', onUp, false);
addGlobalListener(window, 'touchend', onUp, false);
addGlobalListener(window, 'pointerup', onUp, false);
};
let onUp = (e) => {
let id = e.pointerId ?? e.changedTouches?.[0].identifier;
if (id === currentPointer.current) {
focusInput();
state.setThumbDragging(index, false);
removeGlobalListener(window, 'mouseup', onUp, false);
removeGlobalListener(window, 'touchend', onUp, false);
removeGlobalListener(window, 'pointerup', onUp, false);
}
};
// We install mouse handlers for the drag motion on the thumb div, but

@@ -108,3 +157,3 @@ // not the key handler for moving the thumb with the slider. Instead,

type: 'range',
tabIndex: isEditable ? 0 : undefined,
tabIndex: !isDisabled ? 0 : undefined,
min: state.getThumbMinValue(index),

@@ -114,5 +163,4 @@ max: state.getThumbMaxValue(index),

value: value,
readOnly: isReadOnly,
disabled: isDisabled,
'aria-orientation': 'horizontal',
'aria-orientation': opts.orientation,
'aria-valuetext': state.getThumbValueLabel(index),

@@ -126,11 +174,12 @@ 'aria-required': isRequired || undefined,

}),
thumbProps: isEditable ? mergeProps({
onMouseDown: draggableProps.onMouseDown,
onMouseEnter: draggableProps.onMouseEnter,
onMouseOut: draggableProps.onMouseOut
}, {
onMouseDown: focusInput
}) : {},
thumbProps: !isDisabled ? mergeProps(
moveProps,
{
onMouseDown: () => {onDown(null);},
onPointerDown: (e: React.PointerEvent) => {onDown(e.pointerId);},
onTouchStart: (e: React.TouchEvent) => {onDown(e.changedTouches[0].identifier);}
}
) : {},
labelProps
};
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc