@react-aria/selection 3.0.0-nightly.2962 → 3.0.0-nightly.2969
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/DOMLayoutDelegate.main.js +53 -0
- package/dist/DOMLayoutDelegate.main.js.map +1 -0
- package/dist/DOMLayoutDelegate.mjs +48 -0
- package/dist/DOMLayoutDelegate.module.js +48 -0
- package/dist/DOMLayoutDelegate.module.js.map +1 -0
- package/dist/ListKeyboardDelegate.main.js +27 -38
- package/dist/ListKeyboardDelegate.main.js.map +1 -1
- package/dist/ListKeyboardDelegate.mjs +27 -38
- package/dist/ListKeyboardDelegate.module.js +27 -38
- package/dist/ListKeyboardDelegate.module.js.map +1 -1
- package/dist/import.mjs +3 -1
- package/dist/main.js +3 -0
- package/dist/main.js.map +1 -1
- package/dist/module.js +3 -1
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +19 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/useSelectableCollection.main.js.map +1 -1
- package/dist/useSelectableCollection.module.js.map +1 -1
- package/dist/useSelectableItem.main.js.map +1 -1
- package/dist/useSelectableItem.module.js.map +1 -1
- package/dist/useSelectableList.main.js +4 -2
- package/dist/useSelectableList.main.js.map +1 -1
- package/dist/useSelectableList.mjs +4 -2
- package/dist/useSelectableList.module.js +4 -2
- package/dist/useSelectableList.module.js.map +1 -1
- package/package.json +10 -10
- package/src/DOMLayoutDelegate.ts +58 -0
- package/src/ListKeyboardDelegate.ts +36 -47
- package/src/index.ts +1 -0
- package/src/useSelectableCollection.ts +2 -2
- package/src/useSelectableItem.ts +1 -1
- package/src/useSelectableList.ts +12 -4
|
@@ -10,32 +10,35 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {Collection, Direction, DisabledBehavior, Key, KeyboardDelegate, Node, Orientation} from '@react-types/shared';
|
|
13
|
+
import {Collection, Direction, DisabledBehavior, Key, KeyboardDelegate, LayoutDelegate, Node, Orientation, Rect} from '@react-types/shared';
|
|
14
|
+
import {DOMLayoutDelegate} from './DOMLayoutDelegate';
|
|
14
15
|
import {isScrollable} from '@react-aria/utils';
|
|
15
16
|
import {RefObject} from 'react';
|
|
16
17
|
|
|
17
18
|
interface ListKeyboardDelegateOptions<T> {
|
|
18
19
|
collection: Collection<Node<T>>,
|
|
19
|
-
ref: RefObject<HTMLElement>,
|
|
20
|
+
ref: RefObject<HTMLElement | null>,
|
|
20
21
|
collator?: Intl.Collator,
|
|
21
22
|
layout?: 'stack' | 'grid',
|
|
22
23
|
orientation?: Orientation,
|
|
23
24
|
direction?: Direction,
|
|
24
25
|
disabledKeys?: Set<Key>,
|
|
25
|
-
disabledBehavior?: DisabledBehavior
|
|
26
|
+
disabledBehavior?: DisabledBehavior,
|
|
27
|
+
layoutDelegate?: LayoutDelegate
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
export class ListKeyboardDelegate<T> implements KeyboardDelegate {
|
|
29
31
|
private collection: Collection<Node<T>>;
|
|
30
32
|
private disabledKeys: Set<Key>;
|
|
31
33
|
private disabledBehavior: DisabledBehavior;
|
|
32
|
-
private ref: RefObject<HTMLElement>;
|
|
34
|
+
private ref: RefObject<HTMLElement | null>;
|
|
33
35
|
private collator: Intl.Collator | undefined;
|
|
34
36
|
private layout: 'stack' | 'grid';
|
|
35
37
|
private orientation?: Orientation;
|
|
36
38
|
private direction?: Direction;
|
|
39
|
+
private layoutDelegate: LayoutDelegate;
|
|
37
40
|
|
|
38
|
-
constructor(collection: Collection<Node<T>>, disabledKeys: Set<Key>, ref: RefObject<HTMLElement>, collator?: Intl.Collator);
|
|
41
|
+
constructor(collection: Collection<Node<T>>, disabledKeys: Set<Key>, ref: RefObject<HTMLElement | null>, collator?: Intl.Collator);
|
|
39
42
|
constructor(options: ListKeyboardDelegateOptions<T>);
|
|
40
43
|
constructor(...args: any[]) {
|
|
41
44
|
if (args.length === 1) {
|
|
@@ -48,6 +51,7 @@ export class ListKeyboardDelegate<T> implements KeyboardDelegate {
|
|
|
48
51
|
this.orientation = opts.orientation || 'vertical';
|
|
49
52
|
this.direction = opts.direction;
|
|
50
53
|
this.layout = opts.layout || 'stack';
|
|
54
|
+
this.layoutDelegate = opts.layoutDelegate || new DOMLayoutDelegate(opts.ref);
|
|
51
55
|
} else {
|
|
52
56
|
this.collection = args[0];
|
|
53
57
|
this.disabledKeys = args[1];
|
|
@@ -56,6 +60,7 @@ export class ListKeyboardDelegate<T> implements KeyboardDelegate {
|
|
|
56
60
|
this.layout = 'stack';
|
|
57
61
|
this.orientation = 'vertical';
|
|
58
62
|
this.disabledBehavior = 'all';
|
|
63
|
+
this.layoutDelegate = new DOMLayoutDelegate(this.ref);
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
// If this is a vertical stack, remove the left/right methods completely
|
|
@@ -101,29 +106,29 @@ export class ListKeyboardDelegate<T> implements KeyboardDelegate {
|
|
|
101
106
|
private findKey(
|
|
102
107
|
key: Key,
|
|
103
108
|
nextKey: (key: Key) => Key,
|
|
104
|
-
shouldSkip: (prevRect:
|
|
109
|
+
shouldSkip: (prevRect: Rect, itemRect: Rect) => boolean
|
|
105
110
|
) {
|
|
106
|
-
let
|
|
107
|
-
if (!
|
|
111
|
+
let itemRect = this.layoutDelegate.getItemRect(key);
|
|
112
|
+
if (!itemRect) {
|
|
108
113
|
return null;
|
|
109
114
|
}
|
|
110
115
|
|
|
111
116
|
// Find the item above or below in the same column.
|
|
112
|
-
let prevRect =
|
|
117
|
+
let prevRect = itemRect;
|
|
113
118
|
do {
|
|
114
119
|
key = nextKey(key);
|
|
115
|
-
|
|
116
|
-
} while (
|
|
120
|
+
itemRect = this.layoutDelegate.getItemRect(key);
|
|
121
|
+
} while (itemRect && shouldSkip(prevRect, itemRect));
|
|
117
122
|
|
|
118
123
|
return key;
|
|
119
124
|
}
|
|
120
125
|
|
|
121
|
-
private isSameRow(prevRect:
|
|
122
|
-
return prevRect.
|
|
126
|
+
private isSameRow(prevRect: Rect, itemRect: Rect) {
|
|
127
|
+
return prevRect.y === itemRect.y || prevRect.x !== itemRect.x;
|
|
123
128
|
}
|
|
124
129
|
|
|
125
|
-
private isSameColumn(prevRect:
|
|
126
|
-
return prevRect.
|
|
130
|
+
private isSameColumn(prevRect: Rect, itemRect: Rect) {
|
|
131
|
+
return prevRect.x === itemRect.x || prevRect.y !== itemRect.y;
|
|
127
132
|
}
|
|
128
133
|
|
|
129
134
|
getKeyBelow(key: Key) {
|
|
@@ -202,14 +207,10 @@ export class ListKeyboardDelegate<T> implements KeyboardDelegate {
|
|
|
202
207
|
return null;
|
|
203
208
|
}
|
|
204
209
|
|
|
205
|
-
private getItem(key: Key): HTMLElement {
|
|
206
|
-
return key !== null ? this.ref.current.querySelector(`[data-key="${CSS.escape(key.toString())}"]`) : null;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
210
|
getKeyPageAbove(key: Key) {
|
|
210
211
|
let menu = this.ref.current;
|
|
211
|
-
let
|
|
212
|
-
if (!
|
|
212
|
+
let itemRect = this.layoutDelegate.getItemRect(key);
|
|
213
|
+
if (!itemRect) {
|
|
213
214
|
return null;
|
|
214
215
|
}
|
|
215
216
|
|
|
@@ -217,25 +218,19 @@ export class ListKeyboardDelegate<T> implements KeyboardDelegate {
|
|
|
217
218
|
return this.getFirstKey();
|
|
218
219
|
}
|
|
219
220
|
|
|
220
|
-
let containerRect = menu.getBoundingClientRect();
|
|
221
|
-
let itemRect = item.getBoundingClientRect();
|
|
222
221
|
if (this.orientation === 'horizontal') {
|
|
223
|
-
let
|
|
224
|
-
let pageX = Math.max(0, (itemRect.x - containerX) + itemRect.width - containerRect.width);
|
|
222
|
+
let pageX = Math.max(0, itemRect.x + itemRect.width - this.layoutDelegate.getVisibleRect().width);
|
|
225
223
|
|
|
226
|
-
while (
|
|
224
|
+
while (itemRect && itemRect.x > pageX) {
|
|
227
225
|
key = this.getKeyAbove(key);
|
|
228
|
-
|
|
229
|
-
itemRect = item?.getBoundingClientRect();
|
|
226
|
+
itemRect = key == null ? null : this.layoutDelegate.getItemRect(key);
|
|
230
227
|
}
|
|
231
228
|
} else {
|
|
232
|
-
let
|
|
233
|
-
let pageY = Math.max(0, (itemRect.y - containerY) + itemRect.height - containerRect.height);
|
|
229
|
+
let pageY = Math.max(0, itemRect.y + itemRect.height - this.layoutDelegate.getVisibleRect().height);
|
|
234
230
|
|
|
235
|
-
while (
|
|
231
|
+
while (itemRect && itemRect.y > pageY) {
|
|
236
232
|
key = this.getKeyAbove(key);
|
|
237
|
-
|
|
238
|
-
itemRect = item?.getBoundingClientRect();
|
|
233
|
+
itemRect = key == null ? null : this.layoutDelegate.getItemRect(key);
|
|
239
234
|
}
|
|
240
235
|
}
|
|
241
236
|
|
|
@@ -244,8 +239,8 @@ export class ListKeyboardDelegate<T> implements KeyboardDelegate {
|
|
|
244
239
|
|
|
245
240
|
getKeyPageBelow(key: Key) {
|
|
246
241
|
let menu = this.ref.current;
|
|
247
|
-
let
|
|
248
|
-
if (!
|
|
242
|
+
let itemRect = this.layoutDelegate.getItemRect(key);
|
|
243
|
+
if (!itemRect) {
|
|
249
244
|
return null;
|
|
250
245
|
}
|
|
251
246
|
|
|
@@ -253,25 +248,19 @@ export class ListKeyboardDelegate<T> implements KeyboardDelegate {
|
|
|
253
248
|
return this.getLastKey();
|
|
254
249
|
}
|
|
255
250
|
|
|
256
|
-
let containerRect = menu.getBoundingClientRect();
|
|
257
|
-
let itemRect = item.getBoundingClientRect();
|
|
258
251
|
if (this.orientation === 'horizontal') {
|
|
259
|
-
let
|
|
260
|
-
let pageX = Math.min(menu.scrollWidth, (itemRect.x - containerX) - itemRect.width + containerRect.width);
|
|
252
|
+
let pageX = Math.min(this.layoutDelegate.getContentSize().width, itemRect.y - itemRect.width + this.layoutDelegate.getVisibleRect().width);
|
|
261
253
|
|
|
262
|
-
while (
|
|
254
|
+
while (itemRect && itemRect.x < pageX) {
|
|
263
255
|
key = this.getKeyBelow(key);
|
|
264
|
-
|
|
265
|
-
itemRect = item?.getBoundingClientRect();
|
|
256
|
+
itemRect = key == null ? null : this.layoutDelegate.getItemRect(key);
|
|
266
257
|
}
|
|
267
258
|
} else {
|
|
268
|
-
let
|
|
269
|
-
let pageY = Math.min(menu.scrollHeight, (itemRect.y - containerY) - itemRect.height + containerRect.height);
|
|
259
|
+
let pageY = Math.min(this.layoutDelegate.getContentSize().height, itemRect.y - itemRect.height + this.layoutDelegate.getVisibleRect().height);
|
|
270
260
|
|
|
271
|
-
while (
|
|
261
|
+
while (itemRect && itemRect.y < pageY) {
|
|
272
262
|
key = this.getKeyBelow(key);
|
|
273
|
-
|
|
274
|
-
itemRect = item?.getBoundingClientRect();
|
|
263
|
+
itemRect = key == null ? null : this.layoutDelegate.getItemRect(key);
|
|
275
264
|
}
|
|
276
265
|
}
|
|
277
266
|
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export {useSelectableCollection} from './useSelectableCollection';
|
|
|
14
14
|
export {useSelectableItem} from './useSelectableItem';
|
|
15
15
|
export {useSelectableList} from './useSelectableList';
|
|
16
16
|
export {ListKeyboardDelegate} from './ListKeyboardDelegate';
|
|
17
|
+
export {DOMLayoutDelegate} from './DOMLayoutDelegate';
|
|
17
18
|
export {useTypeSelect} from './useTypeSelect';
|
|
18
19
|
|
|
19
20
|
export type {AriaSelectableCollectionOptions, SelectableCollectionAria} from './useSelectableCollection';
|
|
@@ -33,7 +33,7 @@ export interface AriaSelectableCollectionOptions {
|
|
|
33
33
|
/**
|
|
34
34
|
* The ref attached to the element representing the collection.
|
|
35
35
|
*/
|
|
36
|
-
ref: RefObject<HTMLElement>,
|
|
36
|
+
ref: RefObject<HTMLElement | null>,
|
|
37
37
|
/**
|
|
38
38
|
* Whether the collection or one of its items should be automatically focused upon render.
|
|
39
39
|
* @default false
|
|
@@ -80,7 +80,7 @@ export interface AriaSelectableCollectionOptions {
|
|
|
80
80
|
* The ref attached to the scrollable body. Used to provide automatic scrolling on item focus for non-virtualized collections.
|
|
81
81
|
* If not provided, defaults to the collection ref.
|
|
82
82
|
*/
|
|
83
|
-
scrollRef?: RefObject<HTMLElement>,
|
|
83
|
+
scrollRef?: RefObject<HTMLElement | null>,
|
|
84
84
|
/**
|
|
85
85
|
* The behavior of links in the collection.
|
|
86
86
|
* - 'action': link behaves like onAction.
|
package/src/useSelectableItem.ts
CHANGED
|
@@ -30,7 +30,7 @@ export interface SelectableItemOptions {
|
|
|
30
30
|
/**
|
|
31
31
|
* Ref to the item.
|
|
32
32
|
*/
|
|
33
|
-
ref: RefObject<FocusableElement>,
|
|
33
|
+
ref: RefObject<FocusableElement | null>,
|
|
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).
|
package/src/useSelectableList.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import {AriaSelectableCollectionOptions, useSelectableCollection} from './useSelectableCollection';
|
|
14
|
-
import {Collection, DOMAttributes, Key, KeyboardDelegate, Node} from '@react-types/shared';
|
|
14
|
+
import {Collection, DOMAttributes, Key, KeyboardDelegate, LayoutDelegate, Node} from '@react-types/shared';
|
|
15
15
|
import {ListKeyboardDelegate} from './ListKeyboardDelegate';
|
|
16
16
|
import {useCollator} from '@react-aria/i18n';
|
|
17
17
|
import {useMemo} from 'react';
|
|
@@ -25,6 +25,12 @@ export interface AriaSelectableListOptions extends Omit<AriaSelectableCollection
|
|
|
25
25
|
* A delegate object that implements behavior for keyboard focus movement.
|
|
26
26
|
*/
|
|
27
27
|
keyboardDelegate?: KeyboardDelegate,
|
|
28
|
+
/**
|
|
29
|
+
* A delegate object that provides layout information for items in the collection.
|
|
30
|
+
* By default this uses the DOM, but this can be overridden to implement things like
|
|
31
|
+
* virtualized scrolling.
|
|
32
|
+
*/
|
|
33
|
+
layoutDelegate?: LayoutDelegate,
|
|
28
34
|
/**
|
|
29
35
|
* The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with.
|
|
30
36
|
*/
|
|
@@ -47,7 +53,8 @@ export function useSelectableList(props: AriaSelectableListOptions): SelectableL
|
|
|
47
53
|
collection,
|
|
48
54
|
disabledKeys,
|
|
49
55
|
ref,
|
|
50
|
-
keyboardDelegate
|
|
56
|
+
keyboardDelegate,
|
|
57
|
+
layoutDelegate
|
|
51
58
|
} = props;
|
|
52
59
|
|
|
53
60
|
// By default, a KeyboardDelegate is provided which uses the DOM to query layout information (e.g. for page up/page down).
|
|
@@ -60,9 +67,10 @@ export function useSelectableList(props: AriaSelectableListOptions): SelectableL
|
|
|
60
67
|
disabledKeys,
|
|
61
68
|
disabledBehavior,
|
|
62
69
|
ref,
|
|
63
|
-
collator
|
|
70
|
+
collator,
|
|
71
|
+
layoutDelegate
|
|
64
72
|
})
|
|
65
|
-
), [keyboardDelegate, collection, disabledKeys, ref, collator, disabledBehavior]);
|
|
73
|
+
), [keyboardDelegate, layoutDelegate, collection, disabledKeys, ref, collator, disabledBehavior]);
|
|
66
74
|
|
|
67
75
|
let {collectionProps} = useSelectableCollection({
|
|
68
76
|
...props,
|