@react-aria/spinbutton 3.0.0-nightly-ecd229153-251022 → 3.0.0-nightly-070dfd621-251024
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/types.d.ts.map +1 -1
- package/dist/useSpinButton.main.js +30 -12
- package/dist/useSpinButton.main.js.map +1 -1
- package/dist/useSpinButton.mjs +31 -13
- package/dist/useSpinButton.module.js +31 -13
- package/dist/useSpinButton.module.js.map +1 -1
- package/package.json +6 -6
- package/src/useSpinButton.ts +34 -13
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;AAsBA,gCAAiC,SAAQ,SAAS,EAAE,WAAW,MAAM,CAAC,EAAE,UAAU,MAAM,CAAC,EAAE,eAAe,MAAM,CAAC;IAC/G,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;CAC9B;AAED;IACE,eAAe,EAAE,aAAa,CAAC;IAC/B,oBAAoB,EAAE,eAAe,CAAC;IACtC,oBAAoB,EAAE,eAAe,CAAA;CACtC;AAED,8BACE,KAAK,EAAE,eAAe,GACrB,cAAc,
|
|
1
|
+
{"mappings":";;AAsBA,gCAAiC,SAAQ,SAAS,EAAE,WAAW,MAAM,CAAC,EAAE,UAAU,MAAM,CAAC,EAAE,eAAe,MAAM,CAAC;IAC/G,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;CAC9B;AAED;IACE,eAAe,EAAE,aAAa,CAAC;IAC/B,oBAAoB,EAAE,eAAe,CAAC;IACtC,oBAAoB,EAAE,eAAe,CAAA;CACtC;AAED,8BACE,KAAK,EAAE,eAAe,GACrB,cAAc,CAgRhB","sources":["packages/@react-aria/spinbutton/src/packages/@react-aria/spinbutton/src/useSpinButton.ts","packages/@react-aria/spinbutton/src/packages/@react-aria/spinbutton/src/index.ts","packages/@react-aria/spinbutton/src/index.ts"],"sourcesContent":[null,null,"/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\nexport type {SpinButtonProps, SpinbuttonAria} from './useSpinButton';\nexport {useSpinButton} from './useSpinButton';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
|
|
@@ -148,6 +148,20 @@ function $37bbd4c129023f61$export$e908e06f4b8e3402(props) {
|
|
|
148
148
|
// This means that the user is trying to scroll or interact in some way that shouldn't trigger
|
|
149
149
|
// an increment or decrement.
|
|
150
150
|
let isUp = (0, $2pZbw$react.useRef)(false);
|
|
151
|
+
let [isIncrementPressed, setIsIncrementPressed] = (0, $2pZbw$react.useState)(null);
|
|
152
|
+
(0, $2pZbw$react.useEffect)(()=>{
|
|
153
|
+
if (isIncrementPressed === 'touch') onIncrementPressStart(60);
|
|
154
|
+
else if (isIncrementPressed) onIncrementPressStart(400);
|
|
155
|
+
}, [
|
|
156
|
+
isIncrementPressed
|
|
157
|
+
]);
|
|
158
|
+
let [isDecrementPressed, setIsDecrementPressed] = (0, $2pZbw$react.useState)(null);
|
|
159
|
+
(0, $2pZbw$react.useEffect)(()=>{
|
|
160
|
+
if (isDecrementPressed === 'touch') onDecrementPressStart(60);
|
|
161
|
+
else if (isDecrementPressed) onDecrementPressStart(400);
|
|
162
|
+
}, [
|
|
163
|
+
isDecrementPressed
|
|
164
|
+
]);
|
|
151
165
|
return {
|
|
152
166
|
spinButtonProps: {
|
|
153
167
|
role: 'spinbutton',
|
|
@@ -164,18 +178,18 @@ function $37bbd4c129023f61$export$e908e06f4b8e3402(props) {
|
|
|
164
178
|
},
|
|
165
179
|
incrementButtonProps: {
|
|
166
180
|
onPressStart: (e)=>{
|
|
167
|
-
if (e.pointerType !== 'touch')
|
|
181
|
+
if (e.pointerType !== 'touch') setIsIncrementPressed('mouse');
|
|
168
182
|
else {
|
|
169
183
|
if (_async.current) clearAsync();
|
|
170
|
-
// For touch users, don't trigger an increment on press start, we'll wait for the press end to trigger it if
|
|
171
|
-
// the control isn't spinning.
|
|
172
|
-
_async.current = window.setTimeout(()=>{
|
|
173
|
-
onIncrementPressStart(60);
|
|
174
|
-
}, 600);
|
|
175
184
|
addGlobalListener(window, 'touchmove', onTouchMove, {
|
|
176
185
|
capture: true
|
|
177
186
|
});
|
|
178
187
|
isUp.current = false;
|
|
188
|
+
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
189
|
+
// the control isn't spinning.
|
|
190
|
+
_async.current = window.setTimeout(()=>{
|
|
191
|
+
setIsIncrementPressed('touch');
|
|
192
|
+
}, 600);
|
|
179
193
|
}
|
|
180
194
|
addGlobalListener(window, 'contextmenu', cancelContextMenu);
|
|
181
195
|
},
|
|
@@ -184,30 +198,32 @@ function $37bbd4c129023f61$export$e908e06f4b8e3402(props) {
|
|
|
184
198
|
prevTouchPosition.current = null;
|
|
185
199
|
clearAsync();
|
|
186
200
|
removeAllGlobalListeners();
|
|
201
|
+
setIsIncrementPressed(null);
|
|
187
202
|
},
|
|
188
203
|
onPressEnd: (e)=>{
|
|
189
204
|
if (e.pointerType === 'touch') {
|
|
190
205
|
if (!isSpinning.current && isUp.current) onIncrement === null || onIncrement === void 0 ? void 0 : onIncrement();
|
|
191
206
|
}
|
|
192
207
|
isUp.current = false;
|
|
208
|
+
setIsIncrementPressed(null);
|
|
193
209
|
},
|
|
194
210
|
onFocus: onFocus,
|
|
195
211
|
onBlur: onBlur
|
|
196
212
|
},
|
|
197
213
|
decrementButtonProps: {
|
|
198
214
|
onPressStart: (e)=>{
|
|
199
|
-
if (e.pointerType !== 'touch')
|
|
215
|
+
if (e.pointerType !== 'touch') setIsDecrementPressed('mouse');
|
|
200
216
|
else {
|
|
201
217
|
if (_async.current) clearAsync();
|
|
202
|
-
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
203
|
-
// the control isn't spinning.
|
|
204
|
-
_async.current = window.setTimeout(()=>{
|
|
205
|
-
onDecrementPressStart(60);
|
|
206
|
-
}, 600);
|
|
207
218
|
addGlobalListener(window, 'touchmove', onTouchMove, {
|
|
208
219
|
capture: true
|
|
209
220
|
});
|
|
210
221
|
isUp.current = false;
|
|
222
|
+
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
223
|
+
// the control isn't spinning.
|
|
224
|
+
_async.current = window.setTimeout(()=>{
|
|
225
|
+
setIsDecrementPressed('touch');
|
|
226
|
+
}, 600);
|
|
211
227
|
}
|
|
212
228
|
},
|
|
213
229
|
onPressUp: (e)=>{
|
|
@@ -215,12 +231,14 @@ function $37bbd4c129023f61$export$e908e06f4b8e3402(props) {
|
|
|
215
231
|
prevTouchPosition.current = null;
|
|
216
232
|
clearAsync();
|
|
217
233
|
removeAllGlobalListeners();
|
|
234
|
+
setIsDecrementPressed(null);
|
|
218
235
|
},
|
|
219
236
|
onPressEnd: (e)=>{
|
|
220
237
|
if (e.pointerType === 'touch') {
|
|
221
238
|
if (!isSpinning.current && isUp.current) onDecrement === null || onDecrement === void 0 ? void 0 : onDecrement();
|
|
222
239
|
}
|
|
223
240
|
isUp.current = false;
|
|
241
|
+
setIsDecrementPressed(null);
|
|
224
242
|
},
|
|
225
243
|
onFocus: onFocus,
|
|
226
244
|
onBlur: onBlur
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["packages/@react-aria/spinbutton/src/useSpinButton.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {announce, clearAnnouncer} from '@react-aria/live-announcer';\nimport {AriaButtonProps} from '@react-types/button';\nimport {DOMAttributes, InputBase, RangeInputBase, Validation, ValueBase} from '@react-types/shared';\n// @ts-ignore\nimport intlMessages from '../intl/*.json';\nimport {useCallback, useEffect, useRef} from 'react';\nimport {useEffectEvent, useGlobalListeners} from '@react-aria/utils';\nimport {useLocalizedStringFormatter} from '@react-aria/i18n';\n\n\nexport interface SpinButtonProps extends InputBase, Validation<number>, ValueBase<number>, RangeInputBase<number> {\n textValue?: string,\n onIncrement?: () => void,\n onIncrementPage?: () => void,\n onDecrement?: () => void,\n onDecrementPage?: () => void,\n onDecrementToMin?: () => void,\n onIncrementToMax?: () => void\n}\n\nexport interface SpinbuttonAria {\n spinButtonProps: DOMAttributes,\n incrementButtonProps: AriaButtonProps,\n decrementButtonProps: AriaButtonProps\n}\n\nexport function useSpinButton(\n props: SpinButtonProps\n): SpinbuttonAria {\n const _async = useRef<number>(undefined);\n let {\n value,\n textValue,\n minValue,\n maxValue,\n isDisabled,\n isReadOnly,\n isRequired,\n onIncrement,\n onIncrementPage,\n onDecrement,\n onDecrementPage,\n onDecrementToMin,\n onIncrementToMax\n } = props;\n const stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/spinbutton');\n\n let prevTouchPosition = useRef<{x: number, y: number} | null>(null);\n let isSpinning = useRef(false);\n const clearAsync = () => {\n clearTimeout(_async.current);\n isSpinning.current = false;\n };\n\n\n useEffect(() => {\n return () => clearAsync();\n }, []);\n\n let onKeyDown = (e) => {\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey || isReadOnly || e.nativeEvent.isComposing) {\n return;\n }\n\n switch (e.key) {\n case 'PageUp':\n if (onIncrementPage) {\n e.preventDefault();\n onIncrementPage?.();\n break;\n }\n // fallthrough!\n case 'ArrowUp':\n case 'Up':\n if (onIncrement) {\n e.preventDefault();\n onIncrement?.();\n }\n break;\n case 'PageDown':\n if (onDecrementPage) {\n e.preventDefault();\n onDecrementPage?.();\n break;\n }\n // fallthrough\n case 'ArrowDown':\n case 'Down':\n if (onDecrement) {\n e.preventDefault();\n onDecrement?.();\n }\n break;\n case 'Home':\n if (onDecrementToMin) {\n e.preventDefault();\n onDecrementToMin?.();\n }\n break;\n case 'End':\n if (onIncrementToMax) {\n e.preventDefault();\n onIncrementToMax?.();\n }\n break;\n }\n };\n\n let isFocused = useRef(false);\n let onFocus = () => {\n isFocused.current = true;\n };\n\n let onBlur = () => {\n isFocused.current = false;\n };\n\n // Replace Unicode hyphen-minus (U+002D) with minus sign (U+2212).\n // This ensures that macOS VoiceOver announces it as \"minus\" even with other characters between the minus sign\n // and the number (e.g. currency symbol). Otherwise it announces nothing because it assumes the character is a hyphen.\n // In addition, replace the empty string with the word \"Empty\" so that iOS VoiceOver does not read \"50%\" for an empty field.\n let ariaTextValue = textValue === '' ? stringFormatter.format('Empty') : (textValue || `${value}`).replace('-', '\\u2212');\n\n useEffect(() => {\n if (isFocused.current) {\n clearAnnouncer('assertive');\n announce(ariaTextValue, 'assertive');\n }\n }, [ariaTextValue]);\n\n // For touch users, if they move their finger like they're scrolling, we don't want to trigger a spin.\n let onTouchMove = useCallback((e) => {\n if (!prevTouchPosition.current) {\n prevTouchPosition.current = {x: e.touches[0].clientX, y: e.touches[0].clientY};\n }\n let touchPosition = {x: e.touches[0].clientX, y: e.touches[0].clientY};\n // Arbitrary distance that worked in testing, even with slight movements or a slow-ish start to scrolling.\n if (Math.abs(touchPosition.x - prevTouchPosition.current.x) > 1 || Math.abs(touchPosition.y - prevTouchPosition.current.y) > 1) {\n clearAsync();\n }\n prevTouchPosition.current = touchPosition;\n }, []);\n\n const onIncrementPressStart = useEffectEvent(\n (initialStepDelay: number) => {\n clearAsync();\n isSpinning.current = true;\n onIncrement?.();\n // Start spinning after initial delay\n _async.current = window.setTimeout(\n () => {\n if ((maxValue === undefined || isNaN(maxValue)) || (value === undefined || isNaN(value)) || value < maxValue) {\n onIncrementPressStart(60);\n }\n },\n initialStepDelay\n );\n }\n );\n\n const onDecrementPressStart = useEffectEvent(\n (initialStepDelay: number) => {\n clearAsync();\n isSpinning.current = true;\n onDecrement?.();\n // Start spinning after initial delay\n _async.current = window.setTimeout(\n () => {\n if ((minValue === undefined || isNaN(minValue)) || (value === undefined || isNaN(value)) || value > minValue) {\n onDecrementPressStart(60);\n }\n },\n initialStepDelay\n );\n }\n );\n\n let cancelContextMenu = (e) => {\n e.preventDefault();\n };\n\n let {addGlobalListener, removeAllGlobalListeners} = useGlobalListeners();\n\n // Tracks in touch if the press end event was preceded by a press up.\n // If it wasn't, then we know the finger left the button while still in contact with the screen.\n // This means that the user is trying to scroll or interact in some way that shouldn't trigger\n // an increment or decrement.\n let isUp = useRef(false);\n\n return {\n spinButtonProps: {\n role: 'spinbutton',\n 'aria-valuenow': value !== undefined && !isNaN(value) ? value : undefined,\n 'aria-valuetext': ariaTextValue,\n 'aria-valuemin': minValue,\n 'aria-valuemax': maxValue,\n 'aria-disabled': isDisabled || undefined,\n 'aria-readonly': isReadOnly || undefined,\n 'aria-required': isRequired || undefined,\n onKeyDown,\n onFocus,\n onBlur\n },\n incrementButtonProps: {\n onPressStart: (e) => {\n if (e.pointerType !== 'touch') {\n onIncrementPressStart(400);\n } else {\n if (_async.current) {\n clearAsync();\n }\n // For touch users, don't trigger an increment on press start, we'll wait for the press end to trigger it if\n // the control isn't spinning.\n _async.current = window.setTimeout(() => {\n onIncrementPressStart(60);\n }, 600);\n\n addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});\n isUp.current = false;\n }\n addGlobalListener(window, 'contextmenu', cancelContextMenu);\n },\n onPressUp: (e) => {\n if (e.pointerType === 'touch') {\n isUp.current = true;\n }\n prevTouchPosition.current = null;\n clearAsync();\n removeAllGlobalListeners();\n },\n onPressEnd: (e) => {\n if (e.pointerType === 'touch') {\n if (!isSpinning.current && isUp.current) {\n onIncrement?.();\n }\n }\n isUp.current = false;\n },\n onFocus,\n onBlur\n },\n decrementButtonProps: {\n onPressStart: (e) => {\n if (e.pointerType !== 'touch') {\n onDecrementPressStart(400);\n } else {\n if (_async.current) {\n clearAsync();\n }\n // For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if\n // the control isn't spinning.\n _async.current = window.setTimeout(() => {\n onDecrementPressStart(60);\n }, 600);\n\n addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});\n isUp.current = false;\n }\n },\n onPressUp: (e) => {\n if (e.pointerType === 'touch') {\n isUp.current = true;\n }\n prevTouchPosition.current = null;\n clearAsync();\n removeAllGlobalListeners();\n },\n onPressEnd: (e) => {\n if (e.pointerType === 'touch') {\n if (!isSpinning.current && isUp.current) {\n onDecrement?.();\n }\n }\n isUp.current = false;\n },\n onFocus,\n onBlur\n }\n };\n}\n"],"names":[],"version":3,"file":"useSpinButton.main.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/spinbutton/src/useSpinButton.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {announce, clearAnnouncer} from '@react-aria/live-announcer';\nimport {AriaButtonProps} from '@react-types/button';\nimport {DOMAttributes, InputBase, RangeInputBase, Validation, ValueBase} from '@react-types/shared';\n// @ts-ignore\nimport intlMessages from '../intl/*.json';\nimport {useCallback, useEffect, useRef, useState} from 'react';\nimport {useEffectEvent, useGlobalListeners} from '@react-aria/utils';\nimport {useLocalizedStringFormatter} from '@react-aria/i18n';\n\n\nexport interface SpinButtonProps extends InputBase, Validation<number>, ValueBase<number>, RangeInputBase<number> {\n textValue?: string,\n onIncrement?: () => void,\n onIncrementPage?: () => void,\n onDecrement?: () => void,\n onDecrementPage?: () => void,\n onDecrementToMin?: () => void,\n onIncrementToMax?: () => void\n}\n\nexport interface SpinbuttonAria {\n spinButtonProps: DOMAttributes,\n incrementButtonProps: AriaButtonProps,\n decrementButtonProps: AriaButtonProps\n}\n\nexport function useSpinButton(\n props: SpinButtonProps\n): SpinbuttonAria {\n const _async = useRef<number>(undefined);\n let {\n value,\n textValue,\n minValue,\n maxValue,\n isDisabled,\n isReadOnly,\n isRequired,\n onIncrement,\n onIncrementPage,\n onDecrement,\n onDecrementPage,\n onDecrementToMin,\n onIncrementToMax\n } = props;\n const stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/spinbutton');\n\n let prevTouchPosition = useRef<{x: number, y: number} | null>(null);\n let isSpinning = useRef(false);\n const clearAsync = () => {\n clearTimeout(_async.current);\n isSpinning.current = false;\n };\n\n useEffect(() => {\n return () => clearAsync();\n }, []);\n\n let onKeyDown = (e) => {\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey || isReadOnly || e.nativeEvent.isComposing) {\n return;\n }\n\n switch (e.key) {\n case 'PageUp':\n if (onIncrementPage) {\n e.preventDefault();\n onIncrementPage?.();\n break;\n }\n // fallthrough!\n case 'ArrowUp':\n case 'Up':\n if (onIncrement) {\n e.preventDefault();\n onIncrement?.();\n }\n break;\n case 'PageDown':\n if (onDecrementPage) {\n e.preventDefault();\n onDecrementPage?.();\n break;\n }\n // fallthrough\n case 'ArrowDown':\n case 'Down':\n if (onDecrement) {\n e.preventDefault();\n onDecrement?.();\n }\n break;\n case 'Home':\n if (onDecrementToMin) {\n e.preventDefault();\n onDecrementToMin?.();\n }\n break;\n case 'End':\n if (onIncrementToMax) {\n e.preventDefault();\n onIncrementToMax?.();\n }\n break;\n }\n };\n\n let isFocused = useRef(false);\n let onFocus = () => {\n isFocused.current = true;\n };\n\n let onBlur = () => {\n isFocused.current = false;\n };\n\n // Replace Unicode hyphen-minus (U+002D) with minus sign (U+2212).\n // This ensures that macOS VoiceOver announces it as \"minus\" even with other characters between the minus sign\n // and the number (e.g. currency symbol). Otherwise it announces nothing because it assumes the character is a hyphen.\n // In addition, replace the empty string with the word \"Empty\" so that iOS VoiceOver does not read \"50%\" for an empty field.\n let ariaTextValue = textValue === '' ? stringFormatter.format('Empty') : (textValue || `${value}`).replace('-', '\\u2212');\n\n useEffect(() => {\n if (isFocused.current) {\n clearAnnouncer('assertive');\n announce(ariaTextValue, 'assertive');\n }\n }, [ariaTextValue]);\n\n // For touch users, if they move their finger like they're scrolling, we don't want to trigger a spin.\n let onTouchMove = useCallback((e) => {\n if (!prevTouchPosition.current) {\n prevTouchPosition.current = {x: e.touches[0].clientX, y: e.touches[0].clientY};\n }\n let touchPosition = {x: e.touches[0].clientX, y: e.touches[0].clientY};\n // Arbitrary distance that worked in testing, even with slight movements or a slow-ish start to scrolling.\n if (Math.abs(touchPosition.x - prevTouchPosition.current.x) > 1 || Math.abs(touchPosition.y - prevTouchPosition.current.y) > 1) {\n clearAsync();\n }\n prevTouchPosition.current = touchPosition;\n }, []);\n\n const onIncrementPressStart = useEffectEvent(\n (initialStepDelay: number) => {\n clearAsync();\n isSpinning.current = true;\n onIncrement?.();\n // Start spinning after initial delay\n _async.current = window.setTimeout(\n () => {\n if ((maxValue === undefined || isNaN(maxValue)) || (value === undefined || isNaN(value)) || value < maxValue) {\n onIncrementPressStart(60);\n }\n },\n initialStepDelay\n );\n }\n );\n\n const onDecrementPressStart = useEffectEvent(\n (initialStepDelay: number) => {\n clearAsync();\n isSpinning.current = true;\n onDecrement?.();\n // Start spinning after initial delay\n _async.current = window.setTimeout(\n () => {\n if ((minValue === undefined || isNaN(minValue)) || (value === undefined || isNaN(value)) || value > minValue) {\n onDecrementPressStart(60);\n }\n },\n initialStepDelay\n );\n }\n );\n\n let cancelContextMenu = (e) => {\n e.preventDefault();\n };\n\n let {addGlobalListener, removeAllGlobalListeners} = useGlobalListeners();\n\n // Tracks in touch if the press end event was preceded by a press up.\n // If it wasn't, then we know the finger left the button while still in contact with the screen.\n // This means that the user is trying to scroll or interact in some way that shouldn't trigger\n // an increment or decrement.\n let isUp = useRef(false);\n\n let [isIncrementPressed, setIsIncrementPressed] = useState<'touch' | 'mouse' | null>(null);\n useEffect(() => {\n if (isIncrementPressed === 'touch') {\n onIncrementPressStart(60);\n } else if (isIncrementPressed) {\n onIncrementPressStart(400);\n }\n }, [isIncrementPressed]);\n\n let [isDecrementPressed, setIsDecrementPressed] = useState<'touch' | 'mouse' | null>(null);\n useEffect(() => {\n if (isDecrementPressed === 'touch') {\n onDecrementPressStart(60);\n } else if (isDecrementPressed) {\n onDecrementPressStart(400);\n }\n }, [isDecrementPressed]);\n\n return {\n spinButtonProps: {\n role: 'spinbutton',\n 'aria-valuenow': value !== undefined && !isNaN(value) ? value : undefined,\n 'aria-valuetext': ariaTextValue,\n 'aria-valuemin': minValue,\n 'aria-valuemax': maxValue,\n 'aria-disabled': isDisabled || undefined,\n 'aria-readonly': isReadOnly || undefined,\n 'aria-required': isRequired || undefined,\n onKeyDown,\n onFocus,\n onBlur\n },\n incrementButtonProps: {\n onPressStart: (e) => {\n if (e.pointerType !== 'touch') {\n setIsIncrementPressed('mouse');\n } else {\n if (_async.current) {\n clearAsync();\n }\n\n addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});\n isUp.current = false;\n // For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if\n // the control isn't spinning.\n _async.current = window.setTimeout(() => {\n setIsIncrementPressed('touch');\n }, 600);\n }\n addGlobalListener(window, 'contextmenu', cancelContextMenu);\n },\n onPressUp: (e) => {\n if (e.pointerType === 'touch') {\n isUp.current = true;\n }\n prevTouchPosition.current = null;\n clearAsync();\n removeAllGlobalListeners();\n setIsIncrementPressed(null);\n },\n onPressEnd: (e) => {\n if (e.pointerType === 'touch') {\n if (!isSpinning.current && isUp.current) {\n onIncrement?.();\n }\n }\n isUp.current = false;\n setIsIncrementPressed(null);\n },\n onFocus,\n onBlur\n },\n decrementButtonProps: {\n onPressStart: (e) => {\n if (e.pointerType !== 'touch') {\n setIsDecrementPressed('mouse');\n } else {\n if (_async.current) {\n clearAsync();\n }\n\n addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});\n isUp.current = false;\n // For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if\n // the control isn't spinning.\n _async.current = window.setTimeout(() => {\n setIsDecrementPressed('touch');\n }, 600);\n }\n },\n onPressUp: (e) => {\n if (e.pointerType === 'touch') {\n isUp.current = true;\n }\n prevTouchPosition.current = null;\n clearAsync();\n removeAllGlobalListeners();\n setIsDecrementPressed(null);\n },\n onPressEnd: (e) => {\n if (e.pointerType === 'touch') {\n if (!isSpinning.current && isUp.current) {\n onDecrement?.();\n }\n }\n isUp.current = false;\n setIsDecrementPressed(null);\n },\n onFocus,\n onBlur\n }\n };\n}\n"],"names":[],"version":3,"file":"useSpinButton.main.js.map"}
|
package/dist/useSpinButton.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import $5rwhf$intlStringsmodulejs from "./intlStrings.mjs";
|
|
2
2
|
import {clearAnnouncer as $5rwhf$clearAnnouncer, announce as $5rwhf$announce} from "@react-aria/live-announcer";
|
|
3
|
-
import {useRef as $5rwhf$useRef, useEffect as $5rwhf$useEffect, useCallback as $5rwhf$useCallback} from "react";
|
|
3
|
+
import {useRef as $5rwhf$useRef, useEffect as $5rwhf$useEffect, useCallback as $5rwhf$useCallback, useState as $5rwhf$useState} from "react";
|
|
4
4
|
import {useEffectEvent as $5rwhf$useEffectEvent, useGlobalListeners as $5rwhf$useGlobalListeners} from "@react-aria/utils";
|
|
5
5
|
import {useLocalizedStringFormatter as $5rwhf$useLocalizedStringFormatter} from "@react-aria/i18n";
|
|
6
6
|
|
|
@@ -142,6 +142,20 @@ function $d2e8511e6f209edf$export$e908e06f4b8e3402(props) {
|
|
|
142
142
|
// This means that the user is trying to scroll or interact in some way that shouldn't trigger
|
|
143
143
|
// an increment or decrement.
|
|
144
144
|
let isUp = (0, $5rwhf$useRef)(false);
|
|
145
|
+
let [isIncrementPressed, setIsIncrementPressed] = (0, $5rwhf$useState)(null);
|
|
146
|
+
(0, $5rwhf$useEffect)(()=>{
|
|
147
|
+
if (isIncrementPressed === 'touch') onIncrementPressStart(60);
|
|
148
|
+
else if (isIncrementPressed) onIncrementPressStart(400);
|
|
149
|
+
}, [
|
|
150
|
+
isIncrementPressed
|
|
151
|
+
]);
|
|
152
|
+
let [isDecrementPressed, setIsDecrementPressed] = (0, $5rwhf$useState)(null);
|
|
153
|
+
(0, $5rwhf$useEffect)(()=>{
|
|
154
|
+
if (isDecrementPressed === 'touch') onDecrementPressStart(60);
|
|
155
|
+
else if (isDecrementPressed) onDecrementPressStart(400);
|
|
156
|
+
}, [
|
|
157
|
+
isDecrementPressed
|
|
158
|
+
]);
|
|
145
159
|
return {
|
|
146
160
|
spinButtonProps: {
|
|
147
161
|
role: 'spinbutton',
|
|
@@ -158,18 +172,18 @@ function $d2e8511e6f209edf$export$e908e06f4b8e3402(props) {
|
|
|
158
172
|
},
|
|
159
173
|
incrementButtonProps: {
|
|
160
174
|
onPressStart: (e)=>{
|
|
161
|
-
if (e.pointerType !== 'touch')
|
|
175
|
+
if (e.pointerType !== 'touch') setIsIncrementPressed('mouse');
|
|
162
176
|
else {
|
|
163
177
|
if (_async.current) clearAsync();
|
|
164
|
-
// For touch users, don't trigger an increment on press start, we'll wait for the press end to trigger it if
|
|
165
|
-
// the control isn't spinning.
|
|
166
|
-
_async.current = window.setTimeout(()=>{
|
|
167
|
-
onIncrementPressStart(60);
|
|
168
|
-
}, 600);
|
|
169
178
|
addGlobalListener(window, 'touchmove', onTouchMove, {
|
|
170
179
|
capture: true
|
|
171
180
|
});
|
|
172
181
|
isUp.current = false;
|
|
182
|
+
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
183
|
+
// the control isn't spinning.
|
|
184
|
+
_async.current = window.setTimeout(()=>{
|
|
185
|
+
setIsIncrementPressed('touch');
|
|
186
|
+
}, 600);
|
|
173
187
|
}
|
|
174
188
|
addGlobalListener(window, 'contextmenu', cancelContextMenu);
|
|
175
189
|
},
|
|
@@ -178,30 +192,32 @@ function $d2e8511e6f209edf$export$e908e06f4b8e3402(props) {
|
|
|
178
192
|
prevTouchPosition.current = null;
|
|
179
193
|
clearAsync();
|
|
180
194
|
removeAllGlobalListeners();
|
|
195
|
+
setIsIncrementPressed(null);
|
|
181
196
|
},
|
|
182
197
|
onPressEnd: (e)=>{
|
|
183
198
|
if (e.pointerType === 'touch') {
|
|
184
199
|
if (!isSpinning.current && isUp.current) onIncrement === null || onIncrement === void 0 ? void 0 : onIncrement();
|
|
185
200
|
}
|
|
186
201
|
isUp.current = false;
|
|
202
|
+
setIsIncrementPressed(null);
|
|
187
203
|
},
|
|
188
204
|
onFocus: onFocus,
|
|
189
205
|
onBlur: onBlur
|
|
190
206
|
},
|
|
191
207
|
decrementButtonProps: {
|
|
192
208
|
onPressStart: (e)=>{
|
|
193
|
-
if (e.pointerType !== 'touch')
|
|
209
|
+
if (e.pointerType !== 'touch') setIsDecrementPressed('mouse');
|
|
194
210
|
else {
|
|
195
211
|
if (_async.current) clearAsync();
|
|
196
|
-
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
197
|
-
// the control isn't spinning.
|
|
198
|
-
_async.current = window.setTimeout(()=>{
|
|
199
|
-
onDecrementPressStart(60);
|
|
200
|
-
}, 600);
|
|
201
212
|
addGlobalListener(window, 'touchmove', onTouchMove, {
|
|
202
213
|
capture: true
|
|
203
214
|
});
|
|
204
215
|
isUp.current = false;
|
|
216
|
+
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
217
|
+
// the control isn't spinning.
|
|
218
|
+
_async.current = window.setTimeout(()=>{
|
|
219
|
+
setIsDecrementPressed('touch');
|
|
220
|
+
}, 600);
|
|
205
221
|
}
|
|
206
222
|
},
|
|
207
223
|
onPressUp: (e)=>{
|
|
@@ -209,12 +225,14 @@ function $d2e8511e6f209edf$export$e908e06f4b8e3402(props) {
|
|
|
209
225
|
prevTouchPosition.current = null;
|
|
210
226
|
clearAsync();
|
|
211
227
|
removeAllGlobalListeners();
|
|
228
|
+
setIsDecrementPressed(null);
|
|
212
229
|
},
|
|
213
230
|
onPressEnd: (e)=>{
|
|
214
231
|
if (e.pointerType === 'touch') {
|
|
215
232
|
if (!isSpinning.current && isUp.current) onDecrement === null || onDecrement === void 0 ? void 0 : onDecrement();
|
|
216
233
|
}
|
|
217
234
|
isUp.current = false;
|
|
235
|
+
setIsDecrementPressed(null);
|
|
218
236
|
},
|
|
219
237
|
onFocus: onFocus,
|
|
220
238
|
onBlur: onBlur
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import $5rwhf$intlStringsmodulejs from "./intlStrings.module.js";
|
|
2
2
|
import {clearAnnouncer as $5rwhf$clearAnnouncer, announce as $5rwhf$announce} from "@react-aria/live-announcer";
|
|
3
|
-
import {useRef as $5rwhf$useRef, useEffect as $5rwhf$useEffect, useCallback as $5rwhf$useCallback} from "react";
|
|
3
|
+
import {useRef as $5rwhf$useRef, useEffect as $5rwhf$useEffect, useCallback as $5rwhf$useCallback, useState as $5rwhf$useState} from "react";
|
|
4
4
|
import {useEffectEvent as $5rwhf$useEffectEvent, useGlobalListeners as $5rwhf$useGlobalListeners} from "@react-aria/utils";
|
|
5
5
|
import {useLocalizedStringFormatter as $5rwhf$useLocalizedStringFormatter} from "@react-aria/i18n";
|
|
6
6
|
|
|
@@ -142,6 +142,20 @@ function $d2e8511e6f209edf$export$e908e06f4b8e3402(props) {
|
|
|
142
142
|
// This means that the user is trying to scroll or interact in some way that shouldn't trigger
|
|
143
143
|
// an increment or decrement.
|
|
144
144
|
let isUp = (0, $5rwhf$useRef)(false);
|
|
145
|
+
let [isIncrementPressed, setIsIncrementPressed] = (0, $5rwhf$useState)(null);
|
|
146
|
+
(0, $5rwhf$useEffect)(()=>{
|
|
147
|
+
if (isIncrementPressed === 'touch') onIncrementPressStart(60);
|
|
148
|
+
else if (isIncrementPressed) onIncrementPressStart(400);
|
|
149
|
+
}, [
|
|
150
|
+
isIncrementPressed
|
|
151
|
+
]);
|
|
152
|
+
let [isDecrementPressed, setIsDecrementPressed] = (0, $5rwhf$useState)(null);
|
|
153
|
+
(0, $5rwhf$useEffect)(()=>{
|
|
154
|
+
if (isDecrementPressed === 'touch') onDecrementPressStart(60);
|
|
155
|
+
else if (isDecrementPressed) onDecrementPressStart(400);
|
|
156
|
+
}, [
|
|
157
|
+
isDecrementPressed
|
|
158
|
+
]);
|
|
145
159
|
return {
|
|
146
160
|
spinButtonProps: {
|
|
147
161
|
role: 'spinbutton',
|
|
@@ -158,18 +172,18 @@ function $d2e8511e6f209edf$export$e908e06f4b8e3402(props) {
|
|
|
158
172
|
},
|
|
159
173
|
incrementButtonProps: {
|
|
160
174
|
onPressStart: (e)=>{
|
|
161
|
-
if (e.pointerType !== 'touch')
|
|
175
|
+
if (e.pointerType !== 'touch') setIsIncrementPressed('mouse');
|
|
162
176
|
else {
|
|
163
177
|
if (_async.current) clearAsync();
|
|
164
|
-
// For touch users, don't trigger an increment on press start, we'll wait for the press end to trigger it if
|
|
165
|
-
// the control isn't spinning.
|
|
166
|
-
_async.current = window.setTimeout(()=>{
|
|
167
|
-
onIncrementPressStart(60);
|
|
168
|
-
}, 600);
|
|
169
178
|
addGlobalListener(window, 'touchmove', onTouchMove, {
|
|
170
179
|
capture: true
|
|
171
180
|
});
|
|
172
181
|
isUp.current = false;
|
|
182
|
+
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
183
|
+
// the control isn't spinning.
|
|
184
|
+
_async.current = window.setTimeout(()=>{
|
|
185
|
+
setIsIncrementPressed('touch');
|
|
186
|
+
}, 600);
|
|
173
187
|
}
|
|
174
188
|
addGlobalListener(window, 'contextmenu', cancelContextMenu);
|
|
175
189
|
},
|
|
@@ -178,30 +192,32 @@ function $d2e8511e6f209edf$export$e908e06f4b8e3402(props) {
|
|
|
178
192
|
prevTouchPosition.current = null;
|
|
179
193
|
clearAsync();
|
|
180
194
|
removeAllGlobalListeners();
|
|
195
|
+
setIsIncrementPressed(null);
|
|
181
196
|
},
|
|
182
197
|
onPressEnd: (e)=>{
|
|
183
198
|
if (e.pointerType === 'touch') {
|
|
184
199
|
if (!isSpinning.current && isUp.current) onIncrement === null || onIncrement === void 0 ? void 0 : onIncrement();
|
|
185
200
|
}
|
|
186
201
|
isUp.current = false;
|
|
202
|
+
setIsIncrementPressed(null);
|
|
187
203
|
},
|
|
188
204
|
onFocus: onFocus,
|
|
189
205
|
onBlur: onBlur
|
|
190
206
|
},
|
|
191
207
|
decrementButtonProps: {
|
|
192
208
|
onPressStart: (e)=>{
|
|
193
|
-
if (e.pointerType !== 'touch')
|
|
209
|
+
if (e.pointerType !== 'touch') setIsDecrementPressed('mouse');
|
|
194
210
|
else {
|
|
195
211
|
if (_async.current) clearAsync();
|
|
196
|
-
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
197
|
-
// the control isn't spinning.
|
|
198
|
-
_async.current = window.setTimeout(()=>{
|
|
199
|
-
onDecrementPressStart(60);
|
|
200
|
-
}, 600);
|
|
201
212
|
addGlobalListener(window, 'touchmove', onTouchMove, {
|
|
202
213
|
capture: true
|
|
203
214
|
});
|
|
204
215
|
isUp.current = false;
|
|
216
|
+
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
217
|
+
// the control isn't spinning.
|
|
218
|
+
_async.current = window.setTimeout(()=>{
|
|
219
|
+
setIsDecrementPressed('touch');
|
|
220
|
+
}, 600);
|
|
205
221
|
}
|
|
206
222
|
},
|
|
207
223
|
onPressUp: (e)=>{
|
|
@@ -209,12 +225,14 @@ function $d2e8511e6f209edf$export$e908e06f4b8e3402(props) {
|
|
|
209
225
|
prevTouchPosition.current = null;
|
|
210
226
|
clearAsync();
|
|
211
227
|
removeAllGlobalListeners();
|
|
228
|
+
setIsDecrementPressed(null);
|
|
212
229
|
},
|
|
213
230
|
onPressEnd: (e)=>{
|
|
214
231
|
if (e.pointerType === 'touch') {
|
|
215
232
|
if (!isSpinning.current && isUp.current) onDecrement === null || onDecrement === void 0 ? void 0 : onDecrement();
|
|
216
233
|
}
|
|
217
234
|
isUp.current = false;
|
|
235
|
+
setIsDecrementPressed(null);
|
|
218
236
|
},
|
|
219
237
|
onFocus: onFocus,
|
|
220
238
|
onBlur: onBlur
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;;AAAA;;;;;;;;;;CAUC;;;;;AA4BM,SAAS,0CACd,KAAsB;IAEtB,MAAM,SAAS,CAAA,GAAA,aAAK,EAAU;IAC9B,IAAI,SACF,KAAK,aACL,SAAS,YACT,QAAQ,YACR,QAAQ,cACR,UAAU,cACV,UAAU,cACV,UAAU,eACV,WAAW,mBACX,eAAe,eACf,WAAW,mBACX,eAAe,oBACf,gBAAgB,oBAChB,gBAAgB,EACjB,GAAG;IACJ,MAAM,kBAAkB,CAAA,GAAA,kCAA0B,EAAE,CAAA,GAAA,oDAAW,GAAG;IAElE,IAAI,oBAAoB,CAAA,GAAA,aAAK,EAAiC;IAC9D,IAAI,aAAa,CAAA,GAAA,aAAK,EAAE;IACxB,MAAM,aAAa;QACjB,aAAa,OAAO,OAAO;QAC3B,WAAW,OAAO,GAAG;IACvB;IAGA,CAAA,GAAA,gBAAQ,EAAE;QACR,OAAO,IAAM;IACf,GAAG,EAAE;IAEL,IAAI,YAAY,CAAC;QACf,IAAI,EAAE,OAAO,IAAI,EAAE,OAAO,IAAI,EAAE,QAAQ,IAAI,EAAE,MAAM,IAAI,cAAc,EAAE,WAAW,CAAC,WAAW,EAC7F;QAGF,OAAQ,EAAE,GAAG;YACX,KAAK;gBACH,IAAI,iBAAiB;oBACnB,EAAE,cAAc;oBAChB,4BAAA,sCAAA;oBACA;gBACF;YACF,eAAe;YACf,KAAK;YACL,KAAK;gBACH,IAAI,aAAa;oBACf,EAAE,cAAc;oBAChB,wBAAA,kCAAA;gBACF;gBACA;YACF,KAAK;gBACH,IAAI,iBAAiB;oBACnB,EAAE,cAAc;oBAChB,4BAAA,sCAAA;oBACA;gBACF;YACF,cAAc;YACd,KAAK;YACL,KAAK;gBACH,IAAI,aAAa;oBACf,EAAE,cAAc;oBAChB,wBAAA,kCAAA;gBACF;gBACA;YACF,KAAK;gBACH,IAAI,kBAAkB;oBACpB,EAAE,cAAc;oBAChB,6BAAA,uCAAA;gBACF;gBACA;YACF,KAAK;gBACH,IAAI,kBAAkB;oBACpB,EAAE,cAAc;oBAChB,6BAAA,uCAAA;gBACF;gBACA;QACJ;IACF;IAEA,IAAI,YAAY,CAAA,GAAA,aAAK,EAAE;IACvB,IAAI,UAAU;QACZ,UAAU,OAAO,GAAG;IACtB;IAEA,IAAI,SAAS;QACX,UAAU,OAAO,GAAG;IACtB;IAEA,kEAAkE;IAClE,8GAA8G;IAC9G,sHAAsH;IACtH,4HAA4H;IAC5H,IAAI,gBAAgB,cAAc,KAAK,gBAAgB,MAAM,CAAC,WAAW,AAAC,CAAA,aAAa,GAAG,OAAO,AAAD,EAAG,OAAO,CAAC,KAAK;IAEhH,CAAA,GAAA,gBAAQ,EAAE;QACR,IAAI,UAAU,OAAO,EAAE;YACrB,CAAA,GAAA,qBAAa,EAAE;YACf,CAAA,GAAA,eAAO,EAAE,eAAe;QAC1B;IACF,GAAG;QAAC;KAAc;IAElB,sGAAsG;IACtG,IAAI,cAAc,CAAA,GAAA,kBAAU,EAAE,CAAC;QAC7B,IAAI,CAAC,kBAAkB,OAAO,EAC5B,kBAAkB,OAAO,GAAG;YAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO;YAAE,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO;QAAA;QAE/E,IAAI,gBAAgB;YAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO;YAAE,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO;QAAA;QACrE,0GAA0G;QAC1G,IAAI,KAAK,GAAG,CAAC,cAAc,CAAC,GAAG,kBAAkB,OAAO,CAAC,CAAC,IAAI,KAAK,KAAK,GAAG,CAAC,cAAc,CAAC,GAAG,kBAAkB,OAAO,CAAC,CAAC,IAAI,GAC3H;QAEF,kBAAkB,OAAO,GAAG;IAC9B,GAAG,EAAE;IAEL,MAAM,wBAAwB,CAAA,GAAA,qBAAa,EACzC,CAAC;QACC;QACA,WAAW,OAAO,GAAG;QACrB,wBAAA,kCAAA;QACA,qCAAqC;QACrC,OAAO,OAAO,GAAG,OAAO,UAAU,CAChC;YACE,IAAI,AAAC,aAAa,aAAa,MAAM,aAAe,UAAU,aAAa,MAAM,UAAW,QAAQ,UAClG,sBAAsB;QAE1B,GACA;IAEJ;IAGF,MAAM,wBAAwB,CAAA,GAAA,qBAAa,EACzC,CAAC;QACC;QACA,WAAW,OAAO,GAAG;QACrB,wBAAA,kCAAA;QACA,qCAAqC;QACrC,OAAO,OAAO,GAAG,OAAO,UAAU,CAChC;YACE,IAAI,AAAC,aAAa,aAAa,MAAM,aAAe,UAAU,aAAa,MAAM,UAAW,QAAQ,UAClG,sBAAsB;QAE1B,GACA;IAEJ;IAGF,IAAI,oBAAoB,CAAC;QACvB,EAAE,cAAc;IAClB;IAEA,IAAI,qBAAC,iBAAiB,4BAAE,wBAAwB,EAAC,GAAG,CAAA,GAAA,yBAAiB;IAErE,qEAAqE;IACrE,gGAAgG;IAChG,8FAA8F;IAC9F,6BAA6B;IAC7B,IAAI,OAAO,CAAA,GAAA,aAAK,EAAE;IAElB,OAAO;QACL,iBAAiB;YACf,MAAM;YACN,iBAAiB,UAAU,aAAa,CAAC,MAAM,SAAS,QAAQ;YAChE,kBAAkB;YAClB,iBAAiB;YACjB,iBAAiB;YACjB,iBAAiB,cAAc;YAC/B,iBAAiB,cAAc;YAC/B,iBAAiB,cAAc;uBAC/B;qBACA;oBACA;QACF;QACA,sBAAsB;YACpB,cAAc,CAAC;gBACb,IAAI,EAAE,WAAW,KAAK,SACpB,sBAAsB;qBACjB;oBACL,IAAI,OAAO,OAAO,EAChB;oBAEF,4GAA4G;oBAC5G,8BAA8B;oBAC9B,OAAO,OAAO,GAAG,OAAO,UAAU,CAAC;wBACjC,sBAAsB;oBACxB,GAAG;oBAEH,kBAAkB,QAAQ,aAAa,aAAa;wBAAC,SAAS;oBAAI;oBAClE,KAAK,OAAO,GAAG;gBACjB;gBACA,kBAAkB,QAAQ,eAAe;YAC3C;YACA,WAAW,CAAC;gBACV,IAAI,EAAE,WAAW,KAAK,SACpB,KAAK,OAAO,GAAG;gBAEjB,kBAAkB,OAAO,GAAG;gBAC5B;gBACA;YACF;YACA,YAAY,CAAC;gBACX,IAAI,EAAE,WAAW,KAAK,SACpB;oBAAA,IAAI,CAAC,WAAW,OAAO,IAAI,KAAK,OAAO,EACrC,wBAAA,kCAAA;gBACF;gBAEF,KAAK,OAAO,GAAG;YACjB;qBACA;oBACA;QACF;QACA,sBAAsB;YACpB,cAAc,CAAC;gBACb,IAAI,EAAE,WAAW,KAAK,SACpB,sBAAsB;qBACjB;oBACL,IAAI,OAAO,OAAO,EAChB;oBAEF,2GAA2G;oBAC3G,8BAA8B;oBAC9B,OAAO,OAAO,GAAG,OAAO,UAAU,CAAC;wBACjC,sBAAsB;oBACxB,GAAG;oBAEH,kBAAkB,QAAQ,aAAa,aAAa;wBAAC,SAAS;oBAAI;oBAClE,KAAK,OAAO,GAAG;gBACjB;YACF;YACA,WAAW,CAAC;gBACV,IAAI,EAAE,WAAW,KAAK,SACpB,KAAK,OAAO,GAAG;gBAEjB,kBAAkB,OAAO,GAAG;gBAC5B;gBACA;YACF;YACA,YAAY,CAAC;gBACX,IAAI,EAAE,WAAW,KAAK,SACpB;oBAAA,IAAI,CAAC,WAAW,OAAO,IAAI,KAAK,OAAO,EACrC,wBAAA,kCAAA;gBACF;gBAEF,KAAK,OAAO,GAAG;YACjB;qBACA;oBACA;QACF;IACF;AACF","sources":["packages/@react-aria/spinbutton/src/useSpinButton.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {announce, clearAnnouncer} from '@react-aria/live-announcer';\nimport {AriaButtonProps} from '@react-types/button';\nimport {DOMAttributes, InputBase, RangeInputBase, Validation, ValueBase} from '@react-types/shared';\n// @ts-ignore\nimport intlMessages from '../intl/*.json';\nimport {useCallback, useEffect, useRef} from 'react';\nimport {useEffectEvent, useGlobalListeners} from '@react-aria/utils';\nimport {useLocalizedStringFormatter} from '@react-aria/i18n';\n\n\nexport interface SpinButtonProps extends InputBase, Validation<number>, ValueBase<number>, RangeInputBase<number> {\n textValue?: string,\n onIncrement?: () => void,\n onIncrementPage?: () => void,\n onDecrement?: () => void,\n onDecrementPage?: () => void,\n onDecrementToMin?: () => void,\n onIncrementToMax?: () => void\n}\n\nexport interface SpinbuttonAria {\n spinButtonProps: DOMAttributes,\n incrementButtonProps: AriaButtonProps,\n decrementButtonProps: AriaButtonProps\n}\n\nexport function useSpinButton(\n props: SpinButtonProps\n): SpinbuttonAria {\n const _async = useRef<number>(undefined);\n let {\n value,\n textValue,\n minValue,\n maxValue,\n isDisabled,\n isReadOnly,\n isRequired,\n onIncrement,\n onIncrementPage,\n onDecrement,\n onDecrementPage,\n onDecrementToMin,\n onIncrementToMax\n } = props;\n const stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/spinbutton');\n\n let prevTouchPosition = useRef<{x: number, y: number} | null>(null);\n let isSpinning = useRef(false);\n const clearAsync = () => {\n clearTimeout(_async.current);\n isSpinning.current = false;\n };\n\n\n useEffect(() => {\n return () => clearAsync();\n }, []);\n\n let onKeyDown = (e) => {\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey || isReadOnly || e.nativeEvent.isComposing) {\n return;\n }\n\n switch (e.key) {\n case 'PageUp':\n if (onIncrementPage) {\n e.preventDefault();\n onIncrementPage?.();\n break;\n }\n // fallthrough!\n case 'ArrowUp':\n case 'Up':\n if (onIncrement) {\n e.preventDefault();\n onIncrement?.();\n }\n break;\n case 'PageDown':\n if (onDecrementPage) {\n e.preventDefault();\n onDecrementPage?.();\n break;\n }\n // fallthrough\n case 'ArrowDown':\n case 'Down':\n if (onDecrement) {\n e.preventDefault();\n onDecrement?.();\n }\n break;\n case 'Home':\n if (onDecrementToMin) {\n e.preventDefault();\n onDecrementToMin?.();\n }\n break;\n case 'End':\n if (onIncrementToMax) {\n e.preventDefault();\n onIncrementToMax?.();\n }\n break;\n }\n };\n\n let isFocused = useRef(false);\n let onFocus = () => {\n isFocused.current = true;\n };\n\n let onBlur = () => {\n isFocused.current = false;\n };\n\n // Replace Unicode hyphen-minus (U+002D) with minus sign (U+2212).\n // This ensures that macOS VoiceOver announces it as \"minus\" even with other characters between the minus sign\n // and the number (e.g. currency symbol). Otherwise it announces nothing because it assumes the character is a hyphen.\n // In addition, replace the empty string with the word \"Empty\" so that iOS VoiceOver does not read \"50%\" for an empty field.\n let ariaTextValue = textValue === '' ? stringFormatter.format('Empty') : (textValue || `${value}`).replace('-', '\\u2212');\n\n useEffect(() => {\n if (isFocused.current) {\n clearAnnouncer('assertive');\n announce(ariaTextValue, 'assertive');\n }\n }, [ariaTextValue]);\n\n // For touch users, if they move their finger like they're scrolling, we don't want to trigger a spin.\n let onTouchMove = useCallback((e) => {\n if (!prevTouchPosition.current) {\n prevTouchPosition.current = {x: e.touches[0].clientX, y: e.touches[0].clientY};\n }\n let touchPosition = {x: e.touches[0].clientX, y: e.touches[0].clientY};\n // Arbitrary distance that worked in testing, even with slight movements or a slow-ish start to scrolling.\n if (Math.abs(touchPosition.x - prevTouchPosition.current.x) > 1 || Math.abs(touchPosition.y - prevTouchPosition.current.y) > 1) {\n clearAsync();\n }\n prevTouchPosition.current = touchPosition;\n }, []);\n\n const onIncrementPressStart = useEffectEvent(\n (initialStepDelay: number) => {\n clearAsync();\n isSpinning.current = true;\n onIncrement?.();\n // Start spinning after initial delay\n _async.current = window.setTimeout(\n () => {\n if ((maxValue === undefined || isNaN(maxValue)) || (value === undefined || isNaN(value)) || value < maxValue) {\n onIncrementPressStart(60);\n }\n },\n initialStepDelay\n );\n }\n );\n\n const onDecrementPressStart = useEffectEvent(\n (initialStepDelay: number) => {\n clearAsync();\n isSpinning.current = true;\n onDecrement?.();\n // Start spinning after initial delay\n _async.current = window.setTimeout(\n () => {\n if ((minValue === undefined || isNaN(minValue)) || (value === undefined || isNaN(value)) || value > minValue) {\n onDecrementPressStart(60);\n }\n },\n initialStepDelay\n );\n }\n );\n\n let cancelContextMenu = (e) => {\n e.preventDefault();\n };\n\n let {addGlobalListener, removeAllGlobalListeners} = useGlobalListeners();\n\n // Tracks in touch if the press end event was preceded by a press up.\n // If it wasn't, then we know the finger left the button while still in contact with the screen.\n // This means that the user is trying to scroll or interact in some way that shouldn't trigger\n // an increment or decrement.\n let isUp = useRef(false);\n\n return {\n spinButtonProps: {\n role: 'spinbutton',\n 'aria-valuenow': value !== undefined && !isNaN(value) ? value : undefined,\n 'aria-valuetext': ariaTextValue,\n 'aria-valuemin': minValue,\n 'aria-valuemax': maxValue,\n 'aria-disabled': isDisabled || undefined,\n 'aria-readonly': isReadOnly || undefined,\n 'aria-required': isRequired || undefined,\n onKeyDown,\n onFocus,\n onBlur\n },\n incrementButtonProps: {\n onPressStart: (e) => {\n if (e.pointerType !== 'touch') {\n onIncrementPressStart(400);\n } else {\n if (_async.current) {\n clearAsync();\n }\n // For touch users, don't trigger an increment on press start, we'll wait for the press end to trigger it if\n // the control isn't spinning.\n _async.current = window.setTimeout(() => {\n onIncrementPressStart(60);\n }, 600);\n\n addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});\n isUp.current = false;\n }\n addGlobalListener(window, 'contextmenu', cancelContextMenu);\n },\n onPressUp: (e) => {\n if (e.pointerType === 'touch') {\n isUp.current = true;\n }\n prevTouchPosition.current = null;\n clearAsync();\n removeAllGlobalListeners();\n },\n onPressEnd: (e) => {\n if (e.pointerType === 'touch') {\n if (!isSpinning.current && isUp.current) {\n onIncrement?.();\n }\n }\n isUp.current = false;\n },\n onFocus,\n onBlur\n },\n decrementButtonProps: {\n onPressStart: (e) => {\n if (e.pointerType !== 'touch') {\n onDecrementPressStart(400);\n } else {\n if (_async.current) {\n clearAsync();\n }\n // For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if\n // the control isn't spinning.\n _async.current = window.setTimeout(() => {\n onDecrementPressStart(60);\n }, 600);\n\n addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});\n isUp.current = false;\n }\n },\n onPressUp: (e) => {\n if (e.pointerType === 'touch') {\n isUp.current = true;\n }\n prevTouchPosition.current = null;\n clearAsync();\n removeAllGlobalListeners();\n },\n onPressEnd: (e) => {\n if (e.pointerType === 'touch') {\n if (!isSpinning.current && isUp.current) {\n onDecrement?.();\n }\n }\n isUp.current = false;\n },\n onFocus,\n onBlur\n }\n };\n}\n"],"names":[],"version":3,"file":"useSpinButton.module.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/spinbutton/src/useSpinButton.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {announce, clearAnnouncer} from '@react-aria/live-announcer';\nimport {AriaButtonProps} from '@react-types/button';\nimport {DOMAttributes, InputBase, RangeInputBase, Validation, ValueBase} from '@react-types/shared';\n// @ts-ignore\nimport intlMessages from '../intl/*.json';\nimport {useCallback, useEffect, useRef, useState} from 'react';\nimport {useEffectEvent, useGlobalListeners} from '@react-aria/utils';\nimport {useLocalizedStringFormatter} from '@react-aria/i18n';\n\n\nexport interface SpinButtonProps extends InputBase, Validation<number>, ValueBase<number>, RangeInputBase<number> {\n textValue?: string,\n onIncrement?: () => void,\n onIncrementPage?: () => void,\n onDecrement?: () => void,\n onDecrementPage?: () => void,\n onDecrementToMin?: () => void,\n onIncrementToMax?: () => void\n}\n\nexport interface SpinbuttonAria {\n spinButtonProps: DOMAttributes,\n incrementButtonProps: AriaButtonProps,\n decrementButtonProps: AriaButtonProps\n}\n\nexport function useSpinButton(\n props: SpinButtonProps\n): SpinbuttonAria {\n const _async = useRef<number>(undefined);\n let {\n value,\n textValue,\n minValue,\n maxValue,\n isDisabled,\n isReadOnly,\n isRequired,\n onIncrement,\n onIncrementPage,\n onDecrement,\n onDecrementPage,\n onDecrementToMin,\n onIncrementToMax\n } = props;\n const stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/spinbutton');\n\n let prevTouchPosition = useRef<{x: number, y: number} | null>(null);\n let isSpinning = useRef(false);\n const clearAsync = () => {\n clearTimeout(_async.current);\n isSpinning.current = false;\n };\n\n useEffect(() => {\n return () => clearAsync();\n }, []);\n\n let onKeyDown = (e) => {\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey || isReadOnly || e.nativeEvent.isComposing) {\n return;\n }\n\n switch (e.key) {\n case 'PageUp':\n if (onIncrementPage) {\n e.preventDefault();\n onIncrementPage?.();\n break;\n }\n // fallthrough!\n case 'ArrowUp':\n case 'Up':\n if (onIncrement) {\n e.preventDefault();\n onIncrement?.();\n }\n break;\n case 'PageDown':\n if (onDecrementPage) {\n e.preventDefault();\n onDecrementPage?.();\n break;\n }\n // fallthrough\n case 'ArrowDown':\n case 'Down':\n if (onDecrement) {\n e.preventDefault();\n onDecrement?.();\n }\n break;\n case 'Home':\n if (onDecrementToMin) {\n e.preventDefault();\n onDecrementToMin?.();\n }\n break;\n case 'End':\n if (onIncrementToMax) {\n e.preventDefault();\n onIncrementToMax?.();\n }\n break;\n }\n };\n\n let isFocused = useRef(false);\n let onFocus = () => {\n isFocused.current = true;\n };\n\n let onBlur = () => {\n isFocused.current = false;\n };\n\n // Replace Unicode hyphen-minus (U+002D) with minus sign (U+2212).\n // This ensures that macOS VoiceOver announces it as \"minus\" even with other characters between the minus sign\n // and the number (e.g. currency symbol). Otherwise it announces nothing because it assumes the character is a hyphen.\n // In addition, replace the empty string with the word \"Empty\" so that iOS VoiceOver does not read \"50%\" for an empty field.\n let ariaTextValue = textValue === '' ? stringFormatter.format('Empty') : (textValue || `${value}`).replace('-', '\\u2212');\n\n useEffect(() => {\n if (isFocused.current) {\n clearAnnouncer('assertive');\n announce(ariaTextValue, 'assertive');\n }\n }, [ariaTextValue]);\n\n // For touch users, if they move their finger like they're scrolling, we don't want to trigger a spin.\n let onTouchMove = useCallback((e) => {\n if (!prevTouchPosition.current) {\n prevTouchPosition.current = {x: e.touches[0].clientX, y: e.touches[0].clientY};\n }\n let touchPosition = {x: e.touches[0].clientX, y: e.touches[0].clientY};\n // Arbitrary distance that worked in testing, even with slight movements or a slow-ish start to scrolling.\n if (Math.abs(touchPosition.x - prevTouchPosition.current.x) > 1 || Math.abs(touchPosition.y - prevTouchPosition.current.y) > 1) {\n clearAsync();\n }\n prevTouchPosition.current = touchPosition;\n }, []);\n\n const onIncrementPressStart = useEffectEvent(\n (initialStepDelay: number) => {\n clearAsync();\n isSpinning.current = true;\n onIncrement?.();\n // Start spinning after initial delay\n _async.current = window.setTimeout(\n () => {\n if ((maxValue === undefined || isNaN(maxValue)) || (value === undefined || isNaN(value)) || value < maxValue) {\n onIncrementPressStart(60);\n }\n },\n initialStepDelay\n );\n }\n );\n\n const onDecrementPressStart = useEffectEvent(\n (initialStepDelay: number) => {\n clearAsync();\n isSpinning.current = true;\n onDecrement?.();\n // Start spinning after initial delay\n _async.current = window.setTimeout(\n () => {\n if ((minValue === undefined || isNaN(minValue)) || (value === undefined || isNaN(value)) || value > minValue) {\n onDecrementPressStart(60);\n }\n },\n initialStepDelay\n );\n }\n );\n\n let cancelContextMenu = (e) => {\n e.preventDefault();\n };\n\n let {addGlobalListener, removeAllGlobalListeners} = useGlobalListeners();\n\n // Tracks in touch if the press end event was preceded by a press up.\n // If it wasn't, then we know the finger left the button while still in contact with the screen.\n // This means that the user is trying to scroll or interact in some way that shouldn't trigger\n // an increment or decrement.\n let isUp = useRef(false);\n\n let [isIncrementPressed, setIsIncrementPressed] = useState<'touch' | 'mouse' | null>(null);\n useEffect(() => {\n if (isIncrementPressed === 'touch') {\n onIncrementPressStart(60);\n } else if (isIncrementPressed) {\n onIncrementPressStart(400);\n }\n }, [isIncrementPressed]);\n\n let [isDecrementPressed, setIsDecrementPressed] = useState<'touch' | 'mouse' | null>(null);\n useEffect(() => {\n if (isDecrementPressed === 'touch') {\n onDecrementPressStart(60);\n } else if (isDecrementPressed) {\n onDecrementPressStart(400);\n }\n }, [isDecrementPressed]);\n\n return {\n spinButtonProps: {\n role: 'spinbutton',\n 'aria-valuenow': value !== undefined && !isNaN(value) ? value : undefined,\n 'aria-valuetext': ariaTextValue,\n 'aria-valuemin': minValue,\n 'aria-valuemax': maxValue,\n 'aria-disabled': isDisabled || undefined,\n 'aria-readonly': isReadOnly || undefined,\n 'aria-required': isRequired || undefined,\n onKeyDown,\n onFocus,\n onBlur\n },\n incrementButtonProps: {\n onPressStart: (e) => {\n if (e.pointerType !== 'touch') {\n setIsIncrementPressed('mouse');\n } else {\n if (_async.current) {\n clearAsync();\n }\n\n addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});\n isUp.current = false;\n // For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if\n // the control isn't spinning.\n _async.current = window.setTimeout(() => {\n setIsIncrementPressed('touch');\n }, 600);\n }\n addGlobalListener(window, 'contextmenu', cancelContextMenu);\n },\n onPressUp: (e) => {\n if (e.pointerType === 'touch') {\n isUp.current = true;\n }\n prevTouchPosition.current = null;\n clearAsync();\n removeAllGlobalListeners();\n setIsIncrementPressed(null);\n },\n onPressEnd: (e) => {\n if (e.pointerType === 'touch') {\n if (!isSpinning.current && isUp.current) {\n onIncrement?.();\n }\n }\n isUp.current = false;\n setIsIncrementPressed(null);\n },\n onFocus,\n onBlur\n },\n decrementButtonProps: {\n onPressStart: (e) => {\n if (e.pointerType !== 'touch') {\n setIsDecrementPressed('mouse');\n } else {\n if (_async.current) {\n clearAsync();\n }\n\n addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});\n isUp.current = false;\n // For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if\n // the control isn't spinning.\n _async.current = window.setTimeout(() => {\n setIsDecrementPressed('touch');\n }, 600);\n }\n },\n onPressUp: (e) => {\n if (e.pointerType === 'touch') {\n isUp.current = true;\n }\n prevTouchPosition.current = null;\n clearAsync();\n removeAllGlobalListeners();\n setIsDecrementPressed(null);\n },\n onPressEnd: (e) => {\n if (e.pointerType === 'touch') {\n if (!isSpinning.current && isUp.current) {\n onDecrement?.();\n }\n }\n isUp.current = false;\n setIsDecrementPressed(null);\n },\n onFocus,\n onBlur\n }\n };\n}\n"],"names":[],"version":3,"file":"useSpinButton.module.js.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/spinbutton",
|
|
3
|
-
"version": "3.0.0-nightly-
|
|
3
|
+
"version": "3.0.0-nightly-070dfd621-251024",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
"url": "https://github.com/adobe/react-spectrum"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@react-aria/i18n": "3.0.0-nightly-
|
|
30
|
-
"@react-aria/live-announcer": "3.0.0-nightly-
|
|
31
|
-
"@react-aria/utils": "3.0.0-nightly-
|
|
32
|
-
"@react-types/button": "3.0.0-nightly-
|
|
33
|
-
"@react-types/shared": "3.0.0-nightly-
|
|
29
|
+
"@react-aria/i18n": "3.0.0-nightly-070dfd621-251024",
|
|
30
|
+
"@react-aria/live-announcer": "3.0.0-nightly-070dfd621-251024",
|
|
31
|
+
"@react-aria/utils": "3.0.0-nightly-070dfd621-251024",
|
|
32
|
+
"@react-types/button": "3.0.0-nightly-070dfd621-251024",
|
|
33
|
+
"@react-types/shared": "3.0.0-nightly-070dfd621-251024",
|
|
34
34
|
"@swc/helpers": "^0.5.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
package/src/useSpinButton.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {AriaButtonProps} from '@react-types/button';
|
|
|
15
15
|
import {DOMAttributes, InputBase, RangeInputBase, Validation, ValueBase} from '@react-types/shared';
|
|
16
16
|
// @ts-ignore
|
|
17
17
|
import intlMessages from '../intl/*.json';
|
|
18
|
-
import {useCallback, useEffect, useRef} from 'react';
|
|
18
|
+
import {useCallback, useEffect, useRef, useState} from 'react';
|
|
19
19
|
import {useEffectEvent, useGlobalListeners} from '@react-aria/utils';
|
|
20
20
|
import {useLocalizedStringFormatter} from '@react-aria/i18n';
|
|
21
21
|
|
|
@@ -64,7 +64,6 @@ export function useSpinButton(
|
|
|
64
64
|
isSpinning.current = false;
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
-
|
|
68
67
|
useEffect(() => {
|
|
69
68
|
return () => clearAsync();
|
|
70
69
|
}, []);
|
|
@@ -199,6 +198,24 @@ export function useSpinButton(
|
|
|
199
198
|
// an increment or decrement.
|
|
200
199
|
let isUp = useRef(false);
|
|
201
200
|
|
|
201
|
+
let [isIncrementPressed, setIsIncrementPressed] = useState<'touch' | 'mouse' | null>(null);
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
if (isIncrementPressed === 'touch') {
|
|
204
|
+
onIncrementPressStart(60);
|
|
205
|
+
} else if (isIncrementPressed) {
|
|
206
|
+
onIncrementPressStart(400);
|
|
207
|
+
}
|
|
208
|
+
}, [isIncrementPressed]);
|
|
209
|
+
|
|
210
|
+
let [isDecrementPressed, setIsDecrementPressed] = useState<'touch' | 'mouse' | null>(null);
|
|
211
|
+
useEffect(() => {
|
|
212
|
+
if (isDecrementPressed === 'touch') {
|
|
213
|
+
onDecrementPressStart(60);
|
|
214
|
+
} else if (isDecrementPressed) {
|
|
215
|
+
onDecrementPressStart(400);
|
|
216
|
+
}
|
|
217
|
+
}, [isDecrementPressed]);
|
|
218
|
+
|
|
202
219
|
return {
|
|
203
220
|
spinButtonProps: {
|
|
204
221
|
role: 'spinbutton',
|
|
@@ -216,19 +233,19 @@ export function useSpinButton(
|
|
|
216
233
|
incrementButtonProps: {
|
|
217
234
|
onPressStart: (e) => {
|
|
218
235
|
if (e.pointerType !== 'touch') {
|
|
219
|
-
|
|
236
|
+
setIsIncrementPressed('mouse');
|
|
220
237
|
} else {
|
|
221
238
|
if (_async.current) {
|
|
222
239
|
clearAsync();
|
|
223
240
|
}
|
|
224
|
-
// For touch users, don't trigger an increment on press start, we'll wait for the press end to trigger it if
|
|
225
|
-
// the control isn't spinning.
|
|
226
|
-
_async.current = window.setTimeout(() => {
|
|
227
|
-
onIncrementPressStart(60);
|
|
228
|
-
}, 600);
|
|
229
241
|
|
|
230
242
|
addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});
|
|
231
243
|
isUp.current = false;
|
|
244
|
+
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
245
|
+
// the control isn't spinning.
|
|
246
|
+
_async.current = window.setTimeout(() => {
|
|
247
|
+
setIsIncrementPressed('touch');
|
|
248
|
+
}, 600);
|
|
232
249
|
}
|
|
233
250
|
addGlobalListener(window, 'contextmenu', cancelContextMenu);
|
|
234
251
|
},
|
|
@@ -239,6 +256,7 @@ export function useSpinButton(
|
|
|
239
256
|
prevTouchPosition.current = null;
|
|
240
257
|
clearAsync();
|
|
241
258
|
removeAllGlobalListeners();
|
|
259
|
+
setIsIncrementPressed(null);
|
|
242
260
|
},
|
|
243
261
|
onPressEnd: (e) => {
|
|
244
262
|
if (e.pointerType === 'touch') {
|
|
@@ -247,6 +265,7 @@ export function useSpinButton(
|
|
|
247
265
|
}
|
|
248
266
|
}
|
|
249
267
|
isUp.current = false;
|
|
268
|
+
setIsIncrementPressed(null);
|
|
250
269
|
},
|
|
251
270
|
onFocus,
|
|
252
271
|
onBlur
|
|
@@ -254,19 +273,19 @@ export function useSpinButton(
|
|
|
254
273
|
decrementButtonProps: {
|
|
255
274
|
onPressStart: (e) => {
|
|
256
275
|
if (e.pointerType !== 'touch') {
|
|
257
|
-
|
|
276
|
+
setIsDecrementPressed('mouse');
|
|
258
277
|
} else {
|
|
259
278
|
if (_async.current) {
|
|
260
279
|
clearAsync();
|
|
261
280
|
}
|
|
281
|
+
|
|
282
|
+
addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});
|
|
283
|
+
isUp.current = false;
|
|
262
284
|
// For touch users, don't trigger a decrement on press start, we'll wait for the press end to trigger it if
|
|
263
285
|
// the control isn't spinning.
|
|
264
286
|
_async.current = window.setTimeout(() => {
|
|
265
|
-
|
|
287
|
+
setIsDecrementPressed('touch');
|
|
266
288
|
}, 600);
|
|
267
|
-
|
|
268
|
-
addGlobalListener(window, 'touchmove', onTouchMove, {capture: true});
|
|
269
|
-
isUp.current = false;
|
|
270
289
|
}
|
|
271
290
|
},
|
|
272
291
|
onPressUp: (e) => {
|
|
@@ -276,6 +295,7 @@ export function useSpinButton(
|
|
|
276
295
|
prevTouchPosition.current = null;
|
|
277
296
|
clearAsync();
|
|
278
297
|
removeAllGlobalListeners();
|
|
298
|
+
setIsDecrementPressed(null);
|
|
279
299
|
},
|
|
280
300
|
onPressEnd: (e) => {
|
|
281
301
|
if (e.pointerType === 'touch') {
|
|
@@ -284,6 +304,7 @@ export function useSpinButton(
|
|
|
284
304
|
}
|
|
285
305
|
}
|
|
286
306
|
isUp.current = false;
|
|
307
|
+
setIsDecrementPressed(null);
|
|
287
308
|
},
|
|
288
309
|
onFocus,
|
|
289
310
|
onBlur
|