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

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.
package/README.md CHANGED
@@ -496,7 +496,11 @@ through one document fragment. It then removes only the replaced window. When th
496
496
  has the same length and the same keys in the same order, Farm prepares every binding read and
497
497
  changed DOM target across the complete window first, patches the existing rows in place, and
498
498
  updates the stored row objects used by later events. That path creates no descriptors or DOM rows,
499
- and preserves row identity, focus, and selection. A window may instead grow or shrink while it
499
+ and preserves row identity, focus, and selection. Validated same-key row and window refreshes also
500
+ keep the existing row map and element lookup, and skip redundant cache cleanup instead of
501
+ rebuilding whole-list bookkeeping. Source and key validation still run, and each flush commits the
502
+ new collection token for subsequent updates. Structural changes retain index rebuilding and cache
503
+ cleanup. A window may instead grow or shrink while it
500
504
  reorders keys from inside its own removed interval and mixes them with globally fresh keys. Farm
501
505
  prepares all reused binding updates, new descriptors, binding snapshots, and detached rows before
502
506
  the first DOM write. It removes only retired rows, preserves each reused row, batches adjacent new
@@ -562,12 +566,15 @@ subclassed behavior, structural calls after reordering, an unhinted intermediate
562
566
  React-owned rows, and failed checks keep complete keyed reconciliation.
563
567
 
564
568
  A compiler-safe `filter()` or bounded `slice()` prefix may precede the native reorder suffix in a
565
- concise updater or exact one-return block:
569
+ concise updater or exact one-return block. A filter predicate may be concise or contain exactly one
570
+ direct value-returning `return`:
566
571
 
567
572
  ```tsx
568
573
  setItems((current) =>
569
574
  current
570
- .filter((item) => item.visible)
575
+ .filter((item) => {
576
+ return item.visible;
577
+ })
571
578
  .toSorted((left, right) => left.rank - right.rank)
572
579
  .toReversed(),
573
580
  );
@@ -809,17 +816,22 @@ setItems((current) => current.filter((item) => item.id !== removedId));
809
816
  setItems((current) => {
810
817
  return current.filter((item) => item.id !== removedId);
811
818
  });
819
+ setItems((current) =>
820
+ current.filter((item) => {
821
+ return item.id !== removedId;
822
+ }),
823
+ );
812
824
  ```
813
825
 
814
826
  For compiler-owned host rows whose render and key do not observe the row index, Farm validates the
815
827
  native filter chain, every surviving item identity, and every surviving key before removing only
816
828
  the rejected DOM rows. It does not recreate descriptors or reread bindings for unchanged rows,
817
829
  and queued filters compose before one compiler flush. Index-aware rows or predicates, updater blocks
818
- with extra statements, directives, conditional returns, or no value-returning `return`, block-bodied
819
- predicates, custom filter methods, sparse or subclassed arrays, collection-reading bindings or keys,
820
- React-owned row structures, mixed dirty dependencies, and failed validation use complete keyed
821
- reconciliation. No option or new component is required. The compiler report exposes the emitted-site
822
- count as `keyedArrayFilterHints`.
830
+ with extra statements, directives, conditional returns, or no value-returning `return`, predicate
831
+ blocks with those unsupported shapes, custom filter methods, sparse or subclassed arrays,
832
+ collection-reading bindings or keys, React-owned row structures, mixed dirty dependencies, and
833
+ failed validation use complete keyed reconciliation. No option or new component is required. The
834
+ compiler report exposes the emitted-site count as `keyedArrayFilterHints`.
823
835
 
824
836
  An otherwise eligible host row may also contain an inline synchronous React event:
825
837
 
@@ -3381,7 +3381,6 @@ function createHostConditionalBlockComponent(owner) {
3381
3381
  for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3382
3382
  this.fallbackUnsubscribers = [];
3383
3383
  this.instance?.scope?.cleanup();
3384
- this.root = null;
3385
3384
  this.activeBranch = null;
3386
3385
  this.instance = null;
3387
3386
  }
@@ -3653,7 +3652,6 @@ function createConditionalRangesBlockComponent(owner) {
3653
3652
  for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
3654
3653
  this.fallbackUnsubscribers = [];
3655
3654
  for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
3656
- this.root = null;
3657
3655
  this.rangeInstances = [];
3658
3656
  this.staticSegments = [];
3659
3657
  this.staticValues.length = 0;
@@ -4495,15 +4493,15 @@ function reconcileCompilerKeyedArrayBatchInsert(props, dirtyState, collectionTok
4495
4493
  return void 0;
4496
4494
  }
4497
4495
  }
4498
- const knownKeys = new Set(instances.keys());
4496
+ const incomingKeys = /* @__PURE__ */ new Set();
4499
4497
  const incoming = [];
4500
4498
  try {
4501
4499
  for (let offset = 0; offset < insertCount; offset += 1) {
4502
4500
  const index = update.position + offset;
4503
4501
  const item = finalValue[index];
4504
4502
  const key = keyedRowIdentity(props.rowKey(item, index));
4505
- if (knownKeys.has(key)) return void 0;
4506
- knownKeys.add(key);
4503
+ if (instances.has(key) || incomingKeys.has(key)) return void 0;
4504
+ incomingKeys.add(key);
4507
4505
  const descriptor = props.create(item, index);
4508
4506
  incoming.push({
4509
4507
  key,
@@ -4656,9 +4654,9 @@ function reconcileCompilerKeyedArrayWindowReplace(props, dirtyState, collectionT
4656
4654
  const preparedIncomingKeys = /* @__PURE__ */ new Set();
4657
4655
  const preparedWindows = [];
4658
4656
  const nextInstances = [];
4659
- for (const window of windows) {
4660
- if (window[0] < sourceCursor) return void 0;
4661
- while (sourceCursor < window[0]) {
4657
+ for (const window2 of windows) {
4658
+ if (window2[0] < sourceCursor) return void 0;
4659
+ while (sourceCursor < window2[0]) {
4662
4660
  const instance = previousInstances[sourceCursor];
4663
4661
  if (!instance || instance.index !== sourceCursor || !Object.is(instance.item, finalValue[resultCursor])) {
4664
4662
  return void 0;
@@ -4671,24 +4669,24 @@ function reconcileCompilerKeyedArrayWindowReplace(props, dirtyState, collectionT
4671
4669
  props,
4672
4670
  finalValue,
4673
4671
  resultCursor,
4674
- window[3]
4672
+ window2[3]
4675
4673
  );
4676
4674
  if (!incoming2) return void 0;
4677
- window[1] = resultCursor;
4675
+ window2[1] = resultCursor;
4678
4676
  const prepared3 = prepareCompilerKeyedArrayWindow(
4679
4677
  props,
4680
4678
  instances,
4681
4679
  previousInstances,
4682
4680
  root,
4683
- window,
4681
+ window2,
4684
4682
  incoming2,
4685
4683
  preparedIncomingKeys
4686
4684
  );
4687
4685
  if (!prepared3) return void 0;
4688
4686
  preparedWindows.push(prepared3);
4689
4687
  nextInstances.push(...prepared3[4]);
4690
- sourceCursor += window[2];
4691
- resultCursor += window[3];
4688
+ sourceCursor += window2[2];
4689
+ resultCursor += window2[3];
4692
4690
  }
4693
4691
  while (sourceCursor < previousInstances.length) {
4694
4692
  const instance = previousInstances[sourceCursor];
@@ -4708,30 +4706,32 @@ function reconcileCompilerKeyedArrayWindowReplace(props, dirtyState, collectionT
4708
4706
  }
4709
4707
  return keyedRowInstancesByKey(nextInstances);
4710
4708
  }
4711
- const touchedIndices = /* @__PURE__ */ new Set();
4712
- for (const update2 of updates) {
4713
- for (let index = update2.position; index < update2.position + update2.removedCount; index += 1) {
4714
- touchedIndices.add(index);
4715
- }
4716
- }
4709
+ updates.sort((left, right) => right.position - left.position);
4710
+ let window = updates.pop();
4711
+ const touchedInstances = [];
4717
4712
  for (let index = 0; index < previousInstances.length; index += 1) {
4713
+ while (window && index >= window.position + window.removedCount) {
4714
+ window = updates.pop();
4715
+ }
4718
4716
  const instance = previousInstances[index];
4719
- const touched = touchedIndices.has(index);
4720
- if (!instance || instance.index !== index || (touched ? instance.element.parentNode !== root : !Object.is(instance.item, finalValue[index]))) {
4717
+ if (!instance || instance.index !== index) return void 0;
4718
+ if (window && index >= window.position) {
4719
+ if (instance.element.parentNode !== root) return void 0;
4720
+ touchedInstances.push(instance);
4721
+ } else if (!Object.is(instance.item, finalValue[index])) {
4721
4722
  return void 0;
4722
4723
  }
4723
4724
  }
4724
- const knownKeys = new Set(instances.keys());
4725
4725
  const incomingKeys2 = /* @__PURE__ */ new Set();
4726
4726
  let replacesRows = false;
4727
4727
  const prepared2 = [];
4728
4728
  try {
4729
- for (const index of [...touchedIndices].sort((left, right) => left - right)) {
4730
- const instance = previousInstances[index];
4729
+ for (const instance of touchedInstances) {
4730
+ const index = instance.index;
4731
4731
  const item = finalValue[index];
4732
4732
  const key = keyedRowIdentity(props.rowKey(item, index));
4733
4733
  if (key !== instance.key) {
4734
- if (knownKeys.has(key) || incomingKeys2.has(key)) return void 0;
4734
+ if (instances.has(key) || incomingKeys2.has(key)) return void 0;
4735
4735
  incomingKeys2.add(key);
4736
4736
  replacesRows = true;
4737
4737
  const descriptor = props.create(item, index);
@@ -5555,11 +5555,13 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5555
5555
  this.hasReactOwnedRows()
5556
5556
  );
5557
5557
  if (positionedInstances) {
5558
- this.instances = new Map(positionedInstances);
5559
- this.rebuildElementIndex(this.instances);
5560
- const keys = [...this.instances.keys()];
5561
- this.pruneEventHandlers(keys);
5562
- this.pruneConditionalListeners(keys);
5558
+ if (positionedInstances !== this.instances) {
5559
+ this.instances = new Map(positionedInstances);
5560
+ this.rebuildElementIndex(this.instances);
5561
+ const keys = [...this.instances.keys()];
5562
+ this.pruneEventHandlers(keys);
5563
+ this.pruneConditionalListeners(keys);
5564
+ }
5563
5565
  this.commitCurrentCollection(dirtyState);
5564
5566
  afterCommit?.();
5565
5567
  return;
@@ -5574,9 +5576,9 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
5574
5576
  );
5575
5577
  if (reorderedInstances) {
5576
5578
  const removedRows = reorderedInstances.size < this.instances.size;
5577
- this.instances = new Map(reorderedInstances);
5578
- this.rebuildElementIndex(this.instances);
5579
+ this.instances = reorderedInstances;
5579
5580
  if (removedRows) {
5581
+ this.rebuildElementIndex(this.instances);
5580
5582
  const keys = [...this.instances.keys()];
5581
5583
  this.pruneEventHandlers(keys);
5582
5584
  this.pruneConditionalListeners(keys);
@@ -6303,7 +6305,6 @@ function createKeyedRowsBlockComponent(owner, options = {}) {
6303
6305
  componentWillUnmount() {
6304
6306
  this.mounted = false;
6305
6307
  this.unsubscribe?.();
6306
- this.root = null;
6307
6308
  this.cleanupHostScopes();
6308
6309
  this.instances.clear();
6309
6310
  this.identityTargets.clear();
@@ -6537,7 +6538,6 @@ function createKeyedRangesBlockComponent(owner) {
6537
6538
  componentWillUnmount() {
6538
6539
  this.mounted = false;
6539
6540
  this.unsubscribe?.();
6540
- this.root = null;
6541
6541
  this.rangeInstances = [];
6542
6542
  this.staticSegments = [];
6543
6543
  this.staticValues.length = 0;
@@ -6662,7 +6662,6 @@ function createMixedRangesBlockComponent(owner) {
6662
6662
  this.controller?.cleanup();
6663
6663
  this.controller = null;
6664
6664
  this.clearFallbackSubscriptions();
6665
- this.root = null;
6666
6665
  }
6667
6666
  render() {
6668
6667
  const container = this.currentProps.render();
@@ -7776,13 +7775,11 @@ function createCompiledComponentWithFeatures(definition, runtimeFeatures) {
7776
7775
  }
7777
7776
  componentWillUnmount() {
7778
7777
  this.mounted = false;
7779
- this.root = null;
7780
7778
  this.dirtyState.clear();
7781
7779
  this.inputSelection = null;
7782
7780
  this.blockRefreshListeners.clear();
7783
7781
  this.blockRoots.clear();
7784
7782
  this.blockRootElements.clear();
7785
- this.bindingTargets.clear();
7786
7783
  this.bindingTargetRefs.clear();
7787
7784
  this.indexedDefinition = null;
7788
7785
  this.staticBindingsByDependency = [];