@farm.js/react 0.1.0-beta.10 → 0.1.0-beta.12

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.
@@ -1769,7 +1769,6 @@ function createConditionalBlockComponent(owner) {
1769
1769
  }
1770
1770
  componentWillUnmount() {
1771
1771
  this.unsubscribe?.();
1772
- owner.setRoot(this.props.id, null);
1773
1772
  }
1774
1773
  render() {
1775
1774
  const node = this.props.render();
@@ -1890,33 +1889,65 @@ function materializeCompilerHostChildren(descriptor) {
1890
1889
  children.push(...staticChildren.slice(cursor, cursor + block.trailing));
1891
1890
  return children;
1892
1891
  }
1893
- function collectCompilerHostBlockIds(descriptor, ids) {
1894
- for (const child of flattenCompilerHostElements(descriptor.children)) {
1895
- collectCompilerHostBlockIds(child, ids);
1892
+ function collectActiveCompilerHostBlockIds(descriptor, ids) {
1893
+ for (const child of flattenCompilerHostElements(materializeCompilerHostChildren(descriptor))) {
1894
+ collectActiveCompilerHostBlockIds(child, ids);
1896
1895
  }
1897
1896
  const block = descriptor.block;
1898
- if (!block || ids.has(block.id)) return;
1897
+ if (!block) return;
1899
1898
  ids.add(block.id);
1900
- if (block.kind === "conditional-ranges") {
1901
- for (const range of block.ranges) {
1902
- if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
1903
- if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
1899
+ }
1900
+ function reconcileCompilerFallbackSubscriptions(owner, subscriptions, ids, refresh) {
1901
+ for (const [id, unsubscribe] of subscriptions) {
1902
+ if (ids.has(id)) continue;
1903
+ unsubscribe();
1904
+ subscriptions.delete(id);
1905
+ }
1906
+ for (const id of ids) {
1907
+ if (!subscriptions.has(id)) subscriptions.set(id, owner.subscribe(id, refresh));
1908
+ }
1909
+ }
1910
+ function clearCompilerFallbackSubscriptions(subscriptions) {
1911
+ for (const unsubscribe of subscriptions.values()) unsubscribe();
1912
+ subscriptions.clear();
1913
+ }
1914
+ function hasUnsafeCompilerFallbackKeys(descriptor) {
1915
+ const visitKeyedRange = (range) => {
1916
+ const items = materializeIterable(range.items());
1917
+ const keys = items.map((item, index) => keyedRowIdentity(range.rowKey(item, index)));
1918
+ if (new Set(keys).size !== keys.length) return true;
1919
+ return items.some((item, index) => visit(range.create(item, index)));
1920
+ };
1921
+ const visit = (current) => {
1922
+ for (const child of flattenCompilerHostElements(current.children)) {
1923
+ if (visit(child)) return true;
1924
+ }
1925
+ const block = current.block;
1926
+ if (!block) return false;
1927
+ if (block.kind === "conditional-ranges") {
1928
+ for (const range of block.ranges) {
1929
+ const selection = hostConditionalSelection(range);
1930
+ if (selection.kind === "branch" && visit(selection.branch.create())) return true;
1931
+ }
1932
+ return false;
1904
1933
  }
1905
- } else if (block.kind === "keyed-ranges") {
1906
- for (const range of block.ranges) {
1907
- const first = materializeIterable(range.items())[0];
1908
- if (first !== void 0) collectCompilerHostBlockIds(range.create(first, 0), ids);
1934
+ if (block.kind === "keyed-ranges") {
1935
+ return block.ranges.some(visitKeyedRange);
1909
1936
  }
1910
- } else {
1911
1937
  for (const range of block.ranges) {
1912
- if (range.kind === "conditional") {
1913
- if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
1914
- if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
1915
- } else {
1916
- const first = materializeIterable(range.items())[0];
1917
- if (first !== void 0) collectCompilerHostBlockIds(range.create(first, 0), ids);
1938
+ if (range.kind === "keyed") {
1939
+ if (visitKeyedRange(range)) return true;
1940
+ continue;
1918
1941
  }
1942
+ const selection = hostConditionalSelection(range);
1943
+ if (selection.kind === "branch" && visit(selection.branch.create())) return true;
1919
1944
  }
1945
+ return false;
1946
+ };
1947
+ try {
1948
+ return visit(descriptor);
1949
+ } catch {
1950
+ return true;
1920
1951
  }
1921
1952
  }
1922
1953
  function findCompilerHostTarget(root, path) {
@@ -3222,13 +3253,18 @@ function createHostConditionalBlockComponent(owner) {
3222
3253
  this.fallbackVersion = 0;
3223
3254
  this.propSyncQueued = false;
3224
3255
  this.currentProps = this.props;
3225
- this.fallbackUnsubscribers = [];
3256
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
3257
+ this.fallbackKeysWereUnsafe = false;
3226
3258
  this.activeBranch = null;
3227
3259
  this.instance = null;
3228
3260
  this.requestNestedFallback = () => {
3229
3261
  this.instance?.scope?.cleanup();
3230
3262
  this.activateFallback();
3231
3263
  };
3264
+ this.refreshFallbackDescendant = (afterCommit) => {
3265
+ this.prepareFallbackUpdate();
3266
+ this.forceUpdate(afterCommit);
3267
+ };
3232
3268
  this.captureRoot = (root) => {
3233
3269
  this.root = root;
3234
3270
  };
@@ -3237,25 +3273,32 @@ function createHostConditionalBlockComponent(owner) {
3237
3273
  };
3238
3274
  }
3239
3275
  subscribeFallbackDescendants() {
3240
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3241
- this.fallbackUnsubscribers = [];
3242
3276
  const ids = /* @__PURE__ */ new Set();
3243
- if (this.currentProps.truthy) {
3244
- collectCompilerHostBlockIds(this.currentProps.truthy.create(), ids);
3245
- }
3246
- if (this.currentProps.falsy) {
3247
- collectCompilerHostBlockIds(this.currentProps.falsy.create(), ids);
3277
+ const selection = hostConditionalSelection(this.currentProps);
3278
+ if (selection.kind === "branch") {
3279
+ collectActiveCompilerHostBlockIds(selection.branch.create(), ids);
3248
3280
  }
3249
3281
  ids.delete(this.currentProps.id);
3250
- for (const id of ids) {
3251
- this.fallbackUnsubscribers.push(
3252
- owner.subscribe(id, (afterCommit) => {
3253
- this.fallbackVersion += 1;
3254
- this.forceUpdate(afterCommit);
3255
- })
3256
- );
3282
+ reconcileCompilerFallbackSubscriptions(
3283
+ owner,
3284
+ this.fallbackUnsubscribers,
3285
+ ids,
3286
+ this.refreshFallbackDescendant
3287
+ );
3288
+ }
3289
+ hasUnsafeFallbackKeys() {
3290
+ try {
3291
+ const selection = hostConditionalSelection(this.currentProps);
3292
+ return selection.kind === "branch" && hasUnsafeCompilerFallbackKeys(selection.branch.create());
3293
+ } catch {
3294
+ return true;
3257
3295
  }
3258
3296
  }
3297
+ prepareFallbackUpdate() {
3298
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
3299
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
3300
+ this.fallbackKeysWereUnsafe = unsafeKeys;
3301
+ }
3259
3302
  adopt() {
3260
3303
  if (!this.root) return false;
3261
3304
  const selection = hostConditionalSelection(this.currentProps);
@@ -3294,6 +3337,7 @@ function createHostConditionalBlockComponent(owner) {
3294
3337
  this.instance = null;
3295
3338
  this.activeBranch = null;
3296
3339
  this.subscribeFallbackDescendants();
3340
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3297
3341
  this.fallbackVersion += 1;
3298
3342
  this.setState({ fallback: true }, afterCommit);
3299
3343
  }
@@ -3303,6 +3347,7 @@ function createHostConditionalBlockComponent(owner) {
3303
3347
  return;
3304
3348
  }
3305
3349
  if (this.state.fallback) {
3350
+ this.prepareFallbackUpdate();
3306
3351
  this.forceUpdate(afterCommit);
3307
3352
  return;
3308
3353
  }
@@ -3366,6 +3411,7 @@ function createHostConditionalBlockComponent(owner) {
3366
3411
  }
3367
3412
  shouldComponentUpdate(nextProps, nextState) {
3368
3413
  this.currentProps = nextProps;
3414
+ if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3369
3415
  if (nextState.fallback || this.state.fallback) return true;
3370
3416
  this.schedulePropSync();
3371
3417
  return false;
@@ -3373,15 +3419,20 @@ function createHostConditionalBlockComponent(owner) {
3373
3419
  componentDidMount() {
3374
3420
  this.mounted = true;
3375
3421
  this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3376
- if (!this.adopt()) this.activateFallback();
3422
+ if (this.state.fallback || this.fallbackRequested) {
3423
+ this.subscribeFallbackDescendants();
3424
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3425
+ } else if (!this.adopt()) this.activateFallback();
3426
+ }
3427
+ componentDidUpdate() {
3428
+ if (this.state.fallback) this.subscribeFallbackDescendants();
3377
3429
  }
3378
3430
  componentWillUnmount() {
3379
3431
  this.mounted = false;
3380
3432
  this.unsubscribe?.();
3381
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3382
- this.fallbackUnsubscribers = [];
3433
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3434
+ this.fallbackKeysWereUnsafe = false;
3383
3435
  this.instance?.scope?.cleanup();
3384
- this.root = null;
3385
3436
  this.activeBranch = null;
3386
3437
  this.instance = null;
3387
3438
  }
@@ -3412,7 +3463,8 @@ function createConditionalRangesBlockComponent(owner) {
3412
3463
  this.fallbackVersion = 0;
3413
3464
  this.propFallbackQueued = false;
3414
3465
  this.currentProps = this.props;
3415
- this.fallbackUnsubscribers = [];
3466
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
3467
+ this.fallbackKeysWereUnsafe = false;
3416
3468
  this.rangeInstances = [];
3417
3469
  this.staticSegments = [];
3418
3470
  this.staticValues = [];
@@ -3420,6 +3472,10 @@ function createConditionalRangesBlockComponent(owner) {
3420
3472
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3421
3473
  this.activateFallback();
3422
3474
  };
3475
+ this.refreshFallbackDescendant = (afterCommit) => {
3476
+ this.prepareFallbackUpdate();
3477
+ this.forceUpdate(afterCommit);
3478
+ };
3423
3479
  this.captureRoot = (root) => {
3424
3480
  this.root = root;
3425
3481
  this.currentProps.rootRef?.(root);
@@ -3429,23 +3485,39 @@ function createConditionalRangesBlockComponent(owner) {
3429
3485
  };
3430
3486
  }
3431
3487
  subscribeFallbackDescendants() {
3432
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3433
- this.fallbackUnsubscribers = [];
3434
3488
  const ids = /* @__PURE__ */ new Set();
3435
3489
  for (const range of this.currentProps.ranges) {
3436
- if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
3437
- if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
3490
+ const selection = hostConditionalSelection(range);
3491
+ if (selection.kind === "branch") {
3492
+ collectActiveCompilerHostBlockIds(selection.branch.create(), ids);
3493
+ }
3438
3494
  }
3439
3495
  ids.delete(this.currentProps.id);
3440
- for (const id of ids) {
3441
- this.fallbackUnsubscribers.push(
3442
- owner.subscribe(id, (afterCommit) => {
3443
- this.fallbackVersion += 1;
3444
- this.forceUpdate(afterCommit);
3445
- })
3446
- );
3496
+ reconcileCompilerFallbackSubscriptions(
3497
+ owner,
3498
+ this.fallbackUnsubscribers,
3499
+ ids,
3500
+ this.refreshFallbackDescendant
3501
+ );
3502
+ }
3503
+ hasUnsafeFallbackKeys() {
3504
+ try {
3505
+ for (const range of this.currentProps.ranges) {
3506
+ const selection = hostConditionalSelection(range);
3507
+ if (selection.kind === "branch" && hasUnsafeCompilerFallbackKeys(selection.branch.create())) {
3508
+ return true;
3509
+ }
3510
+ }
3511
+ return false;
3512
+ } catch {
3513
+ return true;
3447
3514
  }
3448
3515
  }
3516
+ prepareFallbackUpdate() {
3517
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
3518
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
3519
+ this.fallbackKeysWereUnsafe = unsafeKeys;
3520
+ }
3449
3521
  readSelections(props) {
3450
3522
  const selections = [];
3451
3523
  for (const range of props.ranges) {
@@ -3589,7 +3661,7 @@ function createConditionalRangesBlockComponent(owner) {
3589
3661
  return;
3590
3662
  }
3591
3663
  if (this.state.fallback) {
3592
- this.fallbackVersion += 1;
3664
+ this.prepareFallbackUpdate();
3593
3665
  this.forceUpdate(afterCommit);
3594
3666
  return;
3595
3667
  }
@@ -3626,6 +3698,7 @@ function createConditionalRangesBlockComponent(owner) {
3626
3698
  this.fallbackRequested = true;
3627
3699
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3628
3700
  this.subscribeFallbackDescendants();
3701
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3629
3702
  this.setState({ fallback: true }, afterCommit);
3630
3703
  }
3631
3704
  schedulePropFallback() {
@@ -3638,6 +3711,7 @@ function createConditionalRangesBlockComponent(owner) {
3638
3711
  }
3639
3712
  shouldComponentUpdate(nextProps, nextState) {
3640
3713
  this.currentProps = nextProps;
3714
+ if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3641
3715
  if (nextState.fallback || this.state.fallback) return true;
3642
3716
  this.schedulePropFallback();
3643
3717
  return false;
@@ -3645,15 +3719,20 @@ function createConditionalRangesBlockComponent(owner) {
3645
3719
  componentDidMount() {
3646
3720
  this.mounted = true;
3647
3721
  this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3648
- if (!this.adopt()) this.activateFallback();
3722
+ if (this.state.fallback || this.fallbackRequested) {
3723
+ this.subscribeFallbackDescendants();
3724
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3725
+ } else if (!this.adopt()) this.activateFallback();
3726
+ }
3727
+ componentDidUpdate() {
3728
+ if (this.state.fallback) this.subscribeFallbackDescendants();
3649
3729
  }
3650
3730
  componentWillUnmount() {
3651
3731
  this.mounted = false;
3652
3732
  this.unsubscribe?.();
3653
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3654
- this.fallbackUnsubscribers = [];
3733
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3734
+ this.fallbackKeysWereUnsafe = false;
3655
3735
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3656
- this.root = null;
3657
3736
  this.rangeInstances = [];
3658
3737
  this.staticSegments = [];
3659
3738
  this.staticValues.length = 0;
@@ -4495,15 +4574,15 @@ function reconcileCompilerKeyedArrayBatchInsert(props, dirtyState, collectionTok
4495
4574
  return void 0;
4496
4575
  }
4497
4576
  }
4498
- const knownKeys = new Set(instances.keys());
4577
+ const incomingKeys = /* @__PURE__ */ new Set();
4499
4578
  const incoming = [];
4500
4579
  try {
4501
4580
  for (let offset = 0; offset < insertCount; offset += 1) {
4502
4581
  const index = update.position + offset;
4503
4582
  const item = finalValue[index];
4504
4583
  const key = keyedRowIdentity(props.rowKey(item, index));
4505
- if (knownKeys.has(key)) return void 0;
4506
- knownKeys.add(key);
4584
+ if (instances.has(key) || incomingKeys.has(key)) return void 0;
4585
+ incomingKeys.add(key);
4507
4586
  const descriptor = props.create(item, index);
4508
4587
  incoming.push({
4509
4588
  key,
@@ -4656,9 +4735,9 @@ function reconcileCompilerKeyedArrayWindowReplace(props, dirtyState, collectionT
4656
4735
  const preparedIncomingKeys = /* @__PURE__ */ new Set();
4657
4736
  const preparedWindows = [];
4658
4737
  const nextInstances = [];
4659
- for (const window of windows) {
4660
- if (window[0] < sourceCursor) return void 0;
4661
- while (sourceCursor < window[0]) {
4738
+ for (const window2 of windows) {
4739
+ if (window2[0] < sourceCursor) return void 0;
4740
+ while (sourceCursor < window2[0]) {
4662
4741
  const instance = previousInstances[sourceCursor];
4663
4742
  if (!instance || instance.index !== sourceCursor || !Object.is(instance.item, finalValue[resultCursor])) {
4664
4743
  return void 0;
@@ -4671,24 +4750,24 @@ function reconcileCompilerKeyedArrayWindowReplace(props, dirtyState, collectionT
4671
4750
  props,
4672
4751
  finalValue,
4673
4752
  resultCursor,
4674
- window[3]
4753
+ window2[3]
4675
4754
  );
4676
4755
  if (!incoming2) return void 0;
4677
- window[1] = resultCursor;
4756
+ window2[1] = resultCursor;
4678
4757
  const prepared3 = prepareCompilerKeyedArrayWindow(
4679
4758
  props,
4680
4759
  instances,
4681
4760
  previousInstances,
4682
4761
  root,
4683
- window,
4762
+ window2,
4684
4763
  incoming2,
4685
4764
  preparedIncomingKeys
4686
4765
  );
4687
4766
  if (!prepared3) return void 0;
4688
4767
  preparedWindows.push(prepared3);
4689
4768
  nextInstances.push(...prepared3[4]);
4690
- sourceCursor += window[2];
4691
- resultCursor += window[3];
4769
+ sourceCursor += window2[2];
4770
+ resultCursor += window2[3];
4692
4771
  }
4693
4772
  while (sourceCursor < previousInstances.length) {
4694
4773
  const instance = previousInstances[sourceCursor];
@@ -4708,30 +4787,32 @@ function reconcileCompilerKeyedArrayWindowReplace(props, dirtyState, collectionT
4708
4787
  }
4709
4788
  return keyedRowInstancesByKey(nextInstances);
4710
4789
  }
4711
- const touchedIndices = /* @__PURE__ */ new Set();
4712
- for (const update2 of updates) {
4713
- for (let index = update2.position; index < update2.position + update2.removedCount; index += 1) {
4714
- touchedIndices.add(index);
4715
- }
4716
- }
4790
+ updates.sort((left, right) => right.position - left.position);
4791
+ let window = updates.pop();
4792
+ const touchedInstances = [];
4717
4793
  for (let index = 0; index < previousInstances.length; index += 1) {
4794
+ while (window && index >= window.position + window.removedCount) {
4795
+ window = updates.pop();
4796
+ }
4718
4797
  const instance = previousInstances[index];
4719
- const touched = touchedIndices.has(index);
4720
- if (!instance || instance.index !== index || (touched ? instance.element.parentNode !== root : !Object.is(instance.item, finalValue[index]))) {
4798
+ if (!instance || instance.index !== index) return void 0;
4799
+ if (window && index >= window.position) {
4800
+ if (instance.element.parentNode !== root) return void 0;
4801
+ touchedInstances.push(instance);
4802
+ } else if (!Object.is(instance.item, finalValue[index])) {
4721
4803
  return void 0;
4722
4804
  }
4723
4805
  }
4724
- const knownKeys = new Set(instances.keys());
4725
4806
  const incomingKeys2 = /* @__PURE__ */ new Set();
4726
4807
  let replacesRows = false;
4727
4808
  const prepared2 = [];
4728
4809
  try {
4729
- for (const index of [...touchedIndices].sort((left, right) => left - right)) {
4730
- const instance = previousInstances[index];
4810
+ for (const instance of touchedInstances) {
4811
+ const index = instance.index;
4731
4812
  const item = finalValue[index];
4732
4813
  const key = keyedRowIdentity(props.rowKey(item, index));
4733
4814
  if (key !== instance.key) {
4734
- if (knownKeys.has(key) || incomingKeys2.has(key)) return void 0;
4815
+ if (instances.has(key) || incomingKeys2.has(key)) return void 0;
4735
4816
  incomingKeys2.add(key);
4736
4817
  replacesRows = true;
4737
4818
  const descriptor = props.create(item, index);
@@ -5555,11 +5636,13 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5555
5636
  this.hasReactOwnedRows()
5556
5637
  );
5557
5638
  if (positionedInstances) {
5558
- this.instances = new Map(positionedInstances);
5559
- this.rebuildElementIndex(this.instances);
5560
- const keys = [...this.instances.keys()];
5561
- this.pruneEventHandlers(keys);
5562
- this.pruneConditionalListeners(keys);
5639
+ if (positionedInstances !== this.instances) {
5640
+ this.instances = new Map(positionedInstances);
5641
+ this.rebuildElementIndex(this.instances);
5642
+ const keys = [...this.instances.keys()];
5643
+ this.pruneEventHandlers(keys);
5644
+ this.pruneConditionalListeners(keys);
5645
+ }
5563
5646
  this.commitCurrentCollection(dirtyState);
5564
5647
  afterCommit?.();
5565
5648
  return;
@@ -5574,9 +5657,9 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5574
5657
  );
5575
5658
  if (reorderedInstances) {
5576
5659
  const removedRows = reorderedInstances.size < this.instances.size;
5577
- this.instances = new Map(reorderedInstances);
5578
- this.rebuildElementIndex(this.instances);
5660
+ this.instances = reorderedInstances;
5579
5661
  if (removedRows) {
5662
+ this.rebuildElementIndex(this.instances);
5580
5663
  const keys = [...this.instances.keys()];
5581
5664
  this.pruneEventHandlers(keys);
5582
5665
  this.pruneConditionalListeners(keys);
@@ -6143,9 +6226,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6143
6226
  }
6144
6227
  if (this.state.fallback) {
6145
6228
  const unsafeKeys = this.hasUnsafeFallbackKeys();
6146
- if (unsafeKeys || this.fallbackKeysWereUnsafe) {
6147
- this.fallbackVersion += 1;
6148
- }
6229
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6149
6230
  this.fallbackKeysWereUnsafe = unsafeKeys;
6150
6231
  this.forceUpdate(afterCommit);
6151
6232
  return;
@@ -6281,6 +6362,11 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6281
6362
  const wasReactOwned = this.hasReactOwnedRows(this.currentProps);
6282
6363
  const willBeReactOwned = this.hasReactOwnedRows(nextProps);
6283
6364
  this.currentProps = nextProps;
6365
+ if (this.state.fallback && nextState.fallback) {
6366
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6367
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6368
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6369
+ }
6284
6370
  if (nextState.fallback || this.state.fallback) return true;
6285
6371
  if (wasReactOwned || willBeReactOwned) {
6286
6372
  this.eventHandlers.clear();
@@ -6303,7 +6389,6 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6303
6389
  componentWillUnmount() {
6304
6390
  this.mounted = false;
6305
6391
  this.unsubscribe?.();
6306
- this.root = null;
6307
6392
  this.cleanupHostScopes();
6308
6393
  this.instances.clear();
6309
6394
  this.identityTargets.clear();
@@ -6340,6 +6425,7 @@ function createKeyedRangesBlockComponent(owner) {
6340
6425
  this.mounted = false;
6341
6426
  this.fallbackRequested = false;
6342
6427
  this.fallbackVersion = 0;
6428
+ this.fallbackKeysWereUnsafe = false;
6343
6429
  this.propFallbackQueued = false;
6344
6430
  this.currentProps = this.props;
6345
6431
  this.rangeInstances = [];
@@ -6368,6 +6454,13 @@ function createKeyedRangesBlockComponent(owner) {
6368
6454
  }
6369
6455
  return ranges;
6370
6456
  }
6457
+ hasUnsafeFallbackKeys() {
6458
+ try {
6459
+ return this.readRanges(this.currentProps) === null;
6460
+ } catch {
6461
+ return true;
6462
+ }
6463
+ }
6371
6464
  adopt(props = this.currentProps) {
6372
6465
  if (!this.root || !Number.isSafeInteger(props.trailing) || props.trailing < 0) return false;
6373
6466
  const rowsByRange = this.readRanges(props);
@@ -6480,7 +6573,9 @@ function createKeyedRangesBlockComponent(owner) {
6480
6573
  return;
6481
6574
  }
6482
6575
  if (this.state.fallback) {
6483
- this.fallbackVersion += 1;
6576
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6577
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6578
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6484
6579
  this.forceUpdate(afterCommit);
6485
6580
  return;
6486
6581
  }
@@ -6513,6 +6608,7 @@ function createKeyedRangesBlockComponent(owner) {
6513
6608
  return;
6514
6609
  }
6515
6610
  this.fallbackRequested = true;
6611
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
6516
6612
  this.setState({ fallback: true }, afterCommit);
6517
6613
  }
6518
6614
  schedulePropFallback() {
@@ -6525,6 +6621,11 @@ function createKeyedRangesBlockComponent(owner) {
6525
6621
  }
6526
6622
  shouldComponentUpdate(nextProps, nextState) {
6527
6623
  this.currentProps = nextProps;
6624
+ if (this.state.fallback && nextState.fallback) {
6625
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6626
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6627
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6628
+ }
6528
6629
  if (nextState.fallback || this.state.fallback) return true;
6529
6630
  this.schedulePropFallback();
6530
6631
  return false;
@@ -6537,7 +6638,6 @@ function createKeyedRangesBlockComponent(owner) {
6537
6638
  componentWillUnmount() {
6538
6639
  this.mounted = false;
6539
6640
  this.unsubscribe?.();
6540
- this.root = null;
6541
6641
  this.rangeInstances = [];
6542
6642
  this.staticSegments = [];
6543
6643
  this.staticValues.length = 0;
@@ -6567,14 +6667,24 @@ function createMixedRangesBlockComponent(owner) {
6567
6667
  this.mounted = false;
6568
6668
  this.fallbackRequested = false;
6569
6669
  this.fallbackVersion = 0;
6670
+ this.fallbackKeysWereUnsafe = false;
6570
6671
  this.propFallbackQueued = false;
6571
6672
  this.currentProps = this.props;
6572
6673
  this.controller = null;
6573
- this.fallbackUnsubscribers = [];
6674
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
6574
6675
  this.captureRoot = (root) => {
6575
6676
  this.root = root;
6576
6677
  this.currentProps.rootRef?.(root);
6577
6678
  };
6679
+ this.refreshFallbackBlock = (afterCommit) => {
6680
+ if (!this.mounted || !this.state.fallback) {
6681
+ afterCommit?.();
6682
+ return;
6683
+ }
6684
+ const nextDescriptor = this.currentProps.create();
6685
+ this.prepareFallbackUpdate(nextDescriptor);
6686
+ this.forceUpdate(afterCommit);
6687
+ };
6578
6688
  this.activateFallback = (afterCommit) => {
6579
6689
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
6580
6690
  afterCommit?.();
@@ -6583,6 +6693,7 @@ function createMixedRangesBlockComponent(owner) {
6583
6693
  this.fallbackRequested = true;
6584
6694
  this.controller?.cleanup();
6585
6695
  this.controller = null;
6696
+ this.fallbackKeysWereUnsafe = hasUnsafeCompilerFallbackKeys(this.currentProps.create());
6586
6697
  this.fallbackVersion += 1;
6587
6698
  this.setState({ fallback: true }, () => {
6588
6699
  this.subscribeFallbackBlocks();
@@ -6591,26 +6702,27 @@ function createMixedRangesBlockComponent(owner) {
6591
6702
  };
6592
6703
  }
6593
6704
  clearFallbackSubscriptions() {
6594
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
6595
- this.fallbackUnsubscribers = [];
6705
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
6706
+ }
6707
+ readFallbackBlockIds(descriptor) {
6708
+ const ids = /* @__PURE__ */ new Set();
6709
+ collectActiveCompilerHostBlockIds(descriptor, ids);
6710
+ return ids;
6711
+ }
6712
+ prepareFallbackUpdate(descriptor) {
6713
+ const unsafeKeys = hasUnsafeCompilerFallbackKeys(descriptor);
6714
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6715
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6596
6716
  }
6597
6717
  subscribeFallbackBlocks() {
6598
- this.clearFallbackSubscriptions();
6599
6718
  const descriptor = this.currentProps.create();
6600
- const ids = /* @__PURE__ */ new Set();
6601
- collectCompilerHostBlockIds(descriptor, ids);
6602
- for (const id of ids) {
6603
- this.fallbackUnsubscribers.push(
6604
- owner.subscribe(id, (afterCommit) => {
6605
- if (!this.mounted || !this.state.fallback) {
6606
- afterCommit?.();
6607
- return;
6608
- }
6609
- this.fallbackVersion += 1;
6610
- this.forceUpdate(afterCommit);
6611
- })
6612
- );
6613
- }
6719
+ const ids = this.readFallbackBlockIds(descriptor);
6720
+ reconcileCompilerFallbackSubscriptions(
6721
+ owner,
6722
+ this.fallbackUnsubscribers,
6723
+ ids,
6724
+ this.refreshFallbackBlock
6725
+ );
6614
6726
  }
6615
6727
  adopt() {
6616
6728
  if (!this.root) return false;
@@ -6646,13 +6758,19 @@ function createMixedRangesBlockComponent(owner) {
6646
6758
  }
6647
6759
  shouldComponentUpdate(nextProps, nextState) {
6648
6760
  this.currentProps = nextProps;
6761
+ if (this.state.fallback && nextState.fallback) {
6762
+ this.prepareFallbackUpdate(this.currentProps.create());
6763
+ }
6649
6764
  if (nextState.fallback || this.state.fallback) return true;
6650
6765
  this.schedulePropFallback();
6651
6766
  return false;
6652
6767
  }
6653
6768
  componentDidMount() {
6654
6769
  this.mounted = true;
6655
- if (!this.adopt()) this.activateFallback();
6770
+ if (this.state.fallback || this.fallbackRequested) {
6771
+ this.fallbackKeysWereUnsafe = hasUnsafeCompilerFallbackKeys(this.currentProps.create());
6772
+ this.subscribeFallbackBlocks();
6773
+ } else if (!this.adopt()) this.activateFallback();
6656
6774
  }
6657
6775
  componentDidUpdate() {
6658
6776
  if (this.state.fallback) this.subscribeFallbackBlocks();
@@ -6662,7 +6780,7 @@ function createMixedRangesBlockComponent(owner) {
6662
6780
  this.controller?.cleanup();
6663
6781
  this.controller = null;
6664
6782
  this.clearFallbackSubscriptions();
6665
- this.root = null;
6783
+ this.fallbackKeysWereUnsafe = false;
6666
6784
  }
6667
6785
  render() {
6668
6786
  const container = this.currentProps.render();
@@ -7776,13 +7894,9 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7776
7894
  }
7777
7895
  componentWillUnmount() {
7778
7896
  this.mounted = false;
7779
- this.root = null;
7780
7897
  this.dirtyState.clear();
7781
7898
  this.inputSelection = null;
7782
7899
  this.blockRefreshListeners.clear();
7783
- this.blockRoots.clear();
7784
- this.blockRootElements.clear();
7785
- this.bindingTargets.clear();
7786
7900
  this.bindingTargetRefs.clear();
7787
7901
  this.indexedDefinition = null;
7788
7902
  this.staticBindingsByDependency = [];