@react-stately/collections 3.11.0 → 3.12.1
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/LICENSE +201 -0
- package/dist/CollectionBuilder.main.js +33 -20
- package/dist/CollectionBuilder.main.js.map +1 -1
- package/dist/CollectionBuilder.mjs +33 -20
- package/dist/CollectionBuilder.module.js +33 -20
- package/dist/CollectionBuilder.module.js.map +1 -1
- package/dist/Item.main.js.map +1 -1
- package/dist/Item.module.js.map +1 -1
- package/dist/Section.main.js.map +1 -1
- package/dist/Section.module.js.map +1 -1
- package/dist/getChildNodes.main.js +4 -3
- package/dist/getChildNodes.main.js.map +1 -1
- package/dist/getChildNodes.mjs +4 -3
- package/dist/getChildNodes.module.js +4 -3
- package/dist/getChildNodes.module.js.map +1 -1
- package/dist/getItemCount.main.js +5 -4
- package/dist/getItemCount.main.js.map +1 -1
- package/dist/getItemCount.mjs +5 -4
- package/dist/getItemCount.module.js +5 -4
- package/dist/getItemCount.module.js.map +1 -1
- package/dist/types.d.ts +6 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/useCollection.main.js.map +1 -1
- package/dist/useCollection.module.js.map +1 -1
- package/package.json +6 -5
- package/src/CollectionBuilder.ts +35 -27
- package/src/Item.ts +1 -1
- package/src/Section.ts +1 -1
- package/src/getChildNodes.ts +8 -5
- package/src/getItemCount.ts +5 -4
- package/src/types.ts +4 -4
- package/src/useCollection.ts +1 -1
package/src/CollectionBuilder.ts
CHANGED
|
@@ -15,19 +15,23 @@ import {PartialNode} from './types';
|
|
|
15
15
|
import React, {ReactElement} from 'react';
|
|
16
16
|
|
|
17
17
|
interface CollectionBuilderState {
|
|
18
|
-
renderer?: (value: any) => ReactElement
|
|
18
|
+
renderer?: (value: any) => ReactElement | null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface CollectReactElement<T> extends ReactElement {
|
|
22
|
+
getCollectionNode(props: any, context: any): Generator<PartialNode<T>, void, Node<T>[]>
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
export class CollectionBuilder<T extends object> {
|
|
22
26
|
private context?: unknown;
|
|
23
27
|
private cache: WeakMap<T, Node<T>> = new WeakMap();
|
|
24
28
|
|
|
25
|
-
build(props: CollectionBase<T
|
|
29
|
+
build(props: Partial<CollectionBase<T>>, context?: unknown) {
|
|
26
30
|
this.context = context;
|
|
27
31
|
return iterable(() => this.iterateCollection(props));
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
private *iterateCollection(props: CollectionBase<T
|
|
34
|
+
private *iterateCollection(props: Partial<CollectionBase<T>>): Generator<Node<T>> {
|
|
31
35
|
let {children, items} = props;
|
|
32
36
|
|
|
33
37
|
if (React.isValidElement<{children: CollectionElement<T>}>(children) && children.type === React.Fragment) {
|
|
@@ -40,15 +44,20 @@ export class CollectionBuilder<T extends object> {
|
|
|
40
44
|
throw new Error('props.children was a function but props.items is missing');
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
let index = 0;
|
|
48
|
+
for (let item of items) {
|
|
44
49
|
yield* this.getFullNode({
|
|
45
|
-
value: item
|
|
50
|
+
value: item,
|
|
51
|
+
index
|
|
46
52
|
}, {renderer: children});
|
|
53
|
+
index++;
|
|
47
54
|
}
|
|
48
55
|
} else {
|
|
49
56
|
let items: CollectionElement<T>[] = [];
|
|
50
57
|
React.Children.forEach(children, child => {
|
|
51
|
-
|
|
58
|
+
if (child) {
|
|
59
|
+
items.push(child);
|
|
60
|
+
}
|
|
52
61
|
});
|
|
53
62
|
|
|
54
63
|
let index = 0;
|
|
@@ -66,7 +75,7 @@ export class CollectionBuilder<T extends object> {
|
|
|
66
75
|
}
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
private getKey(item: CollectionElement<T
|
|
78
|
+
private getKey(item: NonNullable<CollectionElement<T>>, partialNode: PartialNode<T>, state: CollectionBuilderState, parentKey?: Key | null): Key {
|
|
70
79
|
if (item.key != null) {
|
|
71
80
|
return item.key;
|
|
72
81
|
}
|
|
@@ -94,7 +103,7 @@ export class CollectionBuilder<T extends object> {
|
|
|
94
103
|
};
|
|
95
104
|
}
|
|
96
105
|
|
|
97
|
-
private *getFullNode(partialNode: PartialNode<T
|
|
106
|
+
private *getFullNode(partialNode: PartialNode<T> & {index: number}, state: CollectionBuilderState, parentKey?: Key | null, parentNode?: Node<T>): Generator<Node<T>> {
|
|
98
107
|
if (React.isValidElement<{children: CollectionElement<T>}>(partialNode.element) && partialNode.element.type === React.Fragment) {
|
|
99
108
|
let children: CollectionElement<T>[] = [];
|
|
100
109
|
|
|
@@ -102,7 +111,7 @@ export class CollectionBuilder<T extends object> {
|
|
|
102
111
|
children.push(child);
|
|
103
112
|
});
|
|
104
113
|
|
|
105
|
-
let index = partialNode.index;
|
|
114
|
+
let index = partialNode.index ?? 0;
|
|
106
115
|
|
|
107
116
|
for (const child of children) {
|
|
108
117
|
yield* this.getFullNode({
|
|
@@ -132,23 +141,23 @@ export class CollectionBuilder<T extends object> {
|
|
|
132
141
|
// If there's an element with a getCollectionNode function on its type, then it's a supported component.
|
|
133
142
|
// Call this function to get a partial node, and recursively build a full node from there.
|
|
134
143
|
if (React.isValidElement(element)) {
|
|
135
|
-
let type = element.type as
|
|
144
|
+
let type = element.type as unknown as CollectReactElement<T>;
|
|
136
145
|
if (typeof type !== 'function' && typeof type.getCollectionNode !== 'function') {
|
|
137
|
-
let name =
|
|
146
|
+
let name = element.type;
|
|
138
147
|
throw new Error(`Unknown element <${name}> in collection.`);
|
|
139
148
|
}
|
|
140
149
|
|
|
141
150
|
let childNodes = type.getCollectionNode(element.props, this.context) as Generator<PartialNode<T>, void, Node<T>[]>;
|
|
142
|
-
let index = partialNode.index;
|
|
151
|
+
let index = partialNode.index ?? 0;
|
|
143
152
|
let result = childNodes.next();
|
|
144
153
|
while (!result.done && result.value) {
|
|
145
154
|
let childNode = result.value;
|
|
146
155
|
|
|
147
156
|
partialNode.index = index;
|
|
148
157
|
|
|
149
|
-
let nodeKey = childNode.key;
|
|
150
|
-
if (
|
|
151
|
-
nodeKey = childNode.element ? null : this.getKey(element as CollectionElement<T
|
|
158
|
+
let nodeKey = childNode.key ?? null;
|
|
159
|
+
if (nodeKey == null) {
|
|
160
|
+
nodeKey = childNode.element ? null : this.getKey(element as NonNullable<CollectionElement<T>>, partialNode, state, parentKey);
|
|
152
161
|
}
|
|
153
162
|
|
|
154
163
|
let nodes = this.getFullNode({
|
|
@@ -161,7 +170,7 @@ export class CollectionBuilder<T extends object> {
|
|
|
161
170
|
let children = [...nodes];
|
|
162
171
|
for (let node of children) {
|
|
163
172
|
// Cache the node based on its value
|
|
164
|
-
node.value = childNode.value
|
|
173
|
+
node.value = childNode.value ?? partialNode.value ?? null;
|
|
165
174
|
if (node.value) {
|
|
166
175
|
this.cache.set(node.value, node);
|
|
167
176
|
}
|
|
@@ -169,7 +178,7 @@ export class CollectionBuilder<T extends object> {
|
|
|
169
178
|
// The partial node may have specified a type for the child in order to specify a constraint.
|
|
170
179
|
// Verify that the full node that was built recursively matches this type.
|
|
171
180
|
if (partialNode.type && node.type !== partialNode.type) {
|
|
172
|
-
throw new Error(`Unsupported type <${capitalize(node.type)}> in <${capitalize(parentNode
|
|
181
|
+
throw new Error(`Unsupported type <${capitalize(node.type)}> in <${capitalize(parentNode?.type ?? 'unknown parent type')}>. Only <${capitalize(partialNode.type)}> is supported.`);
|
|
173
182
|
}
|
|
174
183
|
|
|
175
184
|
index++;
|
|
@@ -183,7 +192,7 @@ export class CollectionBuilder<T extends object> {
|
|
|
183
192
|
}
|
|
184
193
|
|
|
185
194
|
// Ignore invalid elements
|
|
186
|
-
if (partialNode.key == null) {
|
|
195
|
+
if (partialNode.key == null || partialNode.type == null) {
|
|
187
196
|
return;
|
|
188
197
|
}
|
|
189
198
|
|
|
@@ -194,17 +203,17 @@ export class CollectionBuilder<T extends object> {
|
|
|
194
203
|
props: partialNode.props,
|
|
195
204
|
key: partialNode.key,
|
|
196
205
|
parentKey: parentNode ? parentNode.key : null,
|
|
197
|
-
value: partialNode.value,
|
|
206
|
+
value: partialNode.value ?? null,
|
|
198
207
|
level: parentNode ? parentNode.level + 1 : 0,
|
|
199
208
|
index: partialNode.index,
|
|
200
209
|
rendered: partialNode.rendered,
|
|
201
|
-
textValue: partialNode.textValue,
|
|
210
|
+
textValue: partialNode.textValue ?? '',
|
|
202
211
|
'aria-label': partialNode['aria-label'],
|
|
203
212
|
wrapper: partialNode.wrapper,
|
|
204
213
|
shouldInvalidate: partialNode.shouldInvalidate,
|
|
205
|
-
hasChildNodes: partialNode.hasChildNodes,
|
|
214
|
+
hasChildNodes: partialNode.hasChildNodes || false,
|
|
206
215
|
childNodes: iterable(function *() {
|
|
207
|
-
if (!partialNode.hasChildNodes) {
|
|
216
|
+
if (!partialNode.hasChildNodes || !partialNode.childNodes) {
|
|
208
217
|
return;
|
|
209
218
|
}
|
|
210
219
|
|
|
@@ -219,8 +228,7 @@ export class CollectionBuilder<T extends object> {
|
|
|
219
228
|
child.key = `${node.key}${child.key}`;
|
|
220
229
|
}
|
|
221
230
|
|
|
222
|
-
child
|
|
223
|
-
let nodes = builder.getFullNode(child, builder.getChildState(state, child), node.key, node);
|
|
231
|
+
let nodes = builder.getFullNode({...child, index}, builder.getChildState(state, child), node.key, node);
|
|
224
232
|
for (let node of nodes) {
|
|
225
233
|
index++;
|
|
226
234
|
yield node;
|
|
@@ -235,8 +243,8 @@ export class CollectionBuilder<T extends object> {
|
|
|
235
243
|
|
|
236
244
|
// Wraps an iterator function as an iterable object, and caches the results.
|
|
237
245
|
function iterable<T>(iterator: () => IterableIterator<Node<T>>): Iterable<Node<T>> {
|
|
238
|
-
let cache = [];
|
|
239
|
-
let iterable = null;
|
|
246
|
+
let cache: Array<Node<T>> = [];
|
|
247
|
+
let iterable: null | IterableIterator<Node<T>> = null;
|
|
240
248
|
return {
|
|
241
249
|
*[Symbol.iterator]() {
|
|
242
250
|
for (let item of cache) {
|
|
@@ -256,7 +264,7 @@ function iterable<T>(iterator: () => IterableIterator<Node<T>>): Iterable<Node<T
|
|
|
256
264
|
}
|
|
257
265
|
|
|
258
266
|
type Wrapper = (element: ReactElement) => ReactElement;
|
|
259
|
-
function compose(outer: Wrapper | void, inner: Wrapper | void): Wrapper {
|
|
267
|
+
function compose(outer: Wrapper | void, inner: Wrapper | void): Wrapper | undefined {
|
|
260
268
|
if (outer && inner) {
|
|
261
269
|
return (element) => outer(inner(element));
|
|
262
270
|
}
|
package/src/Item.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {ItemElement, ItemProps} from '@react-types/shared';
|
|
|
14
14
|
import {PartialNode} from './types';
|
|
15
15
|
import React, {JSX, ReactElement} from 'react';
|
|
16
16
|
|
|
17
|
-
function Item<T>(props: ItemProps<T>): ReactElement { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
17
|
+
function Item<T>(props: ItemProps<T>): ReactElement | null { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
|
package/src/Section.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {PartialNode} from './types';
|
|
|
14
14
|
import React, {JSX, ReactElement} from 'react';
|
|
15
15
|
import {SectionProps} from '@react-types/shared';
|
|
16
16
|
|
|
17
|
-
function Section<T>(props: SectionProps<T>): ReactElement { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
17
|
+
function Section<T>(props: SectionProps<T>): ReactElement | null { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
|
package/src/getChildNodes.ts
CHANGED
|
@@ -42,7 +42,7 @@ export function getNthItem<T>(iterable: Iterable<T>, index: number): T | undefin
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
export function getLastItem<T>(iterable: Iterable<T>): T | undefined {
|
|
45
|
-
let lastItem = undefined;
|
|
45
|
+
let lastItem: T | undefined = undefined;
|
|
46
46
|
for (let value of iterable) {
|
|
47
47
|
lastItem = value;
|
|
48
48
|
}
|
|
@@ -81,11 +81,14 @@ export function compareNodeOrder<T>(collection: Collection<Node<T>>, a: Node<T>,
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
function getAncestors<T>(collection: Collection<Node<T>>, node: Node<T>): Node<T>[] {
|
|
84
|
-
let parents = [];
|
|
84
|
+
let parents: Node<T>[] = [];
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
let currNode: Node<T> | null = node;
|
|
87
|
+
while (currNode?.parentKey != null) {
|
|
88
|
+
currNode = collection.getItem(currNode.parentKey);
|
|
89
|
+
if (currNode) {
|
|
90
|
+
parents.unshift(currNode);
|
|
91
|
+
}
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
return parents;
|
package/src/getItemCount.ts
CHANGED
|
@@ -21,18 +21,19 @@ export function getItemCount<T>(collection: Collection<Node<T>>): number {
|
|
|
21
21
|
return count;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
count
|
|
24
|
+
// TS isn't smart enough to know we've ensured count is a number, so use a new variable
|
|
25
|
+
let counter = 0;
|
|
25
26
|
let countItems = (items: Iterable<Node<T>>) => {
|
|
26
27
|
for (let item of items) {
|
|
27
28
|
if (item.type === 'section') {
|
|
28
29
|
countItems(getChildNodes(item, collection));
|
|
29
30
|
} else {
|
|
30
|
-
|
|
31
|
+
counter++;
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
countItems(collection);
|
|
36
|
-
cache.set(collection,
|
|
37
|
-
return
|
|
37
|
+
cache.set(collection, counter);
|
|
38
|
+
return counter;
|
|
38
39
|
}
|
package/src/types.ts
CHANGED
|
@@ -15,17 +15,17 @@ import {ReactElement, ReactNode} from 'react';
|
|
|
15
15
|
|
|
16
16
|
export interface PartialNode<T> {
|
|
17
17
|
type?: string,
|
|
18
|
-
key?: Key,
|
|
18
|
+
key?: Key | null,
|
|
19
19
|
value?: T,
|
|
20
|
-
element?: ReactElement,
|
|
20
|
+
element?: ReactElement | null,
|
|
21
21
|
wrapper?: (element: ReactElement) => ReactElement,
|
|
22
22
|
rendered?: ReactNode,
|
|
23
23
|
textValue?: string,
|
|
24
24
|
'aria-label'?: string,
|
|
25
25
|
index?: number,
|
|
26
|
-
renderer?: (item: T) => ReactElement,
|
|
26
|
+
renderer?: (item: T) => ReactElement | null,
|
|
27
27
|
hasChildNodes?: boolean,
|
|
28
28
|
childNodes?: () => IterableIterator<PartialNode<T>>,
|
|
29
29
|
props?: any,
|
|
30
|
-
shouldInvalidate?: (context:
|
|
30
|
+
shouldInvalidate?: (context: any) => boolean
|
|
31
31
|
}
|
package/src/useCollection.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {CollectionBuilder} from './CollectionBuilder';
|
|
|
15
15
|
import {ReactElement, useMemo} from 'react';
|
|
16
16
|
|
|
17
17
|
interface CollectionOptions<T, C extends Collection<Node<T>>> extends Omit<CollectionStateBase<T, C>, 'children'> {
|
|
18
|
-
children?: ReactElement<any> | ReactElement<any>[] | ((item: T) => ReactElement<any>)
|
|
18
|
+
children?: ReactElement<any> | null | (ReactElement<any> | null)[] | ((item: T) => ReactElement<any> | null)
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
type CollectionFactory<T, C extends Collection<Node<T>>> = (node: Iterable<Node<T>>) => C;
|