@react-stately/layout 3.0.0-nightly-641446f65-240905

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.
@@ -0,0 +1,356 @@
1
+ import {getChildNodes as $img26$getChildNodes} from "@react-stately/collections";
2
+ import {Rect as $img26$Rect, Size as $img26$Size, LayoutInfo as $img26$LayoutInfo, Point as $img26$Point, Layout as $img26$Layout} from "@react-stately/virtualizer";
3
+
4
+ /*
5
+ * Copyright 2020 Adobe. All rights reserved.
6
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License. You may obtain a copy
8
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software distributed under
11
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
12
+ * OF ANY KIND, either express or implied. See the License for the specific language
13
+ * governing permissions and limitations under the License.
14
+ */
15
+
16
+ const $61ef60fc9b1041f4$var$DEFAULT_HEIGHT = 48;
17
+ class $61ef60fc9b1041f4$export$cacbb3924155d68e extends (0, $img26$Layout) {
18
+ getLayoutInfo(key) {
19
+ var _this_layoutNodes_get;
20
+ this.ensureLayoutInfo(key);
21
+ return ((_this_layoutNodes_get = this.layoutNodes.get(key)) === null || _this_layoutNodes_get === void 0 ? void 0 : _this_layoutNodes_get.layoutInfo) || null;
22
+ }
23
+ getVisibleLayoutInfos(rect) {
24
+ // Adjust rect to keep number of visible rows consistent.
25
+ // (only if height > 1 for getDropTargetFromPoint)
26
+ if (rect.height > 1) {
27
+ var _this_rowHeight;
28
+ let rowHeight = (_this_rowHeight = this.rowHeight) !== null && _this_rowHeight !== void 0 ? _this_rowHeight : this.estimatedRowHeight;
29
+ rect.y = Math.floor(rect.y / rowHeight) * rowHeight;
30
+ rect.height = Math.ceil(rect.height / rowHeight) * rowHeight;
31
+ }
32
+ // If layout hasn't yet been done for the requested rect, union the
33
+ // new rect with the existing valid rect, and recompute.
34
+ this.layoutIfNeeded(rect);
35
+ let res = [];
36
+ let addNodes = (nodes)=>{
37
+ for (let node of nodes)if (this.isVisible(node, rect)) {
38
+ res.push(node.layoutInfo);
39
+ if (node.children) addNodes(node.children);
40
+ }
41
+ };
42
+ addNodes(this.rootNodes);
43
+ return res;
44
+ }
45
+ layoutIfNeeded(rect) {
46
+ if (!this.lastCollection) return;
47
+ if (!this.requestedRect.containsRect(rect)) {
48
+ this.requestedRect = this.requestedRect.union(rect);
49
+ this.rootNodes = this.buildCollection();
50
+ }
51
+ // Ensure all of the persisted keys are available.
52
+ for (let key of this.virtualizer.persistedKeys){
53
+ if (this.ensureLayoutInfo(key)) return;
54
+ }
55
+ }
56
+ ensureLayoutInfo(key) {
57
+ // If the layout info wasn't found, it might be outside the bounds of the area that we've
58
+ // computed layout for so far. This can happen when accessing a random key, e.g pressing Home/End.
59
+ // Compute the full layout and try again.
60
+ if (!this.layoutNodes.has(key) && this.requestedRect.area < this.contentSize.area && this.lastCollection) {
61
+ this.requestedRect = new (0, $img26$Rect)(0, 0, Infinity, Infinity);
62
+ this.rootNodes = this.buildCollection();
63
+ this.requestedRect = new (0, $img26$Rect)(0, 0, this.contentSize.width, this.contentSize.height);
64
+ return true;
65
+ }
66
+ return false;
67
+ }
68
+ isVisible(node, rect) {
69
+ return node.layoutInfo.rect.intersects(rect) || node.layoutInfo.isSticky || node.layoutInfo.type === 'header' || this.virtualizer.isPersistedKey(node.layoutInfo.key);
70
+ }
71
+ shouldInvalidateEverything(invalidationContext) {
72
+ // Invalidate cache if the size of the collection changed.
73
+ // In this case, we need to recalculate the entire layout.
74
+ return invalidationContext.sizeChanged;
75
+ }
76
+ update(invalidationContext) {
77
+ this.collection = this.virtualizer.collection;
78
+ // Reset valid rect if we will have to invalidate everything.
79
+ // Otherwise we can reuse cached layout infos outside the current visible rect.
80
+ this.invalidateEverything = this.shouldInvalidateEverything(invalidationContext);
81
+ if (this.invalidateEverything) {
82
+ this.requestedRect = this.virtualizer.visibleRect.copy();
83
+ this.layoutNodes.clear();
84
+ }
85
+ this.rootNodes = this.buildCollection();
86
+ // Remove deleted layout nodes
87
+ if (this.lastCollection && this.collection !== this.lastCollection) {
88
+ for (let key of this.lastCollection.getKeys())if (!this.collection.getItem(key)) {
89
+ let layoutNode = this.layoutNodes.get(key);
90
+ if (layoutNode) this.layoutNodes.delete(key);
91
+ }
92
+ }
93
+ this.lastWidth = this.virtualizer.visibleRect.width;
94
+ this.lastCollection = this.collection;
95
+ this.invalidateEverything = false;
96
+ this.validRect = this.requestedRect.copy();
97
+ }
98
+ buildCollection(y = 0) {
99
+ let skipped = 0;
100
+ let nodes = [];
101
+ for (let node of this.collection){
102
+ var _this_rowHeight;
103
+ let rowHeight = (_this_rowHeight = this.rowHeight) !== null && _this_rowHeight !== void 0 ? _this_rowHeight : this.estimatedRowHeight;
104
+ // Skip rows before the valid rectangle unless they are already cached.
105
+ if (node.type === 'item' && y + rowHeight < this.requestedRect.y && !this.isValid(node, y)) {
106
+ y += rowHeight;
107
+ skipped++;
108
+ continue;
109
+ }
110
+ let layoutNode = this.buildChild(node, 0, y, null);
111
+ y = layoutNode.layoutInfo.rect.maxY;
112
+ nodes.push(layoutNode);
113
+ if (node.type === 'item' && y > this.requestedRect.maxY) {
114
+ y += (this.collection.size - (nodes.length + skipped)) * rowHeight;
115
+ break;
116
+ }
117
+ }
118
+ this.contentSize = new (0, $img26$Size)(this.virtualizer.visibleRect.width, y);
119
+ return nodes;
120
+ }
121
+ isValid(node, y) {
122
+ let cached = this.layoutNodes.get(node.key);
123
+ return !this.invalidateEverything && cached && cached.node === node && y === cached.layoutInfo.rect.y && cached.layoutInfo.rect.intersects(this.validRect) && cached.validRect.containsRect(cached.layoutInfo.rect.intersection(this.requestedRect));
124
+ }
125
+ buildChild(node, x, y, parentKey) {
126
+ if (this.isValid(node, y)) return this.layoutNodes.get(node.key);
127
+ let layoutNode = this.buildNode(node, x, y);
128
+ layoutNode.layoutInfo.parentKey = parentKey !== null && parentKey !== void 0 ? parentKey : null;
129
+ this.layoutNodes.set(node.key, layoutNode);
130
+ return layoutNode;
131
+ }
132
+ buildNode(node, x, y) {
133
+ switch(node.type){
134
+ case 'section':
135
+ return this.buildSection(node, x, y);
136
+ case 'item':
137
+ return this.buildItem(node, x, y);
138
+ case 'header':
139
+ return this.buildSectionHeader(node, x, y);
140
+ case 'loader':
141
+ return this.buildLoader(node, x, y);
142
+ }
143
+ }
144
+ buildLoader(node, x, y) {
145
+ let rect = new (0, $img26$Rect)(x, y, 0, 0);
146
+ let layoutInfo = new (0, $img26$LayoutInfo)('loader', node.key, rect);
147
+ rect.width = this.virtualizer.contentSize.width;
148
+ rect.height = this.loaderHeight || this.rowHeight || this.estimatedRowHeight;
149
+ return {
150
+ layoutInfo: layoutInfo,
151
+ validRect: rect.intersection(this.requestedRect)
152
+ };
153
+ }
154
+ buildSection(node, x, y) {
155
+ let width = this.virtualizer.visibleRect.width;
156
+ let rect = new (0, $img26$Rect)(0, y, width, 0);
157
+ let layoutInfo = new (0, $img26$LayoutInfo)(node.type, node.key, rect);
158
+ let startY = y;
159
+ let skipped = 0;
160
+ let children = [];
161
+ for (let child of (0, $img26$getChildNodes)(node, this.collection)){
162
+ var _this_rowHeight;
163
+ let rowHeight = (_this_rowHeight = this.rowHeight) !== null && _this_rowHeight !== void 0 ? _this_rowHeight : this.estimatedRowHeight;
164
+ // Skip rows before the valid rectangle unless they are already cached.
165
+ if (y + rowHeight < this.requestedRect.y && !this.isValid(node, y)) {
166
+ y += rowHeight;
167
+ skipped++;
168
+ continue;
169
+ }
170
+ let layoutNode = this.buildChild(child, x, y, layoutInfo.key);
171
+ y = layoutNode.layoutInfo.rect.maxY;
172
+ children.push(layoutNode);
173
+ if (y > this.requestedRect.maxY) {
174
+ // Estimate the remaining height for rows that we don't need to layout right now.
175
+ y += ([
176
+ ...(0, $img26$getChildNodes)(node, this.collection)
177
+ ].length - (children.length + skipped)) * rowHeight;
178
+ break;
179
+ }
180
+ }
181
+ rect.height = y - startY;
182
+ return {
183
+ layoutInfo: layoutInfo,
184
+ children: children,
185
+ validRect: layoutInfo.rect.intersection(this.requestedRect),
186
+ node: node
187
+ };
188
+ }
189
+ buildSectionHeader(node, x, y) {
190
+ let width = this.virtualizer.visibleRect.width;
191
+ let rectHeight = this.headingHeight;
192
+ let isEstimated = false;
193
+ // If no explicit height is available, use an estimated height.
194
+ if (rectHeight == null) {
195
+ // If a previous version of this layout info exists, reuse its height.
196
+ // Mark as estimated if the size of the overall virtualizer changed,
197
+ // or the content of the item changed.
198
+ let previousLayoutNode = this.layoutNodes.get(node.key);
199
+ let previousLayoutInfo = previousLayoutNode === null || previousLayoutNode === void 0 ? void 0 : previousLayoutNode.layoutInfo;
200
+ if (previousLayoutInfo) {
201
+ let curNode = this.collection.getItem(node.key);
202
+ let lastNode = this.lastCollection ? this.lastCollection.getItem(node.key) : null;
203
+ rectHeight = previousLayoutInfo.rect.height;
204
+ isEstimated = width !== this.lastWidth || curNode !== lastNode || previousLayoutInfo.estimatedSize;
205
+ } else {
206
+ rectHeight = node.rendered ? this.estimatedHeadingHeight : 0;
207
+ isEstimated = true;
208
+ }
209
+ }
210
+ if (rectHeight == null) rectHeight = $61ef60fc9b1041f4$var$DEFAULT_HEIGHT;
211
+ let headerRect = new (0, $img26$Rect)(0, y, width, rectHeight);
212
+ let header = new (0, $img26$LayoutInfo)('header', node.key, headerRect);
213
+ header.estimatedSize = isEstimated;
214
+ return {
215
+ layoutInfo: header,
216
+ children: [],
217
+ validRect: header.rect.intersection(this.requestedRect),
218
+ node: node
219
+ };
220
+ }
221
+ buildItem(node, x, y) {
222
+ let width = this.virtualizer.visibleRect.width;
223
+ let rectHeight = this.rowHeight;
224
+ let isEstimated = false;
225
+ // If no explicit height is available, use an estimated height.
226
+ if (rectHeight == null) {
227
+ // If a previous version of this layout info exists, reuse its height.
228
+ // Mark as estimated if the size of the overall virtualizer changed,
229
+ // or the content of the item changed.
230
+ let previousLayoutNode = this.layoutNodes.get(node.key);
231
+ if (previousLayoutNode) {
232
+ rectHeight = previousLayoutNode.layoutInfo.rect.height;
233
+ isEstimated = width !== this.lastWidth || node !== previousLayoutNode.node || previousLayoutNode.layoutInfo.estimatedSize;
234
+ } else {
235
+ rectHeight = this.estimatedRowHeight;
236
+ isEstimated = true;
237
+ }
238
+ }
239
+ if (rectHeight == null) rectHeight = $61ef60fc9b1041f4$var$DEFAULT_HEIGHT;
240
+ let rect = new (0, $img26$Rect)(x, y, width - x, rectHeight);
241
+ let layoutInfo = new (0, $img26$LayoutInfo)(node.type, node.key, rect);
242
+ layoutInfo.estimatedSize = isEstimated;
243
+ return {
244
+ layoutInfo: layoutInfo,
245
+ children: [],
246
+ validRect: layoutInfo.rect,
247
+ node: node
248
+ };
249
+ }
250
+ updateItemSize(key, size) {
251
+ let layoutNode = this.layoutNodes.get(key);
252
+ // If no layoutInfo, item has been deleted/removed.
253
+ if (!layoutNode) return false;
254
+ let layoutInfo = layoutNode.layoutInfo;
255
+ layoutInfo.estimatedSize = false;
256
+ if (layoutInfo.rect.height !== size.height) {
257
+ // Copy layout info rather than mutating so that later caches are invalidated.
258
+ let newLayoutInfo = layoutInfo.copy();
259
+ newLayoutInfo.rect.height = size.height;
260
+ layoutNode.layoutInfo = newLayoutInfo;
261
+ // Items after this layoutInfo will need to be repositioned to account for the new height.
262
+ // Adjust the validRect so that only items above remain valid.
263
+ this.validRect.height = Math.min(this.validRect.height, layoutInfo.rect.y - this.validRect.y);
264
+ // The requestedRect also needs to be adjusted to account for the height difference.
265
+ this.requestedRect.height += newLayoutInfo.rect.height - layoutInfo.rect.height;
266
+ // Invalidate layout for this layout node and all parents
267
+ this.updateLayoutNode(key, layoutInfo, newLayoutInfo);
268
+ let node = this.collection.getItem(layoutInfo.parentKey);
269
+ while(node){
270
+ this.updateLayoutNode(node.key, layoutInfo, newLayoutInfo);
271
+ node = this.collection.getItem(node.parentKey);
272
+ }
273
+ return true;
274
+ }
275
+ return false;
276
+ }
277
+ updateLayoutNode(key, oldLayoutInfo, newLayoutInfo) {
278
+ let n = this.layoutNodes.get(key);
279
+ if (n) {
280
+ // Invalidate by intersecting the validRect of this node with the overall validRect.
281
+ n.validRect = n.validRect.intersection(this.validRect);
282
+ // Replace layout info in LayoutNode
283
+ if (n.layoutInfo === oldLayoutInfo) n.layoutInfo = newLayoutInfo;
284
+ }
285
+ }
286
+ getContentSize() {
287
+ return this.contentSize;
288
+ }
289
+ getDropTargetFromPoint(x, y, isValidDropTarget) {
290
+ x += this.virtualizer.visibleRect.x;
291
+ y += this.virtualizer.visibleRect.y;
292
+ let key = this.virtualizer.keyAtPoint(new (0, $img26$Point)(x, y));
293
+ if (key == null || this.collection.size === 0) return {
294
+ type: 'root'
295
+ };
296
+ let layoutInfo = this.getLayoutInfo(key);
297
+ let rect = layoutInfo.rect;
298
+ let target = {
299
+ type: 'item',
300
+ key: layoutInfo.key,
301
+ dropPosition: 'on'
302
+ };
303
+ // If dropping on the item isn't accepted, try the target before or after depending on the y position.
304
+ // Otherwise, if dropping on the item is accepted, still try the before/after positions if within 10px
305
+ // of the top or bottom of the item.
306
+ if (!isValidDropTarget(target)) {
307
+ if (y <= rect.y + rect.height / 2 && isValidDropTarget({
308
+ ...target,
309
+ dropPosition: 'before'
310
+ })) target.dropPosition = 'before';
311
+ else if (isValidDropTarget({
312
+ ...target,
313
+ dropPosition: 'after'
314
+ })) target.dropPosition = 'after';
315
+ } else if (y <= rect.y + 10 && isValidDropTarget({
316
+ ...target,
317
+ dropPosition: 'before'
318
+ })) target.dropPosition = 'before';
319
+ else if (y >= rect.maxY - 10 && isValidDropTarget({
320
+ ...target,
321
+ dropPosition: 'after'
322
+ })) target.dropPosition = 'after';
323
+ return target;
324
+ }
325
+ getDropTargetLayoutInfo(target) {
326
+ let layoutInfo = this.getLayoutInfo(target.key);
327
+ let rect;
328
+ if (target.dropPosition === 'before') rect = new (0, $img26$Rect)(layoutInfo.rect.x, layoutInfo.rect.y - this.dropIndicatorThickness / 2, layoutInfo.rect.width, this.dropIndicatorThickness);
329
+ else if (target.dropPosition === 'after') rect = new (0, $img26$Rect)(layoutInfo.rect.x, layoutInfo.rect.maxY - this.dropIndicatorThickness / 2, layoutInfo.rect.width, this.dropIndicatorThickness);
330
+ else rect = layoutInfo.rect;
331
+ return new (0, $img26$LayoutInfo)('dropIndicator', target.key + ':' + target.dropPosition, rect);
332
+ }
333
+ /**
334
+ * Creates a new ListLayout with options. See the list of properties below for a description
335
+ * of the options that can be provided.
336
+ */ constructor(options = {}){
337
+ super();
338
+ this.rowHeight = options.rowHeight;
339
+ this.estimatedRowHeight = options.estimatedRowHeight;
340
+ this.headingHeight = options.headingHeight;
341
+ this.estimatedHeadingHeight = options.estimatedHeadingHeight;
342
+ this.loaderHeight = options.loaderHeight;
343
+ this.dropIndicatorThickness = options.dropIndicatorThickness || 2;
344
+ this.layoutNodes = new Map();
345
+ this.rootNodes = [];
346
+ this.lastWidth = 0;
347
+ this.lastCollection = null;
348
+ this.validRect = new (0, $img26$Rect)();
349
+ this.requestedRect = new (0, $img26$Rect)();
350
+ this.contentSize = new (0, $img26$Size)();
351
+ }
352
+ }
353
+
354
+
355
+ export {$61ef60fc9b1041f4$export$cacbb3924155d68e as ListLayout};
356
+ //# sourceMappingURL=ListLayout.module.js.map