@react-aria/selection 3.8.2 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +61 -61
- package/dist/main.js.map +1 -1
- package/dist/module.js +56 -44
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +41 -21
- package/dist/types.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/index.ts +10 -5
- package/src/useSelectableCollection.ts +10 -10
- package/src/useSelectableItem.ts +105 -36
- package/src/useSelectableList.ts +7 -7
- package/src/useTypeSelect.ts +6 -6
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;ACgBA;IACE;;OAEG;IACH,gBAAgB,EAAE,gBAAgB,CAAC;IACnC;;OAEG;IACH,gBAAgB,EAAE,wBAAwB,CAAC;IAC3C;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;CAClC;AAED;IACE;;OAEG;IACH,eAAe,EAAE,
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/selection/src/packages/@react-aria/selection/src/utils.ts","packages/@react-aria/selection/src/packages/@react-aria/selection/src/useTypeSelect.ts","packages/@react-aria/selection/src/packages/@react-aria/selection/src/useSelectableCollection.ts","packages/@react-aria/selection/src/packages/@react-aria/selection/src/useSelectableItem.ts","packages/@react-aria/selection/src/packages/@react-aria/selection/src/ListKeyboardDelegate.ts","packages/@react-aria/selection/src/packages/@react-aria/selection/src/useSelectableList.ts","packages/@react-aria/selection/src/packages/@react-aria/selection/src/index.ts","packages/@react-aria/selection/src/index.ts"],"sourcesContent":[null,null,null,null,null,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 */\n\nexport {useSelectableCollection} from './useSelectableCollection';\nexport {useSelectableItem} from './useSelectableItem';\nexport {useSelectableList} from './useSelectableList';\nexport {ListKeyboardDelegate} from './ListKeyboardDelegate';\nexport {useTypeSelect} from './useTypeSelect';\n\nexport type {AriaSelectableCollectionOptions, SelectableCollectionAria} from './useSelectableCollection';\nexport type {AriaSelectableListOptions, SelectableListAria} from './useSelectableList';\nexport type {SelectableItemOptions, SelectableItemStates, SelectableItemAria} from './useSelectableItem';\nexport type {AriaTypeSelectOptions, TypeSelectAria} from './useTypeSelect';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/selection",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -18,19 +18,19 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@babel/runtime": "^7.6.2",
|
|
21
|
-
"@react-aria/focus": "^3.
|
|
22
|
-
"@react-aria/i18n": "^3.
|
|
23
|
-
"@react-aria/interactions": "^3.
|
|
24
|
-
"@react-aria/utils": "^3.
|
|
25
|
-
"@react-stately/collections": "^3.
|
|
26
|
-
"@react-stately/selection": "^3.
|
|
27
|
-
"@react-types/shared": "^3.
|
|
21
|
+
"@react-aria/focus": "^3.7.0",
|
|
22
|
+
"@react-aria/i18n": "^3.5.0",
|
|
23
|
+
"@react-aria/interactions": "^3.10.0",
|
|
24
|
+
"@react-aria/utils": "^3.13.2",
|
|
25
|
+
"@react-stately/collections": "^3.4.2",
|
|
26
|
+
"@react-stately/selection": "^3.10.2",
|
|
27
|
+
"@react-types/shared": "^3.14.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"react": "^16.8.0 || ^17.0.0-rc.1"
|
|
30
|
+
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
|
|
31
31
|
},
|
|
32
32
|
"publishConfig": {
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "cd7c0ec917122c7612f653c22f8ed558f8b66ecd"
|
|
36
36
|
}
|
package/src/index.ts
CHANGED
|
@@ -10,8 +10,13 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
export
|
|
14
|
-
export
|
|
15
|
-
export
|
|
16
|
-
export
|
|
17
|
-
export
|
|
13
|
+
export {useSelectableCollection} from './useSelectableCollection';
|
|
14
|
+
export {useSelectableItem} from './useSelectableItem';
|
|
15
|
+
export {useSelectableList} from './useSelectableList';
|
|
16
|
+
export {ListKeyboardDelegate} from './ListKeyboardDelegate';
|
|
17
|
+
export {useTypeSelect} from './useTypeSelect';
|
|
18
|
+
|
|
19
|
+
export type {AriaSelectableCollectionOptions, SelectableCollectionAria} from './useSelectableCollection';
|
|
20
|
+
export type {AriaSelectableListOptions, SelectableListAria} from './useSelectableList';
|
|
21
|
+
export type {SelectableItemOptions, SelectableItemStates, SelectableItemAria} from './useSelectableItem';
|
|
22
|
+
export type {AriaTypeSelectOptions, TypeSelectAria} from './useTypeSelect';
|
|
@@ -10,16 +10,16 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import {DOMAttributes, FocusableElement, FocusStrategy, KeyboardDelegate} from '@react-types/shared';
|
|
14
|
+
import {FocusEvent, Key, KeyboardEvent, RefObject, useEffect, useRef} from 'react';
|
|
14
15
|
import {focusSafely, getFocusableTreeWalker} from '@react-aria/focus';
|
|
15
|
-
import {FocusStrategy, KeyboardDelegate} from '@react-types/shared';
|
|
16
16
|
import {focusWithoutScrolling, mergeProps, scrollIntoView, useEvent} from '@react-aria/utils';
|
|
17
17
|
import {isCtrlKeyPressed, isNonContiguousSelectionModifier} from './utils';
|
|
18
18
|
import {MultipleSelectionManager} from '@react-stately/selection';
|
|
19
19
|
import {useLocale} from '@react-aria/i18n';
|
|
20
20
|
import {useTypeSelect} from './useTypeSelect';
|
|
21
21
|
|
|
22
|
-
interface
|
|
22
|
+
export interface AriaSelectableCollectionOptions {
|
|
23
23
|
/**
|
|
24
24
|
* An interface for reading and updating multiple selection state.
|
|
25
25
|
*/
|
|
@@ -81,15 +81,15 @@ interface SelectableCollectionOptions {
|
|
|
81
81
|
scrollRef?: RefObject<HTMLElement>
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
interface SelectableCollectionAria {
|
|
84
|
+
export interface SelectableCollectionAria {
|
|
85
85
|
/** Props for the collection element. */
|
|
86
|
-
collectionProps:
|
|
86
|
+
collectionProps: DOMAttributes
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
90
|
* Handles interactions with selectable collections.
|
|
91
91
|
*/
|
|
92
|
-
export function useSelectableCollection(options:
|
|
92
|
+
export function useSelectableCollection(options: AriaSelectableCollectionOptions): SelectableCollectionAria {
|
|
93
93
|
let {
|
|
94
94
|
selectionManager: manager,
|
|
95
95
|
keyboardDelegate: delegate,
|
|
@@ -117,7 +117,7 @@ export function useSelectableCollection(options: SelectableCollectionOptions): S
|
|
|
117
117
|
|
|
118
118
|
// Keyboard events bubble through portals. Don't handle keyboard events
|
|
119
119
|
// for elements outside the collection (e.g. menus).
|
|
120
|
-
if (!ref.current.contains(e.target as
|
|
120
|
+
if (!ref.current.contains(e.target as Element)) {
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
123
123
|
|
|
@@ -238,10 +238,10 @@ export function useSelectableCollection(options: SelectableCollectionOptions): S
|
|
|
238
238
|
ref.current.focus();
|
|
239
239
|
} else {
|
|
240
240
|
let walker = getFocusableTreeWalker(ref.current, {tabbable: true});
|
|
241
|
-
let next:
|
|
242
|
-
let last:
|
|
241
|
+
let next: FocusableElement;
|
|
242
|
+
let last: FocusableElement;
|
|
243
243
|
do {
|
|
244
|
-
last = walker.lastChild() as
|
|
244
|
+
last = walker.lastChild() as FocusableElement;
|
|
245
245
|
if (last) {
|
|
246
246
|
next = last;
|
|
247
247
|
}
|
package/src/useSelectableItem.ts
CHANGED
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import {DOMAttributes, FocusableElement, LongPressEvent, PressEvent} from '@react-types/shared';
|
|
13
14
|
import {focusSafely} from '@react-aria/focus';
|
|
14
|
-
import {HTMLAttributes, Key, RefObject, useEffect, useRef} from 'react';
|
|
15
15
|
import {isCtrlKeyPressed, isNonContiguousSelectionModifier} from './utils';
|
|
16
|
-
import {
|
|
16
|
+
import {Key, RefObject, useEffect, useRef} from 'react';
|
|
17
17
|
import {mergeProps} from '@react-aria/utils';
|
|
18
18
|
import {MultipleSelectionManager} from '@react-stately/selection';
|
|
19
19
|
import {PressProps, useLongPress, usePress} from '@react-aria/interactions';
|
|
20
20
|
|
|
21
|
-
interface SelectableItemOptions {
|
|
21
|
+
export interface SelectableItemOptions {
|
|
22
22
|
/**
|
|
23
23
|
* An interface for reading and updating multiple selection state.
|
|
24
24
|
*/
|
|
@@ -30,7 +30,7 @@ interface SelectableItemOptions {
|
|
|
30
30
|
/**
|
|
31
31
|
* Ref to the item.
|
|
32
32
|
*/
|
|
33
|
-
ref: RefObject<
|
|
33
|
+
ref: RefObject<FocusableElement>,
|
|
34
34
|
/**
|
|
35
35
|
* By default, selection occurs on pointer down. This can be strange if selecting an
|
|
36
36
|
* item causes the UI to disappear immediately (e.g. menus).
|
|
@@ -56,19 +56,40 @@ interface SelectableItemOptions {
|
|
|
56
56
|
/** Whether the item is disabled. */
|
|
57
57
|
isDisabled?: boolean,
|
|
58
58
|
/**
|
|
59
|
-
* Handler that is called when a user performs an action on the
|
|
59
|
+
* Handler that is called when a user performs an action on the item. The exact user event depends on
|
|
60
60
|
* the collection's `selectionBehavior` prop and the interaction modality.
|
|
61
61
|
*/
|
|
62
62
|
onAction?: () => void
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
interface
|
|
65
|
+
export interface SelectableItemStates {
|
|
66
|
+
/** Whether the item is currently in a pressed state. */
|
|
67
|
+
isPressed: boolean,
|
|
68
|
+
/** Whether the item is currently selected. */
|
|
69
|
+
isSelected: boolean,
|
|
70
|
+
/**
|
|
71
|
+
* Whether the item is non-interactive, i.e. both selection and actions are disabled and the item may
|
|
72
|
+
* not be focused. Dependent on `disabledKeys` and `disabledBehavior`.
|
|
73
|
+
*/
|
|
74
|
+
isDisabled: boolean,
|
|
75
|
+
/**
|
|
76
|
+
* Whether the item may be selected, dependent on `selectionMode`, `disabledKeys`, and `disabledBehavior`.
|
|
77
|
+
*/
|
|
78
|
+
allowsSelection: boolean,
|
|
79
|
+
/**
|
|
80
|
+
* Whether the item has an action, dependent on `onAction`, `disabledKeys`,
|
|
81
|
+
* and `disabledBehavior. It may also change depending on the current selection state
|
|
82
|
+
* of the list (e.g. when selection is primary). This can be used to enable or disable hover
|
|
83
|
+
* styles or other visual indications of interactivity.
|
|
84
|
+
*/
|
|
85
|
+
hasAction: boolean
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface SelectableItemAria extends SelectableItemStates {
|
|
66
89
|
/**
|
|
67
90
|
* Props to be spread on the item root node.
|
|
68
91
|
*/
|
|
69
|
-
itemProps:
|
|
70
|
-
/** Whether the item is currently in a pressed state. */
|
|
71
|
-
isPressed: boolean
|
|
92
|
+
itemProps: DOMAttributes
|
|
72
93
|
}
|
|
73
94
|
|
|
74
95
|
/**
|
|
@@ -114,8 +135,8 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
114
135
|
};
|
|
115
136
|
|
|
116
137
|
// Focus the associated DOM node when this item becomes the focusedKey
|
|
117
|
-
let isFocused = key === manager.focusedKey;
|
|
118
138
|
useEffect(() => {
|
|
139
|
+
let isFocused = key === manager.focusedKey;
|
|
119
140
|
if (isFocused && manager.isFocused && !shouldUseVirtualFocus && document.activeElement !== ref.current) {
|
|
120
141
|
if (focus) {
|
|
121
142
|
focus();
|
|
@@ -123,7 +144,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
123
144
|
focusSafely(ref.current);
|
|
124
145
|
}
|
|
125
146
|
}
|
|
126
|
-
}, [ref,
|
|
147
|
+
}, [ref, key, manager.focusedKey, manager.childFocusStrategy, manager.isFocused, shouldUseVirtualFocus]);
|
|
127
148
|
|
|
128
149
|
// Set tabIndex to 0 if the element is focused, or -1 otherwise so that only the last focused
|
|
129
150
|
// item is tabbable. If using virtual focus, don't set a tabIndex at all so that VoiceOver
|
|
@@ -131,7 +152,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
131
152
|
let itemProps: SelectableItemAria['itemProps'] = {};
|
|
132
153
|
if (!shouldUseVirtualFocus) {
|
|
133
154
|
itemProps = {
|
|
134
|
-
tabIndex:
|
|
155
|
+
tabIndex: key === manager.focusedKey ? 0 : -1,
|
|
135
156
|
onFocus(e) {
|
|
136
157
|
if (e.target === ref.current) {
|
|
137
158
|
manager.setFocusedKey(key);
|
|
@@ -140,10 +161,26 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
140
161
|
};
|
|
141
162
|
}
|
|
142
163
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
164
|
+
|
|
165
|
+
// With checkbox selection, onAction (i.e. navigation) becomes primary, and occurs on a single click of the row.
|
|
166
|
+
// Clicking the checkbox enters selection mode, after which clicking anywhere on any row toggles selection for that row.
|
|
167
|
+
// With highlight selection, onAction is secondary, and occurs on double click. Single click selects the row.
|
|
168
|
+
// With touch, onAction occurs on single tap, and long press enters selection mode.
|
|
169
|
+
isDisabled = isDisabled || manager.isDisabled(key);
|
|
146
170
|
let allowsSelection = !isDisabled && manager.canSelectItem(key);
|
|
171
|
+
let allowsActions = onAction && !isDisabled;
|
|
172
|
+
let hasPrimaryAction = allowsActions && (
|
|
173
|
+
manager.selectionBehavior === 'replace'
|
|
174
|
+
? !allowsSelection
|
|
175
|
+
: manager.isEmpty
|
|
176
|
+
);
|
|
177
|
+
let hasSecondaryAction = allowsActions && allowsSelection && manager.selectionBehavior === 'replace';
|
|
178
|
+
let hasAction = hasPrimaryAction || hasSecondaryAction;
|
|
179
|
+
let modality = useRef(null);
|
|
180
|
+
|
|
181
|
+
let longPressEnabled = hasAction && allowsSelection;
|
|
182
|
+
let longPressEnabledOnPressStart = useRef(false);
|
|
183
|
+
let hadPrimaryActionOnPressStart = useRef(false);
|
|
147
184
|
|
|
148
185
|
// By default, selection occurs on pointer down. This can be strange if selecting an
|
|
149
186
|
// item causes the UI to disappear immediately (e.g. menus).
|
|
@@ -156,7 +193,8 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
156
193
|
if (shouldSelectOnPressUp) {
|
|
157
194
|
itemPressProps.onPressStart = (e) => {
|
|
158
195
|
modality.current = e.pointerType;
|
|
159
|
-
|
|
196
|
+
longPressEnabledOnPressStart.current = longPressEnabled;
|
|
197
|
+
if (e.pointerType === 'keyboard' && (!hasAction || isSelectionKey())) {
|
|
160
198
|
onSelect(e);
|
|
161
199
|
}
|
|
162
200
|
};
|
|
@@ -165,12 +203,14 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
165
203
|
// Otherwise, have selection happen onPress (prevents listview row selection when clicking on interactable elements in the row)
|
|
166
204
|
if (!allowsDifferentPressOrigin) {
|
|
167
205
|
itemPressProps.onPress = (e) => {
|
|
168
|
-
if (e.pointerType !== '
|
|
169
|
-
|
|
170
|
-
|
|
206
|
+
if (hasPrimaryAction || (hasSecondaryAction && e.pointerType !== 'mouse')) {
|
|
207
|
+
if (e.pointerType === 'keyboard' && !isActionKey()) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
171
210
|
|
|
172
|
-
if (hasPrimaryAction) {
|
|
173
211
|
onAction();
|
|
212
|
+
} else if (e.pointerType !== 'keyboard') {
|
|
213
|
+
onSelect(e);
|
|
174
214
|
}
|
|
175
215
|
};
|
|
176
216
|
} else {
|
|
@@ -183,19 +223,34 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
183
223
|
itemPressProps.onPress = hasPrimaryAction ? () => onAction() : null;
|
|
184
224
|
}
|
|
185
225
|
} else {
|
|
186
|
-
// On touch, it feels strange to select on touch down, so we special case this.
|
|
187
226
|
itemPressProps.onPressStart = (e) => {
|
|
188
227
|
modality.current = e.pointerType;
|
|
189
|
-
|
|
228
|
+
longPressEnabledOnPressStart.current = longPressEnabled;
|
|
229
|
+
hadPrimaryActionOnPressStart.current = hasPrimaryAction;
|
|
230
|
+
|
|
231
|
+
// Select on mouse down unless there is a primary action which will occur on mouse up.
|
|
232
|
+
// For keyboard, select on key down. If there is an action, the Space key selects on key down,
|
|
233
|
+
// and the Enter key performs onAction on key up.
|
|
234
|
+
if (
|
|
235
|
+
(e.pointerType === 'mouse' && !hasPrimaryAction) ||
|
|
236
|
+
(e.pointerType === 'keyboard' && (!onAction || isSelectionKey()))
|
|
237
|
+
) {
|
|
190
238
|
onSelect(e);
|
|
191
239
|
}
|
|
192
240
|
};
|
|
193
241
|
|
|
194
242
|
itemPressProps.onPress = (e) => {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
243
|
+
// Selection occurs on touch up. Primary actions always occur on pointer up.
|
|
244
|
+
// Both primary and secondary actions occur on Enter key up. The only exception
|
|
245
|
+
// is secondary actions, which occur on double click with a mouse.
|
|
246
|
+
if (
|
|
247
|
+
e.pointerType === 'touch' ||
|
|
248
|
+
e.pointerType === 'pen' ||
|
|
249
|
+
e.pointerType === 'virtual' ||
|
|
250
|
+
(e.pointerType === 'keyboard' && hasAction && isActionKey()) ||
|
|
251
|
+
(e.pointerType === 'mouse' && hadPrimaryActionOnPressStart.current)
|
|
252
|
+
) {
|
|
253
|
+
if (hasAction) {
|
|
199
254
|
onAction();
|
|
200
255
|
} else {
|
|
201
256
|
onSelect(e);
|
|
@@ -223,9 +278,8 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
223
278
|
// Long pressing an item with touch when selectionBehavior = 'replace' switches the selection behavior
|
|
224
279
|
// to 'toggle'. This changes the single tap behavior from performing an action (i.e. navigating) to
|
|
225
280
|
// selecting, and may toggle the appearance of a UI affordance like checkboxes on each item.
|
|
226
|
-
// TODO: what about when drag and drop is also enabled??
|
|
227
281
|
let {longPressProps} = useLongPress({
|
|
228
|
-
isDisabled: !
|
|
282
|
+
isDisabled: !longPressEnabled,
|
|
229
283
|
onLongPress(e) {
|
|
230
284
|
if (e.pointerType === 'touch') {
|
|
231
285
|
onSelect(e);
|
|
@@ -234,20 +288,35 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
234
288
|
}
|
|
235
289
|
});
|
|
236
290
|
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
291
|
+
// Prevent native drag and drop on long press if we also select on long press.
|
|
292
|
+
// Once the user is in selection mode, they can long press again to drag.
|
|
293
|
+
let onDragStart = e => {
|
|
294
|
+
if (modality.current === 'touch' && longPressEnabledOnPressStart.current) {
|
|
295
|
+
e.preventDefault();
|
|
241
296
|
}
|
|
242
|
-
}
|
|
297
|
+
};
|
|
243
298
|
|
|
244
299
|
return {
|
|
245
300
|
itemProps: mergeProps(
|
|
246
301
|
itemProps,
|
|
247
302
|
allowsSelection || hasPrimaryAction ? pressProps : {},
|
|
248
|
-
|
|
249
|
-
{
|
|
303
|
+
longPressEnabled ? longPressProps : {},
|
|
304
|
+
{onDoubleClick, onDragStart}
|
|
250
305
|
),
|
|
251
|
-
isPressed
|
|
306
|
+
isPressed,
|
|
307
|
+
isSelected: manager.isSelected(key),
|
|
308
|
+
isDisabled,
|
|
309
|
+
allowsSelection,
|
|
310
|
+
hasAction
|
|
252
311
|
};
|
|
253
312
|
}
|
|
313
|
+
|
|
314
|
+
function isActionKey() {
|
|
315
|
+
let event = window.event as KeyboardEvent;
|
|
316
|
+
return event?.key === 'Enter';
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function isSelectionKey() {
|
|
320
|
+
let event = window.event as KeyboardEvent;
|
|
321
|
+
return event?.key === ' ' || event?.code === 'Space';
|
|
322
|
+
}
|
package/src/useSelectableList.ts
CHANGED
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {Collection, FocusStrategy, KeyboardDelegate, Node} from '@react-types/shared';
|
|
14
|
-
import {
|
|
13
|
+
import {Collection, DOMAttributes, FocusStrategy, KeyboardDelegate, Node} from '@react-types/shared';
|
|
14
|
+
import {Key, RefObject, useMemo} from 'react';
|
|
15
15
|
import {ListKeyboardDelegate} from './ListKeyboardDelegate';
|
|
16
16
|
import {MultipleSelectionManager} from '@react-stately/selection';
|
|
17
17
|
import {useCollator} from '@react-aria/i18n';
|
|
18
18
|
import {useSelectableCollection} from './useSelectableCollection';
|
|
19
19
|
|
|
20
|
-
interface
|
|
20
|
+
export interface AriaSelectableListOptions {
|
|
21
21
|
/**
|
|
22
22
|
* An interface for reading and updating multiple selection state.
|
|
23
23
|
*/
|
|
@@ -77,17 +77,17 @@ interface SelectableListOptions {
|
|
|
77
77
|
allowsTabNavigation?: boolean
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
interface SelectableListAria {
|
|
80
|
+
export interface SelectableListAria {
|
|
81
81
|
/**
|
|
82
82
|
* Props for the option element.
|
|
83
83
|
*/
|
|
84
|
-
listProps:
|
|
84
|
+
listProps: DOMAttributes
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
88
|
* Handles interactions with a selectable list.
|
|
89
89
|
*/
|
|
90
|
-
export function useSelectableList(props:
|
|
90
|
+
export function useSelectableList(props: AriaSelectableListOptions): SelectableListAria {
|
|
91
91
|
let {
|
|
92
92
|
selectionManager,
|
|
93
93
|
collection,
|
|
@@ -98,7 +98,7 @@ export function useSelectableList(props: SelectableListOptions): SelectableListA
|
|
|
98
98
|
shouldFocusWrap,
|
|
99
99
|
isVirtualized,
|
|
100
100
|
disallowEmptySelection,
|
|
101
|
-
selectOnFocus =
|
|
101
|
+
selectOnFocus = selectionManager.selectionBehavior === 'replace',
|
|
102
102
|
disallowTypeAhead,
|
|
103
103
|
shouldUseVirtualFocus,
|
|
104
104
|
allowsTabNavigation
|
package/src/useTypeSelect.ts
CHANGED
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import {DOMAttributes, KeyboardDelegate} from '@react-types/shared';
|
|
14
|
+
import {Key, KeyboardEvent, useRef} from 'react';
|
|
15
15
|
import {MultipleSelectionManager} from '@react-stately/selection';
|
|
16
16
|
|
|
17
|
-
interface
|
|
17
|
+
export interface AriaTypeSelectOptions {
|
|
18
18
|
/**
|
|
19
19
|
* A delegate that returns collection item keys with respect to visual layout.
|
|
20
20
|
*/
|
|
@@ -29,17 +29,17 @@ interface TypeSelectOptions {
|
|
|
29
29
|
onTypeSelect?: (key: Key) => void
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
interface TypeSelectAria {
|
|
32
|
+
export interface TypeSelectAria {
|
|
33
33
|
/**
|
|
34
34
|
* Props to be spread on the owner of the options.
|
|
35
35
|
*/
|
|
36
|
-
typeSelectProps:
|
|
36
|
+
typeSelectProps: DOMAttributes
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* Handles typeahead interactions with collections.
|
|
41
41
|
*/
|
|
42
|
-
export function useTypeSelect(options:
|
|
42
|
+
export function useTypeSelect(options: AriaTypeSelectOptions): TypeSelectAria {
|
|
43
43
|
let {keyboardDelegate, selectionManager, onTypeSelect} = options;
|
|
44
44
|
let state = useRef({
|
|
45
45
|
search: '',
|