@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.
@@ -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,7 +1774,11 @@ 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() {
@@ -1961,10 +1975,7 @@ function normalizedStaticRangeBindingValue(binding, value) {
1961
1975
  }
1962
1976
  function applyStaticRangeBindings(bindings, segments, values) {
1963
1977
  const activeBindings = bindings || [];
1964
- if (values.length === 0 && activeBindings.length > 0) {
1965
- values.push(...activeBindings.map(() => UNSET_STATIC_RANGE_BINDING));
1966
- }
1967
- if (values.length !== activeBindings.length) return false;
1978
+ const targets = [];
1968
1979
  for (let index = 0; index < activeBindings.length; index += 1) {
1969
1980
  const binding = activeBindings[index];
1970
1981
  if (!Number.isSafeInteger(binding.segment) || binding.segment < 0 || !Number.isSafeInteger(binding.sibling) || binding.sibling < 0) {
@@ -1972,19 +1983,31 @@ function applyStaticRangeBindings(bindings, segments, values) {
1972
1983
  }
1973
1984
  const sibling = segments[binding.segment]?.[binding.sibling];
1974
1985
  const target = sibling && findCompilerHostTarget(sibling, binding.path);
1975
- if (!target) return false;
1976
- const rawValue = binding.read();
1977
- const value = normalizedStaticRangeBindingValue(binding, rawValue);
1978
- if (Object.is(values[index], value)) continue;
1986
+ if (!target || binding.kind !== "text" && (binding.kind !== "style" && binding.kind !== "attribute" || !binding.name)) {
1987
+ return false;
1988
+ }
1989
+ targets[index] = target;
1990
+ }
1991
+ const initializesValues = values.length === 0 && activeBindings.length > 0;
1992
+ if (!initializesValues && values.length !== activeBindings.length) return false;
1993
+ const nextValues = [];
1994
+ for (let index = 0; index < activeBindings.length; index += 1) {
1995
+ const binding = activeBindings[index];
1996
+ nextValues[index] = normalizedStaticRangeBindingValue(binding, binding.read());
1997
+ }
1998
+ for (let index = 0; index < activeBindings.length; index += 1) {
1999
+ const binding = activeBindings[index];
2000
+ const value = nextValues[index];
2001
+ const previous = initializesValues ? UNSET_STATIC_RANGE_BINDING : values[index];
2002
+ if (Object.is(previous, value)) continue;
1979
2003
  values[index] = value;
2004
+ const target = targets[index];
1980
2005
  if (binding.kind === "text") {
1981
2006
  target.textContent = value;
1982
- } else if (binding.kind === "style" && binding.name) {
1983
- updateStyle(target, binding.name, rawValue);
1984
- } else if (binding.kind === "attribute" && binding.name) {
1985
- updateAttribute(target, binding.name, rawValue);
2007
+ } else if (binding.kind === "style") {
2008
+ updateStyle(target, binding.name, value);
1986
2009
  } else {
1987
- return false;
2010
+ updateAttribute(target, binding.name, value);
1988
2011
  }
1989
2012
  }
1990
2013
  return true;
@@ -2240,24 +2263,49 @@ function readKeyedRowBindingValues(props, item, index) {
2240
2263
  );
2241
2264
  }
2242
2265
  function applyKeyedRowBindings(props, instance, item, index) {
2266
+ if (props.bindings.length < 2) {
2267
+ if (props.bindings.length === 1) applyKeyedRowBinding(props, instance, item, index, 0);
2268
+ return;
2269
+ }
2270
+ const nextValues = readKeyedRowBindingValues(props, item, index);
2271
+ let targets;
2243
2272
  for (let bindingIndex = 0; bindingIndex < props.bindings.length; bindingIndex += 1) {
2244
- applyKeyedRowBinding(props, instance, item, index, bindingIndex);
2273
+ if (Object.is(instance.values[bindingIndex], nextValues[bindingIndex])) continue;
2274
+ targets || (targets = []);
2275
+ targets[bindingIndex] = findCompilerHostTarget(
2276
+ instance.element,
2277
+ props.bindings[bindingIndex].path
2278
+ );
2279
+ }
2280
+ if (!targets) return;
2281
+ for (let bindingIndex = 0; bindingIndex < props.bindings.length; bindingIndex += 1) {
2282
+ const value = nextValues[bindingIndex];
2283
+ if (Object.is(instance.values[bindingIndex], value)) continue;
2284
+ commitKeyedRowBinding(
2285
+ props.bindings[bindingIndex],
2286
+ instance,
2287
+ bindingIndex,
2288
+ value,
2289
+ targets[bindingIndex]
2290
+ );
2245
2291
  }
2246
2292
  }
2247
2293
  function applyKeyedRowBinding(props, instance, item, index, bindingIndex) {
2248
2294
  const binding = props.bindings[bindingIndex];
2249
- const rawValue = binding.read(item, index);
2250
- const value = normalizedKeyedRowBindingValue(binding, rawValue);
2295
+ const value = normalizedKeyedRowBindingValue(binding, binding.read(item, index));
2251
2296
  if (Object.is(instance.values[bindingIndex], value)) return;
2252
- instance.values[bindingIndex] = value;
2253
2297
  const target = findCompilerHostTarget(instance.element, binding.path);
2298
+ commitKeyedRowBinding(binding, instance, bindingIndex, value, target);
2299
+ }
2300
+ function commitKeyedRowBinding(binding, instance, bindingIndex, value, target) {
2301
+ instance.values[bindingIndex] = value;
2254
2302
  if (!target) return;
2255
2303
  if (binding.kind === "text") {
2256
2304
  target.textContent = value;
2257
2305
  } else if (binding.kind === "style" && binding.name) {
2258
- updateStyle(target, binding.name, rawValue);
2306
+ updateStyle(target, binding.name, value);
2259
2307
  } else if (binding.kind === "attribute" && binding.name) {
2260
- updateAttribute(target, binding.name, rawValue);
2308
+ updateAttribute(target, binding.name, value);
2261
2309
  }
2262
2310
  }
2263
2311
  function prepareKeyedRowBindingUpdates(props, instance, item, index) {
@@ -2269,21 +2317,13 @@ function prepareKeyedRowBindingUpdates(props, instance, item, index) {
2269
2317
  if (Object.is(instance.values[bindingIndex], value)) continue;
2270
2318
  const target = findCompilerHostTarget(instance.element, binding.path);
2271
2319
  if (!target || binding.kind !== "text" && !binding.name) return void 0;
2272
- updates.push([bindingIndex, rawValue, target, value]);
2320
+ updates.push([bindingIndex, target, value]);
2273
2321
  }
2274
2322
  return updates;
2275
2323
  }
2276
2324
  function applyPreparedKeyedRowBindingUpdates(props, instance, updates) {
2277
- for (const [bindingIndex, rawValue, target, value] of updates) {
2278
- const binding = props.bindings[bindingIndex];
2279
- instance.values[bindingIndex] = value;
2280
- if (binding.kind === "text") {
2281
- target.textContent = value;
2282
- } else if (binding.kind === "style") {
2283
- updateStyle(target, binding.name, rawValue);
2284
- } else {
2285
- updateAttribute(target, binding.name, rawValue);
2286
- }
2325
+ for (const [bindingIndex, target, value] of updates) {
2326
+ commitKeyedRowBinding(props.bindings[bindingIndex], instance, bindingIndex, value, target);
2287
2327
  }
2288
2328
  }
2289
2329
  function keyedRowConditionalSnapshot(conditional, item, index) {
@@ -2345,6 +2385,35 @@ function applyHostConditionalBindings(branch, instance) {
2345
2385
  }
2346
2386
  }
2347
2387
  }
2388
+ function prepareHostConditionalBindings(branch, instance) {
2389
+ for (let bindingIndex = 0; bindingIndex < branch.bindings.length; bindingIndex += 1) {
2390
+ const binding = branch.bindings[bindingIndex];
2391
+ const rawValue = binding.read();
2392
+ const target = findCompilerHostTarget(instance.element, binding.path);
2393
+ if (!target || binding.kind !== "text" && (binding.kind !== "style" && binding.kind !== "attribute" || !binding.name)) {
2394
+ return false;
2395
+ }
2396
+ instance.values[bindingIndex] = [
2397
+ target,
2398
+ normalizedHostConditionalBindingValue(binding, rawValue)
2399
+ ];
2400
+ }
2401
+ return true;
2402
+ }
2403
+ function applyPreparedHostConditionalBindings(branch, instance) {
2404
+ for (let bindingIndex = 0; bindingIndex < branch.bindings.length; bindingIndex += 1) {
2405
+ const binding = branch.bindings[bindingIndex];
2406
+ const [target, value] = instance.values[bindingIndex];
2407
+ instance.values[bindingIndex] = value;
2408
+ if (binding.kind === "text") {
2409
+ target.textContent = value;
2410
+ } else if (binding.kind === "style") {
2411
+ updateStyle(target, binding.name, value);
2412
+ } else {
2413
+ updateAttribute(target, binding.name, value);
2414
+ }
2415
+ }
2416
+ }
2348
2417
  var UNSET_HOST_CONDITIONAL_BINDING = /* @__PURE__ */ Symbol("unset host conditional binding");
2349
2418
  function mountCompilerHostTree(owner, element, descriptor, onFallback) {
2350
2419
  if (!matchesCompilerHostElement(element, descriptor)) return null;
@@ -2432,7 +2501,7 @@ function mountCompilerHostTree(owner, element, descriptor, onFallback) {
2432
2501
  }
2433
2502
  };
2434
2503
  }
2435
- function mountCompilerHostInstance(owner, element, descriptor, branch, onFallback) {
2504
+ function mountCompilerHostInstance(owner, element, descriptor, branch, onFallback, applyBindingsImmediately = true) {
2436
2505
  const scope = mountCompilerHostTree(owner, element, descriptor, onFallback);
2437
2506
  if (!scope) return null;
2438
2507
  const instance = {
@@ -2440,6 +2509,7 @@ function mountCompilerHostInstance(owner, element, descriptor, branch, onFallbac
2440
2509
  scope,
2441
2510
  values: branch.bindings.map(() => UNSET_HOST_CONDITIONAL_BINDING)
2442
2511
  };
2512
+ if (!applyBindingsImmediately) return instance;
2443
2513
  try {
2444
2514
  applyHostConditionalBindings(branch, instance);
2445
2515
  } catch (error) {
@@ -2546,13 +2616,19 @@ var CompilerNestedConditionalRanges = class {
2546
2616
  element,
2547
2617
  descriptor,
2548
2618
  selection.branch,
2549
- this.onFallback
2619
+ this.onFallback,
2620
+ false
2621
+ // Commit only after every sibling range validates.
2550
2622
  );
2551
2623
  if (!host) {
2552
2624
  this.cleanup();
2553
2625
  return false;
2554
2626
  }
2555
2627
  this.instances.push({ key: selection.key, host });
2628
+ if (!prepareHostConditionalBindings(selection.branch, host)) {
2629
+ this.cleanup();
2630
+ return false;
2631
+ }
2556
2632
  cursor += 1;
2557
2633
  }
2558
2634
  const trailingEnd = cursor + this.block.trailing;
@@ -2565,6 +2641,13 @@ var CompilerNestedConditionalRanges = class {
2565
2641
  this.cleanup();
2566
2642
  return false;
2567
2643
  }
2644
+ for (let index = 0; index < selections.length; index += 1) {
2645
+ const selection = selections[index];
2646
+ const instance = this.instances[index];
2647
+ if (selection.kind === "branch" && instance) {
2648
+ applyPreparedHostConditionalBindings(selection.branch, instance.host);
2649
+ }
2650
+ }
2568
2651
  this.unsubscribe = this.owner.subscribe(this.block.id, this.refresh);
2569
2652
  return true;
2570
2653
  }
@@ -2733,6 +2816,7 @@ var CompilerNestedKeyedRanges = class {
2733
2816
  const elements = [...this.root.children];
2734
2817
  const descriptors = flattenCompilerHostElements(materializeCompilerHostChildren(this.host));
2735
2818
  if (elements.length !== descriptors.length) return false;
2819
+ const preparedBindings = [];
2736
2820
  let cursor = 0;
2737
2821
  for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
2738
2822
  const range = this.block.ranges[rangeIndex];
@@ -2749,6 +2833,8 @@ var CompilerNestedKeyedRanges = class {
2749
2833
  this.staticSegments.push(elements.slice(cursor, staticEnd));
2750
2834
  cursor = staticEnd;
2751
2835
  const instances = /* @__PURE__ */ new Map();
2836
+ this.instances.push(instances);
2837
+ const rangeBindingUpdates = [];
2752
2838
  for (let index = 0; index < rows.items.length; index += 1) {
2753
2839
  const element = elements[cursor + index];
2754
2840
  if (!element) {
@@ -2761,7 +2847,7 @@ var CompilerNestedKeyedRanges = class {
2761
2847
  this.cleanup();
2762
2848
  return false;
2763
2849
  }
2764
- instances.set(rows.keys[index], {
2850
+ const instance = {
2765
2851
  key: rows.keys[index],
2766
2852
  element,
2767
2853
  scope,
@@ -2769,10 +2855,23 @@ var CompilerNestedKeyedRanges = class {
2769
2855
  item: rows.items[index],
2770
2856
  index,
2771
2857
  conditionalValues: /* @__PURE__ */ new Map()
2772
- });
2773
- applyKeyedRowBindings(range, instances.get(rows.keys[index]), rows.items[index], index);
2858
+ };
2859
+ let bindingUpdates;
2860
+ try {
2861
+ bindingUpdates = prepareKeyedRowBindingUpdates(range, instance, rows.items[index], index);
2862
+ } catch (error) {
2863
+ scope.cleanup();
2864
+ throw error;
2865
+ }
2866
+ if (!bindingUpdates) {
2867
+ scope.cleanup();
2868
+ this.cleanup();
2869
+ return false;
2870
+ }
2871
+ instances.set(rows.keys[index], instance);
2872
+ rangeBindingUpdates.push(bindingUpdates);
2774
2873
  }
2775
- this.instances.push(instances);
2874
+ preparedBindings.push(rangeBindingUpdates);
2776
2875
  cursor += rows.items.length;
2777
2876
  }
2778
2877
  const trailingEnd = cursor + this.block.trailing;
@@ -2785,6 +2884,18 @@ var CompilerNestedKeyedRanges = class {
2785
2884
  this.cleanup();
2786
2885
  return false;
2787
2886
  }
2887
+ for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
2888
+ const range = this.block.ranges[rangeIndex];
2889
+ let rowIndex = 0;
2890
+ for (const instance of this.instances[rangeIndex].values()) {
2891
+ applyPreparedKeyedRowBindingUpdates(
2892
+ range,
2893
+ instance,
2894
+ preparedBindings[rangeIndex][rowIndex]
2895
+ );
2896
+ rowIndex += 1;
2897
+ }
2898
+ }
2788
2899
  this.unsubscribe = this.owner.subscribe(this.block.id, this.refresh);
2789
2900
  return true;
2790
2901
  }
@@ -2978,6 +3089,7 @@ var CompilerNestedMixedRanges = class {
2978
3089
  const elements = [...this.root.children];
2979
3090
  const descriptors = flattenCompilerHostElements(this.host.children);
2980
3091
  if (elements.length !== descriptors.length) return false;
3092
+ const preparedKeyedBindings = [];
2981
3093
  let cursor = 0;
2982
3094
  for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
2983
3095
  const range = this.block.ranges[rangeIndex];
@@ -3009,7 +3121,9 @@ var CompilerNestedMixedRanges = class {
3009
3121
  element,
3010
3122
  descriptor,
3011
3123
  snapshot.selection.branch,
3012
- this.onFallback
3124
+ this.onFallback,
3125
+ false
3126
+ // Commit only after every sibling range validates.
3013
3127
  );
3014
3128
  if (!host) {
3015
3129
  this.cleanup();
@@ -3019,6 +3133,10 @@ var CompilerNestedMixedRanges = class {
3019
3133
  kind: "conditional",
3020
3134
  value: { key: snapshot.selection.key, host }
3021
3135
  });
3136
+ if (!prepareHostConditionalBindings(snapshot.selection.branch, host)) {
3137
+ this.cleanup();
3138
+ return false;
3139
+ }
3022
3140
  cursor += 1;
3023
3141
  continue;
3024
3142
  }
@@ -3027,6 +3145,8 @@ var CompilerNestedMixedRanges = class {
3027
3145
  return false;
3028
3146
  }
3029
3147
  const keyedInstances = /* @__PURE__ */ new Map();
3148
+ this.instances.push({ kind: "keyed", value: keyedInstances });
3149
+ const keyedBindingUpdates = [];
3030
3150
  for (let index = 0; index < snapshot.rows.items.length; index += 1) {
3031
3151
  const element = elements[cursor + index];
3032
3152
  if (!element) {
@@ -3048,15 +3168,27 @@ var CompilerNestedMixedRanges = class {
3048
3168
  index,
3049
3169
  conditionalValues: /* @__PURE__ */ new Map()
3050
3170
  };
3171
+ let bindingUpdates;
3051
3172
  try {
3052
- applyKeyedRowBindings(range, instance, snapshot.rows.items[index], index);
3173
+ bindingUpdates = prepareKeyedRowBindingUpdates(
3174
+ range,
3175
+ instance,
3176
+ snapshot.rows.items[index],
3177
+ index
3178
+ );
3053
3179
  } catch (error) {
3054
3180
  scope.cleanup();
3055
3181
  throw error;
3056
3182
  }
3183
+ if (!bindingUpdates) {
3184
+ scope.cleanup();
3185
+ this.cleanup();
3186
+ return false;
3187
+ }
3057
3188
  keyedInstances.set(snapshot.rows.keys[index], instance);
3189
+ keyedBindingUpdates.push(bindingUpdates);
3058
3190
  }
3059
- this.instances.push({ kind: "keyed", value: keyedInstances });
3191
+ preparedKeyedBindings[rangeIndex] = keyedBindingUpdates;
3060
3192
  cursor += snapshot.rows.items.length;
3061
3193
  }
3062
3194
  const trailingEnd = cursor + this.block.trailing;
@@ -3069,6 +3201,22 @@ var CompilerNestedMixedRanges = class {
3069
3201
  this.cleanup();
3070
3202
  return false;
3071
3203
  }
3204
+ for (let index = 0; index < snapshots.length; index += 1) {
3205
+ const snapshot = snapshots[index];
3206
+ const instance = this.instances[index];
3207
+ if (snapshot.kind === "conditional" && snapshot.selection.kind === "branch" && instance?.kind === "conditional" && instance.value) {
3208
+ applyPreparedHostConditionalBindings(snapshot.selection.branch, instance.value.host);
3209
+ } else if (snapshot.kind === "keyed" && instance?.kind === "keyed") {
3210
+ const range = this.block.ranges[index];
3211
+ const bindingUpdates = preparedKeyedBindings[index];
3212
+ if (range.kind !== "keyed") continue;
3213
+ let rowIndex = 0;
3214
+ for (const row of instance.value.values()) {
3215
+ applyPreparedKeyedRowBindingUpdates(range, row, bindingUpdates[rowIndex]);
3216
+ rowIndex += 1;
3217
+ }
3218
+ }
3219
+ }
3072
3220
  this.unsubscribe = this.owner.subscribe(this.block.id, this.refresh);
3073
3221
  return true;
3074
3222
  }
@@ -3257,6 +3405,7 @@ function createHostConditionalBlockComponent(owner) {
3257
3405
  this.fallbackKeysWereUnsafe = false;
3258
3406
  this.activeBranch = null;
3259
3407
  this.instance = null;
3408
+ this.definitionVersion = owner.getDefinitionVersion?.();
3260
3409
  this.requestNestedFallback = () => {
3261
3410
  this.instance?.scope?.cleanup();
3262
3411
  this.activateFallback();
@@ -3305,6 +3454,7 @@ function createHostConditionalBlockComponent(owner) {
3305
3454
  if (selection.kind === "fallback") return false;
3306
3455
  if (selection.kind === "empty") {
3307
3456
  if (this.root.childNodes.length !== 0) return false;
3457
+ this.instance?.scope?.cleanup();
3308
3458
  this.activeBranch = null;
3309
3459
  this.instance = null;
3310
3460
  return true;
@@ -3323,6 +3473,7 @@ function createHostConditionalBlockComponent(owner) {
3323
3473
  this.requestNestedFallback
3324
3474
  );
3325
3475
  if (!instance) return false;
3476
+ this.instance?.scope?.cleanup();
3326
3477
  this.activeBranch = selection.key;
3327
3478
  this.instance = instance;
3328
3479
  return true;
@@ -3401,35 +3552,58 @@ function createHostConditionalBlockComponent(owner) {
3401
3552
  this.instance = instance;
3402
3553
  afterCommit?.();
3403
3554
  }
3555
+ listen() {
3556
+ const id = this.currentProps.id;
3557
+ const stop = this.stop;
3558
+ if (this.id === id) return;
3559
+ stop?.();
3560
+ this.stop = owner.subscribe(id, this.refresh);
3561
+ this.id = id;
3562
+ }
3404
3563
  schedulePropSync() {
3405
3564
  if (this.propSyncQueued) return;
3406
3565
  this.propSyncQueued = true;
3407
3566
  queueMicrotask(() => {
3408
3567
  this.propSyncQueued = false;
3409
- if (this.mounted && !this.state.fallback) this.reconcile();
3568
+ if (this.mounted && !this.state.fallback) {
3569
+ this.listen();
3570
+ this.reconcile();
3571
+ }
3410
3572
  });
3411
3573
  }
3412
3574
  shouldComponentUpdate(nextProps, nextState) {
3575
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
3413
3576
  this.currentProps = nextProps;
3414
3577
  if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3415
3578
  if (nextState.fallback || this.state.fallback) return true;
3579
+ if (definitionChanged) return true;
3416
3580
  this.schedulePropSync();
3417
3581
  return false;
3418
3582
  }
3419
3583
  componentDidMount() {
3420
3584
  this.mounted = true;
3421
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3585
+ this.listen();
3422
3586
  if (this.state.fallback || this.fallbackRequested) {
3423
3587
  this.subscribeFallbackDescendants();
3424
3588
  this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3425
3589
  } else if (!this.adopt()) this.activateFallback();
3426
3590
  }
3427
3591
  componentDidUpdate() {
3428
- if (this.state.fallback) this.subscribeFallbackDescendants();
3592
+ this.listen();
3593
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
3594
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
3595
+ this.definitionVersion = nextDefinitionVersion;
3596
+ if (this.state.fallback) {
3597
+ this.subscribeFallbackDescendants();
3598
+ } else if (definitionChanged && !this.adopt()) {
3599
+ this.activateFallback();
3600
+ }
3429
3601
  }
3430
3602
  componentWillUnmount() {
3431
3603
  this.mounted = false;
3432
- this.unsubscribe?.();
3604
+ const stop = this.stop;
3605
+ stop?.();
3606
+ this.id = void 0;
3433
3607
  clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3434
3608
  this.fallbackKeysWereUnsafe = false;
3435
3609
  this.instance?.scope?.cleanup();
@@ -3468,6 +3642,7 @@ function createConditionalRangesBlockComponent(owner) {
3468
3642
  this.rangeInstances = [];
3469
3643
  this.staticSegments = [];
3470
3644
  this.staticValues = [];
3645
+ this.definitionVersion = owner.getDefinitionVersion?.();
3471
3646
  this.requestNestedFallback = () => {
3472
3647
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3473
3648
  this.activateFallback();
@@ -3534,6 +3709,7 @@ function createConditionalRangesBlockComponent(owner) {
3534
3709
  const elements = [...this.root.children];
3535
3710
  const staticSegments = [];
3536
3711
  const instances = [];
3712
+ const staticValues = this.staticValues.slice();
3537
3713
  const cleanupInstances = () => {
3538
3714
  for (const instance of instances) instance?.host.scope?.cleanup();
3539
3715
  };
@@ -3571,7 +3747,9 @@ function createConditionalRangesBlockComponent(owner) {
3571
3747
  element,
3572
3748
  descriptor,
3573
3749
  selection.branch,
3574
- this.requestNestedFallback
3750
+ this.requestNestedFallback,
3751
+ false
3752
+ // Commit only after every sibling range validates.
3575
3753
  );
3576
3754
  if (!host) {
3577
3755
  cleanupInstances();
@@ -3581,6 +3759,15 @@ function createConditionalRangesBlockComponent(owner) {
3581
3759
  key: selection.key,
3582
3760
  host
3583
3761
  });
3762
+ try {
3763
+ if (!prepareHostConditionalBindings(selection.branch, host)) {
3764
+ cleanupInstances();
3765
+ return false;
3766
+ }
3767
+ } catch (error) {
3768
+ cleanupInstances();
3769
+ throw error;
3770
+ }
3584
3771
  cursor += 1;
3585
3772
  }
3586
3773
  if (cursor + props.trailing !== elements.length) {
@@ -3588,14 +3775,27 @@ function createConditionalRangesBlockComponent(owner) {
3588
3775
  return false;
3589
3776
  }
3590
3777
  staticSegments.push(elements.slice(cursor));
3591
- this.staticSegments = staticSegments;
3592
- this.rangeInstances = instances;
3593
- if (!applyStaticRangeBindings(props.bindings, this.staticSegments, this.staticValues)) {
3778
+ try {
3779
+ if (!applyStaticRangeBindings(props.bindings, staticSegments, staticValues)) {
3780
+ cleanupInstances();
3781
+ return false;
3782
+ }
3783
+ for (let index = 0; index < selections.length; index += 1) {
3784
+ const selection = selections[index];
3785
+ const instance = instances[index];
3786
+ if (selection.kind === "branch" && instance) {
3787
+ applyPreparedHostConditionalBindings(selection.branch, instance.host);
3788
+ }
3789
+ }
3790
+ } catch (error) {
3594
3791
  cleanupInstances();
3595
- this.rangeInstances = [];
3596
- this.staticSegments = [];
3597
- return false;
3792
+ throw error;
3598
3793
  }
3794
+ for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3795
+ this.staticSegments = staticSegments;
3796
+ this.rangeInstances = instances;
3797
+ this.staticValues.length = 0;
3798
+ this.staticValues.push(...staticValues);
3599
3799
  return true;
3600
3800
  }
3601
3801
  anchorAfter(rangeIndex) {
@@ -3690,6 +3890,14 @@ function createConditionalRangesBlockComponent(owner) {
3690
3890
  }
3691
3891
  afterCommit?.();
3692
3892
  }
3893
+ listen() {
3894
+ const id = this.currentProps.id;
3895
+ const stop = this.stop;
3896
+ if (this.id === id) return;
3897
+ stop?.();
3898
+ this.stop = owner.subscribe(id, this.refresh);
3899
+ this.id = id;
3900
+ }
3693
3901
  activateFallback(afterCommit) {
3694
3902
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
3695
3903
  afterCommit?.();
@@ -3706,30 +3914,45 @@ function createConditionalRangesBlockComponent(owner) {
3706
3914
  this.propFallbackQueued = true;
3707
3915
  queueMicrotask(() => {
3708
3916
  this.propFallbackQueued = false;
3709
- if (this.mounted && !this.state.fallback) this.activateFallback();
3917
+ if (this.mounted && !this.state.fallback) {
3918
+ this.listen();
3919
+ this.activateFallback();
3920
+ }
3710
3921
  });
3711
3922
  }
3712
3923
  shouldComponentUpdate(nextProps, nextState) {
3924
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
3713
3925
  this.currentProps = nextProps;
3714
3926
  if (this.state.fallback && nextState.fallback) this.prepareFallbackUpdate();
3715
3927
  if (nextState.fallback || this.state.fallback) return true;
3928
+ if (definitionChanged) return true;
3716
3929
  this.schedulePropFallback();
3717
3930
  return false;
3718
3931
  }
3719
3932
  componentDidMount() {
3720
3933
  this.mounted = true;
3721
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
3934
+ this.listen();
3722
3935
  if (this.state.fallback || this.fallbackRequested) {
3723
3936
  this.subscribeFallbackDescendants();
3724
3937
  this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
3725
3938
  } else if (!this.adopt()) this.activateFallback();
3726
3939
  }
3727
3940
  componentDidUpdate() {
3728
- if (this.state.fallback) this.subscribeFallbackDescendants();
3941
+ this.listen();
3942
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
3943
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
3944
+ this.definitionVersion = nextDefinitionVersion;
3945
+ if (this.state.fallback) {
3946
+ this.subscribeFallbackDescendants();
3947
+ } else if (definitionChanged && !this.adopt()) {
3948
+ this.activateFallback();
3949
+ }
3729
3950
  }
3730
3951
  componentWillUnmount() {
3731
3952
  this.mounted = false;
3732
- this.unsubscribe?.();
3953
+ const stop = this.stop;
3954
+ stop?.();
3955
+ this.id = void 0;
3733
3956
  clearCompilerFallbackSubscriptions(this.fallbackUnsubscribers);
3734
3957
  this.fallbackKeysWereUnsafe = false;
3735
3958
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
@@ -5518,6 +5741,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5518
5741
  this.fallbackKeysWereUnsafe = false;
5519
5742
  this.propSyncQueued = false;
5520
5743
  this.currentProps = this.props;
5744
+ this.definitionVersion = owner.getDefinitionVersion?.();
5521
5745
  this.instances = /* @__PURE__ */ new Map();
5522
5746
  this.identityTargets = /* @__PURE__ */ new Map();
5523
5747
  this.membershipTargets = /* @__PURE__ */ new Map();
@@ -5896,13 +6120,14 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5896
6120
  const rows = this.readRows(this.currentProps);
5897
6121
  const elements = [...this.root.children];
5898
6122
  if (!rows || rows.items.length !== elements.length) return false;
6123
+ const reactOwnedRows = this.hasReactOwnedRows();
5899
6124
  const opaqueConditionalPaths = new Set(
5900
6125
  (this.currentProps.conditionals || []).map((conditional) => conditional.path.join("."))
5901
6126
  );
5902
6127
  const instances = /* @__PURE__ */ new Map();
5903
6128
  for (let index = 0; index < rows.items.length; index += 1) {
5904
6129
  const descriptor = this.currentProps.create(rows.items[index], index);
5905
- if (this.hasReactOwnedRows() && !matchesCompilerHostElement(elements[index], descriptor, opaqueConditionalPaths)) {
6130
+ if (reactOwnedRows && !matchesCompilerHostElement(elements[index], descriptor, opaqueConditionalPaths)) {
5906
6131
  this.cleanupHostScopes(instances);
5907
6132
  return false;
5908
6133
  }
@@ -5915,7 +6140,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5915
6140
  key: rows.keys[index],
5916
6141
  element: elements[index],
5917
6142
  scope: scope || void 0,
5918
- values: this.hasReactOwnedRows() ? this.currentProps.bindings.map(() => UNSET_KEYED_ROW_BINDING) : readKeyedRowBindingValues(this.currentProps, rows.items[index], index),
6143
+ values: reactOwnedRows ? this.currentProps.bindings.map(() => UNSET_KEYED_ROW_BINDING) : readKeyedRowBindingValues(this.currentProps, rows.items[index], index),
5919
6144
  item: rows.items[index],
5920
6145
  index,
5921
6146
  conditionalValues: this.readConditionalValues(
@@ -5924,11 +6149,13 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5924
6149
  index
5925
6150
  )
5926
6151
  };
5927
- if (this.hasReactOwnedRows()) {
5928
- applyKeyedRowBindings(this.currentProps, instance, rows.items[index], index);
5929
- }
5930
6152
  instances.set(rows.keys[index], instance);
5931
6153
  }
6154
+ if (reactOwnedRows) {
6155
+ for (const instance of instances.values()) {
6156
+ applyKeyedRowBindings(this.currentProps, instance, instance.item, instance.index);
6157
+ }
6158
+ }
5932
6159
  this.cleanupHostScopes();
5933
6160
  this.instances = instances;
5934
6161
  this.rebuildElementIndex(instances);
@@ -6350,17 +6577,29 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6350
6577
  this.commitCurrentCollection(dirtyState);
6351
6578
  this.notifyConditionalChanges(conditionalChanges, afterCommit);
6352
6579
  }
6580
+ listen() {
6581
+ const id = this.currentProps.id;
6582
+ const stop = this.stop;
6583
+ if (this.id === id) return;
6584
+ stop?.();
6585
+ this.stop = owner.subscribe(id, this.refresh);
6586
+ this.id = id;
6587
+ }
6353
6588
  schedulePropSync() {
6354
6589
  if (this.propSyncQueued) return;
6355
6590
  this.propSyncQueued = true;
6356
6591
  queueMicrotask(() => {
6357
6592
  this.propSyncQueued = false;
6358
- if (this.mounted && !this.state.fallback) this.reconcile();
6593
+ if (this.mounted && !this.state.fallback) {
6594
+ this.listen();
6595
+ this.reconcile();
6596
+ }
6359
6597
  });
6360
6598
  }
6361
6599
  shouldComponentUpdate(nextProps, nextState) {
6362
6600
  const wasReactOwned = this.hasReactOwnedRows(this.currentProps);
6363
6601
  const willBeReactOwned = this.hasReactOwnedRows(nextProps);
6602
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6364
6603
  this.currentProps = nextProps;
6365
6604
  if (this.state.fallback && nextState.fallback) {
6366
6605
  const unsafeKeys = this.hasUnsafeFallbackKeys();
@@ -6368,7 +6607,7 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6368
6607
  this.fallbackKeysWereUnsafe = unsafeKeys;
6369
6608
  }
6370
6609
  if (nextState.fallback || this.state.fallback) return true;
6371
- if (wasReactOwned || willBeReactOwned) {
6610
+ if (definitionChanged || wasReactOwned || willBeReactOwned) {
6372
6611
  this.eventHandlers.clear();
6373
6612
  return true;
6374
6613
  }
@@ -6376,19 +6615,25 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6376
6615
  return false;
6377
6616
  }
6378
6617
  componentDidUpdate(previousProps) {
6379
- if (this.state.fallback || previousProps === this.props || !this.hasReactOwnedRows(previousProps) && !this.hasReactOwnedRows(this.props) || this.adopt()) {
6618
+ this.listen();
6619
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
6620
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
6621
+ this.definitionVersion = nextDefinitionVersion;
6622
+ if (this.state.fallback || previousProps === this.props || !definitionChanged && !this.hasReactOwnedRows(previousProps) && !this.hasReactOwnedRows(this.props) || this.adopt()) {
6380
6623
  return;
6381
6624
  }
6382
6625
  this.activateFallback();
6383
6626
  }
6384
6627
  componentDidMount() {
6385
6628
  this.mounted = true;
6386
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
6629
+ this.listen();
6387
6630
  if (!this.adopt()) this.activateFallback();
6388
6631
  }
6389
6632
  componentWillUnmount() {
6390
6633
  this.mounted = false;
6391
- this.unsubscribe?.();
6634
+ const stop = this.stop;
6635
+ stop?.();
6636
+ this.id = void 0;
6392
6637
  this.cleanupHostScopes();
6393
6638
  this.instances.clear();
6394
6639
  this.identityTargets.clear();
@@ -6431,6 +6676,7 @@ function createKeyedRangesBlockComponent(owner) {
6431
6676
  this.rangeInstances = [];
6432
6677
  this.staticSegments = [];
6433
6678
  this.staticValues = [];
6679
+ this.definitionVersion = owner.getDefinitionVersion?.();
6434
6680
  this.captureRoot = (root) => {
6435
6681
  this.root = root;
6436
6682
  this.currentProps.rootRef?.(root);
@@ -6468,6 +6714,7 @@ function createKeyedRangesBlockComponent(owner) {
6468
6714
  const elements = [...this.root.children];
6469
6715
  const staticSegments = [];
6470
6716
  const instancesByRange = [];
6717
+ const staticValues = this.staticValues.slice();
6471
6718
  let cursor = 0;
6472
6719
  for (let rangeIndex = 0; rangeIndex < props.ranges.length; rangeIndex += 1) {
6473
6720
  const range = props.ranges[rangeIndex];
@@ -6499,13 +6746,11 @@ function createKeyedRangesBlockComponent(owner) {
6499
6746
  }
6500
6747
  if (cursor + props.trailing !== elements.length) return false;
6501
6748
  staticSegments.push(elements.slice(cursor));
6749
+ if (!applyStaticRangeBindings(props.bindings, staticSegments, staticValues)) return false;
6502
6750
  this.staticSegments = staticSegments;
6503
6751
  this.rangeInstances = instancesByRange;
6504
- if (!applyStaticRangeBindings(props.bindings, this.staticSegments, this.staticValues)) {
6505
- this.rangeInstances = [];
6506
- this.staticSegments = [];
6507
- return false;
6508
- }
6752
+ this.staticValues.length = 0;
6753
+ this.staticValues.push(...staticValues);
6509
6754
  return true;
6510
6755
  }
6511
6756
  anchorAfter(rangeIndex) {
@@ -6602,6 +6847,14 @@ function createKeyedRangesBlockComponent(owner) {
6602
6847
  }
6603
6848
  afterCommit?.();
6604
6849
  }
6850
+ listen() {
6851
+ const id = this.currentProps.id;
6852
+ const stop = this.stop;
6853
+ if (this.id === id) return;
6854
+ stop?.();
6855
+ this.stop = owner.subscribe(id, this.refresh);
6856
+ this.id = id;
6857
+ }
6605
6858
  activateFallback(afterCommit) {
6606
6859
  if (!this.mounted || this.state.fallback || this.fallbackRequested) {
6607
6860
  afterCommit?.();
@@ -6616,10 +6869,14 @@ function createKeyedRangesBlockComponent(owner) {
6616
6869
  this.propFallbackQueued = true;
6617
6870
  queueMicrotask(() => {
6618
6871
  this.propFallbackQueued = false;
6619
- if (this.mounted && !this.state.fallback) this.activateFallback();
6872
+ if (this.mounted && !this.state.fallback) {
6873
+ this.listen();
6874
+ this.activateFallback();
6875
+ }
6620
6876
  });
6621
6877
  }
6622
6878
  shouldComponentUpdate(nextProps, nextState) {
6879
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6623
6880
  this.currentProps = nextProps;
6624
6881
  if (this.state.fallback && nextState.fallback) {
6625
6882
  const unsafeKeys = this.hasUnsafeFallbackKeys();
@@ -6627,17 +6884,27 @@ function createKeyedRangesBlockComponent(owner) {
6627
6884
  this.fallbackKeysWereUnsafe = unsafeKeys;
6628
6885
  }
6629
6886
  if (nextState.fallback || this.state.fallback) return true;
6887
+ if (definitionChanged) return true;
6630
6888
  this.schedulePropFallback();
6631
6889
  return false;
6632
6890
  }
6633
6891
  componentDidMount() {
6634
6892
  this.mounted = true;
6635
- this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
6893
+ this.listen();
6636
6894
  if (!this.adopt()) this.activateFallback();
6637
6895
  }
6896
+ componentDidUpdate() {
6897
+ this.listen();
6898
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
6899
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
6900
+ this.definitionVersion = nextDefinitionVersion;
6901
+ if (!this.state.fallback && definitionChanged && !this.adopt()) this.activateFallback();
6902
+ }
6638
6903
  componentWillUnmount() {
6639
6904
  this.mounted = false;
6640
- this.unsubscribe?.();
6905
+ const stop = this.stop;
6906
+ stop?.();
6907
+ this.id = void 0;
6641
6908
  this.rangeInstances = [];
6642
6909
  this.staticSegments = [];
6643
6910
  this.staticValues.length = 0;
@@ -6672,6 +6939,7 @@ function createMixedRangesBlockComponent(owner) {
6672
6939
  this.currentProps = this.props;
6673
6940
  this.controller = null;
6674
6941
  this.fallbackUnsubscribers = /* @__PURE__ */ new Map();
6942
+ this.definitionVersion = owner.getDefinitionVersion?.();
6675
6943
  this.captureRoot = (root) => {
6676
6944
  this.root = root;
6677
6945
  this.currentProps.rootRef?.(root);
@@ -6745,7 +7013,9 @@ function createMixedRangesBlockComponent(owner) {
6745
7013
  controller.cleanup();
6746
7014
  throw error;
6747
7015
  }
7016
+ const previous = this.controller;
6748
7017
  this.controller = controller;
7018
+ previous?.cleanup();
6749
7019
  return true;
6750
7020
  }
6751
7021
  schedulePropFallback() {
@@ -6757,11 +7027,13 @@ function createMixedRangesBlockComponent(owner) {
6757
7027
  });
6758
7028
  }
6759
7029
  shouldComponentUpdate(nextProps, nextState) {
7030
+ const definitionChanged = this.definitionVersion !== owner.getDefinitionVersion?.();
6760
7031
  this.currentProps = nextProps;
6761
7032
  if (this.state.fallback && nextState.fallback) {
6762
7033
  this.prepareFallbackUpdate(this.currentProps.create());
6763
7034
  }
6764
7035
  if (nextState.fallback || this.state.fallback) return true;
7036
+ if (definitionChanged) return true;
6765
7037
  this.schedulePropFallback();
6766
7038
  return false;
6767
7039
  }
@@ -6773,7 +7045,14 @@ function createMixedRangesBlockComponent(owner) {
6773
7045
  } else if (!this.adopt()) this.activateFallback();
6774
7046
  }
6775
7047
  componentDidUpdate() {
6776
- if (this.state.fallback) this.subscribeFallbackBlocks();
7048
+ const nextDefinitionVersion = owner.getDefinitionVersion?.();
7049
+ const definitionChanged = this.definitionVersion !== nextDefinitionVersion;
7050
+ this.definitionVersion = nextDefinitionVersion;
7051
+ if (this.state.fallback) {
7052
+ this.subscribeFallbackBlocks();
7053
+ } else if (definitionChanged && !this.adopt()) {
7054
+ this.activateFallback();
7055
+ }
6777
7056
  }
6778
7057
  componentWillUnmount() {
6779
7058
  this.mounted = false;
@@ -7613,8 +7892,9 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7613
7892
  };
7614
7893
  });
7615
7894
  const featureOwner = {
7616
- setRoot: (id, root) => this.setBlockRoot(id, root),
7617
- subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
7895
+ setRoot: (id, root, expectedRoot) => this.setBlockRoot(id, root, expectedRoot),
7896
+ subscribe: (id, refresh) => this.subscribeToBlock(id, refresh),
7897
+ getDefinitionVersion: () => definitionReference.current
7618
7898
  };
7619
7899
  const blockRuntime = {
7620
7900
  target: (id) => this.bindingTarget(id)
@@ -7753,8 +8033,9 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7753
8033
  }
7754
8034
  snapshot.element.setSelectionRange(snapshot.start, snapshot.end, snapshot.direction);
7755
8035
  }
7756
- setBlockRoot(id, root) {
8036
+ setBlockRoot(id, root, expectedRoot) {
7757
8037
  const previous = this.blockRoots.get(id);
8038
+ if (!root && expectedRoot !== void 0 && previous !== expectedRoot) return;
7758
8039
  if (previous) this.blockRootElements.delete(previous);
7759
8040
  if (root) {
7760
8041
  this.blockRoots.set(id, root);