@react-aria/collections 3.0.0-nightly.5042 → 3.0.0-rc.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/dist/Document.mjs CHANGED
@@ -58,8 +58,21 @@ class $681cc3c98f569e39$export$410b0c854570d131 {
58
58
  var _this_parentNode;
59
59
  return ((_this_parentNode = this.parentNode) === null || _this_parentNode === void 0 ? void 0 : _this_parentNode.isConnected) || false;
60
60
  }
61
+ invalidateChildIndices(child) {
62
+ if (this._minInvalidChildIndex == null || !this._minInvalidChildIndex.isConnected || child.index < this._minInvalidChildIndex.index) {
63
+ this._minInvalidChildIndex = child;
64
+ this.ownerDocument.markDirty(this);
65
+ }
66
+ }
67
+ updateChildIndices() {
68
+ let node = this._minInvalidChildIndex;
69
+ while(node){
70
+ node.index = node.previousSibling ? node.previousSibling.index + 1 : 0;
71
+ node = node.nextSibling;
72
+ }
73
+ this._minInvalidChildIndex = null;
74
+ }
61
75
  appendChild(child) {
62
- this.ownerDocument.startTransaction();
63
76
  if (child.parentNode) child.parentNode.removeChild(child);
64
77
  if (this.firstChild == null) this.firstChild = child;
65
78
  if (this.lastChild) {
@@ -74,41 +87,32 @@ class $681cc3c98f569e39$export$410b0c854570d131 {
74
87
  child.nextSibling = null;
75
88
  this.lastChild = child;
76
89
  this.ownerDocument.markDirty(this);
77
- if (child.hasSetProps) // Only add the node to the collection if we already received props for it.
78
- // Otherwise wait until then so we have the correct id for the node.
79
- this.ownerDocument.addNode(child);
80
- this.ownerDocument.endTransaction();
81
- this.ownerDocument.queueUpdate();
90
+ if (this.isConnected) this.ownerDocument.queueUpdate();
82
91
  }
83
92
  insertBefore(newNode, referenceNode) {
84
93
  if (referenceNode == null) return this.appendChild(newNode);
85
- this.ownerDocument.startTransaction();
86
94
  if (newNode.parentNode) newNode.parentNode.removeChild(newNode);
87
95
  newNode.nextSibling = referenceNode;
88
96
  newNode.previousSibling = referenceNode.previousSibling;
89
- newNode.index = referenceNode.index;
97
+ // Ensure that the newNode's index is less than that of the reference node so that
98
+ // invalidateChildIndices will properly use the newNode as the _minInvalidChildIndex, thus making sure
99
+ // we will properly update the indexes of all sibiling nodes after the newNode. The value here doesn't matter
100
+ // since updateChildIndices should calculate the proper indexes.
101
+ newNode.index = referenceNode.index - 1;
90
102
  if (this.firstChild === referenceNode) this.firstChild = newNode;
91
103
  else if (referenceNode.previousSibling) referenceNode.previousSibling.nextSibling = newNode;
92
104
  referenceNode.previousSibling = newNode;
93
105
  newNode.parentNode = referenceNode.parentNode;
94
- let node = referenceNode;
95
- while(node){
96
- node.index++;
97
- node = node.nextSibling;
98
- }
99
- if (newNode.hasSetProps) this.ownerDocument.addNode(newNode);
100
- this.ownerDocument.endTransaction();
101
- this.ownerDocument.queueUpdate();
106
+ this.invalidateChildIndices(newNode);
107
+ if (this.isConnected) this.ownerDocument.queueUpdate();
102
108
  }
103
109
  removeChild(child) {
104
110
  if (child.parentNode !== this || !this.ownerDocument.isMounted) return;
105
- this.ownerDocument.startTransaction();
106
- let node = child.nextSibling;
107
- while(node){
108
- node.index--;
109
- node = node.nextSibling;
111
+ if (this._minInvalidChildIndex === child) this._minInvalidChildIndex = null;
112
+ if (child.nextSibling) {
113
+ this.invalidateChildIndices(child.nextSibling);
114
+ child.nextSibling.previousSibling = child.previousSibling;
110
115
  }
111
- if (child.nextSibling) child.nextSibling.previousSibling = child.previousSibling;
112
116
  if (child.previousSibling) child.previousSibling.nextSibling = child.nextSibling;
113
117
  if (this.firstChild === child) this.firstChild = child.nextSibling;
114
118
  if (this.lastChild === child) this.lastChild = child.previousSibling;
@@ -116,18 +120,38 @@ class $681cc3c98f569e39$export$410b0c854570d131 {
116
120
  child.nextSibling = null;
117
121
  child.previousSibling = null;
118
122
  child.index = 0;
119
- this.ownerDocument.removeNode(child);
120
- this.ownerDocument.endTransaction();
121
- this.ownerDocument.queueUpdate();
123
+ this.ownerDocument.markDirty(child);
124
+ if (this.isConnected) this.ownerDocument.queueUpdate();
122
125
  }
123
126
  addEventListener() {}
124
127
  removeEventListener() {}
128
+ get previousVisibleSibling() {
129
+ let node = this.previousSibling;
130
+ while(node && node.isHidden)node = node.previousSibling;
131
+ return node;
132
+ }
133
+ get nextVisibleSibling() {
134
+ let node = this.nextSibling;
135
+ while(node && node.isHidden)node = node.nextSibling;
136
+ return node;
137
+ }
138
+ get firstVisibleChild() {
139
+ let node = this.firstChild;
140
+ while(node && node.isHidden)node = node.nextSibling;
141
+ return node;
142
+ }
143
+ get lastVisibleChild() {
144
+ let node = this.lastChild;
145
+ while(node && node.isHidden)node = node.previousSibling;
146
+ return node;
147
+ }
125
148
  constructor(ownerDocument){
126
149
  this._firstChild = null;
127
150
  this._lastChild = null;
128
151
  this._previousSibling = null;
129
152
  this._nextSibling = null;
130
153
  this._parentNode = null;
154
+ this._minInvalidChildIndex = null;
131
155
  this.ownerDocument = ownerDocument;
132
156
  }
133
157
  }
@@ -143,62 +167,97 @@ class $681cc3c98f569e39$export$dc064fe9e59310fd extends $681cc3c98f569e39$export
143
167
  if (this.parentNode instanceof $681cc3c98f569e39$export$dc064fe9e59310fd) return this.parentNode.level + (this.node.type === 'item' ? 1 : 0);
144
168
  return 0;
145
169
  }
170
+ /**
171
+ * Lazily gets a mutable instance of a Node. If the node has already
172
+ * been cloned during this update cycle, it just returns the existing one.
173
+ */ getMutableNode() {
174
+ if (!this.isMutated) {
175
+ this.node = this.node.clone();
176
+ this.isMutated = true;
177
+ }
178
+ this.ownerDocument.markDirty(this);
179
+ return this.node;
180
+ }
146
181
  updateNode() {
147
- var _this_previousSibling, _this_nextSibling, _this_firstChild, _this_lastChild;
148
- let node = this.ownerDocument.getMutableNode(this);
182
+ var _this_previousVisibleSibling, _this_firstVisibleChild, _this_lastVisibleChild;
183
+ let nextSibling = this.nextVisibleSibling;
184
+ let node = this.getMutableNode();
149
185
  node.index = this.index;
150
186
  node.level = this.level;
151
187
  node.parentKey = this.parentNode instanceof $681cc3c98f569e39$export$dc064fe9e59310fd ? this.parentNode.node.key : null;
152
- var _this_previousSibling_node_key;
153
- node.prevKey = (_this_previousSibling_node_key = (_this_previousSibling = this.previousSibling) === null || _this_previousSibling === void 0 ? void 0 : _this_previousSibling.node.key) !== null && _this_previousSibling_node_key !== void 0 ? _this_previousSibling_node_key : null;
154
- var _this_nextSibling_node_key;
155
- node.nextKey = (_this_nextSibling_node_key = (_this_nextSibling = this.nextSibling) === null || _this_nextSibling === void 0 ? void 0 : _this_nextSibling.node.key) !== null && _this_nextSibling_node_key !== void 0 ? _this_nextSibling_node_key : null;
188
+ var _this_previousVisibleSibling_node_key;
189
+ node.prevKey = (_this_previousVisibleSibling_node_key = (_this_previousVisibleSibling = this.previousVisibleSibling) === null || _this_previousVisibleSibling === void 0 ? void 0 : _this_previousVisibleSibling.node.key) !== null && _this_previousVisibleSibling_node_key !== void 0 ? _this_previousVisibleSibling_node_key : null;
190
+ var _nextSibling_node_key;
191
+ node.nextKey = (_nextSibling_node_key = nextSibling === null || nextSibling === void 0 ? void 0 : nextSibling.node.key) !== null && _nextSibling_node_key !== void 0 ? _nextSibling_node_key : null;
156
192
  node.hasChildNodes = !!this.firstChild;
157
- var _this_firstChild_node_key;
158
- node.firstChildKey = (_this_firstChild_node_key = (_this_firstChild = this.firstChild) === null || _this_firstChild === void 0 ? void 0 : _this_firstChild.node.key) !== null && _this_firstChild_node_key !== void 0 ? _this_firstChild_node_key : null;
159
- var _this_lastChild_node_key;
160
- node.lastChildKey = (_this_lastChild_node_key = (_this_lastChild = this.lastChild) === null || _this_lastChild === void 0 ? void 0 : _this_lastChild.node.key) !== null && _this_lastChild_node_key !== void 0 ? _this_lastChild_node_key : null;
193
+ var _this_firstVisibleChild_node_key;
194
+ node.firstChildKey = (_this_firstVisibleChild_node_key = (_this_firstVisibleChild = this.firstVisibleChild) === null || _this_firstVisibleChild === void 0 ? void 0 : _this_firstVisibleChild.node.key) !== null && _this_firstVisibleChild_node_key !== void 0 ? _this_firstVisibleChild_node_key : null;
195
+ var _this_lastVisibleChild_node_key;
196
+ node.lastChildKey = (_this_lastVisibleChild_node_key = (_this_lastVisibleChild = this.lastVisibleChild) === null || _this_lastVisibleChild === void 0 ? void 0 : _this_lastVisibleChild.node.key) !== null && _this_lastVisibleChild_node_key !== void 0 ? _this_lastVisibleChild_node_key : null;
197
+ // Update the colIndex of sibling nodes if this node has a colSpan.
198
+ if ((node.colSpan != null || node.colIndex != null) && nextSibling) {
199
+ var _node_colIndex, _node_colSpan;
200
+ // This queues the next sibling for update, which means this happens recursively.
201
+ let nextColIndex = ((_node_colIndex = node.colIndex) !== null && _node_colIndex !== void 0 ? _node_colIndex : node.index) + ((_node_colSpan = node.colSpan) !== null && _node_colSpan !== void 0 ? _node_colSpan : 1);
202
+ if (nextColIndex !== nextSibling.node.colIndex) {
203
+ let siblingNode = nextSibling.getMutableNode();
204
+ siblingNode.colIndex = nextColIndex;
205
+ }
206
+ }
161
207
  }
162
208
  setProps(obj, ref, rendered, render) {
163
- let node = this.ownerDocument.getMutableNode(this);
164
- let { value: value, textValue: textValue, id: id, ...props } = obj;
209
+ let node = this.getMutableNode();
210
+ let { value: value1, textValue: textValue, id: id, ...props } = obj;
165
211
  props.ref = ref;
166
212
  node.props = props;
167
213
  node.rendered = rendered;
168
214
  node.render = render;
169
- node.value = value;
215
+ node.value = value1;
170
216
  node.textValue = textValue || (typeof props.children === 'string' ? props.children : '') || obj['aria-label'] || '';
171
217
  if (id != null && id !== node.key) {
172
218
  if (this.hasSetProps) throw new Error('Cannot change the id of an item');
173
219
  node.key = id;
174
220
  }
175
- // If this is the first time props have been set, end the transaction started in the constructor
176
- // so this node can be emitted.
177
- if (!this.hasSetProps) {
178
- this.ownerDocument.addNode(this);
179
- this.ownerDocument.endTransaction();
180
- this.hasSetProps = true;
181
- }
182
- this.ownerDocument.queueUpdate();
221
+ if (props.colSpan != null) node.colSpan = props.colSpan;
222
+ this.hasSetProps = true;
223
+ if (this.isConnected) this.ownerDocument.queueUpdate();
183
224
  }
184
225
  get style() {
185
- return {};
226
+ // React sets display: none to hide elements during Suspense.
227
+ // We'll handle this by setting the element to hidden and invalidating
228
+ // its siblings/parent. Hidden elements remain in the Document, but
229
+ // are removed from the Collection.
230
+ let element = this;
231
+ return {
232
+ get display () {
233
+ return element.isHidden ? 'none' : '';
234
+ },
235
+ set display (value){
236
+ let isHidden = value === 'none';
237
+ if (element.isHidden !== isHidden) {
238
+ var _element_parentNode, _element_parentNode1;
239
+ // Mark parent node dirty if this element is currently the first or last visible child.
240
+ if (((_element_parentNode = element.parentNode) === null || _element_parentNode === void 0 ? void 0 : _element_parentNode.firstVisibleChild) === element || ((_element_parentNode1 = element.parentNode) === null || _element_parentNode1 === void 0 ? void 0 : _element_parentNode1.lastVisibleChild) === element) element.ownerDocument.markDirty(element.parentNode);
241
+ // Mark sibling visible elements dirty.
242
+ let prev = element.previousVisibleSibling;
243
+ let next = element.nextVisibleSibling;
244
+ if (prev) element.ownerDocument.markDirty(prev);
245
+ if (next) element.ownerDocument.markDirty(next);
246
+ // Mark self dirty.
247
+ element.isHidden = isHidden;
248
+ element.ownerDocument.markDirty(element);
249
+ }
250
+ }
251
+ };
186
252
  }
187
253
  hasAttribute() {}
188
254
  setAttribute() {}
189
255
  setAttributeNS() {}
190
256
  removeAttribute() {}
191
257
  constructor(type, ownerDocument){
192
- super(ownerDocument);
193
- this.nodeType = 8 // COMMENT_NODE (we'd use ELEMENT_NODE but React DevTools will fail to get its dimensions)
194
- ;
195
- this._index = 0;
196
- this.hasSetProps = false;
258
+ super(ownerDocument), this.nodeType = 8 // COMMENT_NODE (we'd use ELEMENT_NODE but React DevTools will fail to get its dimensions)
259
+ , this.isMutated = true, this._index = 0, this.hasSetProps = false, this.isHidden = false;
197
260
  this.node = new (0, $23b9f4fcf0fe224b$export$d68d59712b04d9d1)(type, `react-aria-${++ownerDocument.nodeId}`);
198
- // Start a transaction so that no updates are emitted from the collection
199
- // until the props for this node are set. We don't know the real id for the
200
- // node until then, so we need to avoid emitting collections in an inconsistent state.
201
- this.ownerDocument.startTransaction();
202
261
  }
203
262
  }
204
263
  class $681cc3c98f569e39$export$b34a105447964f9f extends $681cc3c98f569e39$export$410b0c854570d131 {
@@ -208,72 +267,70 @@ class $681cc3c98f569e39$export$b34a105447964f9f extends $681cc3c98f569e39$export
208
267
  createElement(type) {
209
268
  return new $681cc3c98f569e39$export$dc064fe9e59310fd(type, this);
210
269
  }
211
- /**
212
- * Lazily gets a mutable instance of a Node. If the node has already
213
- * been cloned during this update cycle, it just returns the existing one.
214
- */ getMutableNode(element) {
215
- let node = element.node;
216
- if (!this.mutatedNodes.has(element)) {
217
- node = element.node.clone();
218
- this.mutatedNodes.add(element);
219
- element.node = node;
220
- }
221
- this.markDirty(element);
222
- return node;
223
- }
224
270
  getMutableCollection() {
225
- if (!this.isSSR && !this.collectionMutated) {
226
- this.collection = this.collection.clone();
227
- this.collectionMutated = true;
228
- }
229
- return this.collection;
271
+ if (!this.nextCollection) this.nextCollection = this.collection.clone();
272
+ return this.nextCollection;
230
273
  }
231
274
  markDirty(node) {
232
275
  this.dirtyNodes.add(node);
233
276
  }
234
- startTransaction() {
235
- this.transactionCount++;
236
- }
237
- endTransaction() {
238
- this.transactionCount--;
239
- }
240
277
  addNode(element) {
278
+ if (element.isHidden) return;
241
279
  let collection = this.getMutableCollection();
242
- if (!collection.getItem(element.node.key)) {
243
- collection.addNode(element.node);
244
- for (let child of element)this.addNode(child);
245
- }
246
- this.markDirty(element);
280
+ if (!collection.getItem(element.node.key)) for (let child of element)this.addNode(child);
281
+ collection.addNode(element.node);
247
282
  }
248
283
  removeNode(node) {
249
284
  for (let child of node)this.removeNode(child);
250
285
  let collection = this.getMutableCollection();
251
286
  collection.removeNode(node.node.key);
252
- this.markDirty(node);
253
287
  }
254
288
  /** Finalizes the collection update, updating all nodes and freezing the collection. */ getCollection() {
255
- if (this.transactionCount > 0) return this.collection;
289
+ // If in a subscription update, return a clone of the existing collection.
290
+ // This ensures React will queue a render. React will call getCollection again
291
+ // during render, at which point all the updates will be complete and we can return
292
+ // the new collection.
293
+ if (this.inSubscription) return this.collection.clone();
294
+ // Reset queuedRender to false when getCollection is called during render.
295
+ this.queuedRender = false;
256
296
  this.updateCollection();
257
297
  return this.collection;
258
298
  }
259
299
  updateCollection() {
260
- for (let element of this.dirtyNodes)if (element instanceof $681cc3c98f569e39$export$dc064fe9e59310fd && element.isConnected) element.updateNode();
300
+ // First, remove disconnected nodes and update the indices of dirty element children.
301
+ for (let element of this.dirtyNodes)if (element instanceof $681cc3c98f569e39$export$dc064fe9e59310fd && (!element.isConnected || element.isHidden)) this.removeNode(element);
302
+ else element.updateChildIndices();
303
+ // Next, update dirty collection nodes.
304
+ for (let element of this.dirtyNodes)if (element instanceof $681cc3c98f569e39$export$dc064fe9e59310fd) {
305
+ if (element.isConnected && !element.isHidden) {
306
+ element.updateNode();
307
+ this.addNode(element);
308
+ }
309
+ element.isMutated = false;
310
+ }
261
311
  this.dirtyNodes.clear();
262
- if (this.mutatedNodes.size || this.collectionMutated) {
263
- var _this_firstChild, _this_lastChild;
264
- let collection = this.getMutableCollection();
265
- for (let element of this.mutatedNodes)if (element.isConnected) collection.addNode(element.node);
266
- var _this_firstChild_node_key, _this_lastChild_node_key;
267
- collection.commit((_this_firstChild_node_key = (_this_firstChild = this.firstChild) === null || _this_firstChild === void 0 ? void 0 : _this_firstChild.node.key) !== null && _this_firstChild_node_key !== void 0 ? _this_firstChild_node_key : null, (_this_lastChild_node_key = (_this_lastChild = this.lastChild) === null || _this_lastChild === void 0 ? void 0 : _this_lastChild.node.key) !== null && _this_lastChild_node_key !== void 0 ? _this_lastChild_node_key : null, this.isSSR);
268
- this.mutatedNodes.clear();
312
+ // Finally, update the collection.
313
+ if (this.nextCollection) {
314
+ var _this_firstVisibleChild, _this_lastVisibleChild;
315
+ var _this_firstVisibleChild_node_key, _this_lastVisibleChild_node_key;
316
+ this.nextCollection.commit((_this_firstVisibleChild_node_key = (_this_firstVisibleChild = this.firstVisibleChild) === null || _this_firstVisibleChild === void 0 ? void 0 : _this_firstVisibleChild.node.key) !== null && _this_firstVisibleChild_node_key !== void 0 ? _this_firstVisibleChild_node_key : null, (_this_lastVisibleChild_node_key = (_this_lastVisibleChild = this.lastVisibleChild) === null || _this_lastVisibleChild === void 0 ? void 0 : _this_lastVisibleChild.node.key) !== null && _this_lastVisibleChild_node_key !== void 0 ? _this_lastVisibleChild_node_key : null, this.isSSR);
317
+ if (!this.isSSR) {
318
+ this.collection = this.nextCollection;
319
+ this.nextCollection = null;
320
+ }
269
321
  }
270
- this.collectionMutated = false;
271
322
  }
272
323
  queueUpdate() {
273
- // Don't emit any updates if there is a transaction in progress.
274
- // queueUpdate should be called again after the transaction.
275
- if (this.dirtyNodes.size === 0 || this.transactionCount > 0) return;
324
+ if (this.dirtyNodes.size === 0 || this.queuedRender) return;
325
+ // Only trigger subscriptions once during an update, when the first item changes.
326
+ // React's useSyncExternalStore will call getCollection immediately, to check whether the snapshot changed.
327
+ // If so, React will queue a render to happen after the current commit to our fake DOM finishes.
328
+ // We track whether getCollection is called in a subscription, and once it is called during render,
329
+ // we reset queuedRender back to false.
330
+ this.queuedRender = true;
331
+ this.inSubscription = true;
276
332
  for (let fn of this.subscriptions)fn();
333
+ this.inSubscription = false;
277
334
  }
278
335
  subscribe(fn) {
279
336
  this.subscriptions.add(fn);
@@ -289,20 +346,10 @@ class $681cc3c98f569e39$export$b34a105447964f9f extends $681cc3c98f569e39$export
289
346
  }
290
347
  constructor(collection){
291
348
  // @ts-ignore
292
- super(null);
293
- this.nodeType = 11 // DOCUMENT_FRAGMENT_NODE
294
- ;
295
- this.ownerDocument = this;
296
- this.dirtyNodes = new Set();
297
- this.isSSR = false;
298
- this.nodeId = 0;
299
- this.nodesByProps = new WeakMap();
300
- this.isMounted = true;
301
- this.mutatedNodes = new Set();
302
- this.subscriptions = new Set();
303
- this.transactionCount = 0;
349
+ super(null), this.nodeType = 11 // DOCUMENT_FRAGMENT_NODE
350
+ , this.ownerDocument = this, this.dirtyNodes = new Set(), this.isSSR = false, this.nodeId = 0, this.nodesByProps = new WeakMap(), this.isMounted = true, this.nextCollection = null, this.subscriptions = new Set(), this.queuedRender = false, this.inSubscription = false;
304
351
  this.collection = collection;
305
- this.collectionMutated = true;
352
+ this.nextCollection = collection;
306
353
  }
307
354
  }
308
355