@farm.js/react 0.1.0-beta.11 → 0.1.0-beta.13

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.
@@ -1742,8 +1742,18 @@ function createConditionalBlockComponent(owner) {
1742
1742
  class FarmConditionalBlock extends React.Component {
1743
1743
  constructor() {
1744
1744
  super(...arguments);
1745
+ this.root = null;
1745
1746
  this.captureRoot = (root) => {
1747
+ const previousRoot = this.root;
1748
+ const previousId = this.rootId;
1749
+ this.root = root;
1750
+ if (!root) {
1751
+ if (previousId !== void 0) owner.setRoot(previousId, null, previousRoot);
1752
+ this.rootId = void 0;
1753
+ return;
1754
+ }
1746
1755
  owner.setRoot(this.props.id, root);
1756
+ this.rootId = this.props.id;
1747
1757
  };
1748
1758
  this.refresh = (afterCommit) => {
1749
1759
  this.forceUpdate(afterCommit);
@@ -1758,12 +1768,15 @@ function createConditionalBlockComponent(owner) {
1758
1768
  componentDidUpdate(previous) {
1759
1769
  if (previous.id === this.props.id) return;
1760
1770
  this.unsubscribe?.();
1761
- owner.setRoot(previous.id, null);
1771
+ if (this.root && this.rootId !== this.props.id) {
1772
+ if (this.rootId !== void 0) owner.setRoot(this.rootId, null, this.root);
1773
+ owner.setRoot(this.props.id, this.root);
1774
+ this.rootId = this.props.id;
1775
+ }
1762
1776
  this.subscribe();
1763
1777
  }
1764
1778
  componentWillUnmount() {
1765
1779
  this.unsubscribe?.();
1766
- owner.setRoot(this.props.id, null);
1767
1780
  }
1768
1781
  render() {
1769
1782
  const node = this.props.render();
@@ -1884,33 +1897,65 @@ function materializeCompilerHostChildren(descriptor) {
1884
1897
  children.push(...staticChildren.slice(cursor, cursor + block.trailing));
1885
1898
  return children;
1886
1899
  }
1887
- function collectCompilerHostBlockIds(descriptor, ids) {
1888
- for (const child of flattenCompilerHostElements(descriptor.children)) {
1889
- collectCompilerHostBlockIds(child, ids);
1900
+ function collectActiveCompilerHostBlockIds(descriptor, ids) {
1901
+ for (const child of flattenCompilerHostElements(materializeCompilerHostChildren(descriptor))) {
1902
+ collectActiveCompilerHostBlockIds(child, ids);
1890
1903
  }
1891
1904
  const block = descriptor.block;
1892
- if (!block || ids.has(block.id)) return;
1905
+ if (!block) return;
1893
1906
  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);
1907
+ }
1908
+ function reconcileCompilerFallbackSubscriptions(owner, subscriptions, ids, refresh) {
1909
+ for (const [id, unsubscribe] of subscriptions) {
1910
+ if (ids.has(id)) continue;
1911
+ unsubscribe();
1912
+ subscriptions.delete(id);
1913
+ }
1914
+ for (const id of ids) {
1915
+ if (!subscriptions.has(id)) subscriptions.set(id, owner.subscribe(id, refresh));
1916
+ }
1917
+ }
1918
+ function clearCompilerFallbackSubscriptions(subscriptions) {
1919
+ for (const unsubscribe of subscriptions.values()) unsubscribe();
1920
+ subscriptions.clear();
1921
+ }
1922
+ function hasUnsafeCompilerFallbackKeys(descriptor) {
1923
+ const visitKeyedRange = (range) => {
1924
+ const items = materializeIterable(range.items());
1925
+ const keys = items.map((item, index) => keyedRowIdentity(range.rowKey(item, index)));
1926
+ if (new Set(keys).size !== keys.length) return true;
1927
+ return items.some((item, index) => visit(range.create(item, index)));
1928
+ };
1929
+ const visit = (current) => {
1930
+ for (const child of flattenCompilerHostElements(current.children)) {
1931
+ if (visit(child)) return true;
1932
+ }
1933
+ const block = current.block;
1934
+ if (!block) return false;
1935
+ if (block.kind === "conditional-ranges") {
1936
+ for (const range of block.ranges) {
1937
+ const selection = hostConditionalSelection(range);
1938
+ if (selection.kind === "branch" && visit(selection.branch.create())) return true;
1939
+ }
1940
+ return false;
1898
1941
  }
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);
1942
+ if (block.kind === "keyed-ranges") {
1943
+ return block.ranges.some(visitKeyedRange);
1903
1944
  }
1904
- } else {
1905
1945
  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);
1946
+ if (range.kind === "keyed") {
1947
+ if (visitKeyedRange(range)) return true;
1948
+ continue;
1912
1949
  }
1950
+ const selection = hostConditionalSelection(range);
1951
+ if (selection.kind === "branch" && visit(selection.branch.create())) return true;
1913
1952
  }
1953
+ return false;
1954
+ };
1955
+ try {
1956
+ return visit(descriptor);
1957
+ } catch {
1958
+ return true;
1914
1959
  }
1915
1960
  }
1916
1961
  function findCompilerHostTarget(root, path) {
@@ -3216,13 +3261,19 @@ function createHostConditionalBlockComponent(owner) {
3216
3261
  this.fallbackVersion = 0;
3217
3262
  this.propSyncQueued = false;
3218
3263
  this.currentProps = this.props;
3219
- this.fallbackUnsubscribers = [];
3264
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
3265
+ this.fallbackKeysWereUnsafe = false;
3220
3266
  this.activeBranch = null;
3221
3267
  this.instance = null;
3268
+ this.definitionVersion = owner.getDefinitionVersion?.();
3222
3269
  this.requestNestedFallback = () => {
3223
3270
  this.instance?.scope?.cleanup();
3224
3271
  this.activateFallback();
3225
3272
  };
3273
+ this.refreshFallbackDescendant = (afterCommit) => {
3274
+ this.prepareFallbackUpdate();
3275
+ this.forceUpdate(afterCommit);
3276
+ };
3226
3277
  this.captureRoot = (root) => {
3227
3278
  this.root = root;
3228
3279
  };
@@ -3231,31 +3282,39 @@ function createHostConditionalBlockComponent(owner) {
3231
3282
  };
3232
3283
  }
3233
3284
  subscribeFallbackDescendants() {
3234
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3235
- this.fallbackUnsubscribers = [];
3236
3285
  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);
3286
+ const selection = hostConditionalSelection(this.currentProps);
3287
+ if (selection.kind === "branch") {
3288
+ collectActiveCompilerHostBlockIds(selection.branch.create(), ids);
3242
3289
  }
3243
3290
  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
- );
3291
+ reconcileCompilerFallbackSubscriptions(
3292
+ owner,
3293
+ this.fallbackUnsubscribers,
3294
+ ids,
3295
+ this.refreshFallbackDescendant
3296
+ );
3297
+ }
3298
+ hasUnsafeFallbackKeys() {
3299
+ try {
3300
+ const selection = hostConditionalSelection(this.currentProps);
3301
+ return selection.kind === "branch" && hasUnsafeCompilerFallbackKeys(selection.branch.create());
3302
+ } catch {
3303
+ return true;
3251
3304
  }
3252
3305
  }
3306
+ prepareFallbackUpdate() {
3307
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
3308
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
3309
+ this.fallbackKeysWereUnsafe = unsafeKeys;
3310
+ }
3253
3311
  adopt() {
3254
3312
  if (!this.root) return false;
3255
3313
  const selection = hostConditionalSelection(this.currentProps);
3256
3314
  if (selection.kind === "fallback") return false;
3257
3315
  if (selection.kind === "empty") {
3258
3316
  if (this.root.childNodes.length !== 0) return false;
3317
+ this.instance?.scope?.cleanup();
3259
3318
  this.activeBranch = null;
3260
3319
  this.instance = null;
3261
3320
  return true;
@@ -3274,6 +3333,7 @@ function createHostConditionalBlockComponent(owner) {
3274
3333
  this.requestNestedFallback
3275
3334
  );
3276
3335
  if (!instance) return false;
3336
+ this.instance?.scope?.cleanup();
3277
3337
  this.activeBranch = selection.key;
3278
3338
  this.instance = instance;
3279
3339
  return true;
@@ -3288,6 +3348,7 @@ function createHostConditionalBlockComponent(owner) {
3288
3348
  this.instance = null;
3289
3349
  this.activeBranch = null;
3290
3350
  this.subscribeFallbackDescendants();
3351
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3291
3352
  this.fallbackVersion += 1;
3292
3353
  this.setState({ fallback: true }, afterCommit);
3293
3354
  }
@@ -3297,6 +3358,7 @@ function createHostConditionalBlockComponent(owner) {
3297
3358
  return;
3298
3359
  }
3299
3360
  if (this.state.fallback) {
3361
+ this.prepareFallbackUpdate();
3300
3362
  this.forceUpdate(afterCommit);
3301
3363
  return;
3302
3364
  }
@@ -3350,30 +3412,60 @@ function createHostConditionalBlockComponent(owner) {
3350
3412
  this.instance = instance;
3351
3413
  afterCommit?.();
3352
3414
  }
3415
+ listen() {
3416
+ const id = this.currentProps.id;
3417
+ const stop = this.stop;
3418
+ if (this.id === id) return;
3419
+ stop?.();
3420
+ this.stop = owner.subscribe(id, this.refresh);
3421
+ this.id = id;
3422
+ }
3353
3423
  schedulePropSync() {
3354
3424
  if (this.propSyncQueued) return;
3355
3425
  this.propSyncQueued = true;
3356
3426
  queueMicrotask(() => {
3357
3427
  this.propSyncQueued = false;
3358
- if (this.mounted && !this.state.fallback) this.reconcile();
3428
+ if (this.mounted && !this.state.fallback) {
3429
+ this.listen();
3430
+ this.reconcile();
3431
+ }
3359
3432
  });
3360
3433
  }
3361
3434
  shouldComponentUpdate(nextProps, nextState) {
3435
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
3362
3436
  this.currentProps = nextProps;
3437
+ if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3363
3438
  if (nextState.fallback || this.state.fallback) return true;
3439
+ if (definitionChanged) return true;
3364
3440
  this.schedulePropSync();
3365
3441
  return false;
3366
3442
  }
3367
3443
  componentDidMount() {
3368
3444
  this.mounted = true;
3369
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3370
- if (!this.adopt()) this.activateFallback();
3445
+ this.listen();
3446
+ if (this.state.fallback || this.fallbackRequested) {
3447
+ this.subscribeFallbackDescendants();
3448
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3449
+ } else if (!this.adopt()) this.activateFallback();
3450
+ }
3451
+ componentDidUpdate() {
3452
+ this.listen();
3453
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
3454
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
3455
+ this.definitionVersion = nextDefinitionVersion;
3456
+ if (this.state.fallback) {
3457
+ this.subscribeFallbackDescendants();
3458
+ } else if (definitionChanged && !this.adopt()) {
3459
+ this.activateFallback();
3460
+ }
3371
3461
  }
3372
3462
  componentWillUnmount() {
3373
3463
  this.mounted = false;
3374
- this.unsubscribe?.();
3375
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3376
- this.fallbackUnsubscribers = [];
3464
+ const stop = this.stop;
3465
+ stop?.();
3466
+ this.id = void 0;
3467
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3468
+ this.fallbackKeysWereUnsafe = false;
3377
3469
  this.instance?.scope?.cleanup();
3378
3470
  this.activeBranch = null;
3379
3471
  this.instance = null;
@@ -3405,14 +3497,20 @@ function createConditionalRangesBlockComponent(owner) {
3405
3497
  this.fallbackVersion = 0;
3406
3498
  this.propFallbackQueued = false;
3407
3499
  this.currentProps = this.props;
3408
- this.fallbackUnsubscribers = [];
3500
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
3501
+ this.fallbackKeysWereUnsafe = false;
3409
3502
  this.rangeInstances = [];
3410
3503
  this.staticSegments = [];
3411
3504
  this.staticValues = [];
3505
+ this.definitionVersion = owner.getDefinitionVersion?.();
3412
3506
  this.requestNestedFallback = () => {
3413
3507
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3414
3508
  this.activateFallback();
3415
3509
  };
3510
+ this.refreshFallbackDescendant = (afterCommit) => {
3511
+ this.prepareFallbackUpdate();
3512
+ this.forceUpdate(afterCommit);
3513
+ };
3416
3514
  this.captureRoot = (root) => {
3417
3515
  this.root = root;
3418
3516
  this.currentProps.rootRef?.(root);
@@ -3422,23 +3520,39 @@ function createConditionalRangesBlockComponent(owner) {
3422
3520
  };
3423
3521
  }
3424
3522
  subscribeFallbackDescendants() {
3425
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3426
- this.fallbackUnsubscribers = [];
3427
3523
  const ids = /* @__PURE__ */ new Set();
3428
3524
  for (const range of this.currentProps.ranges) {
3429
- if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
3430
- if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
3525
+ const selection = hostConditionalSelection(range);
3526
+ if (selection.kind === "branch") {
3527
+ collectActiveCompilerHostBlockIds(selection.branch.create(), ids);
3528
+ }
3431
3529
  }
3432
3530
  ids.delete(this.currentProps.id);
3433
- for (const id of ids) {
3434
- this.fallbackUnsubscribers.push(
3435
- owner.subscribe(id, (afterCommit) => {
3436
- this.fallbackVersion += 1;
3437
- this.forceUpdate(afterCommit);
3438
- })
3439
- );
3531
+ reconcileCompilerFallbackSubscriptions(
3532
+ owner,
3533
+ this.fallbackUnsubscribers,
3534
+ ids,
3535
+ this.refreshFallbackDescendant
3536
+ );
3537
+ }
3538
+ hasUnsafeFallbackKeys() {
3539
+ try {
3540
+ for (const range of this.currentProps.ranges) {
3541
+ const selection = hostConditionalSelection(range);
3542
+ if (selection.kind === "branch" && hasUnsafeCompilerFallbackKeys(selection.branch.create())) {
3543
+ return true;
3544
+ }
3545
+ }
3546
+ return false;
3547
+ } catch {
3548
+ return true;
3440
3549
  }
3441
3550
  }
3551
+ prepareFallbackUpdate() {
3552
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
3553
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
3554
+ this.fallbackKeysWereUnsafe = unsafeKeys;
3555
+ }
3442
3556
  readSelections(props) {
3443
3557
  const selections = [];
3444
3558
  for (const range of props.ranges) {
@@ -3455,6 +3569,7 @@ function createConditionalRangesBlockComponent(owner) {
3455
3569
  const elements = [...this.root.children];
3456
3570
  const staticSegments = [];
3457
3571
  const instances = [];
3572
+ const staticValues = this.staticValues.slice();
3458
3573
  const cleanupInstances = () => {
3459
3574
  for (const instance of instances) instance?.host.scope?.cleanup();
3460
3575
  };
@@ -3509,14 +3624,15 @@ function createConditionalRangesBlockComponent(owner) {
3509
3624
  return false;
3510
3625
  }
3511
3626
  staticSegments.push(elements.slice(cursor));
3512
- this.staticSegments = staticSegments;
3513
- this.rangeInstances = instances;
3514
- if (!applyStaticRangeBindings(props.bindings, this.staticSegments, this.staticValues)) {
3627
+ if (!applyStaticRangeBindings(props.bindings, staticSegments, staticValues)) {
3515
3628
  cleanupInstances();
3516
- this.rangeInstances = [];
3517
- this.staticSegments = [];
3518
3629
  return false;
3519
3630
  }
3631
+ for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3632
+ this.staticSegments = staticSegments;
3633
+ this.rangeInstances = instances;
3634
+ this.staticValues.length = 0;
3635
+ this.staticValues.push(...staticValues);
3520
3636
  return true;
3521
3637
  }
3522
3638
  anchorAfter(rangeIndex) {
@@ -3582,7 +3698,7 @@ function createConditionalRangesBlockComponent(owner) {
3582
3698
  return;
3583
3699
  }
3584
3700
  if (this.state.fallback) {
3585
- this.fallbackVersion += 1;
3701
+ this.prepareFallbackUpdate();
3586
3702
  this.forceUpdate(afterCommit);
3587
3703
  return;
3588
3704
  }
@@ -3611,6 +3727,14 @@ function createConditionalRangesBlockComponent(owner) {
3611
3727
  }
3612
3728
  afterCommit?.();
3613
3729
  }
3730
+ listen() {
3731
+ const id = this.currentProps.id;
3732
+ const stop = this.stop;
3733
+ if (this.id === id) return;
3734
+ stop?.();
3735
+ this.stop = owner.subscribe(id, this.refresh);
3736
+ this.id = id;
3737
+ }
3614
3738
  activateFallback(afterCommit) {
3615
3739
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
3616
3740
  afterCommit?.();
@@ -3619,6 +3743,7 @@ function createConditionalRangesBlockComponent(owner) {
3619
3743
  this.fallbackRequested = true;
3620
3744
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3621
3745
  this.subscribeFallbackDescendants();
3746
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3622
3747
  this.setState({ fallback: true }, afterCommit);
3623
3748
  }
3624
3749
  schedulePropFallback() {
@@ -3626,25 +3751,47 @@ function createConditionalRangesBlockComponent(owner) {
3626
3751
  this.propFallbackQueued = true;
3627
3752
  queueMicrotask(() => {
3628
3753
  this.propFallbackQueued = false;
3629
- if (this.mounted && !this.state.fallback) this.activateFallback();
3754
+ if (this.mounted && !this.state.fallback) {
3755
+ this.listen();
3756
+ this.activateFallback();
3757
+ }
3630
3758
  });
3631
3759
  }
3632
3760
  shouldComponentUpdate(nextProps, nextState) {
3761
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
3633
3762
  this.currentProps = nextProps;
3763
+ if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3634
3764
  if (nextState.fallback || this.state.fallback) return true;
3765
+ if (definitionChanged) return true;
3635
3766
  this.schedulePropFallback();
3636
3767
  return false;
3637
3768
  }
3638
3769
  componentDidMount() {
3639
3770
  this.mounted = true;
3640
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3641
- if (!this.adopt()) this.activateFallback();
3771
+ this.listen();
3772
+ if (this.state.fallback || this.fallbackRequested) {
3773
+ this.subscribeFallbackDescendants();
3774
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3775
+ } else if (!this.adopt()) this.activateFallback();
3776
+ }
3777
+ componentDidUpdate() {
3778
+ this.listen();
3779
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
3780
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
3781
+ this.definitionVersion = nextDefinitionVersion;
3782
+ if (this.state.fallback) {
3783
+ this.subscribeFallbackDescendants();
3784
+ } else if (definitionChanged && !this.adopt()) {
3785
+ this.activateFallback();
3786
+ }
3642
3787
  }
3643
3788
  componentWillUnmount() {
3644
3789
  this.mounted = false;
3645
- this.unsubscribe?.();
3646
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3647
- this.fallbackUnsubscribers = [];
3790
+ const stop = this.stop;
3791
+ stop?.();
3792
+ this.id = void 0;
3793
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3794
+ this.fallbackKeysWereUnsafe = false;
3648
3795
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3649
3796
  this.rangeInstances = [];
3650
3797
  this.staticSegments = [];
@@ -5431,6 +5578,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5431
5578
  this.fallbackKeysWereUnsafe = false;
5432
5579
  this.propSyncQueued = false;
5433
5580
  this.currentProps = this.props;
5581
+ this.definitionVersion = owner.getDefinitionVersion?.();
5434
5582
  this.instances = /* @__PURE__ */ new Map();
5435
5583
  this.identityTargets = /* @__PURE__ */ new Map();
5436
5584
  this.membershipTargets = /* @__PURE__ */ new Map();
@@ -5809,13 +5957,14 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5809
5957
  const rows = this.readRows(this.currentProps);
5810
5958
  const elements = [...this.root.children];
5811
5959
  if (!rows || rows.items.length !== elements.length) return false;
5960
+ const reactOwnedRows = this.hasReactOwnedRows();
5812
5961
  const opaqueConditionalPaths = new Set(
5813
5962
  (this.currentProps.conditionals || []).map((conditional) => conditional.path.join("."))
5814
5963
  );
5815
5964
  const instances = /* @__PURE__ */ new Map();
5816
5965
  for (let index = 0; index < rows.items.length; index += 1) {
5817
5966
  const descriptor = this.currentProps.create(rows.items[index], index);
5818
- if (this.hasReactOwnedRows() && !matchesCompilerHostElement(elements[index], descriptor, opaqueConditionalPaths)) {
5967
+ if (reactOwnedRows && !matchesCompilerHostElement(elements[index], descriptor, opaqueConditionalPaths)) {
5819
5968
  this.cleanupHostScopes(instances);
5820
5969
  return false;
5821
5970
  }
@@ -5828,7 +5977,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5828
5977
  key: rows.keys[index],
5829
5978
  element: elements[index],
5830
5979
  scope: scope || void 0,
5831
- values: this.hasReactOwnedRows() ? this.currentProps.bindings.map(() => UNSET_KEYED_ROW_BINDING) : readKeyedRowBindingValues(this.currentProps, rows.items[index], index),
5980
+ values: reactOwnedRows ? this.currentProps.bindings.map(() => UNSET_KEYED_ROW_BINDING) : readKeyedRowBindingValues(this.currentProps, rows.items[index], index),
5832
5981
  item: rows.items[index],
5833
5982
  index,
5834
5983
  conditionalValues: this.readConditionalValues(
@@ -5837,11 +5986,13 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5837
5986
  index
5838
5987
  )
5839
5988
  };
5840
- if (this.hasReactOwnedRows()) {
5841
- applyKeyedRowBindings(this.currentProps, instance, rows.items[index], index);
5842
- }
5843
5989
  instances.set(rows.keys[index], instance);
5844
5990
  }
5991
+ if (reactOwnedRows) {
5992
+ for (const instance of instances.values()) {
5993
+ applyKeyedRowBindings(this.currentProps, instance, instance.item, instance.index);
5994
+ }
5995
+ }
5845
5996
  this.cleanupHostScopes();
5846
5997
  this.instances = instances;
5847
5998
  this.rebuildElementIndex(instances);
@@ -6139,9 +6290,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6139
6290
  }
6140
6291
  if (this.state.fallback) {
6141
6292
  const unsafeKeys = this.hasUnsafeFallbackKeys();
6142
- if (unsafeKeys || this.fallbackKeysWereUnsafe) {
6143
- this.fallbackVersion += 1;
6144
- }
6293
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6145
6294
  this.fallbackKeysWereUnsafe = unsafeKeys;
6146
6295
  this.forceUpdate(afterCommit);
6147
6296
  return;
@@ -6265,20 +6414,37 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6265
6414
  this.commitCurrentCollection(dirtyState);
6266
6415
  this.notifyConditionalChanges(conditionalChanges, afterCommit);
6267
6416
  }
6417
+ listen() {
6418
+ const id = this.currentProps.id;
6419
+ const stop = this.stop;
6420
+ if (this.id === id) return;
6421
+ stop?.();
6422
+ this.stop = owner.subscribe(id, this.refresh);
6423
+ this.id = id;
6424
+ }
6268
6425
  schedulePropSync() {
6269
6426
  if (this.propSyncQueued) return;
6270
6427
  this.propSyncQueued = true;
6271
6428
  queueMicrotask(() => {
6272
6429
  this.propSyncQueued = false;
6273
- if (this.mounted && !this.state.fallback) this.reconcile();
6430
+ if (this.mounted && !this.state.fallback) {
6431
+ this.listen();
6432
+ this.reconcile();
6433
+ }
6274
6434
  });
6275
6435
  }
6276
6436
  shouldComponentUpdate(nextProps, nextState) {
6277
6437
  const wasReactOwned = this.hasReactOwnedRows(this.currentProps);
6278
6438
  const willBeReactOwned = this.hasReactOwnedRows(nextProps);
6439
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6279
6440
  this.currentProps = nextProps;
6441
+ if (this.state.fallback && nextState.fallback) {
6442
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6443
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6444
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6445
+ }
6280
6446
  if (nextState.fallback || this.state.fallback) return true;
6281
- if (wasReactOwned || willBeReactOwned) {
6447
+ if (definitionChanged || wasReactOwned || willBeReactOwned) {
6282
6448
  this.eventHandlers.clear();
6283
6449
  return true;
6284
6450
  }
@@ -6286,19 +6452,25 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6286
6452
  return false;
6287
6453
  }
6288
6454
  componentDidUpdate(previousProps) {
6289
- if (this.state.fallback || previousProps === this.props || !this.hasReactOwnedRows(previousProps) && !this.hasReactOwnedRows(this.props) || this.adopt()) {
6455
+ this.listen();
6456
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
6457
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
6458
+ this.definitionVersion = nextDefinitionVersion;
6459
+ if (this.state.fallback || previousProps === this.props || !definitionChanged && !this.hasReactOwnedRows(previousProps) && !this.hasReactOwnedRows(this.props) || this.adopt()) {
6290
6460
  return;
6291
6461
  }
6292
6462
  this.activateFallback();
6293
6463
  }
6294
6464
  componentDidMount() {
6295
6465
  this.mounted = true;
6296
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
6466
+ this.listen();
6297
6467
  if (!this.adopt()) this.activateFallback();
6298
6468
  }
6299
6469
  componentWillUnmount() {
6300
6470
  this.mounted = false;
6301
- this.unsubscribe?.();
6471
+ const stop = this.stop;
6472
+ stop?.();
6473
+ this.id = void 0;
6302
6474
  this.cleanupHostScopes();
6303
6475
  this.instances.clear();
6304
6476
  this.identityTargets.clear();
@@ -6335,11 +6507,13 @@ function createKeyedRangesBlockComponent(owner) {
6335
6507
  this.mounted = false;
6336
6508
  this.fallbackRequested = false;
6337
6509
  this.fallbackVersion = 0;
6510
+ this.fallbackKeysWereUnsafe = false;
6338
6511
  this.propFallbackQueued = false;
6339
6512
  this.currentProps = this.props;
6340
6513
  this.rangeInstances = [];
6341
6514
  this.staticSegments = [];
6342
6515
  this.staticValues = [];
6516
+ this.definitionVersion = owner.getDefinitionVersion?.();
6343
6517
  this.captureRoot = (root) => {
6344
6518
  this.root = root;
6345
6519
  this.currentProps.rootRef?.(root);
@@ -6363,6 +6537,13 @@ function createKeyedRangesBlockComponent(owner) {
6363
6537
  }
6364
6538
  return ranges;
6365
6539
  }
6540
+ hasUnsafeFallbackKeys() {
6541
+ try {
6542
+ return this.readRanges(this.currentProps) === null;
6543
+ } catch {
6544
+ return true;
6545
+ }
6546
+ }
6366
6547
  adopt(props = this.currentProps) {
6367
6548
  if (!this.root || !Number.isSafeInteger(props.trailing) || props.trailing < 0) return false;
6368
6549
  const rowsByRange = this.readRanges(props);
@@ -6370,6 +6551,7 @@ function createKeyedRangesBlockComponent(owner) {
6370
6551
  const elements = [...this.root.children];
6371
6552
  const staticSegments = [];
6372
6553
  const instancesByRange = [];
6554
+ const staticValues = this.staticValues.slice();
6373
6555
  let cursor = 0;
6374
6556
  for (let rangeIndex = 0; rangeIndex < props.ranges.length; rangeIndex += 1) {
6375
6557
  const range = props.ranges[rangeIndex];
@@ -6401,13 +6583,11 @@ function createKeyedRangesBlockComponent(owner) {
6401
6583
  }
6402
6584
  if (cursor + props.trailing !== elements.length) return false;
6403
6585
  staticSegments.push(elements.slice(cursor));
6586
+ if (!applyStaticRangeBindings(props.bindings, staticSegments, staticValues)) return false;
6404
6587
  this.staticSegments = staticSegments;
6405
6588
  this.rangeInstances = instancesByRange;
6406
- if (!applyStaticRangeBindings(props.bindings, this.staticSegments, this.staticValues)) {
6407
- this.rangeInstances = [];
6408
- this.staticSegments = [];
6409
- return false;
6410
- }
6589
+ this.staticValues.length = 0;
6590
+ this.staticValues.push(...staticValues);
6411
6591
  return true;
6412
6592
  }
6413
6593
  anchorAfter(rangeIndex) {
@@ -6475,7 +6655,9 @@ function createKeyedRangesBlockComponent(owner) {
6475
6655
  return;
6476
6656
  }
6477
6657
  if (this.state.fallback) {
6478
- this.fallbackVersion += 1;
6658
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6659
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6660
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6479
6661
  this.forceUpdate(afterCommit);
6480
6662
  return;
6481
6663
  }
@@ -6502,12 +6684,21 @@ function createKeyedRangesBlockComponent(owner) {
6502
6684
  }
6503
6685
  afterCommit?.();
6504
6686
  }
6687
+ listen() {
6688
+ const id = this.currentProps.id;
6689
+ const stop = this.stop;
6690
+ if (this.id === id) return;
6691
+ stop?.();
6692
+ this.stop = owner.subscribe(id, this.refresh);
6693
+ this.id = id;
6694
+ }
6505
6695
  activateFallback(afterCommit) {
6506
6696
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
6507
6697
  afterCommit?.();
6508
6698
  return;
6509
6699
  }
6510
6700
  this.fallbackRequested = true;
6701
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
6511
6702
  this.setState({ fallback: true }, afterCommit);
6512
6703
  }
6513
6704
  schedulePropFallback() {
@@ -6515,23 +6706,42 @@ function createKeyedRangesBlockComponent(owner) {
6515
6706
  this.propFallbackQueued = true;
6516
6707
  queueMicrotask(() => {
6517
6708
  this.propFallbackQueued = false;
6518
- if (this.mounted && !this.state.fallback) this.activateFallback();
6709
+ if (this.mounted && !this.state.fallback) {
6710
+ this.listen();
6711
+ this.activateFallback();
6712
+ }
6519
6713
  });
6520
6714
  }
6521
6715
  shouldComponentUpdate(nextProps, nextState) {
6716
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6522
6717
  this.currentProps = nextProps;
6718
+ if (this.state.fallback && nextState.fallback) {
6719
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6720
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6721
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6722
+ }
6523
6723
  if (nextState.fallback || this.state.fallback) return true;
6724
+ if (definitionChanged) return true;
6524
6725
  this.schedulePropFallback();
6525
6726
  return false;
6526
6727
  }
6527
6728
  componentDidMount() {
6528
6729
  this.mounted = true;
6529
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
6730
+ this.listen();
6530
6731
  if (!this.adopt()) this.activateFallback();
6531
6732
  }
6733
+ componentDidUpdate() {
6734
+ this.listen();
6735
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
6736
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
6737
+ this.definitionVersion = nextDefinitionVersion;
6738
+ if (!this.state.fallback && definitionChanged && !this.adopt()) this.activateFallback();
6739
+ }
6532
6740
  componentWillUnmount() {
6533
6741
  this.mounted = false;
6534
- this.unsubscribe?.();
6742
+ const stop = this.stop;
6743
+ stop?.();
6744
+ this.id = void 0;
6535
6745
  this.rangeInstances = [];
6536
6746
  this.staticSegments = [];
6537
6747
  this.staticValues.length = 0;
@@ -6561,14 +6771,25 @@ function createMixedRangesBlockComponent(owner) {
6561
6771
  this.mounted = false;
6562
6772
  this.fallbackRequested = false;
6563
6773
  this.fallbackVersion = 0;
6774
+ this.fallbackKeysWereUnsafe = false;
6564
6775
  this.propFallbackQueued = false;
6565
6776
  this.currentProps = this.props;
6566
6777
  this.controller = null;
6567
- this.fallbackUnsubscribers = [];
6778
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
6779
+ this.definitionVersion = owner.getDefinitionVersion?.();
6568
6780
  this.captureRoot = (root) => {
6569
6781
  this.root = root;
6570
6782
  this.currentProps.rootRef?.(root);
6571
6783
  };
6784
+ this.refreshFallbackBlock = (afterCommit) => {
6785
+ if (!this.mounted || !this.state.fallback) {
6786
+ afterCommit?.();
6787
+ return;
6788
+ }
6789
+ const nextDescriptor = this.currentProps.create();
6790
+ this.prepareFallbackUpdate(nextDescriptor);
6791
+ this.forceUpdate(afterCommit);
6792
+ };
6572
6793
  this.activateFallback = (afterCommit) => {
6573
6794
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
6574
6795
  afterCommit?.();
@@ -6577,6 +6798,7 @@ function createMixedRangesBlockComponent(owner) {
6577
6798
  this.fallbackRequested = true;
6578
6799
  this.controller?.cleanup();
6579
6800
  this.controller = null;
6801
+ this.fallbackKeysWereUnsafe = hasUnsafeCompilerFallbackKeys(this.currentProps.create());
6580
6802
  this.fallbackVersion += 1;
6581
6803
  this.setState({ fallback: true }, () => {
6582
6804
  this.subscribeFallbackBlocks();
@@ -6585,26 +6807,27 @@ function createMixedRangesBlockComponent(owner) {
6585
6807
  };
6586
6808
  }
6587
6809
  clearFallbackSubscriptions() {
6588
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
6589
- this.fallbackUnsubscribers = [];
6810
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
6811
+ }
6812
+ readFallbackBlockIds(descriptor) {
6813
+ const ids = /* @__PURE__ */ new Set();
6814
+ collectActiveCompilerHostBlockIds(descriptor, ids);
6815
+ return ids;
6816
+ }
6817
+ prepareFallbackUpdate(descriptor) {
6818
+ const unsafeKeys = hasUnsafeCompilerFallbackKeys(descriptor);
6819
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6820
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6590
6821
  }
6591
6822
  subscribeFallbackBlocks() {
6592
- this.clearFallbackSubscriptions();
6593
6823
  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
- }
6824
+ const ids = this.readFallbackBlockIds(descriptor);
6825
+ reconcileCompilerFallbackSubscriptions(
6826
+ owner,
6827
+ this.fallbackUnsubscribers,
6828
+ ids,
6829
+ this.refreshFallbackBlock
6830
+ );
6608
6831
  }
6609
6832
  adopt() {
6610
6833
  if (!this.root) return false;
@@ -6627,7 +6850,9 @@ function createMixedRangesBlockComponent(owner) {
6627
6850
  controller.cleanup();
6628
6851
  throw error;
6629
6852
  }
6853
+ const previous = this.controller;
6630
6854
  this.controller = controller;
6855
+ previous?.cleanup();
6631
6856
  return true;
6632
6857
  }
6633
6858
  schedulePropFallback() {
@@ -6639,23 +6864,39 @@ function createMixedRangesBlockComponent(owner) {
6639
6864
  });
6640
6865
  }
6641
6866
  shouldComponentUpdate(nextProps, nextState) {
6867
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6642
6868
  this.currentProps = nextProps;
6869
+ if (this.state.fallback && nextState.fallback) {
6870
+ this.prepareFallbackUpdate(this.currentProps.create());
6871
+ }
6643
6872
  if (nextState.fallback || this.state.fallback) return true;
6873
+ if (definitionChanged) return true;
6644
6874
  this.schedulePropFallback();
6645
6875
  return false;
6646
6876
  }
6647
6877
  componentDidMount() {
6648
6878
  this.mounted = true;
6649
- if (!this.adopt()) this.activateFallback();
6879
+ if (this.state.fallback || this.fallbackRequested) {
6880
+ this.fallbackKeysWereUnsafe = hasUnsafeCompilerFallbackKeys(this.currentProps.create());
6881
+ this.subscribeFallbackBlocks();
6882
+ } else if (!this.adopt()) this.activateFallback();
6650
6883
  }
6651
6884
  componentDidUpdate() {
6652
- if (this.state.fallback) this.subscribeFallbackBlocks();
6885
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
6886
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
6887
+ this.definitionVersion = nextDefinitionVersion;
6888
+ if (this.state.fallback) {
6889
+ this.subscribeFallbackBlocks();
6890
+ } else if (definitionChanged && !this.adopt()) {
6891
+ this.activateFallback();
6892
+ }
6653
6893
  }
6654
6894
  componentWillUnmount() {
6655
6895
  this.mounted = false;
6656
6896
  this.controller?.cleanup();
6657
6897
  this.controller = null;
6658
6898
  this.clearFallbackSubscriptions();
6899
+ this.fallbackKeysWereUnsafe = false;
6659
6900
  }
6660
6901
  render() {
6661
6902
  const container = this.currentProps.render();
@@ -7488,8 +7729,9 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7488
7729
  };
7489
7730
  });
7490
7731
  const featureOwner = {
7491
- setRoot: (id, root) => this.setBlockRoot(id, root),
7492
- subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
7732
+ setRoot: (id, root, expectedRoot) => this.setBlockRoot(id, root, expectedRoot),
7733
+ subscribe: (id, refresh) => this.subscribeToBlock(id, refresh),
7734
+ getDefinitionVersion: () => definitionReference.current
7493
7735
  };
7494
7736
  const blockRuntime = {
7495
7737
  target: (id) => this.bindingTarget(id)
@@ -7628,8 +7870,9 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7628
7870
  }
7629
7871
  snapshot.element.setSelectionRange(snapshot.start, snapshot.end, snapshot.direction);
7630
7872
  }
7631
- setBlockRoot(id, root) {
7873
+ setBlockRoot(id, root, expectedRoot) {
7632
7874
  const previous = this.blockRoots.get(id);
7875
+ if (!root && expectedRoot !== void 0 && previous !== expectedRoot) return;
7633
7876
  if (previous) this.blockRootElements.delete(previous);
7634
7877
  if (root) {
7635
7878
  this.blockRoots.set(id, root);
@@ -7772,8 +8015,6 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7772
8015
  this.dirtyState.clear();
7773
8016
  this.inputSelection = null;
7774
8017
  this.blockRefreshListeners.clear();
7775
- this.blockRoots.clear();
7776
- this.blockRootElements.clear();
7777
8018
  this.bindingTargetRefs.clear();
7778
8019
  this.indexedDefinition = null;
7779
8020
  this.staticBindingsByDependency = [];