@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.
@@ -1763,7 +1763,6 @@ function createConditionalBlockComponent(owner) {
1763
1763
  }
1764
1764
  componentWillUnmount() {
1765
1765
  this.unsubscribe?.();
1766
- owner.setRoot(this.props.id, null);
1767
1766
  }
1768
1767
  render() {
1769
1768
  const node = this.props.render();
@@ -1884,33 +1883,65 @@ function materializeCompilerHostChildren(descriptor) {
1884
1883
  children.push(...staticChildren.slice(cursor, cursor + block.trailing));
1885
1884
  return children;
1886
1885
  }
1887
- function collectCompilerHostBlockIds(descriptor, ids) {
1888
- for (const child of flattenCompilerHostElements(descriptor.children)) {
1889
- collectCompilerHostBlockIds(child, ids);
1886
+ function collectActiveCompilerHostBlockIds(descriptor, ids) {
1887
+ for (const child of flattenCompilerHostElements(materializeCompilerHostChildren(descriptor))) {
1888
+ collectActiveCompilerHostBlockIds(child, ids);
1890
1889
  }
1891
1890
  const block = descriptor.block;
1892
- if (!block || ids.has(block.id)) return;
1891
+ if (!block) return;
1893
1892
  ids.add(block.id);
1894
- if (block.kind === "conditional-ranges") {
1895
- for (const range of block.ranges) {
1896
- if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
1897
- if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
1893
+ }
1894
+ function reconcileCompilerFallbackSubscriptions(owner, subscriptions, ids, refresh) {
1895
+ for (const [id, unsubscribe] of subscriptions) {
1896
+ if (ids.has(id)) continue;
1897
+ unsubscribe();
1898
+ subscriptions.delete(id);
1899
+ }
1900
+ for (const id of ids) {
1901
+ if (!subscriptions.has(id)) subscriptions.set(id, owner.subscribe(id, refresh));
1902
+ }
1903
+ }
1904
+ function clearCompilerFallbackSubscriptions(subscriptions) {
1905
+ for (const unsubscribe of subscriptions.values()) unsubscribe();
1906
+ subscriptions.clear();
1907
+ }
1908
+ function hasUnsafeCompilerFallbackKeys(descriptor) {
1909
+ const visitKeyedRange = (range) => {
1910
+ const items = materializeIterable(range.items());
1911
+ const keys = items.map((item, index) => keyedRowIdentity(range.rowKey(item, index)));
1912
+ if (new Set(keys).size !== keys.length) return true;
1913
+ return items.some((item, index) => visit(range.create(item, index)));
1914
+ };
1915
+ const visit = (current) => {
1916
+ for (const child of flattenCompilerHostElements(current.children)) {
1917
+ if (visit(child)) return true;
1918
+ }
1919
+ const block = current.block;
1920
+ if (!block) return false;
1921
+ if (block.kind === "conditional-ranges") {
1922
+ for (const range of block.ranges) {
1923
+ const selection = hostConditionalSelection(range);
1924
+ if (selection.kind === "branch" && visit(selection.branch.create())) return true;
1925
+ }
1926
+ return false;
1898
1927
  }
1899
- } else if (block.kind === "keyed-ranges") {
1900
- for (const range of block.ranges) {
1901
- const first = materializeIterable(range.items())[0];
1902
- if (first !== void 0) collectCompilerHostBlockIds(range.create(first, 0), ids);
1928
+ if (block.kind === "keyed-ranges") {
1929
+ return block.ranges.some(visitKeyedRange);
1903
1930
  }
1904
- } else {
1905
1931
  for (const range of block.ranges) {
1906
- if (range.kind === "conditional") {
1907
- if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
1908
- if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
1909
- } else {
1910
- const first = materializeIterable(range.items())[0];
1911
- if (first !== void 0) collectCompilerHostBlockIds(range.create(first, 0), ids);
1932
+ if (range.kind === "keyed") {
1933
+ if (visitKeyedRange(range)) return true;
1934
+ continue;
1912
1935
  }
1936
+ const selection = hostConditionalSelection(range);
1937
+ if (selection.kind === "branch" && visit(selection.branch.create())) return true;
1913
1938
  }
1939
+ return false;
1940
+ };
1941
+ try {
1942
+ return visit(descriptor);
1943
+ } catch {
1944
+ return true;
1914
1945
  }
1915
1946
  }
1916
1947
  function findCompilerHostTarget(root, path) {
@@ -3216,13 +3247,18 @@ function createHostConditionalBlockComponent(owner) {
3216
3247
  this.fallbackVersion = 0;
3217
3248
  this.propSyncQueued = false;
3218
3249
  this.currentProps = this.props;
3219
- this.fallbackUnsubscribers = [];
3250
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
3251
+ this.fallbackKeysWereUnsafe = false;
3220
3252
  this.activeBranch = null;
3221
3253
  this.instance = null;
3222
3254
  this.requestNestedFallback = () => {
3223
3255
  this.instance?.scope?.cleanup();
3224
3256
  this.activateFallback();
3225
3257
  };
3258
+ this.refreshFallbackDescendant = (afterCommit) => {
3259
+ this.prepareFallbackUpdate();
3260
+ this.forceUpdate(afterCommit);
3261
+ };
3226
3262
  this.captureRoot = (root) => {
3227
3263
  this.root = root;
3228
3264
  };
@@ -3231,25 +3267,32 @@ function createHostConditionalBlockComponent(owner) {
3231
3267
  };
3232
3268
  }
3233
3269
  subscribeFallbackDescendants() {
3234
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3235
- this.fallbackUnsubscribers = [];
3236
3270
  const ids = /* @__PURE__ */ new Set();
3237
- if (this.currentProps.truthy) {
3238
- collectCompilerHostBlockIds(this.currentProps.truthy.create(), ids);
3239
- }
3240
- if (this.currentProps.falsy) {
3241
- collectCompilerHostBlockIds(this.currentProps.falsy.create(), ids);
3271
+ const selection = hostConditionalSelection(this.currentProps);
3272
+ if (selection.kind === "branch") {
3273
+ collectActiveCompilerHostBlockIds(selection.branch.create(), ids);
3242
3274
  }
3243
3275
  ids.delete(this.currentProps.id);
3244
- for (const id of ids) {
3245
- this.fallbackUnsubscribers.push(
3246
- owner.subscribe(id, (afterCommit) => {
3247
- this.fallbackVersion += 1;
3248
- this.forceUpdate(afterCommit);
3249
- })
3250
- );
3276
+ reconcileCompilerFallbackSubscriptions(
3277
+ owner,
3278
+ this.fallbackUnsubscribers,
3279
+ ids,
3280
+ this.refreshFallbackDescendant
3281
+ );
3282
+ }
3283
+ hasUnsafeFallbackKeys() {
3284
+ try {
3285
+ const selection = hostConditionalSelection(this.currentProps);
3286
+ return selection.kind === "branch" && hasUnsafeCompilerFallbackKeys(selection.branch.create());
3287
+ } catch {
3288
+ return true;
3251
3289
  }
3252
3290
  }
3291
+ prepareFallbackUpdate() {
3292
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
3293
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
3294
+ this.fallbackKeysWereUnsafe = unsafeKeys;
3295
+ }
3253
3296
  adopt() {
3254
3297
  if (!this.root) return false;
3255
3298
  const selection = hostConditionalSelection(this.currentProps);
@@ -3288,6 +3331,7 @@ function createHostConditionalBlockComponent(owner) {
3288
3331
  this.instance = null;
3289
3332
  this.activeBranch = null;
3290
3333
  this.subscribeFallbackDescendants();
3334
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3291
3335
  this.fallbackVersion += 1;
3292
3336
  this.setState({ fallback: true }, afterCommit);
3293
3337
  }
@@ -3297,6 +3341,7 @@ function createHostConditionalBlockComponent(owner) {
3297
3341
  return;
3298
3342
  }
3299
3343
  if (this.state.fallback) {
3344
+ this.prepareFallbackUpdate();
3300
3345
  this.forceUpdate(afterCommit);
3301
3346
  return;
3302
3347
  }
@@ -3360,6 +3405,7 @@ function createHostConditionalBlockComponent(owner) {
3360
3405
  }
3361
3406
  shouldComponentUpdate(nextProps, nextState) {
3362
3407
  this.currentProps = nextProps;
3408
+ if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3363
3409
  if (nextState.fallback || this.state.fallback) return true;
3364
3410
  this.schedulePropSync();
3365
3411
  return false;
@@ -3367,15 +3413,20 @@ function createHostConditionalBlockComponent(owner) {
3367
3413
  componentDidMount() {
3368
3414
  this.mounted = true;
3369
3415
  this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3370
- if (!this.adopt()) this.activateFallback();
3416
+ if (this.state.fallback || this.fallbackRequested) {
3417
+ this.subscribeFallbackDescendants();
3418
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3419
+ } else if (!this.adopt()) this.activateFallback();
3420
+ }
3421
+ componentDidUpdate() {
3422
+ if (this.state.fallback) this.subscribeFallbackDescendants();
3371
3423
  }
3372
3424
  componentWillUnmount() {
3373
3425
  this.mounted = false;
3374
3426
  this.unsubscribe?.();
3375
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3376
- this.fallbackUnsubscribers = [];
3427
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3428
+ this.fallbackKeysWereUnsafe = false;
3377
3429
  this.instance?.scope?.cleanup();
3378
- this.root = null;
3379
3430
  this.activeBranch = null;
3380
3431
  this.instance = null;
3381
3432
  }
@@ -3406,7 +3457,8 @@ function createConditionalRangesBlockComponent(owner) {
3406
3457
  this.fallbackVersion = 0;
3407
3458
  this.propFallbackQueued = false;
3408
3459
  this.currentProps = this.props;
3409
- this.fallbackUnsubscribers = [];
3460
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
3461
+ this.fallbackKeysWereUnsafe = false;
3410
3462
  this.rangeInstances = [];
3411
3463
  this.staticSegments = [];
3412
3464
  this.staticValues = [];
@@ -3414,6 +3466,10 @@ function createConditionalRangesBlockComponent(owner) {
3414
3466
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3415
3467
  this.activateFallback();
3416
3468
  };
3469
+ this.refreshFallbackDescendant = (afterCommit) => {
3470
+ this.prepareFallbackUpdate();
3471
+ this.forceUpdate(afterCommit);
3472
+ };
3417
3473
  this.captureRoot = (root) => {
3418
3474
  this.root = root;
3419
3475
  this.currentProps.rootRef?.(root);
@@ -3423,23 +3479,39 @@ function createConditionalRangesBlockComponent(owner) {
3423
3479
  };
3424
3480
  }
3425
3481
  subscribeFallbackDescendants() {
3426
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3427
- this.fallbackUnsubscribers = [];
3428
3482
  const ids = /* @__PURE__ */ new Set();
3429
3483
  for (const range of this.currentProps.ranges) {
3430
- if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
3431
- if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
3484
+ const selection = hostConditionalSelection(range);
3485
+ if (selection.kind === "branch") {
3486
+ collectActiveCompilerHostBlockIds(selection.branch.create(), ids);
3487
+ }
3432
3488
  }
3433
3489
  ids.delete(this.currentProps.id);
3434
- for (const id of ids) {
3435
- this.fallbackUnsubscribers.push(
3436
- owner.subscribe(id, (afterCommit) => {
3437
- this.fallbackVersion += 1;
3438
- this.forceUpdate(afterCommit);
3439
- })
3440
- );
3490
+ reconcileCompilerFallbackSubscriptions(
3491
+ owner,
3492
+ this.fallbackUnsubscribers,
3493
+ ids,
3494
+ this.refreshFallbackDescendant
3495
+ );
3496
+ }
3497
+ hasUnsafeFallbackKeys() {
3498
+ try {
3499
+ for (const range of this.currentProps.ranges) {
3500
+ const selection = hostConditionalSelection(range);
3501
+ if (selection.kind === "branch" && hasUnsafeCompilerFallbackKeys(selection.branch.create())) {
3502
+ return true;
3503
+ }
3504
+ }
3505
+ return false;
3506
+ } catch {
3507
+ return true;
3441
3508
  }
3442
3509
  }
3510
+ prepareFallbackUpdate() {
3511
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
3512
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
3513
+ this.fallbackKeysWereUnsafe = unsafeKeys;
3514
+ }
3443
3515
  readSelections(props) {
3444
3516
  const selections = [];
3445
3517
  for (const range of props.ranges) {
@@ -3583,7 +3655,7 @@ function createConditionalRangesBlockComponent(owner) {
3583
3655
  return;
3584
3656
  }
3585
3657
  if (this.state.fallback) {
3586
- this.fallbackVersion += 1;
3658
+ this.prepareFallbackUpdate();
3587
3659
  this.forceUpdate(afterCommit);
3588
3660
  return;
3589
3661
  }
@@ -3620,6 +3692,7 @@ function createConditionalRangesBlockComponent(owner) {
3620
3692
  this.fallbackRequested = true;
3621
3693
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3622
3694
  this.subscribeFallbackDescendants();
3695
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3623
3696
  this.setState({ fallback: true }, afterCommit);
3624
3697
  }
3625
3698
  schedulePropFallback() {
@@ -3632,6 +3705,7 @@ function createConditionalRangesBlockComponent(owner) {
3632
3705
  }
3633
3706
  shouldComponentUpdate(nextProps, nextState) {
3634
3707
  this.currentProps = nextProps;
3708
+ if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3635
3709
  if (nextState.fallback || this.state.fallback) return true;
3636
3710
  this.schedulePropFallback();
3637
3711
  return false;
@@ -3639,15 +3713,20 @@ function createConditionalRangesBlockComponent(owner) {
3639
3713
  componentDidMount() {
3640
3714
  this.mounted = true;
3641
3715
  this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3642
- if (!this.adopt()) this.activateFallback();
3716
+ if (this.state.fallback || this.fallbackRequested) {
3717
+ this.subscribeFallbackDescendants();
3718
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3719
+ } else if (!this.adopt()) this.activateFallback();
3720
+ }
3721
+ componentDidUpdate() {
3722
+ if (this.state.fallback) this.subscribeFallbackDescendants();
3643
3723
  }
3644
3724
  componentWillUnmount() {
3645
3725
  this.mounted = false;
3646
3726
  this.unsubscribe?.();
3647
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3648
- this.fallbackUnsubscribers = [];
3727
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3728
+ this.fallbackKeysWereUnsafe = false;
3649
3729
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3650
- this.root = null;
3651
3730
  this.rangeInstances = [];
3652
3731
  this.staticSegments = [];
3653
3732
  this.staticValues.length = 0;
@@ -4489,15 +4568,15 @@ function reconcileCompilerKeyedArrayBatchInsert(props, dirtyState, collectionTok
4489
4568
  return void 0;
4490
4569
  }
4491
4570
  }
4492
- const knownKeys = new Set(instances.keys());
4571
+ const incomingKeys = /* @__PURE__ */ new Set();
4493
4572
  const incoming = [];
4494
4573
  try {
4495
4574
  for (let offset = 0; offset < insertCount; offset += 1) {
4496
4575
  const index = update.position + offset;
4497
4576
  const item = finalValue[index];
4498
4577
  const key = keyedRowIdentity(props.rowKey(item, index));
4499
- if (knownKeys.has(key)) return void 0;
4500
- knownKeys.add(key);
4578
+ if (instances.has(key) || incomingKeys.has(key)) return void 0;
4579
+ incomingKeys.add(key);
4501
4580
  const descriptor = props.create(item, index);
4502
4581
  incoming.push({
4503
4582
  key,
@@ -4650,9 +4729,9 @@ function reconcileCompilerKeyedArrayWindowReplace(props, dirtyState, collectionT
4650
4729
  const preparedIncomingKeys = /* @__PURE__ */ new Set();
4651
4730
  const preparedWindows = [];
4652
4731
  const nextInstances = [];
4653
- for (const window of windows) {
4654
- if (window[0] < sourceCursor) return void 0;
4655
- while (sourceCursor < window[0]) {
4732
+ for (const window2 of windows) {
4733
+ if (window2[0] < sourceCursor) return void 0;
4734
+ while (sourceCursor < window2[0]) {
4656
4735
  const instance = previousInstances[sourceCursor];
4657
4736
  if (!instance || instance.index !== sourceCursor || !Object.is(instance.item, finalValue[resultCursor])) {
4658
4737
  return void 0;
@@ -4665,24 +4744,24 @@ function reconcileCompilerKeyedArrayWindowReplace(props, dirtyState, collectionT
4665
4744
  props,
4666
4745
  finalValue,
4667
4746
  resultCursor,
4668
- window[3]
4747
+ window2[3]
4669
4748
  );
4670
4749
  if (!incoming2) return void 0;
4671
- window[1] = resultCursor;
4750
+ window2[1] = resultCursor;
4672
4751
  const prepared3 = prepareCompilerKeyedArrayWindow(
4673
4752
  props,
4674
4753
  instances,
4675
4754
  previousInstances,
4676
4755
  root,
4677
- window,
4756
+ window2,
4678
4757
  incoming2,
4679
4758
  preparedIncomingKeys
4680
4759
  );
4681
4760
  if (!prepared3) return void 0;
4682
4761
  preparedWindows.push(prepared3);
4683
4762
  nextInstances.push(...prepared3[4]);
4684
- sourceCursor += window[2];
4685
- resultCursor += window[3];
4763
+ sourceCursor += window2[2];
4764
+ resultCursor += window2[3];
4686
4765
  }
4687
4766
  while (sourceCursor < previousInstances.length) {
4688
4767
  const instance = previousInstances[sourceCursor];
@@ -4702,30 +4781,32 @@ function reconcileCompilerKeyedArrayWindowReplace(props, dirtyState, collectionT
4702
4781
  }
4703
4782
  return keyedRowInstancesByKey(nextInstances);
4704
4783
  }
4705
- const touchedIndices = /* @__PURE__ */ new Set();
4706
- for (const update2 of updates) {
4707
- for (let index = update2.position; index < update2.position + update2.removedCount; index += 1) {
4708
- touchedIndices.add(index);
4709
- }
4710
- }
4784
+ updates.sort((left, right) => right.position - left.position);
4785
+ let window = updates.pop();
4786
+ const touchedInstances = [];
4711
4787
  for (let index = 0; index < previousInstances.length; index += 1) {
4788
+ while (window && index >= window.position + window.removedCount) {
4789
+ window = updates.pop();
4790
+ }
4712
4791
  const instance = previousInstances[index];
4713
- const touched = touchedIndices.has(index);
4714
- if (!instance || instance.index !== index || (touched ? instance.element.parentNode !== root : !Object.is(instance.item, finalValue[index]))) {
4792
+ if (!instance || instance.index !== index) return void 0;
4793
+ if (window && index >= window.position) {
4794
+ if (instance.element.parentNode !== root) return void 0;
4795
+ touchedInstances.push(instance);
4796
+ } else if (!Object.is(instance.item, finalValue[index])) {
4715
4797
  return void 0;
4716
4798
  }
4717
4799
  }
4718
- const knownKeys = new Set(instances.keys());
4719
4800
  const incomingKeys2 = /* @__PURE__ */ new Set();
4720
4801
  let replacesRows = false;
4721
4802
  const prepared2 = [];
4722
4803
  try {
4723
- for (const index of [...touchedIndices].sort((left, right) => left - right)) {
4724
- const instance = previousInstances[index];
4804
+ for (const instance of touchedInstances) {
4805
+ const index = instance.index;
4725
4806
  const item = finalValue[index];
4726
4807
  const key = keyedRowIdentity(props.rowKey(item, index));
4727
4808
  if (key !== instance.key) {
4728
- if (knownKeys.has(key) || incomingKeys2.has(key)) return void 0;
4809
+ if (instances.has(key) || incomingKeys2.has(key)) return void 0;
4729
4810
  incomingKeys2.add(key);
4730
4811
  replacesRows = true;
4731
4812
  const descriptor = props.create(item, index);
@@ -5549,11 +5630,13 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5549
5630
  this.hasReactOwnedRows()
5550
5631
  );
5551
5632
  if (positionedInstances) {
5552
- this.instances = new Map(positionedInstances);
5553
- this.rebuildElementIndex(this.instances);
5554
- const keys = [...this.instances.keys()];
5555
- this.pruneEventHandlers(keys);
5556
- this.pruneConditionalListeners(keys);
5633
+ if (positionedInstances !== this.instances) {
5634
+ this.instances = new Map(positionedInstances);
5635
+ this.rebuildElementIndex(this.instances);
5636
+ const keys = [...this.instances.keys()];
5637
+ this.pruneEventHandlers(keys);
5638
+ this.pruneConditionalListeners(keys);
5639
+ }
5557
5640
  this.commitCurrentCollection(dirtyState);
5558
5641
  afterCommit?.();
5559
5642
  return;
@@ -5568,9 +5651,9 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5568
5651
  );
5569
5652
  if (reorderedInstances) {
5570
5653
  const removedRows = reorderedInstances.size < this.instances.size;
5571
- this.instances = new Map(reorderedInstances);
5572
- this.rebuildElementIndex(this.instances);
5654
+ this.instances = reorderedInstances;
5573
5655
  if (removedRows) {
5656
+ this.rebuildElementIndex(this.instances);
5574
5657
  const keys = [...this.instances.keys()];
5575
5658
  this.pruneEventHandlers(keys);
5576
5659
  this.pruneConditionalListeners(keys);
@@ -6137,9 +6220,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6137
6220
  }
6138
6221
  if (this.state.fallback) {
6139
6222
  const unsafeKeys = this.hasUnsafeFallbackKeys();
6140
- if (unsafeKeys || this.fallbackKeysWereUnsafe) {
6141
- this.fallbackVersion += 1;
6142
- }
6223
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6143
6224
  this.fallbackKeysWereUnsafe = unsafeKeys;
6144
6225
  this.forceUpdate(afterCommit);
6145
6226
  return;
@@ -6275,6 +6356,11 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6275
6356
  const wasReactOwned = this.hasReactOwnedRows(this.currentProps);
6276
6357
  const willBeReactOwned = this.hasReactOwnedRows(nextProps);
6277
6358
  this.currentProps = nextProps;
6359
+ if (this.state.fallback && nextState.fallback) {
6360
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6361
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6362
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6363
+ }
6278
6364
  if (nextState.fallback || this.state.fallback) return true;
6279
6365
  if (wasReactOwned || willBeReactOwned) {
6280
6366
  this.eventHandlers.clear();
@@ -6297,7 +6383,6 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6297
6383
  componentWillUnmount() {
6298
6384
  this.mounted = false;
6299
6385
  this.unsubscribe?.();
6300
- this.root = null;
6301
6386
  this.cleanupHostScopes();
6302
6387
  this.instances.clear();
6303
6388
  this.identityTargets.clear();
@@ -6334,6 +6419,7 @@ function createKeyedRangesBlockComponent(owner) {
6334
6419
  this.mounted = false;
6335
6420
  this.fallbackRequested = false;
6336
6421
  this.fallbackVersion = 0;
6422
+ this.fallbackKeysWereUnsafe = false;
6337
6423
  this.propFallbackQueued = false;
6338
6424
  this.currentProps = this.props;
6339
6425
  this.rangeInstances = [];
@@ -6362,6 +6448,13 @@ function createKeyedRangesBlockComponent(owner) {
6362
6448
  }
6363
6449
  return ranges;
6364
6450
  }
6451
+ hasUnsafeFallbackKeys() {
6452
+ try {
6453
+ return this.readRanges(this.currentProps) === null;
6454
+ } catch {
6455
+ return true;
6456
+ }
6457
+ }
6365
6458
  adopt(props = this.currentProps) {
6366
6459
  if (!this.root || !Number.isSafeInteger(props.trailing) || props.trailing < 0) return false;
6367
6460
  const rowsByRange = this.readRanges(props);
@@ -6474,7 +6567,9 @@ function createKeyedRangesBlockComponent(owner) {
6474
6567
  return;
6475
6568
  }
6476
6569
  if (this.state.fallback) {
6477
- this.fallbackVersion += 1;
6570
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6571
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6572
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6478
6573
  this.forceUpdate(afterCommit);
6479
6574
  return;
6480
6575
  }
@@ -6507,6 +6602,7 @@ function createKeyedRangesBlockComponent(owner) {
6507
6602
  return;
6508
6603
  }
6509
6604
  this.fallbackRequested = true;
6605
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
6510
6606
  this.setState({ fallback: true }, afterCommit);
6511
6607
  }
6512
6608
  schedulePropFallback() {
@@ -6519,6 +6615,11 @@ function createKeyedRangesBlockComponent(owner) {
6519
6615
  }
6520
6616
  shouldComponentUpdate(nextProps, nextState) {
6521
6617
  this.currentProps = nextProps;
6618
+ if (this.state.fallback && nextState.fallback) {
6619
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6620
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6621
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6622
+ }
6522
6623
  if (nextState.fallback || this.state.fallback) return true;
6523
6624
  this.schedulePropFallback();
6524
6625
  return false;
@@ -6531,7 +6632,6 @@ function createKeyedRangesBlockComponent(owner) {
6531
6632
  componentWillUnmount() {
6532
6633
  this.mounted = false;
6533
6634
  this.unsubscribe?.();
6534
- this.root = null;
6535
6635
  this.rangeInstances = [];
6536
6636
  this.staticSegments = [];
6537
6637
  this.staticValues.length = 0;
@@ -6561,14 +6661,24 @@ function createMixedRangesBlockComponent(owner) {
6561
6661
  this.mounted = false;
6562
6662
  this.fallbackRequested = false;
6563
6663
  this.fallbackVersion = 0;
6664
+ this.fallbackKeysWereUnsafe = false;
6564
6665
  this.propFallbackQueued = false;
6565
6666
  this.currentProps = this.props;
6566
6667
  this.controller = null;
6567
- this.fallbackUnsubscribers = [];
6668
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
6568
6669
  this.captureRoot = (root) => {
6569
6670
  this.root = root;
6570
6671
  this.currentProps.rootRef?.(root);
6571
6672
  };
6673
+ this.refreshFallbackBlock = (afterCommit) => {
6674
+ if (!this.mounted || !this.state.fallback) {
6675
+ afterCommit?.();
6676
+ return;
6677
+ }
6678
+ const nextDescriptor = this.currentProps.create();
6679
+ this.prepareFallbackUpdate(nextDescriptor);
6680
+ this.forceUpdate(afterCommit);
6681
+ };
6572
6682
  this.activateFallback = (afterCommit) => {
6573
6683
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
6574
6684
  afterCommit?.();
@@ -6577,6 +6687,7 @@ function createMixedRangesBlockComponent(owner) {
6577
6687
  this.fallbackRequested = true;
6578
6688
  this.controller?.cleanup();
6579
6689
  this.controller = null;
6690
+ this.fallbackKeysWereUnsafe = hasUnsafeCompilerFallbackKeys(this.currentProps.create());
6580
6691
  this.fallbackVersion += 1;
6581
6692
  this.setState({ fallback: true }, () => {
6582
6693
  this.subscribeFallbackBlocks();
@@ -6585,26 +6696,27 @@ function createMixedRangesBlockComponent(owner) {
6585
6696
  };
6586
6697
  }
6587
6698
  clearFallbackSubscriptions() {
6588
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
6589
- this.fallbackUnsubscribers = [];
6699
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
6700
+ }
6701
+ readFallbackBlockIds(descriptor) {
6702
+ const ids = /* @__PURE__ */ new Set();
6703
+ collectActiveCompilerHostBlockIds(descriptor, ids);
6704
+ return ids;
6705
+ }
6706
+ prepareFallbackUpdate(descriptor) {
6707
+ const unsafeKeys = hasUnsafeCompilerFallbackKeys(descriptor);
6708
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6709
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6590
6710
  }
6591
6711
  subscribeFallbackBlocks() {
6592
- this.clearFallbackSubscriptions();
6593
6712
  const descriptor = this.currentProps.create();
6594
- const ids = /* @__PURE__ */ new Set();
6595
- collectCompilerHostBlockIds(descriptor, ids);
6596
- for (const id of ids) {
6597
- this.fallbackUnsubscribers.push(
6598
- owner.subscribe(id, (afterCommit) => {
6599
- if (!this.mounted || !this.state.fallback) {
6600
- afterCommit?.();
6601
- return;
6602
- }
6603
- this.fallbackVersion += 1;
6604
- this.forceUpdate(afterCommit);
6605
- })
6606
- );
6607
- }
6713
+ const ids = this.readFallbackBlockIds(descriptor);
6714
+ reconcileCompilerFallbackSubscriptions(
6715
+ owner,
6716
+ this.fallbackUnsubscribers,
6717
+ ids,
6718
+ this.refreshFallbackBlock
6719
+ );
6608
6720
  }
6609
6721
  adopt() {
6610
6722
  if (!this.root) return false;
@@ -6640,13 +6752,19 @@ function createMixedRangesBlockComponent(owner) {
6640
6752
  }
6641
6753
  shouldComponentUpdate(nextProps, nextState) {
6642
6754
  this.currentProps = nextProps;
6755
+ if (this.state.fallback && nextState.fallback) {
6756
+ this.prepareFallbackUpdate(this.currentProps.create());
6757
+ }
6643
6758
  if (nextState.fallback || this.state.fallback) return true;
6644
6759
  this.schedulePropFallback();
6645
6760
  return false;
6646
6761
  }
6647
6762
  componentDidMount() {
6648
6763
  this.mounted = true;
6649
- if (!this.adopt()) this.activateFallback();
6764
+ if (this.state.fallback || this.fallbackRequested) {
6765
+ this.fallbackKeysWereUnsafe = hasUnsafeCompilerFallbackKeys(this.currentProps.create());
6766
+ this.subscribeFallbackBlocks();
6767
+ } else if (!this.adopt()) this.activateFallback();
6650
6768
  }
6651
6769
  componentDidUpdate() {
6652
6770
  if (this.state.fallback) this.subscribeFallbackBlocks();
@@ -6656,7 +6774,7 @@ function createMixedRangesBlockComponent(owner) {
6656
6774
  this.controller?.cleanup();
6657
6775
  this.controller = null;
6658
6776
  this.clearFallbackSubscriptions();
6659
- this.root = null;
6777
+ this.fallbackKeysWereUnsafe = false;
6660
6778
  }
6661
6779
  render() {
6662
6780
  const container = this.currentProps.render();
@@ -7770,13 +7888,9 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7770
7888
  }
7771
7889
  componentWillUnmount() {
7772
7890
  this.mounted = false;
7773
- this.root = null;
7774
7891
  this.dirtyState.clear();
7775
7892
  this.inputSelection = null;
7776
7893
  this.blockRefreshListeners.clear();
7777
- this.blockRoots.clear();
7778
- this.blockRootElements.clear();
7779
- this.bindingTargets.clear();
7780
7894
  this.bindingTargetRefs.clear();
7781
7895
  this.indexedDefinition = null;
7782
7896
  this.staticBindingsByDependency = [];