@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.
- package/README.md +7 -6
- package/UPSTREAM.md +58 -69
- package/package.json +11 -11
- package/src/calendar/useCalendarGrid.tsx +64 -62
- package/src/collections/Document.ts +3 -0
- package/src/color/useColorArea.tsx +95 -69
- package/src/color/useColorWheel.tsx +38 -37
- package/src/combobox/{useComboBox.ts → useComboBox.tsx} +243 -258
- package/src/components/ComboBox.ts +35 -2
- package/src/components/Dialog.ts +12 -1
- package/src/components/DropZone.tsx +3 -2
- package/src/components/FileTrigger.tsx +1 -0
- package/src/components/GridList.ts +11 -2
- package/src/components/ListBox.ts +1 -1
- package/src/components/Menu.ts +1 -0
- package/src/components/Meter.ts +3 -1
- package/src/components/Popover.ts +20 -8
- package/src/components/PreviewTrigger.tsx +101 -0
- package/src/components/ProgressBar.ts +10 -2
- package/src/components/Select.ts +1 -1
- package/src/components/Table.ts +26 -15
- package/src/components/TokenField.tsx +395 -0
- package/src/components/Tooltip.ts +4 -6
- package/src/components/Tree.ts +14 -7
- package/src/components/Virtualizer.tsx +30 -14
- package/src/components/index.ts +22 -0
- package/src/components/utils.ts +1 -1
- package/src/datepicker/useDateField.tsx +2 -11
- package/src/datepicker/useDatePickerGroup.tsx +44 -33
- package/src/datepicker/useDateSegment.tsx +31 -30
- package/src/dialog/useDialog.ts +8 -1
- package/src/dnd/DragManager.tsx +5 -1
- package/src/dnd/useDrag.tsx +2 -1
- package/src/focus/FocusScope.ts +2 -2
- package/src/grid/useGrid.ts +3 -0
- package/src/grid/{useGridCell.ts → useGridCell.tsx} +128 -66
- package/src/grid/utils.ts +1 -0
- package/src/gridlist/{useGridListItem.ts → useGridListItem.tsx} +154 -112
- package/src/index.ts +22 -0
- package/src/interactions/createEventHandler.ts +11 -8
- package/src/interactions/createKeyboardShortcutHandler.tsx +218 -0
- package/src/interactions/textSelection.ts +3 -3
- package/src/interactions/useContextMenu.tsx +125 -0
- package/src/interactions/useFocusVisible.ts +4 -4
- package/src/interactions/useKeyboard.ts +50 -2
- package/src/interactions/useLongPress.ts +33 -22
- package/src/interactions/useMove.ts +6 -6
- package/src/interactions/usePress.ts +8 -0
- package/src/interactions/utils.ts +10 -10
- package/src/intl/combobox/fi-FI.json +2 -2
- package/src/intl/previewtrigger/ar-AE.json +3 -0
- package/src/intl/previewtrigger/bg-BG.json +3 -0
- package/src/intl/previewtrigger/cs-CZ.json +3 -0
- package/src/intl/previewtrigger/da-DK.json +3 -0
- package/src/intl/previewtrigger/de-DE.json +3 -0
- package/src/intl/previewtrigger/el-GR.json +3 -0
- package/src/intl/previewtrigger/en-US.json +3 -0
- package/src/intl/previewtrigger/es-ES.json +3 -0
- package/src/intl/previewtrigger/et-EE.json +3 -0
- package/src/intl/previewtrigger/fi-FI.json +3 -0
- package/src/intl/previewtrigger/fr-FR.json +3 -0
- package/src/intl/previewtrigger/he-IL.json +3 -0
- package/src/intl/previewtrigger/hr-HR.json +3 -0
- package/src/intl/previewtrigger/hu-HU.json +3 -0
- package/src/intl/previewtrigger/index.ts +73 -0
- package/src/intl/previewtrigger/it-IT.json +3 -0
- package/src/intl/previewtrigger/ja-JP.json +3 -0
- package/src/intl/previewtrigger/ko-KR.json +3 -0
- package/src/intl/previewtrigger/lt-LT.json +3 -0
- package/src/intl/previewtrigger/lv-LV.json +3 -0
- package/src/intl/previewtrigger/nb-NO.json +3 -0
- package/src/intl/previewtrigger/nl-NL.json +3 -0
- package/src/intl/previewtrigger/pl-PL.json +3 -0
- package/src/intl/previewtrigger/pt-BR.json +3 -0
- package/src/intl/previewtrigger/pt-PT.json +3 -0
- package/src/intl/previewtrigger/ro-RO.json +3 -0
- package/src/intl/previewtrigger/ru-RU.json +3 -0
- package/src/intl/previewtrigger/sk-SK.json +3 -0
- package/src/intl/previewtrigger/sl-SI.json +3 -0
- package/src/intl/previewtrigger/sr-SP.json +3 -0
- package/src/intl/previewtrigger/sv-SE.json +3 -0
- package/src/intl/previewtrigger/tr-TR.json +3 -0
- package/src/intl/previewtrigger/uk-UA.json +3 -0
- package/src/intl/previewtrigger/zh-CN.json +3 -0
- package/src/intl/previewtrigger/zh-TW.json +3 -0
- package/src/intl/table/ar-AE.json +3 -3
- package/src/intl/table/bg-BG.json +3 -3
- package/src/intl/table/cs-CZ.json +3 -3
- package/src/intl/table/da-DK.json +3 -3
- package/src/intl/table/de-DE.json +3 -3
- package/src/intl/table/el-GR.json +3 -3
- package/src/intl/table/es-ES.json +3 -3
- package/src/intl/table/et-EE.json +3 -3
- package/src/intl/table/fi-FI.json +3 -3
- package/src/intl/table/fr-FR.json +3 -3
- package/src/intl/table/he-IL.json +3 -3
- package/src/intl/table/hr-HR.json +3 -3
- package/src/intl/table/hu-HU.json +3 -3
- package/src/intl/table/it-IT.json +3 -3
- package/src/intl/table/ja-JP.json +3 -3
- package/src/intl/table/ko-KR.json +3 -3
- package/src/intl/table/lt-LT.json +3 -3
- package/src/intl/table/lv-LV.json +3 -3
- package/src/intl/table/nb-NO.json +3 -3
- package/src/intl/table/nl-NL.json +3 -3
- package/src/intl/table/pl-PL.json +3 -3
- package/src/intl/table/pt-BR.json +3 -3
- package/src/intl/table/pt-PT.json +3 -3
- package/src/intl/table/ro-RO.json +3 -3
- package/src/intl/table/ru-RU.json +3 -3
- package/src/intl/table/sk-SK.json +3 -3
- package/src/intl/table/sl-SI.json +3 -3
- package/src/intl/table/sr-SP.json +3 -3
- package/src/intl/table/sv-SE.json +3 -3
- package/src/intl/table/tr-TR.json +3 -3
- package/src/intl/table/uk-UA.json +3 -3
- package/src/intl/table/zh-CN.json +4 -4
- package/src/intl/table/zh-TW.json +3 -3
- package/src/intl/tree/es-ES.json +1 -1
- package/src/link/useLink.ts +2 -0
- package/src/menu/useMenuItem.ts +33 -36
- package/src/menu/useMenuTrigger.tsx +222 -0
- package/src/menu/{useSubmenuTrigger.ts → useSubmenuTrigger.tsx} +116 -151
- package/src/numberfield/{useNumberField.ts → useNumberField.tsx} +188 -238
- package/src/overlays/Overlay.ts +5 -1
- package/src/overlays/ariaHideOutside.ts +6 -8
- package/src/overlays/useCloseOnScroll.ts +7 -5
- package/src/overlays/{useOverlay.ts → useOverlay.tsx} +76 -83
- package/src/overlays/usePopover.ts +10 -5
- package/src/overlays/usePreventScroll.ts +4 -4
- package/src/progress/useProgressBar.ts +2 -1
- package/src/radio/{useRadioGroup.ts → useRadioGroup.tsx} +87 -79
- package/src/searchfield/useSearchField.tsx +152 -0
- package/src/select/useSelect.ts +20 -20
- package/src/selection/useSelectableCollection.tsx +755 -0
- package/src/selection/useSelectableItem.ts +48 -11
- package/src/slider/{useSliderThumb.ts → useSliderThumb.tsx} +120 -158
- package/src/spinbutton/useSpinButton.tsx +335 -0
- package/src/stately/combobox/useComboBoxState.ts +1 -1
- package/src/stately/grid/useGridState.ts +9 -10
- package/src/stately/index.ts +11 -0
- package/src/stately/menu/useMenuTriggerState.ts +1 -1
- package/src/stately/menu/useSubmenuTriggerState.ts +2 -0
- package/src/stately/overlays/useOverlayTriggerState.ts +12 -1
- package/src/stately/radio/useRadioGroupState.ts +5 -1
- package/src/stately/table/TableUtils.ts +15 -1
- package/src/stately/table/useTableState.ts +7 -0
- package/src/stately/tokenfield/TokenFieldValue.tsx +440 -0
- package/src/stately/tokenfield/useTokenFieldState.tsx +57 -0
- package/src/stately/tooltip/useTooltipTriggerState.ts +16 -7
- package/src/stately/virtualizer/Layout.tsx +2 -0
- package/src/stately/virtualizer/ScrollAnchor.tsx +338 -0
- package/src/stately/virtualizer/Virtualizer.tsx +52 -1
- package/src/stately/virtualizer/types.tsx +2 -0
- package/src/table/useTableCell.ts +12 -0
- package/src/table/useTableColumnHeader.ts +8 -1
- package/src/table/useTableColumnResize.tsx +359 -0
- package/src/tag/useTag.ts +22 -15
- package/src/textfield/useTextField.ts +2 -0
- package/src/tokenfield/useToken.tsx +64 -0
- package/src/tokenfield/useTokenField.tsx +849 -0
- package/src/tooltip/usePreviewTrigger.tsx +266 -0
- package/src/tooltip/useSafeArea.tsx +171 -0
- package/src/upstream-exports/react-aria/mergeRefs.tsx +3 -0
- package/src/upstream-exports/react-aria/usePreviewTrigger.tsx +18 -0
- package/src/upstream-exports/react-aria/useTokenField.tsx +22 -0
- package/src/upstream-exports/react-stately/private/collections/getChildNodes.tsx +8 -0
- package/src/upstream-exports/react-stately/private/collections/getItemCount.tsx +2 -0
- package/src/upstream-exports/react-stately/private/grid/GridCollection.tsx +7 -0
- package/src/upstream-exports/react-stately/private/grid/useGridState.tsx +6 -0
- package/src/upstream-exports/react-stately/private/utils/number.tsx +2 -0
- package/src/upstream-exports/react-stately/useComboBoxState.tsx +23 -0
- package/src/upstream-exports/react-stately/useListState.tsx +15 -0
- package/src/upstream-exports/react-stately/useMenuTriggerState.tsx +26 -0
- package/src/upstream-exports/react-stately/useMultipleSelectionState.tsx +21 -0
- package/src/upstream-exports/react-stately/useNumberFieldState.tsx +20 -0
- package/src/upstream-exports/react-stately/useOverlayTriggerState.tsx +20 -0
- package/src/upstream-exports/react-stately/useRadioGroupState.tsx +16 -0
- package/src/upstream-exports/react-stately/useSearchFieldState.tsx +19 -0
- package/src/upstream-exports/react-stately/useSliderState.tsx +20 -0
- package/src/upstream-exports/react-stately/useTableState.tsx +45 -0
- package/src/upstream-exports/react-stately/useTokenFieldState.tsx +25 -0
- package/src/upstream-exports/react-stately/useTooltipTriggerState.tsx +20 -0
- package/src/upstream-exports/react-stately/useTreeState.tsx +14 -0
- package/src/utils/domHelpers.ts +74 -17
- package/src/utils/isVirtualEvent.ts +2 -1
- package/src/utils/openLink.ts +8 -3
- package/src/utils/platform.ts +7 -3
- package/src/utils/scrollIntoView.ts +4 -4
- package/src/utils/shadowdom/DOMFunctions.ts +42 -2
- package/src/utils/useId.ts +11 -2
- package/src/utils/useLoadMoreSentinel.ts +8 -3
- package/src/utils/useViewportSize.ts +3 -3
- package/src/virtualizer/ScrollView.tsx +13 -4
- package/src/virtualizer/VirtualizerItem.tsx +4 -1
- package/src/virtualizer/useVirtualizerItem.tsx +43 -3
- package/src/menu/useMenuTrigger.ts +0 -189
- package/src/searchfield/useSearchField.ts +0 -156
- package/src/selection/useSelectableCollection.ts +0 -750
- package/src/spinbutton/useSpinButton.ts +0 -380
- package/src/table/useTableColumnResize.ts +0 -374
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
// Ported from react-aria (source: .react-spectrum/packages/react-aria/src/menu/useMenuTrigger.ts).
|
|
2
|
-
// octane adaptations:
|
|
3
|
-
// - `useOverlayTrigger` comes from the freshly-ported overlays glue
|
|
4
|
-
// (src/overlays/useOverlayTrigger.ts) — the rest of the overlays area (positioning,
|
|
5
|
-
// modal machinery) remains unported.
|
|
6
|
-
// - The trigger `onKeyDown` receives either the NATIVE KeyboardEvent (when spread straight
|
|
7
|
-
// onto an element) or the ported BaseEvent Proxy wrapper (when routed through
|
|
8
|
-
// useButton/useKeyboard). Upstream detects the wrapper with `'continuePropagation' in e`;
|
|
9
|
-
// the ported wrapper is a Proxy with only a `get` trap, so detection uses
|
|
10
|
-
// `typeof e.continuePropagation === 'function'` (the same probe createEventHandler uses
|
|
11
|
-
// for nested wrappers). Upstream's synthetic `e.isDefaultPrevented()` becomes the native
|
|
12
|
-
// `e.defaultPrevented`.
|
|
13
|
-
// - The Parcel glob intl import becomes the generated '../intl/menu' dictionary index.
|
|
14
|
-
// - Public-hook slot threading (splitSlot/subSlot) per the binding convention.
|
|
15
|
-
import type { AriaButtonProps } from '../button/useButton';
|
|
16
|
-
import type { AriaMenuOptions } from './useMenu';
|
|
17
|
-
import type { FocusableElement, RefObject } from '@react-types/shared';
|
|
18
|
-
import { focusWithoutScrolling } from '../utils/focusWithoutScrolling';
|
|
19
|
-
import intlMessages from '../intl/menu';
|
|
20
|
-
import type { MenuTriggerState, MenuTriggerType } from '../stately/menu/useMenuTriggerState';
|
|
21
|
-
import type { PressProps } from '../interactions/usePress';
|
|
22
|
-
import { useId } from '../utils/useId';
|
|
23
|
-
import { useLocalizedStringFormatter } from '../i18n/useLocalizedStringFormatter';
|
|
24
|
-
import { useLongPress } from '../interactions/useLongPress';
|
|
25
|
-
import { useOverlayTrigger } from '../overlays/useOverlayTrigger';
|
|
26
|
-
|
|
27
|
-
import { S, splitSlot, subSlot } from '../internal';
|
|
28
|
-
|
|
29
|
-
export interface AriaMenuTriggerProps {
|
|
30
|
-
/** The type of menu that the menu trigger opens. */
|
|
31
|
-
type?: 'menu' | 'listbox';
|
|
32
|
-
/** Whether menu trigger is disabled. */
|
|
33
|
-
isDisabled?: boolean;
|
|
34
|
-
/** How menu is triggered. */
|
|
35
|
-
trigger?: MenuTriggerType;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface MenuTriggerAria<T> {
|
|
39
|
-
/** Props for the menu trigger element. */
|
|
40
|
-
menuTriggerProps: AriaButtonProps;
|
|
41
|
-
|
|
42
|
-
/** Props for the menu. */
|
|
43
|
-
menuProps: AriaMenuOptions<T>;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Provides the behavior and accessibility implementation for a menu trigger.
|
|
48
|
-
*
|
|
49
|
-
* @param props - Props for the menu trigger.
|
|
50
|
-
* @param state - State for the menu trigger.
|
|
51
|
-
* @param ref - Ref to the HTML element trigger for the menu.
|
|
52
|
-
*/
|
|
53
|
-
export function useMenuTrigger<T>(
|
|
54
|
-
props: AriaMenuTriggerProps,
|
|
55
|
-
state: MenuTriggerState,
|
|
56
|
-
ref: RefObject<Element | null>,
|
|
57
|
-
): MenuTriggerAria<T>;
|
|
58
|
-
// Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
|
|
59
|
-
export function useMenuTrigger<T>(
|
|
60
|
-
props: AriaMenuTriggerProps,
|
|
61
|
-
state: MenuTriggerState,
|
|
62
|
-
ref: RefObject<Element | null>,
|
|
63
|
-
slot: symbol | undefined,
|
|
64
|
-
): MenuTriggerAria<T>;
|
|
65
|
-
export function useMenuTrigger(...args: any[]): MenuTriggerAria<any> {
|
|
66
|
-
const [user, slotArg] = splitSlot(args);
|
|
67
|
-
const slot = slotArg ?? S('useMenuTrigger');
|
|
68
|
-
const props = user[0] as AriaMenuTriggerProps;
|
|
69
|
-
const state = user[1] as MenuTriggerState;
|
|
70
|
-
const ref = user[2] as RefObject<Element | null>;
|
|
71
|
-
|
|
72
|
-
let { type = 'menu', isDisabled, trigger = 'press' } = props;
|
|
73
|
-
|
|
74
|
-
let menuTriggerId = useId(subSlot(slot, 'triggerId'));
|
|
75
|
-
let { triggerProps, overlayProps } = useOverlayTrigger(
|
|
76
|
-
{ type },
|
|
77
|
-
state,
|
|
78
|
-
ref,
|
|
79
|
-
subSlot(slot, 'overlayTrigger'),
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
let onKeyDown = (e: any) => {
|
|
83
|
-
if (isDisabled) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (trigger === 'longPress' && !e.altKey) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (ref && ref.current) {
|
|
92
|
-
switch (e.key) {
|
|
93
|
-
case 'Enter':
|
|
94
|
-
case ' ':
|
|
95
|
-
// React puts listeners on the same root, so even if propagation was stopped, immediate propagation is still possible.
|
|
96
|
-
// useTypeSelect will handle the spacebar first if it's running, so we don't want to open if it's handled it already.
|
|
97
|
-
// We use isDefaultPrevented() instead of isPropagationStopped() because createEventHandler stops propagation by default.
|
|
98
|
-
// And default prevented means that the event was handled by something else (typeahead), so we don't want to open the menu.
|
|
99
|
-
// octane adaptation: the native `defaultPrevented` flag (forwarded by the
|
|
100
|
-
// BaseEvent Proxy wrapper) replaces the synthetic isDefaultPrevented().
|
|
101
|
-
if (trigger === 'longPress' || e.defaultPrevented) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
// fallthrough
|
|
105
|
-
case 'ArrowDown':
|
|
106
|
-
// Stop propagation, unless it would already be handled by useKeyboard.
|
|
107
|
-
if (typeof e.continuePropagation !== 'function') {
|
|
108
|
-
e.stopPropagation();
|
|
109
|
-
}
|
|
110
|
-
e.preventDefault();
|
|
111
|
-
state.toggle('first');
|
|
112
|
-
break;
|
|
113
|
-
case 'ArrowUp':
|
|
114
|
-
if (typeof e.continuePropagation !== 'function') {
|
|
115
|
-
e.stopPropagation();
|
|
116
|
-
}
|
|
117
|
-
e.preventDefault();
|
|
118
|
-
state.toggle('last');
|
|
119
|
-
break;
|
|
120
|
-
default:
|
|
121
|
-
// Allow other keys.
|
|
122
|
-
if (typeof e.continuePropagation === 'function') {
|
|
123
|
-
e.continuePropagation();
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
let stringFormatter = useLocalizedStringFormatter(
|
|
130
|
-
intlMessages,
|
|
131
|
-
'@react-aria/menu',
|
|
132
|
-
subSlot(slot, 'formatter'),
|
|
133
|
-
);
|
|
134
|
-
let { longPressProps } = useLongPress(
|
|
135
|
-
{
|
|
136
|
-
isDisabled: isDisabled || trigger !== 'longPress',
|
|
137
|
-
accessibilityDescription: stringFormatter.format('longPressMessage'),
|
|
138
|
-
onLongPressStart() {
|
|
139
|
-
state.close();
|
|
140
|
-
},
|
|
141
|
-
onLongPress() {
|
|
142
|
-
state.open('first');
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
subSlot(slot, 'longPress'),
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
let pressProps: PressProps = {
|
|
149
|
-
preventFocusOnPress: true,
|
|
150
|
-
onPressStart(e) {
|
|
151
|
-
// For consistency with native, open the menu on mouse/key down, but touch up.
|
|
152
|
-
if (e.pointerType !== 'touch' && e.pointerType !== 'keyboard' && !isDisabled) {
|
|
153
|
-
// Ensure trigger has focus before opening the menu so it can be restored by FocusScope on close.
|
|
154
|
-
focusWithoutScrolling(e.target as FocusableElement);
|
|
155
|
-
|
|
156
|
-
// If opened with a screen reader, auto focus the first item.
|
|
157
|
-
// Otherwise, the menu itself will be focused.
|
|
158
|
-
state.open(e.pointerType === 'virtual' ? 'first' : null);
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
onPress(e) {
|
|
162
|
-
if (e.pointerType === 'touch' && !isDisabled) {
|
|
163
|
-
// Ensure trigger has focus before opening the menu so it can be restored by FocusScope on close.
|
|
164
|
-
focusWithoutScrolling(e.target as FocusableElement);
|
|
165
|
-
|
|
166
|
-
state.toggle();
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
// omit onPress from triggerProps since we override it above.
|
|
172
|
-
delete triggerProps.onPress;
|
|
173
|
-
|
|
174
|
-
return {
|
|
175
|
-
// @ts-ignore - TODO we pass out both DOMAttributes AND AriaButtonProps, but useButton will discard the longPress event handlers, it's only through PressResponder magic that this works for RSP and RAC. it does not work in aria examples
|
|
176
|
-
menuTriggerProps: {
|
|
177
|
-
...triggerProps,
|
|
178
|
-
...(trigger === 'press' ? pressProps : longPressProps),
|
|
179
|
-
id: menuTriggerId,
|
|
180
|
-
onKeyDown,
|
|
181
|
-
},
|
|
182
|
-
menuProps: {
|
|
183
|
-
...overlayProps,
|
|
184
|
-
'aria-labelledby': menuTriggerId,
|
|
185
|
-
autoFocus: state.focusStrategy || true,
|
|
186
|
-
onClose: state.close,
|
|
187
|
-
},
|
|
188
|
-
};
|
|
189
|
-
}
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
// Ported from react-aria (source: .react-spectrum/packages/react-aria/src/searchfield/useSearchField.ts).
|
|
2
|
-
// octane adaptations: the Parcel glob intl import becomes the generated
|
|
3
|
-
// src/intl/searchfield index (verbatim dictionaries); per-element attribute types →
|
|
4
|
-
// structural bags; the keydown handler receives the wrapped BaseEvent from the ported
|
|
5
|
-
// useKeyboard (so `continuePropagation()` works); public-hook slot threading.
|
|
6
|
-
import type { RefObject, ValidationResult } from '@react-types/shared';
|
|
7
|
-
|
|
8
|
-
import type { AriaButtonProps } from '../button/useButton';
|
|
9
|
-
import { AriaTextFieldProps, useTextField } from '../textfield/useTextField';
|
|
10
|
-
import { S, splitSlot, subSlot } from '../internal';
|
|
11
|
-
import { chain } from '../utils/chain';
|
|
12
|
-
import intlMessages from '../intl/searchfield';
|
|
13
|
-
import type {
|
|
14
|
-
SearchFieldProps,
|
|
15
|
-
SearchFieldState,
|
|
16
|
-
} from '../stately/searchfield/useSearchFieldState';
|
|
17
|
-
import { useLocalizedStringFormatter } from '../i18n/useLocalizedStringFormatter';
|
|
18
|
-
|
|
19
|
-
type DOMAttributes = Record<string, any>;
|
|
20
|
-
|
|
21
|
-
export interface AriaSearchFieldProps extends SearchFieldProps, Omit<AriaTextFieldProps, 'type'> {
|
|
22
|
-
/**
|
|
23
|
-
* An enumerated attribute that defines what action label or icon to preset for the enter key on
|
|
24
|
-
* virtual keyboards. See
|
|
25
|
-
* [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/enterkeyhint).
|
|
26
|
-
*/
|
|
27
|
-
enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send';
|
|
28
|
-
/**
|
|
29
|
-
* The type of input to render. See
|
|
30
|
-
* [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdeftype).
|
|
31
|
-
*
|
|
32
|
-
* @default 'search'
|
|
33
|
-
*/
|
|
34
|
-
type?: 'text' | 'search' | 'url' | 'tel' | 'email' | 'password' | (string & {});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface SearchFieldAria extends ValidationResult {
|
|
38
|
-
/** Props for the text field's visible label element (if any). */
|
|
39
|
-
labelProps: DOMAttributes;
|
|
40
|
-
/** Props for the input element. */
|
|
41
|
-
inputProps: DOMAttributes;
|
|
42
|
-
/** Props for the clear button. */
|
|
43
|
-
clearButtonProps: AriaButtonProps;
|
|
44
|
-
/** Props for the searchfield's description element, if any. */
|
|
45
|
-
descriptionProps: DOMAttributes;
|
|
46
|
-
/** Props for the searchfield's error message element, if any. */
|
|
47
|
-
errorMessageProps: DOMAttributes;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Provides the behavior and accessibility implementation for a search field.
|
|
52
|
-
*/
|
|
53
|
-
export function useSearchField(
|
|
54
|
-
props: AriaSearchFieldProps,
|
|
55
|
-
state: SearchFieldState,
|
|
56
|
-
inputRef: RefObject<HTMLInputElement | null>,
|
|
57
|
-
): SearchFieldAria;
|
|
58
|
-
// Slot-threading form: sibling ported hooks pass their derived sub-slot as the trailing arg.
|
|
59
|
-
export function useSearchField(
|
|
60
|
-
props: AriaSearchFieldProps,
|
|
61
|
-
state: SearchFieldState,
|
|
62
|
-
inputRef: RefObject<HTMLInputElement | null>,
|
|
63
|
-
slot: symbol | undefined,
|
|
64
|
-
): SearchFieldAria;
|
|
65
|
-
export function useSearchField(...args: any[]): SearchFieldAria {
|
|
66
|
-
const [user, slotArg] = splitSlot(args);
|
|
67
|
-
const slot = slotArg ?? S('useSearchField');
|
|
68
|
-
const props = user[0] as AriaSearchFieldProps;
|
|
69
|
-
const state = user[1] as SearchFieldState;
|
|
70
|
-
const inputRef = user[2] as RefObject<HTMLInputElement | null>;
|
|
71
|
-
|
|
72
|
-
let stringFormatter = useLocalizedStringFormatter(
|
|
73
|
-
intlMessages,
|
|
74
|
-
'@react-aria/searchfield',
|
|
75
|
-
subSlot(slot, 'strings'),
|
|
76
|
-
);
|
|
77
|
-
let { isDisabled, isReadOnly, onSubmit, onClear, type = 'search' } = props;
|
|
78
|
-
let onKeyDown = (e: any) => {
|
|
79
|
-
const key = e.key;
|
|
80
|
-
|
|
81
|
-
if (key === 'Enter' && (isDisabled || isReadOnly)) {
|
|
82
|
-
e.preventDefault();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (isDisabled || isReadOnly) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// for backward compatibility;
|
|
90
|
-
// otherwise, "Enter" on an input would trigger a form submit, the default browser behavior
|
|
91
|
-
if (key === 'Enter' && onSubmit) {
|
|
92
|
-
e.preventDefault();
|
|
93
|
-
onSubmit(state.value);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (key === 'Escape') {
|
|
97
|
-
// Also check the inputRef value for the case where the value was set directly on the input element instead of going through
|
|
98
|
-
// the hook
|
|
99
|
-
if (state.value === '' && (!inputRef.current || inputRef.current.value === '')) {
|
|
100
|
-
e.continuePropagation();
|
|
101
|
-
} else {
|
|
102
|
-
e.preventDefault();
|
|
103
|
-
state.setValue('');
|
|
104
|
-
if (onClear) {
|
|
105
|
-
onClear();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
let onClearButtonClick = () => {
|
|
112
|
-
state.setValue('');
|
|
113
|
-
|
|
114
|
-
if (onClear) {
|
|
115
|
-
onClear();
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
let onPressStart = () => {
|
|
120
|
-
// this is in PressStart for mobile so that touching the clear button doesn't remove focus from
|
|
121
|
-
// the input and close the keyboard
|
|
122
|
-
inputRef.current?.focus();
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
let { labelProps, inputProps, descriptionProps, errorMessageProps, ...validation } = useTextField(
|
|
126
|
-
{
|
|
127
|
-
...props,
|
|
128
|
-
value: state.value,
|
|
129
|
-
onChange: state.setValue,
|
|
130
|
-
onKeyDown: !isReadOnly ? chain(onKeyDown, props.onKeyDown) : props.onKeyDown,
|
|
131
|
-
type,
|
|
132
|
-
} as any,
|
|
133
|
-
inputRef,
|
|
134
|
-
subSlot(slot, 'textField'),
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
labelProps,
|
|
139
|
-
inputProps: {
|
|
140
|
-
...inputProps,
|
|
141
|
-
// already handled by useSearchFieldState
|
|
142
|
-
defaultValue: undefined,
|
|
143
|
-
},
|
|
144
|
-
clearButtonProps: {
|
|
145
|
-
'aria-label': stringFormatter.format('Clear search'),
|
|
146
|
-
excludeFromTabOrder: true,
|
|
147
|
-
preventFocusOnPress: true,
|
|
148
|
-
isDisabled: isDisabled || isReadOnly,
|
|
149
|
-
onPress: onClearButtonClick,
|
|
150
|
-
onPressStart,
|
|
151
|
-
},
|
|
152
|
-
descriptionProps,
|
|
153
|
-
errorMessageProps,
|
|
154
|
-
...validation,
|
|
155
|
-
};
|
|
156
|
-
}
|