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

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,7 +1768,11 @@ 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() {
@@ -1955,10 +1969,7 @@ function normalizedStaticRangeBindingValue(binding, value) {
1955
1969
  }
1956
1970
  function applyStaticRangeBindings(bindings, segments, values) {
1957
1971
  const activeBindings = bindings || [];
1958
- if (values.length === 0 && activeBindings.length > 0) {
1959
- values.push(...activeBindings.map(() => UNSET_STATIC_RANGE_BINDING));
1960
- }
1961
- if (values.length !== activeBindings.length) return false;
1972
+ const targets = [];
1962
1973
  for (let index = 0; index < activeBindings.length; index += 1) {
1963
1974
  const binding = activeBindings[index];
1964
1975
  if (!Number.isSafeInteger(binding.segment) || binding.segment < 0 || !Number.isSafeInteger(binding.sibling) || binding.sibling < 0) {
@@ -1966,19 +1977,31 @@ function applyStaticRangeBindings(bindings, segments, values) {
1966
1977
  }
1967
1978
  const sibling = segments[binding.segment]?.[binding.sibling];
1968
1979
  const target = sibling && findCompilerHostTarget(sibling, binding.path);
1969
- if (!target) return false;
1970
- const rawValue = binding.read();
1971
- const value = normalizedStaticRangeBindingValue(binding, rawValue);
1972
- if (Object.is(values[index], value)) continue;
1980
+ if (!target || binding.kind !== "text" && (binding.kind !== "style" && binding.kind !== "attribute" || !binding.name)) {
1981
+ return false;
1982
+ }
1983
+ targets[index] = target;
1984
+ }
1985
+ const initializesValues = values.length === 0 && activeBindings.length > 0;
1986
+ if (!initializesValues && values.length !== activeBindings.length) return false;
1987
+ const nextValues = [];
1988
+ for (let index = 0; index < activeBindings.length; index += 1) {
1989
+ const binding = activeBindings[index];
1990
+ nextValues[index] = normalizedStaticRangeBindingValue(binding, binding.read());
1991
+ }
1992
+ for (let index = 0; index < activeBindings.length; index += 1) {
1993
+ const binding = activeBindings[index];
1994
+ const value = nextValues[index];
1995
+ const previous = initializesValues ? UNSET_STATIC_RANGE_BINDING : values[index];
1996
+ if (Object.is(previous, value)) continue;
1973
1997
  values[index] = value;
1998
+ const target = targets[index];
1974
1999
  if (binding.kind === "text") {
1975
2000
  target.textContent = value;
1976
- } else if (binding.kind === "style" && binding.name) {
1977
- updateStyle(target, binding.name, rawValue);
1978
- } else if (binding.kind === "attribute" && binding.name) {
1979
- updateAttribute(target, binding.name, rawValue);
2001
+ } else if (binding.kind === "style") {
2002
+ updateStyle(target, binding.name, value);
1980
2003
  } else {
1981
- return false;
2004
+ updateAttribute(target, binding.name, value);
1982
2005
  }
1983
2006
  }
1984
2007
  return true;
@@ -2234,24 +2257,49 @@ function readKeyedRowBindingValues(props, item, index) {
2234
2257
  );
2235
2258
  }
2236
2259
  function applyKeyedRowBindings(props, instance, item, index) {
2260
+ if (props.bindings.length < 2) {
2261
+ if (props.bindings.length === 1) applyKeyedRowBinding(props, instance, item, index, 0);
2262
+ return;
2263
+ }
2264
+ const nextValues = readKeyedRowBindingValues(props, item, index);
2265
+ let targets;
2237
2266
  for (let bindingIndex = 0; bindingIndex < props.bindings.length; bindingIndex += 1) {
2238
- applyKeyedRowBinding(props, instance, item, index, bindingIndex);
2267
+ if (Object.is(instance.values[bindingIndex], nextValues[bindingIndex])) continue;
2268
+ targets || (targets = []);
2269
+ targets[bindingIndex] = findCompilerHostTarget(
2270
+ instance.element,
2271
+ props.bindings[bindingIndex].path
2272
+ );
2273
+ }
2274
+ if (!targets) return;
2275
+ for (let bindingIndex = 0; bindingIndex < props.bindings.length; bindingIndex += 1) {
2276
+ const value = nextValues[bindingIndex];
2277
+ if (Object.is(instance.values[bindingIndex], value)) continue;
2278
+ commitKeyedRowBinding(
2279
+ props.bindings[bindingIndex],
2280
+ instance,
2281
+ bindingIndex,
2282
+ value,
2283
+ targets[bindingIndex]
2284
+ );
2239
2285
  }
2240
2286
  }
2241
2287
  function applyKeyedRowBinding(props, instance, item, index, bindingIndex) {
2242
2288
  const binding = props.bindings[bindingIndex];
2243
- const rawValue = binding.read(item, index);
2244
- const value = normalizedKeyedRowBindingValue(binding, rawValue);
2289
+ const value = normalizedKeyedRowBindingValue(binding, binding.read(item, index));
2245
2290
  if (Object.is(instance.values[bindingIndex], value)) return;
2246
- instance.values[bindingIndex] = value;
2247
2291
  const target = findCompilerHostTarget(instance.element, binding.path);
2292
+ commitKeyedRowBinding(binding, instance, bindingIndex, value, target);
2293
+ }
2294
+ function commitKeyedRowBinding(binding, instance, bindingIndex, value, target) {
2295
+ instance.values[bindingIndex] = value;
2248
2296
  if (!target) return;
2249
2297
  if (binding.kind === "text") {
2250
2298
  target.textContent = value;
2251
2299
  } else if (binding.kind === "style" && binding.name) {
2252
- updateStyle(target, binding.name, rawValue);
2300
+ updateStyle(target, binding.name, value);
2253
2301
  } else if (binding.kind === "attribute" && binding.name) {
2254
- updateAttribute(target, binding.name, rawValue);
2302
+ updateAttribute(target, binding.name, value);
2255
2303
  }
2256
2304
  }
2257
2305
  function prepareKeyedRowBindingUpdates(props, instance, item, index) {
@@ -2263,21 +2311,13 @@ function prepareKeyedRowBindingUpdates(props, instance, item, index) {
2263
2311
  if (Object.is(instance.values[bindingIndex], value)) continue;
2264
2312
  const target = findCompilerHostTarget(instance.element, binding.path);
2265
2313
  if (!target || binding.kind !== "text" && !binding.name) return void 0;
2266
- updates.push([bindingIndex, rawValue, target, value]);
2314
+ updates.push([bindingIndex, target, value]);
2267
2315
  }
2268
2316
  return updates;
2269
2317
  }
2270
2318
  function applyPreparedKeyedRowBindingUpdates(props, instance, updates) {
2271
- for (const [bindingIndex, rawValue, target, value] of updates) {
2272
- const binding = props.bindings[bindingIndex];
2273
- instance.values[bindingIndex] = value;
2274
- if (binding.kind === "text") {
2275
- target.textContent = value;
2276
- } else if (binding.kind === "style") {
2277
- updateStyle(target, binding.name, rawValue);
2278
- } else {
2279
- updateAttribute(target, binding.name, rawValue);
2280
- }
2319
+ for (const [bindingIndex, target, value] of updates) {
2320
+ commitKeyedRowBinding(props.bindings[bindingIndex], instance, bindingIndex, value, target);
2281
2321
  }
2282
2322
  }
2283
2323
  function keyedRowConditionalSnapshot(conditional, item, index) {
@@ -2339,6 +2379,35 @@ function applyHostConditionalBindings(branch, instance) {
2339
2379
  }
2340
2380
  }
2341
2381
  }
2382
+ function prepareHostConditionalBindings(branch, instance) {
2383
+ for (let bindingIndex = 0; bindingIndex < branch.bindings.length; bindingIndex += 1) {
2384
+ const binding = branch.bindings[bindingIndex];
2385
+ const rawValue = binding.read();
2386
+ const target = findCompilerHostTarget(instance.element, binding.path);
2387
+ if (!target || binding.kind !== "text" && (binding.kind !== "style" && binding.kind !== "attribute" || !binding.name)) {
2388
+ return false;
2389
+ }
2390
+ instance.values[bindingIndex] = [
2391
+ target,
2392
+ normalizedHostConditionalBindingValue(binding, rawValue)
2393
+ ];
2394
+ }
2395
+ return true;
2396
+ }
2397
+ function applyPreparedHostConditionalBindings(branch, instance) {
2398
+ for (let bindingIndex = 0; bindingIndex < branch.bindings.length; bindingIndex += 1) {
2399
+ const binding = branch.bindings[bindingIndex];
2400
+ const [target, value] = instance.values[bindingIndex];
2401
+ instance.values[bindingIndex] = value;
2402
+ if (binding.kind === "text") {
2403
+ target.textContent = value;
2404
+ } else if (binding.kind === "style") {
2405
+ updateStyle(target, binding.name, value);
2406
+ } else {
2407
+ updateAttribute(target, binding.name, value);
2408
+ }
2409
+ }
2410
+ }
2342
2411
  var UNSET_HOST_CONDITIONAL_BINDING = /* @__PURE__ */ Symbol("unset host conditional binding");
2343
2412
  function mountCompilerHostTree(owner, element, descriptor, onFallback) {
2344
2413
  if (!matchesCompilerHostElement(element, descriptor)) return null;
@@ -2426,7 +2495,7 @@ function mountCompilerHostTree(owner, element, descriptor, onFallback) {
2426
2495
  }
2427
2496
  };
2428
2497
  }
2429
- function mountCompilerHostInstance(owner, element, descriptor, branch, onFallback) {
2498
+ function mountCompilerHostInstance(owner, element, descriptor, branch, onFallback, applyBindingsImmediately = true) {
2430
2499
  const scope = mountCompilerHostTree(owner, element, descriptor, onFallback);
2431
2500
  if (!scope) return null;
2432
2501
  const instance = {
@@ -2434,6 +2503,7 @@ function mountCompilerHostInstance(owner, element, descriptor, branch, onFallbac
2434
2503
  scope,
2435
2504
  values: branch.bindings.map(() => UNSET_HOST_CONDITIONAL_BINDING)
2436
2505
  };
2506
+ if (!applyBindingsImmediately) return instance;
2437
2507
  try {
2438
2508
  applyHostConditionalBindings(branch, instance);
2439
2509
  } catch (error) {
@@ -2540,13 +2610,19 @@ var CompilerNestedConditionalRanges = class {
2540
2610
  element,
2541
2611
  descriptor,
2542
2612
  selection.branch,
2543
- this.onFallback
2613
+ this.onFallback,
2614
+ false
2615
+ // Commit only after every sibling range validates.
2544
2616
  );
2545
2617
  if (!host) {
2546
2618
  this.cleanup();
2547
2619
  return false;
2548
2620
  }
2549
2621
  this.instances.push({ key: selection.key, host });
2622
+ if (!prepareHostConditionalBindings(selection.branch, host)) {
2623
+ this.cleanup();
2624
+ return false;
2625
+ }
2550
2626
  cursor += 1;
2551
2627
  }
2552
2628
  const trailingEnd = cursor + this.block.trailing;
@@ -2559,6 +2635,13 @@ var CompilerNestedConditionalRanges = class {
2559
2635
  this.cleanup();
2560
2636
  return false;
2561
2637
  }
2638
+ for (let index = 0; index < selections.length; index += 1) {
2639
+ const selection = selections[index];
2640
+ const instance = this.instances[index];
2641
+ if (selection.kind === "branch" && instance) {
2642
+ applyPreparedHostConditionalBindings(selection.branch, instance.host);
2643
+ }
2644
+ }
2562
2645
  this.unsubscribe = this.owner.subscribe(this.block.id, this.refresh);
2563
2646
  return true;
2564
2647
  }
@@ -2727,6 +2810,7 @@ var CompilerNestedKeyedRanges = class {
2727
2810
  const elements = [...this.root.children];
2728
2811
  const descriptors = flattenCompilerHostElements(materializeCompilerHostChildren(this.host));
2729
2812
  if (elements.length !== descriptors.length) return false;
2813
+ const preparedBindings = [];
2730
2814
  let cursor = 0;
2731
2815
  for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
2732
2816
  const range = this.block.ranges[rangeIndex];
@@ -2743,6 +2827,8 @@ var CompilerNestedKeyedRanges = class {
2743
2827
  this.staticSegments.push(elements.slice(cursor, staticEnd));
2744
2828
  cursor = staticEnd;
2745
2829
  const instances = /* @__PURE__ */ new Map();
2830
+ this.instances.push(instances);
2831
+ const rangeBindingUpdates = [];
2746
2832
  for (let index = 0; index < rows.items.length; index += 1) {
2747
2833
  const element = elements[cursor + index];
2748
2834
  if (!element) {
@@ -2755,7 +2841,7 @@ var CompilerNestedKeyedRanges = class {
2755
2841
  this.cleanup();
2756
2842
  return false;
2757
2843
  }
2758
- instances.set(rows.keys[index], {
2844
+ const instance = {
2759
2845
  key: rows.keys[index],
2760
2846
  element,
2761
2847
  scope,
@@ -2763,10 +2849,23 @@ var CompilerNestedKeyedRanges = class {
2763
2849
  item: rows.items[index],
2764
2850
  index,
2765
2851
  conditionalValues: /* @__PURE__ */ new Map()
2766
- });
2767
- applyKeyedRowBindings(range, instances.get(rows.keys[index]), rows.items[index], index);
2852
+ };
2853
+ let bindingUpdates;
2854
+ try {
2855
+ bindingUpdates = prepareKeyedRowBindingUpdates(range, instance, rows.items[index], index);
2856
+ } catch (error) {
2857
+ scope.cleanup();
2858
+ throw error;
2859
+ }
2860
+ if (!bindingUpdates) {
2861
+ scope.cleanup();
2862
+ this.cleanup();
2863
+ return false;
2864
+ }
2865
+ instances.set(rows.keys[index], instance);
2866
+ rangeBindingUpdates.push(bindingUpdates);
2768
2867
  }
2769
- this.instances.push(instances);
2868
+ preparedBindings.push(rangeBindingUpdates);
2770
2869
  cursor += rows.items.length;
2771
2870
  }
2772
2871
  const trailingEnd = cursor + this.block.trailing;
@@ -2779,6 +2878,18 @@ var CompilerNestedKeyedRanges = class {
2779
2878
  this.cleanup();
2780
2879
  return false;
2781
2880
  }
2881
+ for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
2882
+ const range = this.block.ranges[rangeIndex];
2883
+ let rowIndex = 0;
2884
+ for (const instance of this.instances[rangeIndex].values()) {
2885
+ applyPreparedKeyedRowBindingUpdates(
2886
+ range,
2887
+ instance,
2888
+ preparedBindings[rangeIndex][rowIndex]
2889
+ );
2890
+ rowIndex += 1;
2891
+ }
2892
+ }
2782
2893
  this.unsubscribe = this.owner.subscribe(this.block.id, this.refresh);
2783
2894
  return true;
2784
2895
  }
@@ -2972,6 +3083,7 @@ var CompilerNestedMixedRanges = class {
2972
3083
  const elements = [...this.root.children];
2973
3084
  const descriptors = flattenCompilerHostElements(this.host.children);
2974
3085
  if (elements.length !== descriptors.length) return false;
3086
+ const preparedKeyedBindings = [];
2975
3087
  let cursor = 0;
2976
3088
  for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
2977
3089
  const range = this.block.ranges[rangeIndex];
@@ -3003,7 +3115,9 @@ var CompilerNestedMixedRanges = class {
3003
3115
  element,
3004
3116
  descriptor,
3005
3117
  snapshot.selection.branch,
3006
- this.onFallback
3118
+ this.onFallback,
3119
+ false
3120
+ // Commit only after every sibling range validates.
3007
3121
  );
3008
3122
  if (!host) {
3009
3123
  this.cleanup();
@@ -3013,6 +3127,10 @@ var CompilerNestedMixedRanges = class {
3013
3127
  kind: "conditional",
3014
3128
  value: { key: snapshot.selection.key, host }
3015
3129
  });
3130
+ if (!prepareHostConditionalBindings(snapshot.selection.branch, host)) {
3131
+ this.cleanup();
3132
+ return false;
3133
+ }
3016
3134
  cursor += 1;
3017
3135
  continue;
3018
3136
  }
@@ -3021,6 +3139,8 @@ var CompilerNestedMixedRanges = class {
3021
3139
  return false;
3022
3140
  }
3023
3141
  const keyedInstances = /* @__PURE__ */ new Map();
3142
+ this.instances.push({ kind: "keyed", value: keyedInstances });
3143
+ const keyedBindingUpdates = [];
3024
3144
  for (let index = 0; index < snapshot.rows.items.length; index += 1) {
3025
3145
  const element = elements[cursor + index];
3026
3146
  if (!element) {
@@ -3042,15 +3162,27 @@ var CompilerNestedMixedRanges = class {
3042
3162
  index,
3043
3163
  conditionalValues: /* @__PURE__ */ new Map()
3044
3164
  };
3165
+ let bindingUpdates;
3045
3166
  try {
3046
- applyKeyedRowBindings(range, instance, snapshot.rows.items[index], index);
3167
+ bindingUpdates = prepareKeyedRowBindingUpdates(
3168
+ range,
3169
+ instance,
3170
+ snapshot.rows.items[index],
3171
+ index
3172
+ );
3047
3173
  } catch (error) {
3048
3174
  scope.cleanup();
3049
3175
  throw error;
3050
3176
  }
3177
+ if (!bindingUpdates) {
3178
+ scope.cleanup();
3179
+ this.cleanup();
3180
+ return false;
3181
+ }
3051
3182
  keyedInstances.set(snapshot.rows.keys[index], instance);
3183
+ keyedBindingUpdates.push(bindingUpdates);
3052
3184
  }
3053
- this.instances.push({ kind: "keyed", value: keyedInstances });
3185
+ preparedKeyedBindings[rangeIndex] = keyedBindingUpdates;
3054
3186
  cursor += snapshot.rows.items.length;
3055
3187
  }
3056
3188
  const trailingEnd = cursor + this.block.trailing;
@@ -3063,6 +3195,22 @@ var CompilerNestedMixedRanges = class {
3063
3195
  this.cleanup();
3064
3196
  return false;
3065
3197
  }
3198
+ for (let index = 0; index < snapshots.length; index += 1) {
3199
+ const snapshot = snapshots[index];
3200
+ const instance = this.instances[index];
3201
+ if (snapshot.kind === "conditional" && snapshot.selection.kind === "branch" && instance?.kind === "conditional" && instance.value) {
3202
+ applyPreparedHostConditionalBindings(snapshot.selection.branch, instance.value.host);
3203
+ } else if (snapshot.kind === "keyed" && instance?.kind === "keyed") {
3204
+ const range = this.block.ranges[index];
3205
+ const bindingUpdates = preparedKeyedBindings[index];
3206
+ if (range.kind !== "keyed") continue;
3207
+ let rowIndex = 0;
3208
+ for (const row of instance.value.values()) {
3209
+ applyPreparedKeyedRowBindingUpdates(range, row, bindingUpdates[rowIndex]);
3210
+ rowIndex += 1;
3211
+ }
3212
+ }
3213
+ }
3066
3214
  this.unsubscribe = this.owner.subscribe(this.block.id, this.refresh);
3067
3215
  return true;
3068
3216
  }
@@ -3251,6 +3399,7 @@ function createHostConditionalBlockComponent(owner) {
3251
3399
  this.fallbackKeysWereUnsafe = false;
3252
3400
  this.activeBranch = null;
3253
3401
  this.instance = null;
3402
+ this.definitionVersion = owner.getDefinitionVersion?.();
3254
3403
  this.requestNestedFallback = () => {
3255
3404
  this.instance?.scope?.cleanup();
3256
3405
  this.activateFallback();
@@ -3299,6 +3448,7 @@ function createHostConditionalBlockComponent(owner) {
3299
3448
  if (selection.kind === "fallback") return false;
3300
3449
  if (selection.kind === "empty") {
3301
3450
  if (this.root.childNodes.length !== 0) return false;
3451
+ this.instance?.scope?.cleanup();
3302
3452
  this.activeBranch = null;
3303
3453
  this.instance = null;
3304
3454
  return true;
@@ -3317,6 +3467,7 @@ function createHostConditionalBlockComponent(owner) {
3317
3467
  this.requestNestedFallback
3318
3468
  );
3319
3469
  if (!instance) return false;
3470
+ this.instance?.scope?.cleanup();
3320
3471
  this.activeBranch = selection.key;
3321
3472
  this.instance = instance;
3322
3473
  return true;
@@ -3395,35 +3546,58 @@ function createHostConditionalBlockComponent(owner) {
3395
3546
  this.instance = instance;
3396
3547
  afterCommit?.();
3397
3548
  }
3549
+ listen() {
3550
+ const id = this.currentProps.id;
3551
+ const stop = this.stop;
3552
+ if (this.id === id) return;
3553
+ stop?.();
3554
+ this.stop = owner.subscribe(id, this.refresh);
3555
+ this.id = id;
3556
+ }
3398
3557
  schedulePropSync() {
3399
3558
  if (this.propSyncQueued) return;
3400
3559
  this.propSyncQueued = true;
3401
3560
  queueMicrotask(() => {
3402
3561
  this.propSyncQueued = false;
3403
- if (this.mounted && !this.state.fallback) this.reconcile();
3562
+ if (this.mounted && !this.state.fallback) {
3563
+ this.listen();
3564
+ this.reconcile();
3565
+ }
3404
3566
  });
3405
3567
  }
3406
3568
  shouldComponentUpdate(nextProps, nextState) {
3569
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
3407
3570
  this.currentProps = nextProps;
3408
3571
  if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3409
3572
  if (nextState.fallback || this.state.fallback) return true;
3573
+ if (definitionChanged) return true;
3410
3574
  this.schedulePropSync();
3411
3575
  return false;
3412
3576
  }
3413
3577
  componentDidMount() {
3414
3578
  this.mounted = true;
3415
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3579
+ this.listen();
3416
3580
  if (this.state.fallback || this.fallbackRequested) {
3417
3581
  this.subscribeFallbackDescendants();
3418
3582
  this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3419
3583
  } else if (!this.adopt()) this.activateFallback();
3420
3584
  }
3421
3585
  componentDidUpdate() {
3422
- if (this.state.fallback) this.subscribeFallbackDescendants();
3586
+ this.listen();
3587
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
3588
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
3589
+ this.definitionVersion = nextDefinitionVersion;
3590
+ if (this.state.fallback) {
3591
+ this.subscribeFallbackDescendants();
3592
+ } else if (definitionChanged && !this.adopt()) {
3593
+ this.activateFallback();
3594
+ }
3423
3595
  }
3424
3596
  componentWillUnmount() {
3425
3597
  this.mounted = false;
3426
- this.unsubscribe?.();
3598
+ const stop = this.stop;
3599
+ stop?.();
3600
+ this.id = void 0;
3427
3601
  clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3428
3602
  this.fallbackKeysWereUnsafe = false;
3429
3603
  this.instance?.scope?.cleanup();
@@ -3462,6 +3636,7 @@ function createConditionalRangesBlockComponent(owner) {
3462
3636
  this.rangeInstances = [];
3463
3637
  this.staticSegments = [];
3464
3638
  this.staticValues = [];
3639
+ this.definitionVersion = owner.getDefinitionVersion?.();
3465
3640
  this.requestNestedFallback = () => {
3466
3641
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3467
3642
  this.activateFallback();
@@ -3528,6 +3703,7 @@ function createConditionalRangesBlockComponent(owner) {
3528
3703
  const elements = [...this.root.children];
3529
3704
  const staticSegments = [];
3530
3705
  const instances = [];
3706
+ const staticValues = this.staticValues.slice();
3531
3707
  const cleanupInstances = () => {
3532
3708
  for (const instance of instances) instance?.host.scope?.cleanup();
3533
3709
  };
@@ -3565,7 +3741,9 @@ function createConditionalRangesBlockComponent(owner) {
3565
3741
  element,
3566
3742
  descriptor,
3567
3743
  selection.branch,
3568
- this.requestNestedFallback
3744
+ this.requestNestedFallback,
3745
+ false
3746
+ // Commit only after every sibling range validates.
3569
3747
  );
3570
3748
  if (!host) {
3571
3749
  cleanupInstances();
@@ -3575,6 +3753,15 @@ function createConditionalRangesBlockComponent(owner) {
3575
3753
  key: selection.key,
3576
3754
  host
3577
3755
  });
3756
+ try {
3757
+ if (!prepareHostConditionalBindings(selection.branch, host)) {
3758
+ cleanupInstances();
3759
+ return false;
3760
+ }
3761
+ } catch (error) {
3762
+ cleanupInstances();
3763
+ throw error;
3764
+ }
3578
3765
  cursor += 1;
3579
3766
  }
3580
3767
  if (cursor + props.trailing !== elements.length) {
@@ -3582,14 +3769,27 @@ function createConditionalRangesBlockComponent(owner) {
3582
3769
  return false;
3583
3770
  }
3584
3771
  staticSegments.push(elements.slice(cursor));
3585
- this.staticSegments = staticSegments;
3586
- this.rangeInstances = instances;
3587
- if (!applyStaticRangeBindings(props.bindings, this.staticSegments, this.staticValues)) {
3772
+ try {
3773
+ if (!applyStaticRangeBindings(props.bindings, staticSegments, staticValues)) {
3774
+ cleanupInstances();
3775
+ return false;
3776
+ }
3777
+ for (let index = 0; index < selections.length; index += 1) {
3778
+ const selection = selections[index];
3779
+ const instance = instances[index];
3780
+ if (selection.kind === "branch" && instance) {
3781
+ applyPreparedHostConditionalBindings(selection.branch, instance.host);
3782
+ }
3783
+ }
3784
+ } catch (error) {
3588
3785
  cleanupInstances();
3589
- this.rangeInstances = [];
3590
- this.staticSegments = [];
3591
- return false;
3786
+ throw error;
3592
3787
  }
3788
+ for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3789
+ this.staticSegments = staticSegments;
3790
+ this.rangeInstances = instances;
3791
+ this.staticValues.length = 0;
3792
+ this.staticValues.push(...staticValues);
3593
3793
  return true;
3594
3794
  }
3595
3795
  anchorAfter(rangeIndex) {
@@ -3684,6 +3884,14 @@ function createConditionalRangesBlockComponent(owner) {
3684
3884
  }
3685
3885
  afterCommit?.();
3686
3886
  }
3887
+ listen() {
3888
+ const id = this.currentProps.id;
3889
+ const stop = this.stop;
3890
+ if (this.id === id) return;
3891
+ stop?.();
3892
+ this.stop = owner.subscribe(id, this.refresh);
3893
+ this.id = id;
3894
+ }
3687
3895
  activateFallback(afterCommit) {
3688
3896
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
3689
3897
  afterCommit?.();
@@ -3700,30 +3908,45 @@ function createConditionalRangesBlockComponent(owner) {
3700
3908
  this.propFallbackQueued = true;
3701
3909
  queueMicrotask(() => {
3702
3910
  this.propFallbackQueued = false;
3703
- if (this.mounted && !this.state.fallback) this.activateFallback();
3911
+ if (this.mounted && !this.state.fallback) {
3912
+ this.listen();
3913
+ this.activateFallback();
3914
+ }
3704
3915
  });
3705
3916
  }
3706
3917
  shouldComponentUpdate(nextProps, nextState) {
3918
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
3707
3919
  this.currentProps = nextProps;
3708
3920
  if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3709
3921
  if (nextState.fallback || this.state.fallback) return true;
3922
+ if (definitionChanged) return true;
3710
3923
  this.schedulePropFallback();
3711
3924
  return false;
3712
3925
  }
3713
3926
  componentDidMount() {
3714
3927
  this.mounted = true;
3715
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3928
+ this.listen();
3716
3929
  if (this.state.fallback || this.fallbackRequested) {
3717
3930
  this.subscribeFallbackDescendants();
3718
3931
  this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3719
3932
  } else if (!this.adopt()) this.activateFallback();
3720
3933
  }
3721
3934
  componentDidUpdate() {
3722
- if (this.state.fallback) this.subscribeFallbackDescendants();
3935
+ this.listen();
3936
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
3937
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
3938
+ this.definitionVersion = nextDefinitionVersion;
3939
+ if (this.state.fallback) {
3940
+ this.subscribeFallbackDescendants();
3941
+ } else if (definitionChanged && !this.adopt()) {
3942
+ this.activateFallback();
3943
+ }
3723
3944
  }
3724
3945
  componentWillUnmount() {
3725
3946
  this.mounted = false;
3726
- this.unsubscribe?.();
3947
+ const stop = this.stop;
3948
+ stop?.();
3949
+ this.id = void 0;
3727
3950
  clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3728
3951
  this.fallbackKeysWereUnsafe = false;
3729
3952
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
@@ -5512,6 +5735,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5512
5735
  this.fallbackKeysWereUnsafe = false;
5513
5736
  this.propSyncQueued = false;
5514
5737
  this.currentProps = this.props;
5738
+ this.definitionVersion = owner.getDefinitionVersion?.();
5515
5739
  this.instances = /* @__PURE__ */ new Map();
5516
5740
  this.identityTargets = /* @__PURE__ */ new Map();
5517
5741
  this.membershipTargets = /* @__PURE__ */ new Map();
@@ -5890,13 +6114,14 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5890
6114
  const rows = this.readRows(this.currentProps);
5891
6115
  const elements = [...this.root.children];
5892
6116
  if (!rows || rows.items.length !== elements.length) return false;
6117
+ const reactOwnedRows = this.hasReactOwnedRows();
5893
6118
  const opaqueConditionalPaths = new Set(
5894
6119
  (this.currentProps.conditionals || []).map((conditional) => conditional.path.join("."))
5895
6120
  );
5896
6121
  const instances = /* @__PURE__ */ new Map();
5897
6122
  for (let index = 0; index < rows.items.length; index += 1) {
5898
6123
  const descriptor = this.currentProps.create(rows.items[index], index);
5899
- if (this.hasReactOwnedRows() && !matchesCompilerHostElement(elements[index], descriptor, opaqueConditionalPaths)) {
6124
+ if (reactOwnedRows && !matchesCompilerHostElement(elements[index], descriptor, opaqueConditionalPaths)) {
5900
6125
  this.cleanupHostScopes(instances);
5901
6126
  return false;
5902
6127
  }
@@ -5909,7 +6134,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5909
6134
  key: rows.keys[index],
5910
6135
  element: elements[index],
5911
6136
  scope: scope || void 0,
5912
- values: this.hasReactOwnedRows() ? this.currentProps.bindings.map(() => UNSET_KEYED_ROW_BINDING) : readKeyedRowBindingValues(this.currentProps, rows.items[index], index),
6137
+ values: reactOwnedRows ? this.currentProps.bindings.map(() => UNSET_KEYED_ROW_BINDING) : readKeyedRowBindingValues(this.currentProps, rows.items[index], index),
5913
6138
  item: rows.items[index],
5914
6139
  index,
5915
6140
  conditionalValues: this.readConditionalValues(
@@ -5918,11 +6143,13 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5918
6143
  index
5919
6144
  )
5920
6145
  };
5921
- if (this.hasReactOwnedRows()) {
5922
- applyKeyedRowBindings(this.currentProps, instance, rows.items[index], index);
5923
- }
5924
6146
  instances.set(rows.keys[index], instance);
5925
6147
  }
6148
+ if (reactOwnedRows) {
6149
+ for (const instance of instances.values()) {
6150
+ applyKeyedRowBindings(this.currentProps, instance, instance.item, instance.index);
6151
+ }
6152
+ }
5926
6153
  this.cleanupHostScopes();
5927
6154
  this.instances = instances;
5928
6155
  this.rebuildElementIndex(instances);
@@ -6344,17 +6571,29 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6344
6571
  this.commitCurrentCollection(dirtyState);
6345
6572
  this.notifyConditionalChanges(conditionalChanges, afterCommit);
6346
6573
  }
6574
+ listen() {
6575
+ const id = this.currentProps.id;
6576
+ const stop = this.stop;
6577
+ if (this.id === id) return;
6578
+ stop?.();
6579
+ this.stop = owner.subscribe(id, this.refresh);
6580
+ this.id = id;
6581
+ }
6347
6582
  schedulePropSync() {
6348
6583
  if (this.propSyncQueued) return;
6349
6584
  this.propSyncQueued = true;
6350
6585
  queueMicrotask(() => {
6351
6586
  this.propSyncQueued = false;
6352
- if (this.mounted && !this.state.fallback) this.reconcile();
6587
+ if (this.mounted && !this.state.fallback) {
6588
+ this.listen();
6589
+ this.reconcile();
6590
+ }
6353
6591
  });
6354
6592
  }
6355
6593
  shouldComponentUpdate(nextProps, nextState) {
6356
6594
  const wasReactOwned = this.hasReactOwnedRows(this.currentProps);
6357
6595
  const willBeReactOwned = this.hasReactOwnedRows(nextProps);
6596
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6358
6597
  this.currentProps = nextProps;
6359
6598
  if (this.state.fallback && nextState.fallback) {
6360
6599
  const unsafeKeys = this.hasUnsafeFallbackKeys();
@@ -6362,7 +6601,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6362
6601
  this.fallbackKeysWereUnsafe = unsafeKeys;
6363
6602
  }
6364
6603
  if (nextState.fallback || this.state.fallback) return true;
6365
- if (wasReactOwned || willBeReactOwned) {
6604
+ if (definitionChanged || wasReactOwned || willBeReactOwned) {
6366
6605
  this.eventHandlers.clear();
6367
6606
  return true;
6368
6607
  }
@@ -6370,19 +6609,25 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6370
6609
  return false;
6371
6610
  }
6372
6611
  componentDidUpdate(previousProps) {
6373
- if (this.state.fallback || previousProps === this.props || !this.hasReactOwnedRows(previousProps) && !this.hasReactOwnedRows(this.props) || this.adopt()) {
6612
+ this.listen();
6613
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
6614
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
6615
+ this.definitionVersion = nextDefinitionVersion;
6616
+ if (this.state.fallback || previousProps === this.props || !definitionChanged && !this.hasReactOwnedRows(previousProps) && !this.hasReactOwnedRows(this.props) || this.adopt()) {
6374
6617
  return;
6375
6618
  }
6376
6619
  this.activateFallback();
6377
6620
  }
6378
6621
  componentDidMount() {
6379
6622
  this.mounted = true;
6380
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
6623
+ this.listen();
6381
6624
  if (!this.adopt()) this.activateFallback();
6382
6625
  }
6383
6626
  componentWillUnmount() {
6384
6627
  this.mounted = false;
6385
- this.unsubscribe?.();
6628
+ const stop = this.stop;
6629
+ stop?.();
6630
+ this.id = void 0;
6386
6631
  this.cleanupHostScopes();
6387
6632
  this.instances.clear();
6388
6633
  this.identityTargets.clear();
@@ -6425,6 +6670,7 @@ function createKeyedRangesBlockComponent(owner) {
6425
6670
  this.rangeInstances = [];
6426
6671
  this.staticSegments = [];
6427
6672
  this.staticValues = [];
6673
+ this.definitionVersion = owner.getDefinitionVersion?.();
6428
6674
  this.captureRoot = (root) => {
6429
6675
  this.root = root;
6430
6676
  this.currentProps.rootRef?.(root);
@@ -6462,6 +6708,7 @@ function createKeyedRangesBlockComponent(owner) {
6462
6708
  const elements = [...this.root.children];
6463
6709
  const staticSegments = [];
6464
6710
  const instancesByRange = [];
6711
+ const staticValues = this.staticValues.slice();
6465
6712
  let cursor = 0;
6466
6713
  for (let rangeIndex = 0; rangeIndex < props.ranges.length; rangeIndex += 1) {
6467
6714
  const range = props.ranges[rangeIndex];
@@ -6493,13 +6740,11 @@ function createKeyedRangesBlockComponent(owner) {
6493
6740
  }
6494
6741
  if (cursor + props.trailing !== elements.length) return false;
6495
6742
  staticSegments.push(elements.slice(cursor));
6743
+ if (!applyStaticRangeBindings(props.bindings, staticSegments, staticValues)) return false;
6496
6744
  this.staticSegments = staticSegments;
6497
6745
  this.rangeInstances = instancesByRange;
6498
- if (!applyStaticRangeBindings(props.bindings, this.staticSegments, this.staticValues)) {
6499
- this.rangeInstances = [];
6500
- this.staticSegments = [];
6501
- return false;
6502
- }
6746
+ this.staticValues.length = 0;
6747
+ this.staticValues.push(...staticValues);
6503
6748
  return true;
6504
6749
  }
6505
6750
  anchorAfter(rangeIndex) {
@@ -6596,6 +6841,14 @@ function createKeyedRangesBlockComponent(owner) {
6596
6841
  }
6597
6842
  afterCommit?.();
6598
6843
  }
6844
+ listen() {
6845
+ const id = this.currentProps.id;
6846
+ const stop = this.stop;
6847
+ if (this.id === id) return;
6848
+ stop?.();
6849
+ this.stop = owner.subscribe(id, this.refresh);
6850
+ this.id = id;
6851
+ }
6599
6852
  activateFallback(afterCommit) {
6600
6853
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
6601
6854
  afterCommit?.();
@@ -6610,10 +6863,14 @@ function createKeyedRangesBlockComponent(owner) {
6610
6863
  this.propFallbackQueued = true;
6611
6864
  queueMicrotask(() => {
6612
6865
  this.propFallbackQueued = false;
6613
- if (this.mounted && !this.state.fallback) this.activateFallback();
6866
+ if (this.mounted && !this.state.fallback) {
6867
+ this.listen();
6868
+ this.activateFallback();
6869
+ }
6614
6870
  });
6615
6871
  }
6616
6872
  shouldComponentUpdate(nextProps, nextState) {
6873
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6617
6874
  this.currentProps = nextProps;
6618
6875
  if (this.state.fallback && nextState.fallback) {
6619
6876
  const unsafeKeys = this.hasUnsafeFallbackKeys();
@@ -6621,17 +6878,27 @@ function createKeyedRangesBlockComponent(owner) {
6621
6878
  this.fallbackKeysWereUnsafe = unsafeKeys;
6622
6879
  }
6623
6880
  if (nextState.fallback || this.state.fallback) return true;
6881
+ if (definitionChanged) return true;
6624
6882
  this.schedulePropFallback();
6625
6883
  return false;
6626
6884
  }
6627
6885
  componentDidMount() {
6628
6886
  this.mounted = true;
6629
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
6887
+ this.listen();
6630
6888
  if (!this.adopt()) this.activateFallback();
6631
6889
  }
6890
+ componentDidUpdate() {
6891
+ this.listen();
6892
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
6893
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
6894
+ this.definitionVersion = nextDefinitionVersion;
6895
+ if (!this.state.fallback && definitionChanged && !this.adopt()) this.activateFallback();
6896
+ }
6632
6897
  componentWillUnmount() {
6633
6898
  this.mounted = false;
6634
- this.unsubscribe?.();
6899
+ const stop = this.stop;
6900
+ stop?.();
6901
+ this.id = void 0;
6635
6902
  this.rangeInstances = [];
6636
6903
  this.staticSegments = [];
6637
6904
  this.staticValues.length = 0;
@@ -6666,6 +6933,7 @@ function createMixedRangesBlockComponent(owner) {
6666
6933
  this.currentProps = this.props;
6667
6934
  this.controller = null;
6668
6935
  this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
6936
+ this.definitionVersion = owner.getDefinitionVersion?.();
6669
6937
  this.captureRoot = (root) => {
6670
6938
  this.root = root;
6671
6939
  this.currentProps.rootRef?.(root);
@@ -6739,7 +7007,9 @@ function createMixedRangesBlockComponent(owner) {
6739
7007
  controller.cleanup();
6740
7008
  throw error;
6741
7009
  }
7010
+ const previous = this.controller;
6742
7011
  this.controller = controller;
7012
+ previous?.cleanup();
6743
7013
  return true;
6744
7014
  }
6745
7015
  schedulePropFallback() {
@@ -6751,11 +7021,13 @@ function createMixedRangesBlockComponent(owner) {
6751
7021
  });
6752
7022
  }
6753
7023
  shouldComponentUpdate(nextProps, nextState) {
7024
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6754
7025
  this.currentProps = nextProps;
6755
7026
  if (this.state.fallback && nextState.fallback) {
6756
7027
  this.prepareFallbackUpdate(this.currentProps.create());
6757
7028
  }
6758
7029
  if (nextState.fallback || this.state.fallback) return true;
7030
+ if (definitionChanged) return true;
6759
7031
  this.schedulePropFallback();
6760
7032
  return false;
6761
7033
  }
@@ -6767,7 +7039,14 @@ function createMixedRangesBlockComponent(owner) {
6767
7039
  } else if (!this.adopt()) this.activateFallback();
6768
7040
  }
6769
7041
  componentDidUpdate() {
6770
- if (this.state.fallback) this.subscribeFallbackBlocks();
7042
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
7043
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
7044
+ this.definitionVersion = nextDefinitionVersion;
7045
+ if (this.state.fallback) {
7046
+ this.subscribeFallbackBlocks();
7047
+ } else if (definitionChanged && !this.adopt()) {
7048
+ this.activateFallback();
7049
+ }
6771
7050
  }
6772
7051
  componentWillUnmount() {
6773
7052
  this.mounted = false;
@@ -7607,8 +7886,9 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7607
7886
  };
7608
7887
  });
7609
7888
  const featureOwner = {
7610
- setRoot: (id, root) => this.setBlockRoot(id, root),
7611
- subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
7889
+ setRoot: (id, root, expectedRoot) => this.setBlockRoot(id, root, expectedRoot),
7890
+ subscribe: (id, refresh) => this.subscribeToBlock(id, refresh),
7891
+ getDefinitionVersion: () => definitionReference.current
7612
7892
  };
7613
7893
  const blockRuntime = {
7614
7894
  target: (id) => this.bindingTarget(id)
@@ -7747,8 +8027,9 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7747
8027
  }
7748
8028
  snapshot.element.setSelectionRange(snapshot.start, snapshot.end, snapshot.direction);
7749
8029
  }
7750
- setBlockRoot(id, root) {
8030
+ setBlockRoot(id, root, expectedRoot) {
7751
8031
  const previous = this.blockRoots.get(id);
8032
+ if (!root && expectedRoot !== void 0 && previous !== expectedRoot) return;
7752
8033
  if (previous) this.blockRootElements.delete(previous);
7753
8034
  if (root) {
7754
8035
  this.blockRoots.set(id, root);