@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.
@@ -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,CA2PhB","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"}
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') onIncrementPressStart(400);
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') onDecrementPressStart(400);
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"}
@@ -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') onIncrementPressStart(400);
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') onDecrementPressStart(400);
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') onIncrementPressStart(400);
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') onDecrementPressStart(400);
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":"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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.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-ecd229153-251022",
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-ecd229153-251022",
30
- "@react-aria/live-announcer": "3.0.0-nightly-ecd229153-251022",
31
- "@react-aria/utils": "3.0.0-nightly-ecd229153-251022",
32
- "@react-types/button": "3.0.0-nightly-ecd229153-251022",
33
- "@react-types/shared": "3.0.0-nightly-ecd229153-251022",
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": {
@@ -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
- onIncrementPressStart(400);
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
- onDecrementPressStart(400);
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
- onDecrementPressStart(60);
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