@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.
@@ -1748,8 +1748,18 @@ function createConditionalBlockComponent(owner) {
1748
1748
  class FarmConditionalBlock extends React__default.default.Component {
1749
1749
  constructor() {
1750
1750
  super(...arguments);
1751
+ this.root = null;
1751
1752
  this.captureRoot = (root) => {
1753
+ const previousRoot = this.root;
1754
+ const previousId = this.rootId;
1755
+ this.root = root;
1756
+ if (!root) {
1757
+ if (previousId !== void 0) owner.setRoot(previousId, null, previousRoot);
1758
+ this.rootId = void 0;
1759
+ return;
1760
+ }
1752
1761
  owner.setRoot(this.props.id, root);
1762
+ this.rootId = this.props.id;
1753
1763
  };
1754
1764
  this.refresh = (afterCommit) => {
1755
1765
  this.forceUpdate(afterCommit);
@@ -1764,12 +1774,15 @@ function createConditionalBlockComponent(owner) {
1764
1774
  componentDidUpdate(previous) {
1765
1775
  if (previous.id === this.props.id) return;
1766
1776
  this.unsubscribe?.();
1767
- owner.setRoot(previous.id, null);
1777
+ if (this.root && this.rootId !== this.props.id) {
1778
+ if (this.rootId !== void 0) owner.setRoot(this.rootId, null, this.root);
1779
+ owner.setRoot(this.props.id, this.root);
1780
+ this.rootId = this.props.id;
1781
+ }
1768
1782
  this.subscribe();
1769
1783
  }
1770
1784
  componentWillUnmount() {
1771
1785
  this.unsubscribe?.();
1772
- owner.setRoot(this.props.id, null);
1773
1786
  }
1774
1787
  render() {
1775
1788
  const node = this.props.render();
@@ -1890,33 +1903,65 @@ function materializeCompilerHostChildren(descriptor) {
1890
1903
  children.push(...staticChildren.slice(cursor, cursor + block.trailing));
1891
1904
  return children;
1892
1905
  }
1893
- function collectCompilerHostBlockIds(descriptor, ids) {
1894
- for (const child of flattenCompilerHostElements(descriptor.children)) {
1895
- collectCompilerHostBlockIds(child, ids);
1906
+ function collectActiveCompilerHostBlockIds(descriptor, ids) {
1907
+ for (const child of flattenCompilerHostElements(materializeCompilerHostChildren(descriptor))) {
1908
+ collectActiveCompilerHostBlockIds(child, ids);
1896
1909
  }
1897
1910
  const block = descriptor.block;
1898
- if (!block || ids.has(block.id)) return;
1911
+ if (!block) return;
1899
1912
  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);
1913
+ }
1914
+ function reconcileCompilerFallbackSubscriptions(owner, subscriptions, ids, refresh) {
1915
+ for (const [id, unsubscribe] of subscriptions) {
1916
+ if (ids.has(id)) continue;
1917
+ unsubscribe();
1918
+ subscriptions.delete(id);
1919
+ }
1920
+ for (const id of ids) {
1921
+ if (!subscriptions.has(id)) subscriptions.set(id, owner.subscribe(id, refresh));
1922
+ }
1923
+ }
1924
+ function clearCompilerFallbackSubscriptions(subscriptions) {
1925
+ for (const unsubscribe of subscriptions.values()) unsubscribe();
1926
+ subscriptions.clear();
1927
+ }
1928
+ function hasUnsafeCompilerFallbackKeys(descriptor) {
1929
+ const visitKeyedRange = (range) => {
1930
+ const items = materializeIterable(range.items());
1931
+ const keys = items.map((item, index) => keyedRowIdentity(range.rowKey(item, index)));
1932
+ if (new Set(keys).size !== keys.length) return true;
1933
+ return items.some((item, index) => visit(range.create(item, index)));
1934
+ };
1935
+ const visit = (current) => {
1936
+ for (const child of flattenCompilerHostElements(current.children)) {
1937
+ if (visit(child)) return true;
1938
+ }
1939
+ const block = current.block;
1940
+ if (!block) return false;
1941
+ if (block.kind === "conditional-ranges") {
1942
+ for (const range of block.ranges) {
1943
+ const selection = hostConditionalSelection(range);
1944
+ if (selection.kind === "branch" && visit(selection.branch.create())) return true;
1945
+ }
1946
+ return false;
1904
1947
  }
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);
1948
+ if (block.kind === "keyed-ranges") {
1949
+ return block.ranges.some(visitKeyedRange);
1909
1950
  }
1910
- } else {
1911
1951
  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);
1952
+ if (range.kind === "keyed") {
1953
+ if (visitKeyedRange(range)) return true;
1954
+ continue;
1918
1955
  }
1956
+ const selection = hostConditionalSelection(range);
1957
+ if (selection.kind === "branch" && visit(selection.branch.create())) return true;
1919
1958
  }
1959
+ return false;
1960
+ };
1961
+ try {
1962
+ return visit(descriptor);
1963
+ } catch {
1964
+ return true;
1920
1965
  }
1921
1966
  }
1922
1967
  function findCompilerHostTarget(root, path) {
@@ -3222,13 +3267,19 @@ function createHostConditionalBlockComponent(owner) {
3222
3267
  this.fallbackVersion = 0;
3223
3268
  this.propSyncQueued = false;
3224
3269
  this.currentProps = this.props;
3225
- this.fallbackUnsubscribers = [];
3270
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
3271
+ this.fallbackKeysWereUnsafe = false;
3226
3272
  this.activeBranch = null;
3227
3273
  this.instance = null;
3274
+ this.definitionVersion = owner.getDefinitionVersion?.();
3228
3275
  this.requestNestedFallback = () => {
3229
3276
  this.instance?.scope?.cleanup();
3230
3277
  this.activateFallback();
3231
3278
  };
3279
+ this.refreshFallbackDescendant = (afterCommit) => {
3280
+ this.prepareFallbackUpdate();
3281
+ this.forceUpdate(afterCommit);
3282
+ };
3232
3283
  this.captureRoot = (root) => {
3233
3284
  this.root = root;
3234
3285
  };
@@ -3237,31 +3288,39 @@ function createHostConditionalBlockComponent(owner) {
3237
3288
  };
3238
3289
  }
3239
3290
  subscribeFallbackDescendants() {
3240
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3241
- this.fallbackUnsubscribers = [];
3242
3291
  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);
3292
+ const selection = hostConditionalSelection(this.currentProps);
3293
+ if (selection.kind === "branch") {
3294
+ collectActiveCompilerHostBlockIds(selection.branch.create(), ids);
3248
3295
  }
3249
3296
  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
- );
3297
+ reconcileCompilerFallbackSubscriptions(
3298
+ owner,
3299
+ this.fallbackUnsubscribers,
3300
+ ids,
3301
+ this.refreshFallbackDescendant
3302
+ );
3303
+ }
3304
+ hasUnsafeFallbackKeys() {
3305
+ try {
3306
+ const selection = hostConditionalSelection(this.currentProps);
3307
+ return selection.kind === "branch" && hasUnsafeCompilerFallbackKeys(selection.branch.create());
3308
+ } catch {
3309
+ return true;
3257
3310
  }
3258
3311
  }
3312
+ prepareFallbackUpdate() {
3313
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
3314
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
3315
+ this.fallbackKeysWereUnsafe = unsafeKeys;
3316
+ }
3259
3317
  adopt() {
3260
3318
  if (!this.root) return false;
3261
3319
  const selection = hostConditionalSelection(this.currentProps);
3262
3320
  if (selection.kind === "fallback") return false;
3263
3321
  if (selection.kind === "empty") {
3264
3322
  if (this.root.childNodes.length !== 0) return false;
3323
+ this.instance?.scope?.cleanup();
3265
3324
  this.activeBranch = null;
3266
3325
  this.instance = null;
3267
3326
  return true;
@@ -3280,6 +3339,7 @@ function createHostConditionalBlockComponent(owner) {
3280
3339
  this.requestNestedFallback
3281
3340
  );
3282
3341
  if (!instance) return false;
3342
+ this.instance?.scope?.cleanup();
3283
3343
  this.activeBranch = selection.key;
3284
3344
  this.instance = instance;
3285
3345
  return true;
@@ -3294,6 +3354,7 @@ function createHostConditionalBlockComponent(owner) {
3294
3354
  this.instance = null;
3295
3355
  this.activeBranch = null;
3296
3356
  this.subscribeFallbackDescendants();
3357
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3297
3358
  this.fallbackVersion += 1;
3298
3359
  this.setState({ fallback: true }, afterCommit);
3299
3360
  }
@@ -3303,6 +3364,7 @@ function createHostConditionalBlockComponent(owner) {
3303
3364
  return;
3304
3365
  }
3305
3366
  if (this.state.fallback) {
3367
+ this.prepareFallbackUpdate();
3306
3368
  this.forceUpdate(afterCommit);
3307
3369
  return;
3308
3370
  }
@@ -3356,30 +3418,60 @@ function createHostConditionalBlockComponent(owner) {
3356
3418
  this.instance = instance;
3357
3419
  afterCommit?.();
3358
3420
  }
3421
+ listen() {
3422
+ const id = this.currentProps.id;
3423
+ const stop = this.stop;
3424
+ if (this.id === id) return;
3425
+ stop?.();
3426
+ this.stop = owner.subscribe(id, this.refresh);
3427
+ this.id = id;
3428
+ }
3359
3429
  schedulePropSync() {
3360
3430
  if (this.propSyncQueued) return;
3361
3431
  this.propSyncQueued = true;
3362
3432
  queueMicrotask(() => {
3363
3433
  this.propSyncQueued = false;
3364
- if (this.mounted && !this.state.fallback) this.reconcile();
3434
+ if (this.mounted && !this.state.fallback) {
3435
+ this.listen();
3436
+ this.reconcile();
3437
+ }
3365
3438
  });
3366
3439
  }
3367
3440
  shouldComponentUpdate(nextProps, nextState) {
3441
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
3368
3442
  this.currentProps = nextProps;
3443
+ if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3369
3444
  if (nextState.fallback || this.state.fallback) return true;
3445
+ if (definitionChanged) return true;
3370
3446
  this.schedulePropSync();
3371
3447
  return false;
3372
3448
  }
3373
3449
  componentDidMount() {
3374
3450
  this.mounted = true;
3375
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3376
- if (!this.adopt()) this.activateFallback();
3451
+ this.listen();
3452
+ if (this.state.fallback || this.fallbackRequested) {
3453
+ this.subscribeFallbackDescendants();
3454
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3455
+ } else if (!this.adopt()) this.activateFallback();
3456
+ }
3457
+ componentDidUpdate() {
3458
+ this.listen();
3459
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
3460
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
3461
+ this.definitionVersion = nextDefinitionVersion;
3462
+ if (this.state.fallback) {
3463
+ this.subscribeFallbackDescendants();
3464
+ } else if (definitionChanged && !this.adopt()) {
3465
+ this.activateFallback();
3466
+ }
3377
3467
  }
3378
3468
  componentWillUnmount() {
3379
3469
  this.mounted = false;
3380
- this.unsubscribe?.();
3381
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3382
- this.fallbackUnsubscribers = [];
3470
+ const stop = this.stop;
3471
+ stop?.();
3472
+ this.id = void 0;
3473
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3474
+ this.fallbackKeysWereUnsafe = false;
3383
3475
  this.instance?.scope?.cleanup();
3384
3476
  this.activeBranch = null;
3385
3477
  this.instance = null;
@@ -3411,14 +3503,20 @@ function createConditionalRangesBlockComponent(owner) {
3411
3503
  this.fallbackVersion = 0;
3412
3504
  this.propFallbackQueued = false;
3413
3505
  this.currentProps = this.props;
3414
- this.fallbackUnsubscribers = [];
3506
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
3507
+ this.fallbackKeysWereUnsafe = false;
3415
3508
  this.rangeInstances = [];
3416
3509
  this.staticSegments = [];
3417
3510
  this.staticValues = [];
3511
+ this.definitionVersion = owner.getDefinitionVersion?.();
3418
3512
  this.requestNestedFallback = () => {
3419
3513
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3420
3514
  this.activateFallback();
3421
3515
  };
3516
+ this.refreshFallbackDescendant = (afterCommit) => {
3517
+ this.prepareFallbackUpdate();
3518
+ this.forceUpdate(afterCommit);
3519
+ };
3422
3520
  this.captureRoot = (root) => {
3423
3521
  this.root = root;
3424
3522
  this.currentProps.rootRef?.(root);
@@ -3428,23 +3526,39 @@ function createConditionalRangesBlockComponent(owner) {
3428
3526
  };
3429
3527
  }
3430
3528
  subscribeFallbackDescendants() {
3431
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3432
- this.fallbackUnsubscribers = [];
3433
3529
  const ids = /* @__PURE__ */ new Set();
3434
3530
  for (const range of this.currentProps.ranges) {
3435
- if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
3436
- if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
3531
+ const selection = hostConditionalSelection(range);
3532
+ if (selection.kind === "branch") {
3533
+ collectActiveCompilerHostBlockIds(selection.branch.create(), ids);
3534
+ }
3437
3535
  }
3438
3536
  ids.delete(this.currentProps.id);
3439
- for (const id of ids) {
3440
- this.fallbackUnsubscribers.push(
3441
- owner.subscribe(id, (afterCommit) => {
3442
- this.fallbackVersion += 1;
3443
- this.forceUpdate(afterCommit);
3444
- })
3445
- );
3537
+ reconcileCompilerFallbackSubscriptions(
3538
+ owner,
3539
+ this.fallbackUnsubscribers,
3540
+ ids,
3541
+ this.refreshFallbackDescendant
3542
+ );
3543
+ }
3544
+ hasUnsafeFallbackKeys() {
3545
+ try {
3546
+ for (const range of this.currentProps.ranges) {
3547
+ const selection = hostConditionalSelection(range);
3548
+ if (selection.kind === "branch" && hasUnsafeCompilerFallbackKeys(selection.branch.create())) {
3549
+ return true;
3550
+ }
3551
+ }
3552
+ return false;
3553
+ } catch {
3554
+ return true;
3446
3555
  }
3447
3556
  }
3557
+ prepareFallbackUpdate() {
3558
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
3559
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
3560
+ this.fallbackKeysWereUnsafe = unsafeKeys;
3561
+ }
3448
3562
  readSelections(props) {
3449
3563
  const selections = [];
3450
3564
  for (const range of props.ranges) {
@@ -3461,6 +3575,7 @@ function createConditionalRangesBlockComponent(owner) {
3461
3575
  const elements = [...this.root.children];
3462
3576
  const staticSegments = [];
3463
3577
  const instances = [];
3578
+ const staticValues = this.staticValues.slice();
3464
3579
  const cleanupInstances = () => {
3465
3580
  for (const instance of instances) instance?.host.scope?.cleanup();
3466
3581
  };
@@ -3515,14 +3630,15 @@ function createConditionalRangesBlockComponent(owner) {
3515
3630
  return false;
3516
3631
  }
3517
3632
  staticSegments.push(elements.slice(cursor));
3518
- this.staticSegments = staticSegments;
3519
- this.rangeInstances = instances;
3520
- if (!applyStaticRangeBindings(props.bindings, this.staticSegments, this.staticValues)) {
3633
+ if (!applyStaticRangeBindings(props.bindings, staticSegments, staticValues)) {
3521
3634
  cleanupInstances();
3522
- this.rangeInstances = [];
3523
- this.staticSegments = [];
3524
3635
  return false;
3525
3636
  }
3637
+ for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3638
+ this.staticSegments = staticSegments;
3639
+ this.rangeInstances = instances;
3640
+ this.staticValues.length = 0;
3641
+ this.staticValues.push(...staticValues);
3526
3642
  return true;
3527
3643
  }
3528
3644
  anchorAfter(rangeIndex) {
@@ -3588,7 +3704,7 @@ function createConditionalRangesBlockComponent(owner) {
3588
3704
  return;
3589
3705
  }
3590
3706
  if (this.state.fallback) {
3591
- this.fallbackVersion += 1;
3707
+ this.prepareFallbackUpdate();
3592
3708
  this.forceUpdate(afterCommit);
3593
3709
  return;
3594
3710
  }
@@ -3617,6 +3733,14 @@ function createConditionalRangesBlockComponent(owner) {
3617
3733
  }
3618
3734
  afterCommit?.();
3619
3735
  }
3736
+ listen() {
3737
+ const id = this.currentProps.id;
3738
+ const stop = this.stop;
3739
+ if (this.id === id) return;
3740
+ stop?.();
3741
+ this.stop = owner.subscribe(id, this.refresh);
3742
+ this.id = id;
3743
+ }
3620
3744
  activateFallback(afterCommit) {
3621
3745
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
3622
3746
  afterCommit?.();
@@ -3625,6 +3749,7 @@ function createConditionalRangesBlockComponent(owner) {
3625
3749
  this.fallbackRequested = true;
3626
3750
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3627
3751
  this.subscribeFallbackDescendants();
3752
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3628
3753
  this.setState({ fallback: true }, afterCommit);
3629
3754
  }
3630
3755
  schedulePropFallback() {
@@ -3632,25 +3757,47 @@ function createConditionalRangesBlockComponent(owner) {
3632
3757
  this.propFallbackQueued = true;
3633
3758
  queueMicrotask(() => {
3634
3759
  this.propFallbackQueued = false;
3635
- if (this.mounted && !this.state.fallback) this.activateFallback();
3760
+ if (this.mounted && !this.state.fallback) {
3761
+ this.listen();
3762
+ this.activateFallback();
3763
+ }
3636
3764
  });
3637
3765
  }
3638
3766
  shouldComponentUpdate(nextProps, nextState) {
3767
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
3639
3768
  this.currentProps = nextProps;
3769
+ if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3640
3770
  if (nextState.fallback || this.state.fallback) return true;
3771
+ if (definitionChanged) return true;
3641
3772
  this.schedulePropFallback();
3642
3773
  return false;
3643
3774
  }
3644
3775
  componentDidMount() {
3645
3776
  this.mounted = true;
3646
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3647
- if (!this.adopt()) this.activateFallback();
3777
+ this.listen();
3778
+ if (this.state.fallback || this.fallbackRequested) {
3779
+ this.subscribeFallbackDescendants();
3780
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3781
+ } else if (!this.adopt()) this.activateFallback();
3782
+ }
3783
+ componentDidUpdate() {
3784
+ this.listen();
3785
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
3786
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
3787
+ this.definitionVersion = nextDefinitionVersion;
3788
+ if (this.state.fallback) {
3789
+ this.subscribeFallbackDescendants();
3790
+ } else if (definitionChanged && !this.adopt()) {
3791
+ this.activateFallback();
3792
+ }
3648
3793
  }
3649
3794
  componentWillUnmount() {
3650
3795
  this.mounted = false;
3651
- this.unsubscribe?.();
3652
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3653
- this.fallbackUnsubscribers = [];
3796
+ const stop = this.stop;
3797
+ stop?.();
3798
+ this.id = void 0;
3799
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3800
+ this.fallbackKeysWereUnsafe = false;
3654
3801
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3655
3802
  this.rangeInstances = [];
3656
3803
  this.staticSegments = [];
@@ -5437,6 +5584,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5437
5584
  this.fallbackKeysWereUnsafe = false;
5438
5585
  this.propSyncQueued = false;
5439
5586
  this.currentProps = this.props;
5587
+ this.definitionVersion = owner.getDefinitionVersion?.();
5440
5588
  this.instances = /* @__PURE__ */ new Map();
5441
5589
  this.identityTargets = /* @__PURE__ */ new Map();
5442
5590
  this.membershipTargets = /* @__PURE__ */ new Map();
@@ -5815,13 +5963,14 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5815
5963
  const rows = this.readRows(this.currentProps);
5816
5964
  const elements = [...this.root.children];
5817
5965
  if (!rows || rows.items.length !== elements.length) return false;
5966
+ const reactOwnedRows = this.hasReactOwnedRows();
5818
5967
  const opaqueConditionalPaths = new Set(
5819
5968
  (this.currentProps.conditionals || []).map((conditional) => conditional.path.join("."))
5820
5969
  );
5821
5970
  const instances = /* @__PURE__ */ new Map();
5822
5971
  for (let index = 0; index < rows.items.length; index += 1) {
5823
5972
  const descriptor = this.currentProps.create(rows.items[index], index);
5824
- if (this.hasReactOwnedRows() && !matchesCompilerHostElement(elements[index], descriptor, opaqueConditionalPaths)) {
5973
+ if (reactOwnedRows && !matchesCompilerHostElement(elements[index], descriptor, opaqueConditionalPaths)) {
5825
5974
  this.cleanupHostScopes(instances);
5826
5975
  return false;
5827
5976
  }
@@ -5834,7 +5983,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5834
5983
  key: rows.keys[index],
5835
5984
  element: elements[index],
5836
5985
  scope: scope || void 0,
5837
- values: this.hasReactOwnedRows() ? this.currentProps.bindings.map(() => UNSET_KEYED_ROW_BINDING) : readKeyedRowBindingValues(this.currentProps, rows.items[index], index),
5986
+ values: reactOwnedRows ? this.currentProps.bindings.map(() => UNSET_KEYED_ROW_BINDING) : readKeyedRowBindingValues(this.currentProps, rows.items[index], index),
5838
5987
  item: rows.items[index],
5839
5988
  index,
5840
5989
  conditionalValues: this.readConditionalValues(
@@ -5843,11 +5992,13 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5843
5992
  index
5844
5993
  )
5845
5994
  };
5846
- if (this.hasReactOwnedRows()) {
5847
- applyKeyedRowBindings(this.currentProps, instance, rows.items[index], index);
5848
- }
5849
5995
  instances.set(rows.keys[index], instance);
5850
5996
  }
5997
+ if (reactOwnedRows) {
5998
+ for (const instance of instances.values()) {
5999
+ applyKeyedRowBindings(this.currentProps, instance, instance.item, instance.index);
6000
+ }
6001
+ }
5851
6002
  this.cleanupHostScopes();
5852
6003
  this.instances = instances;
5853
6004
  this.rebuildElementIndex(instances);
@@ -6145,9 +6296,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6145
6296
  }
6146
6297
  if (this.state.fallback) {
6147
6298
  const unsafeKeys = this.hasUnsafeFallbackKeys();
6148
- if (unsafeKeys || this.fallbackKeysWereUnsafe) {
6149
- this.fallbackVersion += 1;
6150
- }
6299
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6151
6300
  this.fallbackKeysWereUnsafe = unsafeKeys;
6152
6301
  this.forceUpdate(afterCommit);
6153
6302
  return;
@@ -6271,20 +6420,37 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6271
6420
  this.commitCurrentCollection(dirtyState);
6272
6421
  this.notifyConditionalChanges(conditionalChanges, afterCommit);
6273
6422
  }
6423
+ listen() {
6424
+ const id = this.currentProps.id;
6425
+ const stop = this.stop;
6426
+ if (this.id === id) return;
6427
+ stop?.();
6428
+ this.stop = owner.subscribe(id, this.refresh);
6429
+ this.id = id;
6430
+ }
6274
6431
  schedulePropSync() {
6275
6432
  if (this.propSyncQueued) return;
6276
6433
  this.propSyncQueued = true;
6277
6434
  queueMicrotask(() => {
6278
6435
  this.propSyncQueued = false;
6279
- if (this.mounted && !this.state.fallback) this.reconcile();
6436
+ if (this.mounted && !this.state.fallback) {
6437
+ this.listen();
6438
+ this.reconcile();
6439
+ }
6280
6440
  });
6281
6441
  }
6282
6442
  shouldComponentUpdate(nextProps, nextState) {
6283
6443
  const wasReactOwned = this.hasReactOwnedRows(this.currentProps);
6284
6444
  const willBeReactOwned = this.hasReactOwnedRows(nextProps);
6445
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6285
6446
  this.currentProps = nextProps;
6447
+ if (this.state.fallback && nextState.fallback) {
6448
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6449
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6450
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6451
+ }
6286
6452
  if (nextState.fallback || this.state.fallback) return true;
6287
- if (wasReactOwned || willBeReactOwned) {
6453
+ if (definitionChanged || wasReactOwned || willBeReactOwned) {
6288
6454
  this.eventHandlers.clear();
6289
6455
  return true;
6290
6456
  }
@@ -6292,19 +6458,25 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6292
6458
  return false;
6293
6459
  }
6294
6460
  componentDidUpdate(previousProps) {
6295
- if (this.state.fallback || previousProps === this.props || !this.hasReactOwnedRows(previousProps) && !this.hasReactOwnedRows(this.props) || this.adopt()) {
6461
+ this.listen();
6462
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
6463
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
6464
+ this.definitionVersion = nextDefinitionVersion;
6465
+ if (this.state.fallback || previousProps === this.props || !definitionChanged && !this.hasReactOwnedRows(previousProps) && !this.hasReactOwnedRows(this.props) || this.adopt()) {
6296
6466
  return;
6297
6467
  }
6298
6468
  this.activateFallback();
6299
6469
  }
6300
6470
  componentDidMount() {
6301
6471
  this.mounted = true;
6302
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
6472
+ this.listen();
6303
6473
  if (!this.adopt()) this.activateFallback();
6304
6474
  }
6305
6475
  componentWillUnmount() {
6306
6476
  this.mounted = false;
6307
- this.unsubscribe?.();
6477
+ const stop = this.stop;
6478
+ stop?.();
6479
+ this.id = void 0;
6308
6480
  this.cleanupHostScopes();
6309
6481
  this.instances.clear();
6310
6482
  this.identityTargets.clear();
@@ -6341,11 +6513,13 @@ function createKeyedRangesBlockComponent(owner) {
6341
6513
  this.mounted = false;
6342
6514
  this.fallbackRequested = false;
6343
6515
  this.fallbackVersion = 0;
6516
+ this.fallbackKeysWereUnsafe = false;
6344
6517
  this.propFallbackQueued = false;
6345
6518
  this.currentProps = this.props;
6346
6519
  this.rangeInstances = [];
6347
6520
  this.staticSegments = [];
6348
6521
  this.staticValues = [];
6522
+ this.definitionVersion = owner.getDefinitionVersion?.();
6349
6523
  this.captureRoot = (root) => {
6350
6524
  this.root = root;
6351
6525
  this.currentProps.rootRef?.(root);
@@ -6369,6 +6543,13 @@ function createKeyedRangesBlockComponent(owner) {
6369
6543
  }
6370
6544
  return ranges;
6371
6545
  }
6546
+ hasUnsafeFallbackKeys() {
6547
+ try {
6548
+ return this.readRanges(this.currentProps) === null;
6549
+ } catch {
6550
+ return true;
6551
+ }
6552
+ }
6372
6553
  adopt(props = this.currentProps) {
6373
6554
  if (!this.root || !Number.isSafeInteger(props.trailing) || props.trailing < 0) return false;
6374
6555
  const rowsByRange = this.readRanges(props);
@@ -6376,6 +6557,7 @@ function createKeyedRangesBlockComponent(owner) {
6376
6557
  const elements = [...this.root.children];
6377
6558
  const staticSegments = [];
6378
6559
  const instancesByRange = [];
6560
+ const staticValues = this.staticValues.slice();
6379
6561
  let cursor = 0;
6380
6562
  for (let rangeIndex = 0; rangeIndex < props.ranges.length; rangeIndex += 1) {
6381
6563
  const range = props.ranges[rangeIndex];
@@ -6407,13 +6589,11 @@ function createKeyedRangesBlockComponent(owner) {
6407
6589
  }
6408
6590
  if (cursor + props.trailing !== elements.length) return false;
6409
6591
  staticSegments.push(elements.slice(cursor));
6592
+ if (!applyStaticRangeBindings(props.bindings, staticSegments, staticValues)) return false;
6410
6593
  this.staticSegments = staticSegments;
6411
6594
  this.rangeInstances = instancesByRange;
6412
- if (!applyStaticRangeBindings(props.bindings, this.staticSegments, this.staticValues)) {
6413
- this.rangeInstances = [];
6414
- this.staticSegments = [];
6415
- return false;
6416
- }
6595
+ this.staticValues.length = 0;
6596
+ this.staticValues.push(...staticValues);
6417
6597
  return true;
6418
6598
  }
6419
6599
  anchorAfter(rangeIndex) {
@@ -6481,7 +6661,9 @@ function createKeyedRangesBlockComponent(owner) {
6481
6661
  return;
6482
6662
  }
6483
6663
  if (this.state.fallback) {
6484
- this.fallbackVersion += 1;
6664
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6665
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6666
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6485
6667
  this.forceUpdate(afterCommit);
6486
6668
  return;
6487
6669
  }
@@ -6508,12 +6690,21 @@ function createKeyedRangesBlockComponent(owner) {
6508
6690
  }
6509
6691
  afterCommit?.();
6510
6692
  }
6693
+ listen() {
6694
+ const id = this.currentProps.id;
6695
+ const stop = this.stop;
6696
+ if (this.id === id) return;
6697
+ stop?.();
6698
+ this.stop = owner.subscribe(id, this.refresh);
6699
+ this.id = id;
6700
+ }
6511
6701
  activateFallback(afterCommit) {
6512
6702
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
6513
6703
  afterCommit?.();
6514
6704
  return;
6515
6705
  }
6516
6706
  this.fallbackRequested = true;
6707
+ this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
6517
6708
  this.setState({ fallback: true }, afterCommit);
6518
6709
  }
6519
6710
  schedulePropFallback() {
@@ -6521,23 +6712,42 @@ function createKeyedRangesBlockComponent(owner) {
6521
6712
  this.propFallbackQueued = true;
6522
6713
  queueMicrotask(() => {
6523
6714
  this.propFallbackQueued = false;
6524
- if (this.mounted && !this.state.fallback) this.activateFallback();
6715
+ if (this.mounted && !this.state.fallback) {
6716
+ this.listen();
6717
+ this.activateFallback();
6718
+ }
6525
6719
  });
6526
6720
  }
6527
6721
  shouldComponentUpdate(nextProps, nextState) {
6722
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6528
6723
  this.currentProps = nextProps;
6724
+ if (this.state.fallback && nextState.fallback) {
6725
+ const unsafeKeys = this.hasUnsafeFallbackKeys();
6726
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6727
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6728
+ }
6529
6729
  if (nextState.fallback || this.state.fallback) return true;
6730
+ if (definitionChanged) return true;
6530
6731
  this.schedulePropFallback();
6531
6732
  return false;
6532
6733
  }
6533
6734
  componentDidMount() {
6534
6735
  this.mounted = true;
6535
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
6736
+ this.listen();
6536
6737
  if (!this.adopt()) this.activateFallback();
6537
6738
  }
6739
+ componentDidUpdate() {
6740
+ this.listen();
6741
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
6742
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
6743
+ this.definitionVersion = nextDefinitionVersion;
6744
+ if (!this.state.fallback && definitionChanged && !this.adopt()) this.activateFallback();
6745
+ }
6538
6746
  componentWillUnmount() {
6539
6747
  this.mounted = false;
6540
- this.unsubscribe?.();
6748
+ const stop = this.stop;
6749
+ stop?.();
6750
+ this.id = void 0;
6541
6751
  this.rangeInstances = [];
6542
6752
  this.staticSegments = [];
6543
6753
  this.staticValues.length = 0;
@@ -6567,14 +6777,25 @@ function createMixedRangesBlockComponent(owner) {
6567
6777
  this.mounted = false;
6568
6778
  this.fallbackRequested = false;
6569
6779
  this.fallbackVersion = 0;
6780
+ this.fallbackKeysWereUnsafe = false;
6570
6781
  this.propFallbackQueued = false;
6571
6782
  this.currentProps = this.props;
6572
6783
  this.controller = null;
6573
- this.fallbackUnsubscribers = [];
6784
+ this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
6785
+ this.definitionVersion = owner.getDefinitionVersion?.();
6574
6786
  this.captureRoot = (root) => {
6575
6787
  this.root = root;
6576
6788
  this.currentProps.rootRef?.(root);
6577
6789
  };
6790
+ this.refreshFallbackBlock = (afterCommit) => {
6791
+ if (!this.mounted || !this.state.fallback) {
6792
+ afterCommit?.();
6793
+ return;
6794
+ }
6795
+ const nextDescriptor = this.currentProps.create();
6796
+ this.prepareFallbackUpdate(nextDescriptor);
6797
+ this.forceUpdate(afterCommit);
6798
+ };
6578
6799
  this.activateFallback = (afterCommit) => {
6579
6800
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
6580
6801
  afterCommit?.();
@@ -6583,6 +6804,7 @@ function createMixedRangesBlockComponent(owner) {
6583
6804
  this.fallbackRequested = true;
6584
6805
  this.controller?.cleanup();
6585
6806
  this.controller = null;
6807
+ this.fallbackKeysWereUnsafe = hasUnsafeCompilerFallbackKeys(this.currentProps.create());
6586
6808
  this.fallbackVersion += 1;
6587
6809
  this.setState({ fallback: true }, () => {
6588
6810
  this.subscribeFallbackBlocks();
@@ -6591,26 +6813,27 @@ function createMixedRangesBlockComponent(owner) {
6591
6813
  };
6592
6814
  }
6593
6815
  clearFallbackSubscriptions() {
6594
- for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
6595
- this.fallbackUnsubscribers = [];
6816
+ clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
6817
+ }
6818
+ readFallbackBlockIds(descriptor) {
6819
+ const ids = /* @__PURE__ */ new Set();
6820
+ collectActiveCompilerHostBlockIds(descriptor, ids);
6821
+ return ids;
6822
+ }
6823
+ prepareFallbackUpdate(descriptor) {
6824
+ const unsafeKeys = hasUnsafeCompilerFallbackKeys(descriptor);
6825
+ if (unsafeKeys || this.fallbackKeysWereUnsafe) this.fallbackVersion += 1;
6826
+ this.fallbackKeysWereUnsafe = unsafeKeys;
6596
6827
  }
6597
6828
  subscribeFallbackBlocks() {
6598
- this.clearFallbackSubscriptions();
6599
6829
  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
- }
6830
+ const ids = this.readFallbackBlockIds(descriptor);
6831
+ reconcileCompilerFallbackSubscriptions(
6832
+ owner,
6833
+ this.fallbackUnsubscribers,
6834
+ ids,
6835
+ this.refreshFallbackBlock
6836
+ );
6614
6837
  }
6615
6838
  adopt() {
6616
6839
  if (!this.root) return false;
@@ -6633,7 +6856,9 @@ function createMixedRangesBlockComponent(owner) {
6633
6856
  controller.cleanup();
6634
6857
  throw error;
6635
6858
  }
6859
+ const previous = this.controller;
6636
6860
  this.controller = controller;
6861
+ previous?.cleanup();
6637
6862
  return true;
6638
6863
  }
6639
6864
  schedulePropFallback() {
@@ -6645,23 +6870,39 @@ function createMixedRangesBlockComponent(owner) {
6645
6870
  });
6646
6871
  }
6647
6872
  shouldComponentUpdate(nextProps, nextState) {
6873
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6648
6874
  this.currentProps = nextProps;
6875
+ if (this.state.fallback && nextState.fallback) {
6876
+ this.prepareFallbackUpdate(this.currentProps.create());
6877
+ }
6649
6878
  if (nextState.fallback || this.state.fallback) return true;
6879
+ if (definitionChanged) return true;
6650
6880
  this.schedulePropFallback();
6651
6881
  return false;
6652
6882
  }
6653
6883
  componentDidMount() {
6654
6884
  this.mounted = true;
6655
- if (!this.adopt()) this.activateFallback();
6885
+ if (this.state.fallback || this.fallbackRequested) {
6886
+ this.fallbackKeysWereUnsafe = hasUnsafeCompilerFallbackKeys(this.currentProps.create());
6887
+ this.subscribeFallbackBlocks();
6888
+ } else if (!this.adopt()) this.activateFallback();
6656
6889
  }
6657
6890
  componentDidUpdate() {
6658
- if (this.state.fallback) this.subscribeFallbackBlocks();
6891
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
6892
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
6893
+ this.definitionVersion = nextDefinitionVersion;
6894
+ if (this.state.fallback) {
6895
+ this.subscribeFallbackBlocks();
6896
+ } else if (definitionChanged && !this.adopt()) {
6897
+ this.activateFallback();
6898
+ }
6659
6899
  }
6660
6900
  componentWillUnmount() {
6661
6901
  this.mounted = false;
6662
6902
  this.controller?.cleanup();
6663
6903
  this.controller = null;
6664
6904
  this.clearFallbackSubscriptions();
6905
+ this.fallbackKeysWereUnsafe = false;
6665
6906
  }
6666
6907
  render() {
6667
6908
  const container = this.currentProps.render();
@@ -7494,8 +7735,9 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7494
7735
  };
7495
7736
  });
7496
7737
  const featureOwner = {
7497
- setRoot: (id, root) => this.setBlockRoot(id, root),
7498
- subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
7738
+ setRoot: (id, root, expectedRoot) => this.setBlockRoot(id, root, expectedRoot),
7739
+ subscribe: (id, refresh) => this.subscribeToBlock(id, refresh),
7740
+ getDefinitionVersion: () => definitionReference.current
7499
7741
  };
7500
7742
  const blockRuntime = {
7501
7743
  target: (id) => this.bindingTarget(id)
@@ -7634,8 +7876,9 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7634
7876
  }
7635
7877
  snapshot.element.setSelectionRange(snapshot.start, snapshot.end, snapshot.direction);
7636
7878
  }
7637
- setBlockRoot(id, root) {
7879
+ setBlockRoot(id, root, expectedRoot) {
7638
7880
  const previous = this.blockRoots.get(id);
7881
+ if (!root && expectedRoot !== void 0 && previous !== expectedRoot) return;
7639
7882
  if (previous) this.blockRootElements.delete(previous);
7640
7883
  if (root) {
7641
7884
  this.blockRoots.set(id, root);
@@ -7778,8 +8021,6 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7778
8021
  this.dirtyState.clear();
7779
8022
  this.inputSelection = null;
7780
8023
  this.blockRefreshListeners.clear();
7781
- this.blockRoots.clear();
7782
- this.blockRootElements.clear();
7783
8024
  this.bindingTargetRefs.clear();
7784
8025
  this.indexedDefinition = null;
7785
8026
  this.staticBindingsByDependency = [];