react-aria-components 1.8.0 → 1.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/Autocomplete.main.js.map +1 -1
- package/dist/Autocomplete.module.js.map +1 -1
- package/dist/Checkbox.main.js +4 -1
- package/dist/Checkbox.main.js.map +1 -1
- package/dist/Checkbox.mjs +5 -2
- package/dist/Checkbox.module.js +5 -2
- package/dist/Checkbox.module.js.map +1 -1
- package/dist/Collection.main.js +31 -7
- package/dist/Collection.main.js.map +1 -1
- package/dist/Collection.mjs +32 -9
- package/dist/Collection.module.js +32 -9
- package/dist/Collection.module.js.map +1 -1
- package/dist/ColorPicker.main.js.map +1 -1
- package/dist/ColorPicker.module.js.map +1 -1
- package/dist/ComboBox.main.js +10 -1
- package/dist/ComboBox.main.js.map +1 -1
- package/dist/ComboBox.mjs +10 -1
- package/dist/ComboBox.module.js +10 -1
- package/dist/ComboBox.module.js.map +1 -1
- package/dist/DatePicker.main.js +11 -2
- package/dist/DatePicker.main.js.map +1 -1
- package/dist/DatePicker.mjs +11 -2
- package/dist/DatePicker.module.js +11 -2
- package/dist/DatePicker.module.js.map +1 -1
- package/dist/Dialog.main.js +15 -1
- package/dist/Dialog.main.js.map +1 -1
- package/dist/Dialog.mjs +17 -3
- package/dist/Dialog.module.js +17 -3
- package/dist/Dialog.module.js.map +1 -1
- package/dist/DragAndDrop.main.js.map +1 -1
- package/dist/DragAndDrop.module.js.map +1 -1
- package/dist/GridList.main.js +59 -4
- package/dist/GridList.main.js.map +1 -1
- package/dist/GridList.mjs +60 -6
- package/dist/GridList.module.js +60 -6
- package/dist/GridList.module.js.map +1 -1
- package/dist/ListBox.main.js +61 -3
- package/dist/ListBox.main.js.map +1 -1
- package/dist/ListBox.mjs +62 -5
- package/dist/ListBox.module.js +62 -5
- package/dist/ListBox.module.js.map +1 -1
- package/dist/Menu.main.js.map +1 -1
- package/dist/Menu.module.js.map +1 -1
- package/dist/Popover.main.js +12 -2
- package/dist/Popover.main.js.map +1 -1
- package/dist/Popover.mjs +13 -3
- package/dist/Popover.module.js +13 -3
- package/dist/Popover.module.js.map +1 -1
- package/dist/RadioGroup.main.js +4 -1
- package/dist/RadioGroup.main.js.map +1 -1
- package/dist/RadioGroup.mjs +5 -2
- package/dist/RadioGroup.module.js +5 -2
- package/dist/RadioGroup.module.js.map +1 -1
- package/dist/Select.main.js +10 -2
- package/dist/Select.main.js.map +1 -1
- package/dist/Select.mjs +10 -2
- package/dist/Select.module.js +10 -2
- package/dist/Select.module.js.map +1 -1
- package/dist/Table.main.js +42 -10
- package/dist/Table.main.js.map +1 -1
- package/dist/Table.mjs +43 -11
- package/dist/Table.module.js +43 -11
- package/dist/Table.module.js.map +1 -1
- package/dist/TagGroup.main.js +1 -1
- package/dist/TagGroup.main.js.map +1 -1
- package/dist/TagGroup.mjs +1 -1
- package/dist/TagGroup.module.js +1 -1
- package/dist/TagGroup.module.js.map +1 -1
- package/dist/Tooltip.main.js.map +1 -1
- package/dist/Tooltip.module.js.map +1 -1
- package/dist/Tree.main.js +296 -18
- package/dist/Tree.main.js.map +1 -1
- package/dist/Tree.mjs +299 -21
- package/dist/Tree.module.js +299 -21
- package/dist/Tree.module.js.map +1 -1
- package/dist/TreeDropTargetDelegate.main.js +213 -0
- package/dist/TreeDropTargetDelegate.main.js.map +1 -0
- package/dist/TreeDropTargetDelegate.mjs +208 -0
- package/dist/TreeDropTargetDelegate.module.js +208 -0
- package/dist/TreeDropTargetDelegate.module.js.map +1 -0
- package/dist/Virtualizer.main.js +8 -10
- package/dist/Virtualizer.main.js.map +1 -1
- package/dist/Virtualizer.mjs +9 -11
- package/dist/Virtualizer.module.js +9 -11
- package/dist/Virtualizer.module.js.map +1 -1
- package/dist/import.mjs +5 -5
- package/dist/main.js +4 -1
- package/dist/main.js.map +1 -1
- package/dist/module.js +5 -5
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +115 -50
- package/dist/types.d.ts.map +1 -1
- package/dist/useDragAndDrop.main.js +2 -2
- package/dist/useDragAndDrop.main.js.map +1 -1
- package/dist/useDragAndDrop.mjs +2 -2
- package/dist/useDragAndDrop.module.js +2 -2
- package/dist/useDragAndDrop.module.js.map +1 -1
- package/package.json +32 -28
- package/src/Autocomplete.tsx +2 -2
- package/src/Checkbox.tsx +2 -2
- package/src/Collection.tsx +39 -5
- package/src/ColorPicker.tsx +2 -2
- package/src/ComboBox.tsx +5 -1
- package/src/DatePicker.tsx +7 -2
- package/src/Dialog.tsx +18 -4
- package/src/DragAndDrop.tsx +1 -1
- package/src/GridList.tsx +69 -7
- package/src/ListBox.tsx +70 -6
- package/src/Menu.tsx +2 -1
- package/src/Popover.tsx +21 -5
- package/src/RadioGroup.tsx +2 -2
- package/src/Select.tsx +13 -3
- package/src/Table.tsx +44 -16
- package/src/TagGroup.tsx +1 -1
- package/src/Tooltip.tsx +2 -2
- package/src/Tree.tsx +364 -38
- package/src/TreeDropTargetDelegate.ts +304 -0
- package/src/Virtualizer.tsx +9 -14
- package/src/index.ts +8 -7
- package/src/useDragAndDrop.tsx +2 -1
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import {Direction, DropTarget, DropTargetDelegate, ItemDropTarget, Key, Node, RootDropTarget} from '@react-types/shared';
|
|
2
|
+
|
|
3
|
+
interface TreeCollection<T> extends Iterable<Node<T>> {
|
|
4
|
+
getItem(key: Key): Node<T> | null,
|
|
5
|
+
getChildren?(key: Key): Iterable<Node<T>>,
|
|
6
|
+
getKeyAfter(key: Key): Key | null,
|
|
7
|
+
getKeyBefore(key: Key): Key | null
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface TreeState<T> {
|
|
11
|
+
collection: TreeCollection<T>,
|
|
12
|
+
expandedKeys: Set<Key>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface PointerTracking {
|
|
16
|
+
lastY: number,
|
|
17
|
+
lastX: number,
|
|
18
|
+
yDirection: 'up' | 'down' | null,
|
|
19
|
+
xDirection: 'left' | 'right' | null,
|
|
20
|
+
boundaryContext: {
|
|
21
|
+
parentKey: Key,
|
|
22
|
+
lastSwitchY: number,
|
|
23
|
+
lastSwitchX: number,
|
|
24
|
+
preferredTargetIndex?: number
|
|
25
|
+
} | null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const X_SWITCH_THRESHOLD = 10;
|
|
29
|
+
const Y_SWITCH_THRESHOLD = 5;
|
|
30
|
+
export class TreeDropTargetDelegate<T> {
|
|
31
|
+
private delegate: DropTargetDelegate | null = null;
|
|
32
|
+
private state: TreeState<T> | null = null;
|
|
33
|
+
private direction: Direction = 'ltr';
|
|
34
|
+
private pointerTracking: PointerTracking = {
|
|
35
|
+
lastY: 0,
|
|
36
|
+
lastX: 0,
|
|
37
|
+
yDirection: null,
|
|
38
|
+
xDirection: null,
|
|
39
|
+
boundaryContext: null
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
setup(delegate: DropTargetDelegate, state: TreeState<T>, direction: Direction): void {
|
|
43
|
+
this.delegate = delegate;
|
|
44
|
+
this.state = state;
|
|
45
|
+
this.direction = direction;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getDropTargetFromPoint(x: number, y: number, isValidDropTarget: (target: DropTarget) => boolean): DropTarget | null {
|
|
49
|
+
let baseTarget = this.delegate!.getDropTargetFromPoint(x, y, isValidDropTarget);
|
|
50
|
+
if (!baseTarget || baseTarget.type === 'root') {
|
|
51
|
+
return baseTarget;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return this.resolveDropTarget(baseTarget, x, y, isValidDropTarget);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private resolveDropTarget(
|
|
58
|
+
target: ItemDropTarget,
|
|
59
|
+
x: number,
|
|
60
|
+
y: number,
|
|
61
|
+
isValidDropTarget: (target: DropTarget) => boolean
|
|
62
|
+
): RootDropTarget | ItemDropTarget | null {
|
|
63
|
+
let tracking = this.pointerTracking;
|
|
64
|
+
|
|
65
|
+
// Calculate movement directions
|
|
66
|
+
let deltaY = y - tracking.lastY;
|
|
67
|
+
let deltaX = x - tracking.lastX;
|
|
68
|
+
let currentYMovement: 'up' | 'down' | null = tracking.yDirection;
|
|
69
|
+
let currentXMovement: 'left' | 'right' | null = tracking.xDirection;
|
|
70
|
+
|
|
71
|
+
if (Math.abs(deltaY) > Y_SWITCH_THRESHOLD) {
|
|
72
|
+
currentYMovement = deltaY > 0 ? 'down' : 'up';
|
|
73
|
+
tracking.yDirection = currentYMovement;
|
|
74
|
+
tracking.lastY = y;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (Math.abs(deltaX) > X_SWITCH_THRESHOLD) {
|
|
78
|
+
currentXMovement = deltaX > 0 ? 'right' : 'left';
|
|
79
|
+
tracking.xDirection = currentXMovement;
|
|
80
|
+
tracking.lastX = x;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Normalize to 'after'
|
|
84
|
+
if (target.dropPosition === 'before') {
|
|
85
|
+
let keyBefore = this.state!.collection.getKeyBefore(target.key);
|
|
86
|
+
if (keyBefore != null) {
|
|
87
|
+
target = {
|
|
88
|
+
type: 'item',
|
|
89
|
+
key: keyBefore,
|
|
90
|
+
dropPosition: 'after'
|
|
91
|
+
} as const;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let potentialTargets = this.getPotentialTargets(target, isValidDropTarget);
|
|
96
|
+
|
|
97
|
+
if (potentialTargets.length === 0) {
|
|
98
|
+
return {type: 'root'};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let resolvedItemTarget: ItemDropTarget;
|
|
102
|
+
if (potentialTargets.length > 1) {
|
|
103
|
+
resolvedItemTarget = this.selectTarget(potentialTargets, target, x, y, currentYMovement, currentXMovement);
|
|
104
|
+
} else {
|
|
105
|
+
resolvedItemTarget = potentialTargets[0];
|
|
106
|
+
// Reset boundary context since we're not in a boundary case
|
|
107
|
+
tracking.boundaryContext = null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return resolvedItemTarget;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Returns potential targets for an ambiguous drop position (e.g. after the last child of a parent, or after the parent itself)
|
|
114
|
+
// Ordered by level, from innermost to outermost.
|
|
115
|
+
private getPotentialTargets(originalTarget: ItemDropTarget, isValidDropTarget: (target: DropTarget) => boolean): ItemDropTarget[] {
|
|
116
|
+
if (originalTarget.dropPosition === 'on') {
|
|
117
|
+
return [originalTarget];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let target = originalTarget;
|
|
121
|
+
let collection = this.state!.collection;
|
|
122
|
+
|
|
123
|
+
let currentItem = collection.getItem(target.key);
|
|
124
|
+
while (currentItem && currentItem?.type !== 'item' && currentItem.nextKey != null) {
|
|
125
|
+
target.key = currentItem.nextKey;
|
|
126
|
+
currentItem = collection.getItem(currentItem.nextKey);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let potentialTargets = [target];
|
|
130
|
+
|
|
131
|
+
// If target has children and is expanded, use "before first child"
|
|
132
|
+
if (currentItem && currentItem.hasChildNodes && this.state!.expandedKeys.has(currentItem.key) && collection.getChildren && target.dropPosition === 'after') {
|
|
133
|
+
let firstChildItemNode: Node<T> | null = null;
|
|
134
|
+
for (let child of collection.getChildren(currentItem.key)) {
|
|
135
|
+
if (child.type === 'item') {
|
|
136
|
+
firstChildItemNode = child;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (firstChildItemNode) {
|
|
142
|
+
const beforeFirstChildTarget = {
|
|
143
|
+
type: 'item',
|
|
144
|
+
key: firstChildItemNode.key,
|
|
145
|
+
dropPosition: 'before'
|
|
146
|
+
} as const;
|
|
147
|
+
|
|
148
|
+
if (isValidDropTarget(beforeFirstChildTarget)) {
|
|
149
|
+
return [beforeFirstChildTarget];
|
|
150
|
+
} else {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (currentItem?.nextKey != null) {
|
|
157
|
+
return [originalTarget];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Walk up the parent chain to find ancestors that are the last child at their level
|
|
161
|
+
let parentKey = currentItem?.parentKey;
|
|
162
|
+
let ancestorTargets: ItemDropTarget[] = [];
|
|
163
|
+
|
|
164
|
+
while (parentKey) {
|
|
165
|
+
let parentItem = collection.getItem(parentKey);
|
|
166
|
+
let nextItem = parentItem?.nextKey ? collection.getItem(parentItem.nextKey) : null;
|
|
167
|
+
let isLastChildAtLevel = !nextItem || nextItem.parentKey !== parentKey;
|
|
168
|
+
|
|
169
|
+
if (isLastChildAtLevel) {
|
|
170
|
+
let afterParentTarget = {
|
|
171
|
+
type: 'item',
|
|
172
|
+
key: parentKey,
|
|
173
|
+
dropPosition: 'after'
|
|
174
|
+
} as const;
|
|
175
|
+
|
|
176
|
+
if (isValidDropTarget(afterParentTarget)) {
|
|
177
|
+
ancestorTargets.push(afterParentTarget);
|
|
178
|
+
}
|
|
179
|
+
if (nextItem) {
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
parentKey = parentItem?.parentKey;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (ancestorTargets.length > 0) {
|
|
188
|
+
potentialTargets.push(...ancestorTargets);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Handle converting "after" to "before next" for non-ambiguous cases
|
|
192
|
+
if (potentialTargets.length === 1) {
|
|
193
|
+
let nextKey = collection.getKeyAfter(target.key);
|
|
194
|
+
let nextNode = nextKey ? collection.getItem(nextKey) : null;
|
|
195
|
+
if (nextKey != null && nextNode && currentItem && nextNode.level != null && currentItem.level != null && nextNode.level > currentItem.level) {
|
|
196
|
+
let beforeTarget = {
|
|
197
|
+
type: 'item',
|
|
198
|
+
key: nextKey,
|
|
199
|
+
dropPosition: 'before'
|
|
200
|
+
} as const;
|
|
201
|
+
if (isValidDropTarget(beforeTarget)) {
|
|
202
|
+
return [beforeTarget];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return potentialTargets.filter(isValidDropTarget);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private selectTarget(
|
|
211
|
+
potentialTargets: ItemDropTarget[],
|
|
212
|
+
originalTarget: ItemDropTarget,
|
|
213
|
+
x: number,
|
|
214
|
+
y: number,
|
|
215
|
+
currentYMovement: 'up' | 'down' | null,
|
|
216
|
+
currentXMovement: 'left' | 'right' | null
|
|
217
|
+
): ItemDropTarget {
|
|
218
|
+
if (potentialTargets.length < 2) {
|
|
219
|
+
return potentialTargets[0];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
let tracking = this.pointerTracking;
|
|
223
|
+
let currentItem = this.state!.collection.getItem(originalTarget.key);
|
|
224
|
+
let parentKey = currentItem?.parentKey;
|
|
225
|
+
|
|
226
|
+
if (!parentKey) {
|
|
227
|
+
return potentialTargets[0];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// More than 1 potential target - use Y for initial target, then X for switching levels
|
|
231
|
+
// Initialize boundary context if needed
|
|
232
|
+
if (!tracking.boundaryContext || tracking.boundaryContext.parentKey !== parentKey) {
|
|
233
|
+
// If entering from below, start with outer-most
|
|
234
|
+
let initialTargetIndex = tracking.yDirection === 'up' ? potentialTargets.length - 1 : 0;
|
|
235
|
+
tracking.boundaryContext = {
|
|
236
|
+
parentKey,
|
|
237
|
+
preferredTargetIndex: initialTargetIndex,
|
|
238
|
+
lastSwitchY: y,
|
|
239
|
+
lastSwitchX: x
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let boundaryContext = tracking.boundaryContext;
|
|
244
|
+
let distanceFromLastXSwitch = Math.abs(x - boundaryContext.lastSwitchX);
|
|
245
|
+
let distanceFromLastYSwitch = Math.abs(y - boundaryContext.lastSwitchY);
|
|
246
|
+
|
|
247
|
+
// Switch between targets based on Y movement
|
|
248
|
+
if (distanceFromLastYSwitch > Y_SWITCH_THRESHOLD && currentYMovement) {
|
|
249
|
+
let currentIndex = boundaryContext.preferredTargetIndex || 0;
|
|
250
|
+
|
|
251
|
+
if (currentYMovement === 'down' && currentIndex === 0) {
|
|
252
|
+
// Moving down from inner-most, switch to outer-most
|
|
253
|
+
boundaryContext.preferredTargetIndex = potentialTargets.length - 1;
|
|
254
|
+
} else if (currentYMovement === 'up' && currentIndex === potentialTargets.length - 1) {
|
|
255
|
+
// Moving up from outer-most, switch to inner-most
|
|
256
|
+
boundaryContext.preferredTargetIndex = 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Reset x tracking so that moving diagonally doesn't cause flickering.
|
|
260
|
+
tracking.xDirection = null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// X movement controls level selection
|
|
264
|
+
if (distanceFromLastXSwitch > X_SWITCH_THRESHOLD && currentXMovement) {
|
|
265
|
+
let currentTargetIndex = boundaryContext.preferredTargetIndex || 0;
|
|
266
|
+
|
|
267
|
+
if (currentXMovement === 'left') {
|
|
268
|
+
if (this.direction === 'ltr') {
|
|
269
|
+
// LTR: left = move to higher level in tree (increase index)
|
|
270
|
+
if (currentTargetIndex < potentialTargets.length - 1) {
|
|
271
|
+
boundaryContext.preferredTargetIndex = currentTargetIndex + 1;
|
|
272
|
+
boundaryContext.lastSwitchX = x;
|
|
273
|
+
}
|
|
274
|
+
} else {
|
|
275
|
+
// RTL: left = move to lower level in tree (decrease index)
|
|
276
|
+
if (currentTargetIndex > 0) {
|
|
277
|
+
boundaryContext.preferredTargetIndex = currentTargetIndex - 1;
|
|
278
|
+
boundaryContext.lastSwitchX = x;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
} else if (currentXMovement === 'right') {
|
|
282
|
+
if (this.direction === 'ltr') {
|
|
283
|
+
// LTR: right = move to lower level in tree (decrease index)
|
|
284
|
+
if (currentTargetIndex > 0) {
|
|
285
|
+
boundaryContext.preferredTargetIndex = currentTargetIndex - 1;
|
|
286
|
+
boundaryContext.lastSwitchX = x;
|
|
287
|
+
}
|
|
288
|
+
} else {
|
|
289
|
+
// RTL: right = move to higher level in tree (increase index)
|
|
290
|
+
if (currentTargetIndex < potentialTargets.length - 1) {
|
|
291
|
+
boundaryContext.preferredTargetIndex = currentTargetIndex + 1;
|
|
292
|
+
boundaryContext.lastSwitchX = x;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Reset y tracking so that moving diagonally doesn't cause flickering.
|
|
298
|
+
tracking.yDirection = null;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
let targetIndex = Math.max(0, Math.min(boundaryContext.preferredTargetIndex || 0, potentialTargets.length - 1));
|
|
302
|
+
return potentialTargets[targetIndex];
|
|
303
|
+
}
|
|
304
|
+
}
|
package/src/Virtualizer.tsx
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {CollectionBranchProps, CollectionRenderer, CollectionRendererContext, CollectionRootProps} from './Collection';
|
|
14
|
-
import {
|
|
13
|
+
import {CollectionBranchProps, CollectionRenderer, CollectionRendererContext, CollectionRootProps, renderAfterDropIndicators} from './Collection';
|
|
14
|
+
import {DropTargetDelegate, ItemDropTarget, Node} from '@react-types/shared';
|
|
15
15
|
import {Layout, ReusableView, useVirtualizerState, VirtualizerState} from '@react-stately/virtualizer';
|
|
16
|
-
import React, {createContext, ReactNode, useContext, useMemo} from 'react';
|
|
16
|
+
import React, {createContext, JSX, ReactNode, useContext, useMemo} from 'react';
|
|
17
17
|
import {useScrollView, VirtualizerItem} from '@react-aria/virtualizer';
|
|
18
18
|
|
|
19
19
|
type View = ReusableView<Node<unknown>, ReactNode>;
|
|
@@ -50,7 +50,7 @@ const LayoutContext = createContext<LayoutContextValue | null>(null);
|
|
|
50
50
|
* It supports very large collections by only rendering visible items to the DOM, reusing
|
|
51
51
|
* them as the user scrolls.
|
|
52
52
|
*/
|
|
53
|
-
export function Virtualizer<O>(props: VirtualizerProps<O>):
|
|
53
|
+
export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
|
|
54
54
|
let {children, layout: layoutProp, layoutOptions} = props;
|
|
55
55
|
let layout = useMemo(() => typeof layoutProp === 'function' ? new layoutProp() : layoutProp, [layoutProp]);
|
|
56
56
|
let renderer: CollectionRenderer = useMemo(() => ({
|
|
@@ -102,10 +102,6 @@ function CollectionRoot({collection, persistedKeys, scrollRef, renderDropIndicat
|
|
|
102
102
|
onScrollEnd: state.endScrolling
|
|
103
103
|
}, scrollRef!);
|
|
104
104
|
|
|
105
|
-
if (state.contentSize.area === 0) {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
105
|
return (
|
|
110
106
|
<div {...contentProps}>
|
|
111
107
|
<VirtualizerContext.Provider value={state}>
|
|
@@ -141,13 +137,13 @@ function renderWrapper(
|
|
|
141
137
|
);
|
|
142
138
|
|
|
143
139
|
let {collection, layout} = reusableView.virtualizer;
|
|
144
|
-
let
|
|
145
|
-
if (type === 'item' && renderDropIndicator && layout.getDropTargetLayoutInfo) {
|
|
140
|
+
let node = reusableView.content;
|
|
141
|
+
if (node?.type === 'item' && renderDropIndicator && layout.getDropTargetLayoutInfo) {
|
|
146
142
|
rendered = (
|
|
147
143
|
<React.Fragment key={reusableView.key}>
|
|
148
|
-
{renderDropIndicatorWrapper(parent, reusableView, 'before', renderDropIndicator)}
|
|
144
|
+
{renderDropIndicatorWrapper(parent, reusableView, {type: 'item', key: reusableView.content!.key, dropPosition: 'before'}, renderDropIndicator)}
|
|
149
145
|
{rendered}
|
|
150
|
-
{collection
|
|
146
|
+
{renderAfterDropIndicators(collection, node, target => renderDropIndicatorWrapper(parent, reusableView, target, renderDropIndicator))}
|
|
151
147
|
</React.Fragment>
|
|
152
148
|
);
|
|
153
149
|
}
|
|
@@ -158,10 +154,9 @@ function renderWrapper(
|
|
|
158
154
|
function renderDropIndicatorWrapper(
|
|
159
155
|
parent: View | null,
|
|
160
156
|
reusableView: View,
|
|
161
|
-
|
|
157
|
+
target: ItemDropTarget,
|
|
162
158
|
renderDropIndicator: (target: ItemDropTarget) => ReactNode
|
|
163
159
|
) {
|
|
164
|
-
let target: DropTarget = {type: 'item', key: reusableView.content!.key, dropPosition};
|
|
165
160
|
let indicator = renderDropIndicator(target);
|
|
166
161
|
if (indicator) {
|
|
167
162
|
let layoutInfo = reusableView.virtualizer.layout.getDropTargetLayoutInfo!(target);
|
package/src/index.ts
CHANGED
|
@@ -30,7 +30,7 @@ export {ColorSwatchPicker, ColorSwatchPickerItem, ColorSwatchPickerContext} from
|
|
|
30
30
|
export {ColorThumb} from './ColorThumb';
|
|
31
31
|
export {ColorWheel, ColorWheelTrack, ColorWheelTrackContext, ColorWheelStateContext} from './ColorWheel';
|
|
32
32
|
export {ComboBox, ComboBoxContext, ComboBoxStateContext} from './ComboBox';
|
|
33
|
-
export {composeRenderProps, DEFAULT_SLOT, Provider, useContextProps, useSlottedContext} from './utils';
|
|
33
|
+
export {composeRenderProps, DEFAULT_SLOT, Provider, useContextProps, useRenderProps, useSlottedContext} from './utils';
|
|
34
34
|
export {DateField, DateInput, DateSegment, TimeField, DateFieldContext, TimeFieldContext, DateFieldStateContext, TimeFieldStateContext} from './DateField';
|
|
35
35
|
export {DatePicker, DateRangePicker, DatePickerContext, DateRangePickerContext, DatePickerStateContext, DateRangePickerStateContext} from './DatePicker';
|
|
36
36
|
export {DialogTrigger, Dialog, DialogContext, OverlayTriggerStateContext} from './Dialog';
|
|
@@ -39,7 +39,7 @@ export {DropZone, DropZoneContext} from './DropZone';
|
|
|
39
39
|
export {FieldError, FieldErrorContext} from './FieldError';
|
|
40
40
|
export {FileTrigger} from './FileTrigger';
|
|
41
41
|
export {Form, FormContext} from './Form';
|
|
42
|
-
export {GridList, GridListItem, GridListContext} from './GridList';
|
|
42
|
+
export {UNSTABLE_GridListLoadingSentinel, GridList, GridListItem, GridListContext} from './GridList';
|
|
43
43
|
export {Group, GroupContext} from './Group';
|
|
44
44
|
export {Header, HeaderContext} from './Header';
|
|
45
45
|
export {Heading} from './Heading';
|
|
@@ -49,7 +49,7 @@ export {Collection, createLeafComponent as UNSTABLE_createLeafComponent, createB
|
|
|
49
49
|
export {Keyboard, KeyboardContext} from './Keyboard';
|
|
50
50
|
export {Label, LabelContext} from './Label';
|
|
51
51
|
export {Link, LinkContext} from './Link';
|
|
52
|
-
export {ListBox, ListBoxItem, ListBoxSection, ListBoxContext, ListStateContext} from './ListBox';
|
|
52
|
+
export {UNSTABLE_ListBoxLoadingSentinel, ListBox, ListBoxItem, ListBoxSection, ListBoxContext, ListStateContext} from './ListBox';
|
|
53
53
|
export {Menu, MenuItem, MenuTrigger, MenuSection, MenuContext, MenuStateContext, RootMenuTriggerStateContext, SubmenuTrigger} from './Menu';
|
|
54
54
|
export {Meter, MeterContext} from './Meter';
|
|
55
55
|
export {Modal, ModalOverlay, ModalContext} from './Modal';
|
|
@@ -63,7 +63,7 @@ export {Select, SelectValue, SelectContext, SelectValueContext, SelectStateConte
|
|
|
63
63
|
export {Separator, SeparatorContext} from './Separator';
|
|
64
64
|
export {Slider, SliderOutput, SliderTrack, SliderThumb, SliderContext, SliderOutputContext, SliderTrackContext, SliderStateContext} from './Slider';
|
|
65
65
|
export {Switch, SwitchContext} from './Switch';
|
|
66
|
-
export {
|
|
66
|
+
export {UNSTABLE_TableLoadingSentinel, Table, Row, Cell, Column, ColumnResizer, TableHeader, TableBody, TableContext, ResizableTableContainer, useTableOptions, TableStateContext, TableColumnResizeStateContext} from './Table';
|
|
67
67
|
export {TableLayout} from './TableLayout';
|
|
68
68
|
export {Tabs, TabList, TabPanel, Tab, TabsContext, TabListStateContext} from './Tabs';
|
|
69
69
|
export {TagGroup, TagGroupContext, TagList, TagListContext, Tag} from './TagGroup';
|
|
@@ -141,11 +141,12 @@ export type {TooltipProps, TooltipRenderProps, TooltipTriggerComponentProps} fro
|
|
|
141
141
|
export type {TreeProps, TreeRenderProps, TreeItemProps, TreeItemRenderProps, TreeItemContentProps, TreeItemContentRenderProps} from './Tree';
|
|
142
142
|
export type {DragAndDropHooks, DragAndDropOptions} from './useDragAndDrop';
|
|
143
143
|
export type {DropIndicatorProps, DropIndicatorRenderProps} from './DragAndDrop';
|
|
144
|
-
export type {ContextValue, SlotProps} from './utils';
|
|
144
|
+
export type {ContextValue, RenderProps, SlotProps, StyleRenderProps} from './utils';
|
|
145
145
|
export type {VirtualizerProps} from './Virtualizer';
|
|
146
146
|
|
|
147
147
|
export type {DateValue, DateRange, TimeValue} from 'react-aria';
|
|
148
148
|
export type {DirectoryDropItem, DraggableCollectionEndEvent, DraggableCollectionMoveEvent, DraggableCollectionStartEvent, DragPreviewRenderer, DragTypes, DropItem, DropOperation, DroppableCollectionDropEvent, DroppableCollectionEnterEvent, DroppableCollectionExitEvent, DroppableCollectionInsertDropEvent, DroppableCollectionMoveEvent, DroppableCollectionOnItemDropEvent, DroppableCollectionReorderEvent, DroppableCollectionRootDropEvent, DropPosition, DropTarget, FileDropItem, ItemDropTarget, RootDropTarget, TextDropItem, PressEvent} from 'react-aria';
|
|
149
|
-
export type {Color,
|
|
150
|
-
export type {
|
|
149
|
+
export type {CalendarState, CheckboxGroupState, Color, ColorAreaState, ColorFieldState, ColorFormat, ColorPickerState, ColorSliderState, ColorSpace, ColorWheelState, ComboBoxState, DateFieldState, DatePickerState, DateRangePickerState, DisclosureState, DisclosureGroupState, Key, ListState, NumberFieldState, OverlayTriggerState, QueuedToast, RadioGroupState, RangeCalendarState, RootMenuTriggerState, SearchFieldState, Selection, SelectState, SliderState, SortDescriptor, SortDirection, SelectionMode, TableState, TabListState, TimeFieldState, ToastOptions, ToastState, ToggleGroupState, ToggleState, TooltipTriggerState, TreeState} from 'react-stately';
|
|
150
|
+
export type {AutocompleteState} from '@react-stately/autocomplete';
|
|
151
151
|
export type {ListLayoutOptions, GridLayoutOptions, WaterfallLayoutOptions} from '@react-stately/layout';
|
|
152
|
+
export type {ValidationResult, RouterConfig} from '@react-types/shared';
|
package/src/useDragAndDrop.tsx
CHANGED
|
@@ -104,6 +104,7 @@ export function useDragAndDrop(options: DragAndDropOptions): DragAndDrop {
|
|
|
104
104
|
onInsert,
|
|
105
105
|
onItemDrop,
|
|
106
106
|
onReorder,
|
|
107
|
+
onMove,
|
|
107
108
|
onRootDrop,
|
|
108
109
|
getItems,
|
|
109
110
|
renderDragPreview,
|
|
@@ -112,7 +113,7 @@ export function useDragAndDrop(options: DragAndDropOptions): DragAndDrop {
|
|
|
112
113
|
} = options;
|
|
113
114
|
|
|
114
115
|
let isDraggable = !!getItems;
|
|
115
|
-
let isDroppable = !!(onDrop || onInsert || onItemDrop || onReorder || onRootDrop);
|
|
116
|
+
let isDroppable = !!(onDrop || onInsert || onItemDrop || onReorder || onMove || onRootDrop);
|
|
116
117
|
|
|
117
118
|
let hooks = {} as DragAndDropHooks;
|
|
118
119
|
if (isDraggable) {
|