@octanejs/aria 0.0.46 → 0.0.48

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.
Files changed (201) hide show
  1. package/README.md +7 -6
  2. package/UPSTREAM.md +58 -69
  3. package/package.json +11 -11
  4. package/src/calendar/useCalendarGrid.tsx +64 -62
  5. package/src/collections/Document.ts +3 -0
  6. package/src/color/useColorArea.tsx +95 -69
  7. package/src/color/useColorWheel.tsx +38 -37
  8. package/src/combobox/{useComboBox.ts → useComboBox.tsx} +243 -258
  9. package/src/components/ComboBox.ts +35 -2
  10. package/src/components/Dialog.ts +12 -1
  11. package/src/components/DropZone.tsx +3 -2
  12. package/src/components/FileTrigger.tsx +1 -0
  13. package/src/components/GridList.ts +11 -2
  14. package/src/components/ListBox.ts +1 -1
  15. package/src/components/Menu.ts +1 -0
  16. package/src/components/Meter.ts +3 -1
  17. package/src/components/Popover.ts +20 -8
  18. package/src/components/PreviewTrigger.tsx +101 -0
  19. package/src/components/ProgressBar.ts +10 -2
  20. package/src/components/Select.ts +1 -1
  21. package/src/components/Table.ts +26 -15
  22. package/src/components/TokenField.tsx +395 -0
  23. package/src/components/Tooltip.ts +4 -6
  24. package/src/components/Tree.ts +14 -7
  25. package/src/components/Virtualizer.tsx +30 -14
  26. package/src/components/index.ts +22 -0
  27. package/src/components/utils.ts +1 -1
  28. package/src/datepicker/useDateField.tsx +2 -11
  29. package/src/datepicker/useDatePickerGroup.tsx +44 -33
  30. package/src/datepicker/useDateSegment.tsx +31 -30
  31. package/src/dialog/useDialog.ts +8 -1
  32. package/src/dnd/DragManager.tsx +5 -1
  33. package/src/dnd/useDrag.tsx +2 -1
  34. package/src/focus/FocusScope.ts +2 -2
  35. package/src/grid/useGrid.ts +3 -0
  36. package/src/grid/{useGridCell.ts → useGridCell.tsx} +128 -66
  37. package/src/grid/utils.ts +1 -0
  38. package/src/gridlist/{useGridListItem.ts → useGridListItem.tsx} +154 -112
  39. package/src/index.ts +22 -0
  40. package/src/interactions/createEventHandler.ts +11 -8
  41. package/src/interactions/createKeyboardShortcutHandler.tsx +218 -0
  42. package/src/interactions/textSelection.ts +3 -3
  43. package/src/interactions/useContextMenu.tsx +125 -0
  44. package/src/interactions/useFocusVisible.ts +4 -4
  45. package/src/interactions/useKeyboard.ts +50 -2
  46. package/src/interactions/useLongPress.ts +33 -22
  47. package/src/interactions/useMove.ts +6 -6
  48. package/src/interactions/usePress.ts +8 -0
  49. package/src/interactions/utils.ts +10 -10
  50. package/src/intl/combobox/fi-FI.json +2 -2
  51. package/src/intl/previewtrigger/ar-AE.json +3 -0
  52. package/src/intl/previewtrigger/bg-BG.json +3 -0
  53. package/src/intl/previewtrigger/cs-CZ.json +3 -0
  54. package/src/intl/previewtrigger/da-DK.json +3 -0
  55. package/src/intl/previewtrigger/de-DE.json +3 -0
  56. package/src/intl/previewtrigger/el-GR.json +3 -0
  57. package/src/intl/previewtrigger/en-US.json +3 -0
  58. package/src/intl/previewtrigger/es-ES.json +3 -0
  59. package/src/intl/previewtrigger/et-EE.json +3 -0
  60. package/src/intl/previewtrigger/fi-FI.json +3 -0
  61. package/src/intl/previewtrigger/fr-FR.json +3 -0
  62. package/src/intl/previewtrigger/he-IL.json +3 -0
  63. package/src/intl/previewtrigger/hr-HR.json +3 -0
  64. package/src/intl/previewtrigger/hu-HU.json +3 -0
  65. package/src/intl/previewtrigger/index.ts +73 -0
  66. package/src/intl/previewtrigger/it-IT.json +3 -0
  67. package/src/intl/previewtrigger/ja-JP.json +3 -0
  68. package/src/intl/previewtrigger/ko-KR.json +3 -0
  69. package/src/intl/previewtrigger/lt-LT.json +3 -0
  70. package/src/intl/previewtrigger/lv-LV.json +3 -0
  71. package/src/intl/previewtrigger/nb-NO.json +3 -0
  72. package/src/intl/previewtrigger/nl-NL.json +3 -0
  73. package/src/intl/previewtrigger/pl-PL.json +3 -0
  74. package/src/intl/previewtrigger/pt-BR.json +3 -0
  75. package/src/intl/previewtrigger/pt-PT.json +3 -0
  76. package/src/intl/previewtrigger/ro-RO.json +3 -0
  77. package/src/intl/previewtrigger/ru-RU.json +3 -0
  78. package/src/intl/previewtrigger/sk-SK.json +3 -0
  79. package/src/intl/previewtrigger/sl-SI.json +3 -0
  80. package/src/intl/previewtrigger/sr-SP.json +3 -0
  81. package/src/intl/previewtrigger/sv-SE.json +3 -0
  82. package/src/intl/previewtrigger/tr-TR.json +3 -0
  83. package/src/intl/previewtrigger/uk-UA.json +3 -0
  84. package/src/intl/previewtrigger/zh-CN.json +3 -0
  85. package/src/intl/previewtrigger/zh-TW.json +3 -0
  86. package/src/intl/table/ar-AE.json +3 -3
  87. package/src/intl/table/bg-BG.json +3 -3
  88. package/src/intl/table/cs-CZ.json +3 -3
  89. package/src/intl/table/da-DK.json +3 -3
  90. package/src/intl/table/de-DE.json +3 -3
  91. package/src/intl/table/el-GR.json +3 -3
  92. package/src/intl/table/es-ES.json +3 -3
  93. package/src/intl/table/et-EE.json +3 -3
  94. package/src/intl/table/fi-FI.json +3 -3
  95. package/src/intl/table/fr-FR.json +3 -3
  96. package/src/intl/table/he-IL.json +3 -3
  97. package/src/intl/table/hr-HR.json +3 -3
  98. package/src/intl/table/hu-HU.json +3 -3
  99. package/src/intl/table/it-IT.json +3 -3
  100. package/src/intl/table/ja-JP.json +3 -3
  101. package/src/intl/table/ko-KR.json +3 -3
  102. package/src/intl/table/lt-LT.json +3 -3
  103. package/src/intl/table/lv-LV.json +3 -3
  104. package/src/intl/table/nb-NO.json +3 -3
  105. package/src/intl/table/nl-NL.json +3 -3
  106. package/src/intl/table/pl-PL.json +3 -3
  107. package/src/intl/table/pt-BR.json +3 -3
  108. package/src/intl/table/pt-PT.json +3 -3
  109. package/src/intl/table/ro-RO.json +3 -3
  110. package/src/intl/table/ru-RU.json +3 -3
  111. package/src/intl/table/sk-SK.json +3 -3
  112. package/src/intl/table/sl-SI.json +3 -3
  113. package/src/intl/table/sr-SP.json +3 -3
  114. package/src/intl/table/sv-SE.json +3 -3
  115. package/src/intl/table/tr-TR.json +3 -3
  116. package/src/intl/table/uk-UA.json +3 -3
  117. package/src/intl/table/zh-CN.json +4 -4
  118. package/src/intl/table/zh-TW.json +3 -3
  119. package/src/intl/tree/es-ES.json +1 -1
  120. package/src/link/useLink.ts +2 -0
  121. package/src/menu/useMenuItem.ts +33 -36
  122. package/src/menu/useMenuTrigger.tsx +222 -0
  123. package/src/menu/{useSubmenuTrigger.ts → useSubmenuTrigger.tsx} +116 -151
  124. package/src/numberfield/{useNumberField.ts → useNumberField.tsx} +188 -238
  125. package/src/overlays/Overlay.ts +5 -1
  126. package/src/overlays/ariaHideOutside.ts +6 -8
  127. package/src/overlays/useCloseOnScroll.ts +7 -5
  128. package/src/overlays/{useOverlay.ts → useOverlay.tsx} +76 -83
  129. package/src/overlays/usePopover.ts +10 -5
  130. package/src/overlays/usePreventScroll.ts +4 -4
  131. package/src/progress/useProgressBar.ts +2 -1
  132. package/src/radio/{useRadioGroup.ts → useRadioGroup.tsx} +87 -79
  133. package/src/searchfield/useSearchField.tsx +152 -0
  134. package/src/select/useSelect.ts +20 -20
  135. package/src/selection/useSelectableCollection.tsx +755 -0
  136. package/src/selection/useSelectableItem.ts +48 -11
  137. package/src/slider/{useSliderThumb.ts → useSliderThumb.tsx} +120 -158
  138. package/src/spinbutton/useSpinButton.tsx +335 -0
  139. package/src/stately/combobox/useComboBoxState.ts +1 -1
  140. package/src/stately/grid/useGridState.ts +9 -10
  141. package/src/stately/index.ts +11 -0
  142. package/src/stately/menu/useMenuTriggerState.ts +1 -1
  143. package/src/stately/menu/useSubmenuTriggerState.ts +2 -0
  144. package/src/stately/overlays/useOverlayTriggerState.ts +12 -1
  145. package/src/stately/radio/useRadioGroupState.ts +5 -1
  146. package/src/stately/table/TableUtils.ts +15 -1
  147. package/src/stately/table/useTableState.ts +7 -0
  148. package/src/stately/tokenfield/TokenFieldValue.tsx +440 -0
  149. package/src/stately/tokenfield/useTokenFieldState.tsx +57 -0
  150. package/src/stately/tooltip/useTooltipTriggerState.ts +16 -7
  151. package/src/stately/virtualizer/Layout.tsx +2 -0
  152. package/src/stately/virtualizer/ScrollAnchor.tsx +338 -0
  153. package/src/stately/virtualizer/Virtualizer.tsx +52 -1
  154. package/src/stately/virtualizer/types.tsx +2 -0
  155. package/src/table/useTableCell.ts +12 -0
  156. package/src/table/useTableColumnHeader.ts +8 -1
  157. package/src/table/useTableColumnResize.tsx +359 -0
  158. package/src/tag/useTag.ts +22 -15
  159. package/src/textfield/useTextField.ts +2 -0
  160. package/src/tokenfield/useToken.tsx +64 -0
  161. package/src/tokenfield/useTokenField.tsx +849 -0
  162. package/src/tooltip/usePreviewTrigger.tsx +266 -0
  163. package/src/tooltip/useSafeArea.tsx +171 -0
  164. package/src/upstream-exports/react-aria/mergeRefs.tsx +3 -0
  165. package/src/upstream-exports/react-aria/usePreviewTrigger.tsx +18 -0
  166. package/src/upstream-exports/react-aria/useTokenField.tsx +22 -0
  167. package/src/upstream-exports/react-stately/private/collections/getChildNodes.tsx +8 -0
  168. package/src/upstream-exports/react-stately/private/collections/getItemCount.tsx +2 -0
  169. package/src/upstream-exports/react-stately/private/grid/GridCollection.tsx +7 -0
  170. package/src/upstream-exports/react-stately/private/grid/useGridState.tsx +6 -0
  171. package/src/upstream-exports/react-stately/private/utils/number.tsx +2 -0
  172. package/src/upstream-exports/react-stately/useComboBoxState.tsx +23 -0
  173. package/src/upstream-exports/react-stately/useListState.tsx +15 -0
  174. package/src/upstream-exports/react-stately/useMenuTriggerState.tsx +26 -0
  175. package/src/upstream-exports/react-stately/useMultipleSelectionState.tsx +21 -0
  176. package/src/upstream-exports/react-stately/useNumberFieldState.tsx +20 -0
  177. package/src/upstream-exports/react-stately/useOverlayTriggerState.tsx +20 -0
  178. package/src/upstream-exports/react-stately/useRadioGroupState.tsx +16 -0
  179. package/src/upstream-exports/react-stately/useSearchFieldState.tsx +19 -0
  180. package/src/upstream-exports/react-stately/useSliderState.tsx +20 -0
  181. package/src/upstream-exports/react-stately/useTableState.tsx +45 -0
  182. package/src/upstream-exports/react-stately/useTokenFieldState.tsx +25 -0
  183. package/src/upstream-exports/react-stately/useTooltipTriggerState.tsx +20 -0
  184. package/src/upstream-exports/react-stately/useTreeState.tsx +14 -0
  185. package/src/utils/domHelpers.ts +74 -17
  186. package/src/utils/isVirtualEvent.ts +2 -1
  187. package/src/utils/openLink.ts +8 -3
  188. package/src/utils/platform.ts +7 -3
  189. package/src/utils/scrollIntoView.ts +4 -4
  190. package/src/utils/shadowdom/DOMFunctions.ts +42 -2
  191. package/src/utils/useId.ts +11 -2
  192. package/src/utils/useLoadMoreSentinel.ts +8 -3
  193. package/src/utils/useViewportSize.ts +3 -3
  194. package/src/virtualizer/ScrollView.tsx +13 -4
  195. package/src/virtualizer/VirtualizerItem.tsx +4 -1
  196. package/src/virtualizer/useVirtualizerItem.tsx +43 -3
  197. package/src/menu/useMenuTrigger.ts +0 -189
  198. package/src/searchfield/useSearchField.ts +0 -156
  199. package/src/selection/useSelectableCollection.ts +0 -750
  200. package/src/spinbutton/useSpinButton.ts +0 -380
  201. package/src/table/useTableColumnResize.ts +0 -374
@@ -24,6 +24,7 @@ import { focusSafely } from '../interactions/focusSafely';
24
24
  import { getActiveElement, getEventTarget } from '../utils/shadowdom/DOMFunctions';
25
25
  import { getCollectionId, isNonContiguousSelectionModifier } from './utils';
26
26
  import { isCtrlKeyPressed } from '../utils/keyboard';
27
+ import { isTabbable } from '../utils/isFocusable';
27
28
  import { mergeProps } from '../utils/mergeProps';
28
29
  import { moveVirtualFocus } from '../focus/virtualFocus';
29
30
  import type { MultipleSelectionManager } from '../stately/selection/types';
@@ -380,7 +381,8 @@ export function useSelectableItem(...args: any[]): SelectableItemAria {
380
381
  };
381
382
  }
382
383
 
383
- itemProps['data-collection'] = getCollectionId(manager.collection);
384
+ let collectionId = getCollectionId(manager.collection);
385
+ itemProps['data-collection'] = collectionId;
384
386
  itemProps['data-key'] = key;
385
387
  itemPressProps.preventFocusOnPress = shouldUseVirtualFocus;
386
388
 
@@ -470,17 +472,52 @@ export function useSelectableItem(...args: any[]): SelectableItemAria {
470
472
  }
471
473
  : undefined;
472
474
 
475
+ let mergedItemProps = mergeProps(
476
+ itemProps,
477
+ allowsSelection || hasPrimaryAction || (shouldUseVirtualFocus && !isDisabled) ? pressProps : {},
478
+ longPressEnabled ? longPressProps : {},
479
+ { onDoubleClick, onDragStartCapture, onClick, id },
480
+ // Prevent DOM focus from moving on mouse down when using virtual focus
481
+ shouldUseVirtualFocus ? { onMouseDown: (e: MouseEvent) => e.preventDefault() } : undefined,
482
+ );
483
+
484
+ // Guard against presses triggering selection when they happen on interactive children or collection items from different collections
485
+ // will need to trigger selection if the target is itself a collection item belonging to the same collection parent (aka a cell in a row) but
486
+ // not if the target is a child of a different collections aka taggroup in table cell.
487
+ let isChildInteraction = (target: Element) => {
488
+ let el: Element | null = target;
489
+ while (el && el !== ref.current) {
490
+ let elCollection = el.getAttribute('data-collection');
491
+ if (elCollection != null) {
492
+ return elCollection !== collectionId;
493
+ }
494
+ el = el.parentElement;
495
+ }
496
+ return isTabbable(target);
497
+ };
498
+
499
+ let baseOnPointerDown = mergedItemProps.onPointerDown;
500
+ mergedItemProps.onPointerDown = (e: PointerEvent) => {
501
+ let target = getEventTarget(e) as Element | null;
502
+ if (target && target !== ref.current && isChildInteraction(target)) {
503
+ e.stopPropagation();
504
+ return;
505
+ }
506
+ baseOnPointerDown?.(e);
507
+ };
508
+
509
+ let baseOnMouseDown = mergedItemProps.onMouseDown;
510
+ mergedItemProps.onMouseDown = (e) => {
511
+ let target = getEventTarget(e) as Element | null;
512
+ if (target && target !== ref.current && isChildInteraction(target)) {
513
+ e.stopPropagation();
514
+ return;
515
+ }
516
+ baseOnMouseDown?.(e);
517
+ };
518
+
473
519
  return {
474
- itemProps: mergeProps(
475
- itemProps,
476
- allowsSelection || hasPrimaryAction || (shouldUseVirtualFocus && !isDisabled)
477
- ? pressProps
478
- : {},
479
- longPressEnabled ? longPressProps : {},
480
- { onDoubleClick, onDragStartCapture, onClick, id },
481
- // Prevent DOM focus from moving on mouse down when using virtual focus
482
- shouldUseVirtualFocus ? { onMouseDown: (e: MouseEvent) => e.preventDefault() } : undefined,
483
- ),
520
+ itemProps: mergedItemProps,
484
521
  isPressed,
485
522
  isSelected: manager.isSelected(key),
486
523
  isFocused: manager.isFocused && manager.focusedKey === key,
@@ -1,16 +1,7 @@
1
- // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/slider/useSliderThumb.ts).
2
- // octane adaptations:
3
- // - Handlers receive NATIVE events. The visually-hidden range input's value listener is
4
- // `onInput` (octane has no synthetic onChange; for range inputs React's onChange fires
5
- // on the native `input` event, so the timing is identical — this mirrors how the browser
6
- // reports native keyboard/drag stepping of a range input).
7
- // - React's InputHTMLAttributes/LabelHTMLAttributes element types collapse to the local
8
- // structural `DOMAttributes` prop bag; mouse/pointer/touch handler params are native.
9
- // - `clamp` comes from the ported stately number utils; `SliderState` from the ported
10
- // stately slider hook.
11
- // - Public-hook slot threading (splitSlot/subSlot); explicit dependency arrays are kept
12
- // verbatim.
13
- import type {
1
+ /** @jsxImportSource octane */
2
+ type DOMAttributes = Record<string, any>;
3
+ // Ported from adobe/react-spectrum@5ecb3333001313e83898cd07644227897e3bae1f (packages/react-aria/src/slider/useSliderThumb.ts).
4
+ import {
14
5
  AriaLabelingProps,
15
6
  AriaValidationProps,
16
7
  DOMProps,
@@ -21,15 +12,22 @@ import type {
21
12
  RefObject,
22
13
  ValidationState,
23
14
  } from '@react-types/shared';
24
- // octane adaptation: FocusableProps is the ported native-event version.
25
15
  import type { FocusableProps } from '../interactions/useFocusable';
26
- import { clamp } from '../stately/utils/number';
16
+ import { clamp } from '../upstream-exports/react-stately/private/utils/number';
27
17
  import { focusWithoutScrolling } from '../utils/focusWithoutScrolling';
28
18
  import { getEventTarget } from '../utils/shadowdom/DOMFunctions';
29
19
  import { getSliderThumbId, sliderData } from './utils';
30
20
  import { mergeProps } from '../utils/mergeProps';
31
- import { useCallback, useEffect, useRef } from 'octane';
32
- import type { SliderState } from '../stately/slider/useSliderState';
21
+ import { withSlot } from 'octane';
22
+ import React, {
23
+ ChangeEvent,
24
+ InputHTMLAttributes,
25
+ LabelHTMLAttributes,
26
+ useCallback,
27
+ useEffect,
28
+ useRef,
29
+ } from '../compat/react';
30
+ import { SliderState } from '../upstream-exports/react-stately/useSliderState';
33
31
  import { useFocusable } from '../interactions/useFocusable';
34
32
  import { useFormReset } from '../utils/useFormReset';
35
33
  import { useGlobalListeners } from '../utils/useGlobalListeners';
@@ -38,12 +36,6 @@ import { useLabel } from '../label/useLabel';
38
36
  import { useLocale } from '../i18n/I18nProvider';
39
37
  import { useMove } from '../interactions/useMove';
40
38
 
41
- import { S, splitSlot, subSlot } from '../internal';
42
-
43
- // octane adaptation: minimal structural DOMAttributes (upstream's drags React's synthetic
44
- // handler types along).
45
- type DOMAttributes = Record<string, any>;
46
-
47
39
  export interface SliderThumbProps extends FocusableProps, LabelableProps {
48
40
  /**
49
41
  * The orientation of the Slider.
@@ -82,10 +74,10 @@ export interface SliderThumbAria {
82
74
  thumbProps: DOMAttributes;
83
75
 
84
76
  /** Props for the visually hidden range input element. */
85
- inputProps: DOMAttributes;
77
+ inputProps: InputHTMLAttributes<HTMLInputElement>;
86
78
 
87
79
  /** Props for the label element for this thumb (optional). */
88
- labelProps: DOMAttributes;
80
+ labelProps: LabelHTMLAttributes<HTMLLabelElement>;
89
81
 
90
82
  /** Whether this thumb is currently being dragged. */
91
83
  isDragging: boolean;
@@ -108,18 +100,14 @@ export interface AriaSliderThumbOptions extends AriaSliderThumbProps {
108
100
  * @param opts Options for this Slider thumb.
109
101
  * @param state Slider state, created via `useSliderState`.
110
102
  */
111
- export function useSliderThumb(opts: AriaSliderThumbOptions, state: SliderState): SliderThumbAria;
112
- // Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
113
103
  export function useSliderThumb(
114
104
  opts: AriaSliderThumbOptions,
115
105
  state: SliderState,
116
- slot: symbol | undefined,
117
- ): SliderThumbAria;
118
- export function useSliderThumb(...args: any[]): SliderThumbAria {
119
- const [user, slotArg] = splitSlot(args);
120
- const slot = slotArg ?? S('useSliderThumb');
121
- const opts = user[0] as AriaSliderThumbOptions;
122
- const state = user[1] as SliderState;
106
+ _slot?: symbol,
107
+ ): SliderThumbAria {
108
+ if (_slot !== undefined) {
109
+ return withSlot(_slot, useSliderThumb, opts, state);
110
+ }
123
111
 
124
112
  let {
125
113
  index = 0,
@@ -136,129 +124,105 @@ export function useSliderThumb(...args: any[]): SliderThumbAria {
136
124
  let isDisabled = opts.isDisabled || state.isDisabled;
137
125
  let isVertical = orientation === 'vertical';
138
126
 
139
- let { direction } = useLocale(subSlot(slot, 'locale'));
140
- let { addGlobalListener, removeGlobalListener } = useGlobalListeners(
141
- subSlot(slot, 'globalListeners'),
142
- );
127
+ let { direction } = useLocale();
128
+ let { addGlobalListener, removeGlobalListener } = useGlobalListeners();
143
129
 
144
130
  let data = sliderData.get(state)!;
145
- const { labelProps, fieldProps } = useLabel(
146
- {
147
- ...opts,
148
- id: getSliderThumbId(state, index),
149
- 'aria-labelledby': `${data.id} ${opts['aria-labelledby'] ?? ''}`.trim(),
150
- },
151
- subSlot(slot, 'label'),
152
- );
131
+ const { labelProps, fieldProps } = useLabel({
132
+ ...opts,
133
+ id: getSliderThumbId(state, index),
134
+ 'aria-labelledby': `${data.id} ${opts['aria-labelledby'] ?? ''}`.trim(),
135
+ });
153
136
 
154
137
  const value = state.values[index];
155
138
 
156
- const focusInput = useCallback(
157
- () => {
158
- if (inputRef.current) {
159
- focusWithoutScrolling(inputRef.current);
160
- }
161
- },
162
- [inputRef],
163
- subSlot(slot, 'focusInput'),
164
- );
139
+ const focusInput = useCallback(() => {
140
+ if (inputRef.current) {
141
+ focusWithoutScrolling(inputRef.current);
142
+ }
143
+ }, [inputRef]);
165
144
 
166
145
  const isFocused = state.focusedThumb === index;
167
146
 
168
- useEffect(
169
- () => {
170
- if (isFocused) {
171
- focusInput();
172
- }
173
- },
174
- [isFocused, focusInput],
175
- subSlot(slot, 'focusFx'),
176
- );
147
+ useEffect(() => {
148
+ if (isFocused) {
149
+ focusInput();
150
+ }
151
+ }, [isFocused, focusInput]);
177
152
 
178
153
  let reverseX = direction === 'rtl';
179
- let currentPosition = useRef<number | null>(null, subSlot(slot, 'position'));
154
+ let currentPosition = useRef<number | null>(null);
180
155
 
181
- let { keyboardProps } = useKeyboard(
182
- {
183
- onKeyDown(e) {
184
- let {
185
- getThumbMaxValue,
186
- getThumbMinValue,
187
- decrementThumb,
188
- incrementThumb,
189
- setThumbValue,
190
- setThumbDragging,
191
- pageSize,
192
- } = state;
193
- // these are the cases that useMove or useSlider don't handle
194
- if (!/^(PageUp|PageDown|Home|End)$/.test(e.key)) {
195
- e.continuePropagation();
196
- return;
197
- }
198
- // same handling as useMove, stopPropagation to prevent useSlider from handling the event as well.
199
- e.preventDefault();
200
- // remember to set this so that onChangeEnd is fired
201
- setThumbDragging(index, true);
202
- switch (e.key) {
203
- case 'PageUp':
204
- incrementThumb(index, pageSize);
205
- break;
206
- case 'PageDown':
207
- decrementThumb(index, pageSize);
208
- break;
209
- case 'Home':
210
- setThumbValue(index, getThumbMinValue(index));
211
- break;
212
- case 'End':
213
- setThumbValue(index, getThumbMaxValue(index));
214
- break;
215
- }
216
- setThumbDragging(index, false);
156
+ let keyboardUpdate = (cb: () => void) => {
157
+ // remember to set this so that onChangeEnd is fired
158
+ state.setThumbDragging(index, true);
159
+ cb();
160
+ state.setThumbDragging(index, false);
161
+ };
162
+
163
+ let { keyboardProps } = useKeyboard({
164
+ shortcuts: {
165
+ PageUp: () => {
166
+ return keyboardUpdate(() => {
167
+ state.incrementThumb(index, state.pageSize);
168
+ });
169
+ },
170
+ PageDown: () => {
171
+ return keyboardUpdate(() => {
172
+ state.decrementThumb(index, state.pageSize);
173
+ });
174
+ },
175
+ Home: () => {
176
+ return keyboardUpdate(() => {
177
+ state.setThumbValue(index, state.getThumbMinValue(index));
178
+ });
179
+ },
180
+ End: () => {
181
+ return keyboardUpdate(() => {
182
+ state.setThumbValue(index, state.getThumbMaxValue(index));
183
+ });
217
184
  },
218
185
  },
219
- subSlot(slot, 'keyboard'),
220
- );
186
+ allowRepeats: true,
187
+ });
221
188
 
222
- let { moveProps } = useMove(
223
- {
224
- onMoveStart() {
225
- currentPosition.current = null;
226
- state.setThumbDragging(index, true);
227
- },
228
- onMove({ deltaX, deltaY, pointerType, shiftKey }) {
229
- const { getThumbPercent, setThumbPercent, decrementThumb, incrementThumb, step, pageSize } =
230
- state;
231
- if (!trackRef.current) {
232
- return;
233
- }
234
- let { width, height } = trackRef.current.getBoundingClientRect();
235
- let size = isVertical ? height : width;
189
+ let { moveProps } = useMove({
190
+ onMoveStart() {
191
+ currentPosition.current = null;
192
+ state.setThumbDragging(index, true);
193
+ },
194
+ onMove({ deltaX, deltaY, pointerType, shiftKey }: import('@react-types/shared').MoveMoveEvent) {
195
+ const { getThumbPercent, setThumbPercent, decrementThumb, incrementThumb, step, pageSize } =
196
+ state;
197
+ if (!trackRef.current) {
198
+ return;
199
+ }
200
+ let { width, height } = trackRef.current.getBoundingClientRect();
201
+ let size = isVertical ? height : width;
236
202
 
237
- if (currentPosition.current == null) {
238
- currentPosition.current = getThumbPercent(index) * size;
239
- }
240
- if (pointerType === 'keyboard') {
241
- if ((deltaX > 0 && reverseX) || (deltaX < 0 && !reverseX) || deltaY > 0) {
242
- decrementThumb(index, shiftKey ? pageSize : step);
243
- } else {
244
- incrementThumb(index, shiftKey ? pageSize : step);
245
- }
203
+ if (currentPosition.current == null) {
204
+ currentPosition.current = getThumbPercent(index) * size;
205
+ }
206
+ if (pointerType === 'keyboard') {
207
+ if ((deltaX > 0 && reverseX) || (deltaX < 0 && !reverseX) || deltaY > 0) {
208
+ decrementThumb(index, shiftKey ? pageSize : step);
246
209
  } else {
247
- let delta = isVertical ? deltaY : deltaX;
248
- if (isVertical || reverseX) {
249
- delta = -delta;
250
- }
251
-
252
- currentPosition.current += delta;
253
- setThumbPercent(index, clamp(currentPosition.current / size, 0, 1));
210
+ incrementThumb(index, shiftKey ? pageSize : step);
254
211
  }
255
- },
256
- onMoveEnd() {
257
- state.setThumbDragging(index, false);
258
- },
212
+ } else {
213
+ let delta = isVertical ? deltaY : deltaX;
214
+ if (isVertical || reverseX) {
215
+ delta = -delta;
216
+ }
217
+
218
+ currentPosition.current += delta;
219
+ setThumbPercent(index, clamp(currentPosition.current / size, 0, 1));
220
+ }
259
221
  },
260
- subSlot(slot, 'move'),
261
- );
222
+ onMoveEnd() {
223
+ state.setThumbDragging(index, false);
224
+ },
225
+ });
262
226
 
263
227
  // Immediately register editability with the state
264
228
  state.setThumbEditable(index, !isDisabled);
@@ -269,10 +233,9 @@ export function useSliderThumb(...args: any[]): SliderThumbAria {
269
233
  onBlur: () => state.setFocusedThumb(undefined),
270
234
  }),
271
235
  inputRef,
272
- subSlot(slot, 'focusable'),
273
236
  );
274
237
 
275
- let currentPointer = useRef<number | undefined>(undefined, subSlot(slot, 'pointer'));
238
+ let currentPointer = useRef<number | undefined>(undefined);
276
239
  let onDown = (id?: number) => {
277
240
  focusInput();
278
241
  currentPointer.current = id;
@@ -283,8 +246,13 @@ export function useSliderThumb(...args: any[]): SliderThumbAria {
283
246
  addGlobalListener(window, 'pointerup', onUp, false);
284
247
  };
285
248
 
286
- let onUp = (e: any) => {
287
- let id = e.pointerId ?? e.changedTouches?.[0].identifier;
249
+ let onUp = (e: globalThis.PointerEvent | globalThis.TouchEvent | globalThis.MouseEvent) => {
250
+ let id =
251
+ 'pointerId' in e
252
+ ? e.pointerId
253
+ : 'changedTouches' in e
254
+ ? e.changedTouches[0]?.identifier
255
+ : undefined;
288
256
  if (id === currentPointer.current) {
289
257
  focusInput();
290
258
  state.setThumbDragging(index, false);
@@ -300,38 +268,34 @@ export function useSliderThumb(...args: any[]): SliderThumbAria {
300
268
  }
301
269
 
302
270
  let interactions = !isDisabled
303
- ? mergeProps(keyboardProps, moveProps, {
304
- onMouseDown: (e: MouseEvent) => {
271
+ ? // oxlint-disable-next-line react/react-compiler
272
+ mergeProps(keyboardProps, moveProps, {
273
+ onMouseDown: (e: React.MouseEvent) => {
305
274
  if (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey) {
306
275
  return;
307
276
  }
308
277
  onDown();
309
278
  },
310
- onPointerDown: (e: PointerEvent) => {
279
+ onPointerDown: (e: React.PointerEvent) => {
311
280
  if (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey) {
312
281
  return;
313
282
  }
314
283
  onDown(e.pointerId);
315
284
  },
316
- onTouchStart: (e: TouchEvent) => {
285
+ onTouchStart: (e: React.TouchEvent) => {
317
286
  onDown(e.changedTouches[0].identifier);
318
287
  },
319
288
  })
320
289
  : {};
321
290
 
322
- useFormReset(
323
- inputRef,
324
- state.defaultValues[index],
325
- (v) => {
326
- state.setThumbValue(index, v);
327
- },
328
- subSlot(slot, 'reset'),
329
- );
291
+ useFormReset(inputRef, state.defaultValues[index], (v) => {
292
+ state.setThumbValue(index, v);
293
+ });
330
294
 
331
295
  // We install mouse handlers for the drag motion on the thumb div, but
332
296
  // not the key handler for moving the thumb with the slider. Instead,
333
297
  // we focus the range input, and let the browser handle the keyboard
334
- // interactions; we then listen to input's native `input` event to update state.
298
+ // interactions; we then listen to input's onChange to update state.
335
299
  return {
336
300
  inputProps: mergeProps(focusableProps, fieldProps, {
337
301
  type: 'range',
@@ -352,8 +316,6 @@ export function useSliderThumb(...args: any[]): SliderThumbAria {
352
316
  .filter(Boolean)
353
317
  .join(' '),
354
318
  'aria-details': [data['aria-details'], opts['aria-details']].filter(Boolean).join(' '),
355
- // octane adaptation: React's synthetic onChange for range inputs rides the
356
- // native `input` event — onInput is the direct equivalent.
357
319
  onInput: (e: Event) => {
358
320
  state.setThumbValue(index, parseFloat((getEventTarget(e) as HTMLInputElement).value));
359
321
  },