@farm.js/react 0.1.0-beta.2 → 0.1.0-beta.4

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.
@@ -1,6 +1,23 @@
1
1
  import React from 'react';
2
2
  import { flushSync } from 'react-dom';
3
3
 
4
+ // src/compiler-runtime.tsx
5
+
6
+ // src/iterable.ts
7
+ var oneShotSnapshots = /* @__PURE__ */ new WeakMap();
8
+ function materializeIterable(source) {
9
+ if (source == null) return [];
10
+ const iterator = source[Symbol.iterator]();
11
+ const oneShot = iterator === source && (typeof source === "object" || typeof source === "function");
12
+ if (oneShot) {
13
+ const cached = oneShotSnapshots.get(source);
14
+ if (cached) return cached;
15
+ }
16
+ const items = Array.from({ [Symbol.iterator]: () => iterator });
17
+ if (oneShot) oneShotSnapshots.set(source, items);
18
+ return items;
19
+ }
20
+
4
21
  // src/compiler-runtime.tsx
5
22
  var COMPILER_HMR_REGISTRY = /* @__PURE__ */ Symbol.for("@farm.js/react/compiler-hmr-registry");
6
23
  function getCompilerHmrRegistry() {
@@ -16,6 +33,11 @@ function renderTextValue(value) {
16
33
  if (value === null || value === void 0 || typeof value === "boolean") return "";
17
34
  return String(value);
18
35
  }
36
+ function isCompilerPrimitive(value) {
37
+ if (value === null) return true;
38
+ const kind = typeof value;
39
+ return kind === "string" || kind === "number" || kind === "boolean" || kind === "bigint" || kind === "undefined";
40
+ }
19
41
  function findBindingTarget(root, path, blockRoots) {
20
42
  let current = root;
21
43
  for (const index of path) {
@@ -254,14 +276,19 @@ function createCompilerHostElement(document, descriptor) {
254
276
  updateAttribute(element, attribute.name, attribute.value);
255
277
  }
256
278
  for (const style of descriptor.styles) updateStyle(element, style.name, style.value);
257
- for (const child of descriptor.children) {
279
+ const appendChild = (child) => {
280
+ if (Array.isArray(child)) {
281
+ for (const nested of child) appendChild(nested);
282
+ return;
283
+ }
258
284
  if (isCompilerHostElement(child)) {
259
285
  element.append(createCompilerHostElement(document, child));
260
- continue;
286
+ return;
261
287
  }
262
288
  const text = renderTextValue(child);
263
289
  if (text) element.append(document.createTextNode(text));
264
- }
290
+ };
291
+ for (const child of materializeCompilerHostChildren(descriptor)) appendChild(child);
265
292
  for (const attribute of descriptor.attributes) {
266
293
  if (attribute.name === "value" && (isSelectElement(element) || isTextAreaElement(element))) {
267
294
  updateAttribute(element, attribute.name, attribute.value);
@@ -271,18 +298,110 @@ function createCompilerHostElement(document, descriptor) {
271
298
  }
272
299
  function matchesCompilerHostElement(element, descriptor, opaquePaths = /* @__PURE__ */ new Set(), path = []) {
273
300
  if (element.tagName.toLowerCase() !== descriptor.tag.toLowerCase()) return false;
274
- if (opaquePaths.has(path.join("."))) return true;
275
- const expectedChildren = descriptor.children.filter(isCompilerHostElement);
301
+ if (opaquePaths.has(path.join(".")) || descriptor.block) return true;
302
+ const expectedChildren = flattenCompilerHostElements(descriptor.children);
276
303
  if (element.children.length !== expectedChildren.length) return false;
277
304
  return expectedChildren.every(
278
305
  (child, index) => matchesCompilerHostElement(element.children[index], child, opaquePaths, [...path, index])
279
306
  );
280
307
  }
308
+ function flattenCompilerHostElements(children) {
309
+ const elements = [];
310
+ const visit = (child) => {
311
+ if (Array.isArray(child)) {
312
+ for (const nested of child) visit(nested);
313
+ } else if (isCompilerHostElement(child)) {
314
+ elements.push(child);
315
+ }
316
+ };
317
+ for (const child of children) visit(child);
318
+ return elements;
319
+ }
320
+ function materializeCompilerHostChildren(descriptor) {
321
+ const block = descriptor.block;
322
+ if (block?.kind !== "keyed-ranges" || !block.staticChildrenOnly) {
323
+ return descriptor.children;
324
+ }
325
+ const staticChildren = flattenCompilerHostElements(descriptor.children);
326
+ const children = [];
327
+ let cursor = 0;
328
+ for (const range of block.ranges) {
329
+ children.push(...staticChildren.slice(cursor, cursor + range.before));
330
+ cursor += range.before;
331
+ const items = materializeIterable(range.items());
332
+ children.push(...items.map((item, index) => range.create(item, index)));
333
+ }
334
+ children.push(...staticChildren.slice(cursor, cursor + block.trailing));
335
+ return children;
336
+ }
337
+ function collectCompilerHostBlockIds(descriptor, ids) {
338
+ for (const child of flattenCompilerHostElements(descriptor.children)) {
339
+ collectCompilerHostBlockIds(child, ids);
340
+ }
341
+ const block = descriptor.block;
342
+ if (!block || ids.has(block.id)) return;
343
+ ids.add(block.id);
344
+ if (block.kind === "conditional-ranges") {
345
+ for (const range of block.ranges) {
346
+ if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
347
+ if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
348
+ }
349
+ } else if (block.kind === "keyed-ranges") {
350
+ for (const range of block.ranges) {
351
+ const first = materializeIterable(range.items())[0];
352
+ if (first !== void 0) collectCompilerHostBlockIds(range.create(first, 0), ids);
353
+ }
354
+ } else {
355
+ for (const range of block.ranges) {
356
+ if (range.kind === "conditional") {
357
+ if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
358
+ if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
359
+ } else {
360
+ const first = materializeIterable(range.items())[0];
361
+ if (first !== void 0) collectCompilerHostBlockIds(range.create(first, 0), ids);
362
+ }
363
+ }
364
+ }
365
+ }
281
366
  function findCompilerHostTarget(root, path) {
282
367
  let current = root;
283
368
  for (const index of path) current = current?.children[index] || null;
284
369
  return current;
285
370
  }
371
+ var UNSET_STATIC_RANGE_BINDING = /* @__PURE__ */ Symbol("unset static range binding");
372
+ function normalizedStaticRangeBindingValue(binding, value) {
373
+ return binding.kind === "text" ? renderTextValue(value) : value;
374
+ }
375
+ function applyStaticRangeBindings(bindings, segments, values) {
376
+ const activeBindings = bindings || [];
377
+ if (values.length === 0 && activeBindings.length > 0) {
378
+ values.push(...activeBindings.map(() => UNSET_STATIC_RANGE_BINDING));
379
+ }
380
+ if (values.length !== activeBindings.length) return false;
381
+ for (let index = 0; index < activeBindings.length; index += 1) {
382
+ const binding = activeBindings[index];
383
+ if (!Number.isSafeInteger(binding.segment) || binding.segment < 0 || !Number.isSafeInteger(binding.sibling) || binding.sibling < 0) {
384
+ return false;
385
+ }
386
+ const sibling = segments[binding.segment]?.[binding.sibling];
387
+ const target = sibling && findCompilerHostTarget(sibling, binding.path);
388
+ if (!target) return false;
389
+ const rawValue = binding.read();
390
+ const value = normalizedStaticRangeBindingValue(binding, rawValue);
391
+ if (Object.is(values[index], value)) continue;
392
+ values[index] = value;
393
+ if (binding.kind === "text") {
394
+ target.textContent = value;
395
+ } else if (binding.kind === "style" && binding.name) {
396
+ updateStyle(target, binding.name, rawValue);
397
+ } else if (binding.kind === "attribute" && binding.name) {
398
+ updateAttribute(target, binding.name, rawValue);
399
+ } else {
400
+ return false;
401
+ }
402
+ }
403
+ return true;
404
+ }
286
405
  var UNSET_KEYED_ROW_BINDING = /* @__PURE__ */ Symbol("unset interactive keyed-row binding");
287
406
  function keyedRowIdentity(key) {
288
407
  return String(key);
@@ -297,20 +416,23 @@ function readKeyedRowBindingValues(props, item, index) {
297
416
  }
298
417
  function applyKeyedRowBindings(props, instance, item, index) {
299
418
  for (let bindingIndex = 0; bindingIndex < props.bindings.length; bindingIndex += 1) {
300
- const binding = props.bindings[bindingIndex];
301
- const rawValue = binding.read(item, index);
302
- const value = normalizedKeyedRowBindingValue(binding, rawValue);
303
- if (Object.is(instance.values[bindingIndex], value)) continue;
304
- instance.values[bindingIndex] = value;
305
- const target = findCompilerHostTarget(instance.element, binding.path);
306
- if (!target) continue;
307
- if (binding.kind === "text") {
308
- target.textContent = value;
309
- } else if (binding.kind === "style" && binding.name) {
310
- updateStyle(target, binding.name, rawValue);
311
- } else if (binding.kind === "attribute" && binding.name) {
312
- updateAttribute(target, binding.name, rawValue);
313
- }
419
+ applyKeyedRowBinding(props, instance, item, index, bindingIndex);
420
+ }
421
+ }
422
+ function applyKeyedRowBinding(props, instance, item, index, bindingIndex) {
423
+ const binding = props.bindings[bindingIndex];
424
+ const rawValue = binding.read(item, index);
425
+ const value = normalizedKeyedRowBindingValue(binding, rawValue);
426
+ if (Object.is(instance.values[bindingIndex], value)) return;
427
+ instance.values[bindingIndex] = value;
428
+ const target = findCompilerHostTarget(instance.element, binding.path);
429
+ if (!target) return;
430
+ if (binding.kind === "text") {
431
+ target.textContent = value;
432
+ } else if (binding.kind === "style" && binding.name) {
433
+ updateStyle(target, binding.name, rawValue);
434
+ } else if (binding.kind === "attribute" && binding.name) {
435
+ updateAttribute(target, binding.name, rawValue);
314
436
  }
315
437
  }
316
438
  function keyedRowConditionalSnapshot(conditional, item, index) {
@@ -329,13 +451,15 @@ function keyedRowConditionalSnapshot(conditional, item, index) {
329
451
  ];
330
452
  }
331
453
  function readKeyedRowConditionalValues(props, item, index) {
454
+ if (!props.conditionals?.length) return EMPTY_KEYED_ROW_CONDITIONAL_VALUES;
332
455
  return new Map(
333
- (props.conditionals || []).map((conditional) => [
456
+ props.conditionals.map((conditional) => [
334
457
  conditional.id,
335
458
  keyedRowConditionalSnapshot(conditional, item, index)
336
459
  ])
337
460
  );
338
461
  }
462
+ var EMPTY_KEYED_ROW_CONDITIONAL_VALUES = /* @__PURE__ */ new Map();
339
463
  function keyedRowConditionalChanged(previous, next) {
340
464
  return !previous || previous.length !== next.length || next.some((value, index) => !Object.is(value, previous[index]));
341
465
  }
@@ -352,11 +476,6 @@ function hostConditionalSelection(props) {
352
476
  function normalizedHostConditionalBindingValue(binding, value) {
353
477
  return binding.kind === "text" ? renderTextValue(value) : value;
354
478
  }
355
- function readHostConditionalBindingValues(branch) {
356
- return branch.bindings.map(
357
- (binding) => normalizedHostConditionalBindingValue(binding, binding.read())
358
- );
359
- }
360
479
  function applyHostConditionalBindings(branch, instance) {
361
480
  for (let bindingIndex = 0; bindingIndex < branch.bindings.length; bindingIndex += 1) {
362
481
  const binding = branch.bindings[bindingIndex];
@@ -375,6 +494,903 @@ function applyHostConditionalBindings(branch, instance) {
375
494
  }
376
495
  }
377
496
  }
497
+ var UNSET_HOST_CONDITIONAL_BINDING = /* @__PURE__ */ Symbol("unset host conditional binding");
498
+ function mountCompilerHostTree(owner, element, descriptor, onFallback) {
499
+ if (!matchesCompilerHostElement(element, descriptor)) return null;
500
+ if (descriptor.block?.kind === "conditional-ranges") {
501
+ const controller = new CompilerNestedConditionalRanges(
502
+ owner,
503
+ element,
504
+ descriptor,
505
+ descriptor.block,
506
+ onFallback
507
+ );
508
+ try {
509
+ if (controller.adopt()) return controller;
510
+ controller.cleanup();
511
+ return null;
512
+ } catch (error) {
513
+ controller.cleanup();
514
+ throw error;
515
+ }
516
+ }
517
+ if (descriptor.block?.kind === "keyed-ranges") {
518
+ const controller = new CompilerNestedKeyedRanges(
519
+ owner,
520
+ element,
521
+ descriptor,
522
+ descriptor.block,
523
+ onFallback
524
+ );
525
+ try {
526
+ if (controller.adopt()) return controller;
527
+ controller.cleanup();
528
+ return null;
529
+ } catch (error) {
530
+ controller.cleanup();
531
+ throw error;
532
+ }
533
+ }
534
+ if (descriptor.block?.kind === "mixed-ranges") {
535
+ const controller = new CompilerNestedMixedRanges(
536
+ owner,
537
+ element,
538
+ descriptor,
539
+ descriptor.block,
540
+ onFallback
541
+ );
542
+ try {
543
+ if (controller.adopt()) return controller;
544
+ controller.cleanup();
545
+ return null;
546
+ } catch (error) {
547
+ controller.cleanup();
548
+ throw error;
549
+ }
550
+ }
551
+ const descriptors = flattenCompilerHostElements(descriptor.children);
552
+ if (descriptors.length !== element.children.length) return null;
553
+ const scopes = [];
554
+ for (let index = 0; index < descriptors.length; index += 1) {
555
+ const scope = mountCompilerHostTree(
556
+ owner,
557
+ element.children[index],
558
+ descriptors[index],
559
+ onFallback
560
+ );
561
+ if (!scope) {
562
+ for (const mounted of scopes) mounted.cleanup();
563
+ return null;
564
+ }
565
+ scopes.push(scope);
566
+ }
567
+ let active = true;
568
+ return {
569
+ update(nextDescriptor) {
570
+ if (!active || nextDescriptor.block || !matchesCompilerHostElement(element, nextDescriptor)) {
571
+ return false;
572
+ }
573
+ const nextChildren = flattenCompilerHostElements(nextDescriptor.children);
574
+ if (nextChildren.length !== scopes.length) return false;
575
+ return scopes.every((scope, index) => scope.update(nextChildren[index]));
576
+ },
577
+ cleanup() {
578
+ if (!active) return;
579
+ active = false;
580
+ for (const scope of scopes) scope.cleanup();
581
+ }
582
+ };
583
+ }
584
+ function mountCompilerHostInstance(owner, element, descriptor, branch, onFallback) {
585
+ const scope = mountCompilerHostTree(owner, element, descriptor, onFallback);
586
+ if (!scope) return null;
587
+ const instance = {
588
+ element,
589
+ scope,
590
+ values: branch.bindings.map(() => UNSET_HOST_CONDITIONAL_BINDING)
591
+ };
592
+ try {
593
+ applyHostConditionalBindings(branch, instance);
594
+ } catch (error) {
595
+ scope.cleanup();
596
+ throw error;
597
+ }
598
+ return instance;
599
+ }
600
+ var CompilerNestedConditionalRanges = class {
601
+ constructor(owner, root, host, block, onFallback) {
602
+ this.owner = owner;
603
+ this.root = root;
604
+ this.host = host;
605
+ this.block = block;
606
+ this.onFallback = onFallback;
607
+ this.instances = [];
608
+ this.staticSegments = [];
609
+ this.staticScopes = [];
610
+ this.staticValues = [];
611
+ this.active = true;
612
+ this.refresh = (afterCommit) => {
613
+ if (!this.active) {
614
+ afterCommit?.();
615
+ return;
616
+ }
617
+ const selections = this.readSelections();
618
+ if (!selections || selections.length !== this.instances.length) {
619
+ this.onFallback();
620
+ afterCommit?.();
621
+ return;
622
+ }
623
+ if (!applyStaticRangeBindings(this.block.bindings, this.staticSegments, this.staticValues)) {
624
+ this.onFallback();
625
+ afterCommit?.();
626
+ return;
627
+ }
628
+ for (let index = this.instances.length - 1; index >= 0; index -= 1) {
629
+ if (!this.reconcileRange(index, selections[index])) {
630
+ this.onFallback();
631
+ afterCommit?.();
632
+ return;
633
+ }
634
+ }
635
+ afterCommit?.();
636
+ };
637
+ }
638
+ readSelections() {
639
+ const selections = [];
640
+ for (const range of this.block.ranges) {
641
+ const selection = hostConditionalSelection(range);
642
+ if (selection.kind === "fallback") return null;
643
+ selections.push(selection);
644
+ }
645
+ return selections;
646
+ }
647
+ mountStatic(elements, descriptors) {
648
+ if (elements.length !== descriptors.length) return false;
649
+ for (let index = 0; index < elements.length; index += 1) {
650
+ const scope = mountCompilerHostTree(
651
+ this.owner,
652
+ elements[index],
653
+ descriptors[index],
654
+ this.onFallback
655
+ );
656
+ if (!scope) return false;
657
+ this.staticScopes.push(scope);
658
+ }
659
+ return true;
660
+ }
661
+ adopt() {
662
+ if (!Number.isSafeInteger(this.block.trailing) || this.block.trailing < 0) return false;
663
+ const selections = this.readSelections();
664
+ if (!selections) return false;
665
+ const elements = [...this.root.children];
666
+ const descriptors = flattenCompilerHostElements(this.host.children);
667
+ if (elements.length !== descriptors.length) return false;
668
+ let cursor = 0;
669
+ for (let index = 0; index < this.block.ranges.length; index += 1) {
670
+ const range = this.block.ranges[index];
671
+ if (!Number.isSafeInteger(range.before) || range.before < 0) {
672
+ this.cleanup();
673
+ return false;
674
+ }
675
+ const staticEnd = cursor + range.before;
676
+ if (staticEnd > elements.length || !this.mountStatic(elements.slice(cursor, staticEnd), descriptors.slice(cursor, staticEnd))) {
677
+ this.cleanup();
678
+ return false;
679
+ }
680
+ this.staticSegments.push(elements.slice(cursor, staticEnd));
681
+ cursor = staticEnd;
682
+ const selection = selections[index];
683
+ if (selection.kind === "empty") {
684
+ this.instances.push(null);
685
+ continue;
686
+ }
687
+ const element = elements[cursor];
688
+ if (!element) {
689
+ this.cleanup();
690
+ return false;
691
+ }
692
+ const descriptor = selection.branch.create();
693
+ const host = mountCompilerHostInstance(
694
+ this.owner,
695
+ element,
696
+ descriptor,
697
+ selection.branch,
698
+ this.onFallback
699
+ );
700
+ if (!host) {
701
+ this.cleanup();
702
+ return false;
703
+ }
704
+ this.instances.push({ key: selection.key, host });
705
+ cursor += 1;
706
+ }
707
+ const trailingEnd = cursor + this.block.trailing;
708
+ if (trailingEnd !== elements.length || !this.mountStatic(elements.slice(cursor), descriptors.slice(cursor))) {
709
+ this.cleanup();
710
+ return false;
711
+ }
712
+ this.staticSegments.push(elements.slice(cursor));
713
+ if (!applyStaticRangeBindings(this.block.bindings, this.staticSegments, this.staticValues)) {
714
+ this.cleanup();
715
+ return false;
716
+ }
717
+ this.unsubscribe = this.owner.subscribe(this.block.id, this.refresh);
718
+ return true;
719
+ }
720
+ anchorAfter(rangeIndex) {
721
+ for (let next = rangeIndex + 1; next < this.instances.length; next += 1) {
722
+ const staticAnchor = this.staticSegments[next]?.[0];
723
+ if (staticAnchor) return staticAnchor;
724
+ const rangeAnchor = this.instances[next]?.host.element;
725
+ if (rangeAnchor) return rangeAnchor;
726
+ }
727
+ return this.staticSegments[this.instances.length]?.[0] || null;
728
+ }
729
+ reconcileRange(rangeIndex, selection) {
730
+ const previous = this.instances[rangeIndex];
731
+ if (selection.kind === "empty") {
732
+ previous?.host.scope?.cleanup();
733
+ previous?.host.element.remove();
734
+ this.instances[rangeIndex] = null;
735
+ return true;
736
+ }
737
+ if (previous?.key === selection.key) {
738
+ const descriptor2 = selection.branch.create();
739
+ if (!previous.host.scope?.update(descriptor2)) return false;
740
+ applyHostConditionalBindings(selection.branch, previous.host);
741
+ return true;
742
+ }
743
+ const descriptor = selection.branch.create();
744
+ const element = createCompilerHostElement(this.root.ownerDocument, descriptor);
745
+ const host = mountCompilerHostInstance(
746
+ this.owner,
747
+ element,
748
+ descriptor,
749
+ selection.branch,
750
+ this.onFallback
751
+ );
752
+ if (!host) return false;
753
+ previous?.host.scope?.cleanup();
754
+ if (previous) previous.host.element.replaceWith(element);
755
+ else this.root.insertBefore(element, this.anchorAfter(rangeIndex));
756
+ this.instances[rangeIndex] = { key: selection.key, host };
757
+ return true;
758
+ }
759
+ updateStaticScopes(descriptor, selections) {
760
+ const descriptors = flattenCompilerHostElements(descriptor.children);
761
+ let descriptorIndex = 0;
762
+ let scopeIndex = 0;
763
+ for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
764
+ const range = this.block.ranges[rangeIndex];
765
+ for (let index = 0; index < range.before; index += 1) {
766
+ const scope = this.staticScopes[scopeIndex++];
767
+ const child = descriptors[descriptorIndex++];
768
+ if (!scope || !child || !scope.update(child)) return false;
769
+ }
770
+ if (selections[rangeIndex].kind === "branch") descriptorIndex += 1;
771
+ }
772
+ for (let index = 0; index < this.block.trailing; index += 1) {
773
+ const scope = this.staticScopes[scopeIndex++];
774
+ const child = descriptors[descriptorIndex++];
775
+ if (!scope || !child || !scope.update(child)) return false;
776
+ }
777
+ return scopeIndex === this.staticScopes.length && descriptorIndex === descriptors.length;
778
+ }
779
+ update(descriptor) {
780
+ const block = descriptor.block;
781
+ if (!this.active || block?.kind !== "conditional-ranges" || block.id !== this.block.id || block.ranges.length !== this.block.ranges.length || block.trailing !== this.block.trailing || block.ranges.some((range, index) => range.before !== this.block.ranges[index].before)) {
782
+ return false;
783
+ }
784
+ this.host = descriptor;
785
+ this.block = block;
786
+ const selections = this.readSelections();
787
+ if (!selections || !this.updateStaticScopes(descriptor, selections) || !applyStaticRangeBindings(this.block.bindings, this.staticSegments, this.staticValues)) {
788
+ return false;
789
+ }
790
+ for (let index = this.instances.length - 1; index >= 0; index -= 1) {
791
+ if (!this.reconcileRange(index, selections[index])) return false;
792
+ }
793
+ return true;
794
+ }
795
+ cleanup() {
796
+ if (!this.active) return;
797
+ this.active = false;
798
+ this.unsubscribe?.();
799
+ for (const instance of this.instances) instance?.host.scope?.cleanup();
800
+ for (const scope of this.staticScopes) scope.cleanup();
801
+ this.instances.length = 0;
802
+ this.staticSegments.length = 0;
803
+ this.staticScopes.length = 0;
804
+ this.staticValues.length = 0;
805
+ }
806
+ };
807
+ var CompilerNestedKeyedRanges = class {
808
+ constructor(owner, root, host, block, onFallback) {
809
+ this.owner = owner;
810
+ this.root = root;
811
+ this.host = host;
812
+ this.block = block;
813
+ this.onFallback = onFallback;
814
+ this.instances = [];
815
+ this.staticSegments = [];
816
+ this.staticScopes = [];
817
+ this.staticValues = [];
818
+ this.active = true;
819
+ this.refresh = (afterCommit) => {
820
+ if (!this.active) {
821
+ afterCommit?.();
822
+ return;
823
+ }
824
+ const rowsByRange = this.readRanges();
825
+ if (!rowsByRange || rowsByRange.length !== this.instances.length) {
826
+ this.onFallback();
827
+ afterCommit?.();
828
+ return;
829
+ }
830
+ if (!applyStaticRangeBindings(this.block.bindings, this.staticSegments, this.staticValues)) {
831
+ this.onFallback();
832
+ afterCommit?.();
833
+ return;
834
+ }
835
+ const activeElement = this.root.ownerDocument.activeElement;
836
+ const restoreFocus = Boolean(activeElement && this.root.contains(activeElement));
837
+ for (let index = rowsByRange.length - 1; index >= 0; index -= 1) {
838
+ if (!this.reconcileRange(index, rowsByRange[index])) {
839
+ this.onFallback();
840
+ afterCommit?.();
841
+ return;
842
+ }
843
+ }
844
+ if (restoreFocus && activeElement?.isConnected && activeElement.ownerDocument.activeElement !== activeElement && "focus" in activeElement) {
845
+ activeElement.focus({ preventScroll: true });
846
+ }
847
+ afterCommit?.();
848
+ };
849
+ }
850
+ readRange(range) {
851
+ const items = materializeIterable(range.items());
852
+ const keys = items.map((item, index) => keyedRowIdentity(range.rowKey(item, index)));
853
+ return new Set(keys).size === keys.length ? { items, keys } : null;
854
+ }
855
+ readRanges() {
856
+ const ranges = [];
857
+ for (const range of this.block.ranges) {
858
+ const rows = this.readRange(range);
859
+ if (!rows) return null;
860
+ ranges.push(rows);
861
+ }
862
+ return ranges;
863
+ }
864
+ mountStatic(elements, descriptors) {
865
+ if (elements.length !== descriptors.length) return false;
866
+ for (let index = 0; index < elements.length; index += 1) {
867
+ const scope = mountCompilerHostTree(
868
+ this.owner,
869
+ elements[index],
870
+ descriptors[index],
871
+ this.onFallback
872
+ );
873
+ if (!scope) return false;
874
+ this.staticScopes.push(scope);
875
+ }
876
+ return true;
877
+ }
878
+ adopt() {
879
+ if (!Number.isSafeInteger(this.block.trailing) || this.block.trailing < 0) return false;
880
+ const rowsByRange = this.readRanges();
881
+ if (!rowsByRange) return false;
882
+ const elements = [...this.root.children];
883
+ const descriptors = flattenCompilerHostElements(materializeCompilerHostChildren(this.host));
884
+ if (elements.length !== descriptors.length) return false;
885
+ let cursor = 0;
886
+ for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
887
+ const range = this.block.ranges[rangeIndex];
888
+ const rows = rowsByRange[rangeIndex];
889
+ if (!Number.isSafeInteger(range.before) || range.before < 0) {
890
+ this.cleanup();
891
+ return false;
892
+ }
893
+ const staticEnd = cursor + range.before;
894
+ if (staticEnd > elements.length || !this.mountStatic(elements.slice(cursor, staticEnd), descriptors.slice(cursor, staticEnd))) {
895
+ this.cleanup();
896
+ return false;
897
+ }
898
+ this.staticSegments.push(elements.slice(cursor, staticEnd));
899
+ cursor = staticEnd;
900
+ const instances = /* @__PURE__ */ new Map();
901
+ for (let index = 0; index < rows.items.length; index += 1) {
902
+ const element = elements[cursor + index];
903
+ if (!element) {
904
+ this.cleanup();
905
+ return false;
906
+ }
907
+ const descriptor = range.create(rows.items[index], index);
908
+ const scope = mountCompilerHostTree(this.owner, element, descriptor, this.onFallback);
909
+ if (!scope) {
910
+ this.cleanup();
911
+ return false;
912
+ }
913
+ instances.set(rows.keys[index], {
914
+ key: rows.keys[index],
915
+ element,
916
+ scope,
917
+ values: range.bindings.map(() => UNSET_KEYED_ROW_BINDING),
918
+ item: rows.items[index],
919
+ index,
920
+ conditionalValues: /* @__PURE__ */ new Map()
921
+ });
922
+ applyKeyedRowBindings(range, instances.get(rows.keys[index]), rows.items[index], index);
923
+ }
924
+ this.instances.push(instances);
925
+ cursor += rows.items.length;
926
+ }
927
+ const trailingEnd = cursor + this.block.trailing;
928
+ if (trailingEnd !== elements.length || !this.mountStatic(elements.slice(cursor), descriptors.slice(cursor))) {
929
+ this.cleanup();
930
+ return false;
931
+ }
932
+ this.staticSegments.push(elements.slice(cursor));
933
+ if (!applyStaticRangeBindings(this.block.bindings, this.staticSegments, this.staticValues)) {
934
+ this.cleanup();
935
+ return false;
936
+ }
937
+ this.unsubscribe = this.owner.subscribe(this.block.id, this.refresh);
938
+ return true;
939
+ }
940
+ anchorAfter(rangeIndex) {
941
+ for (let next = rangeIndex + 1; next < this.instances.length; next += 1) {
942
+ const staticAnchor = this.staticSegments[next]?.[0];
943
+ if (staticAnchor) return staticAnchor;
944
+ const rowAnchor = this.instances[next].values().next().value?.element;
945
+ if (rowAnchor) return rowAnchor;
946
+ }
947
+ return this.staticSegments[this.instances.length]?.[0] || null;
948
+ }
949
+ reconcileRange(rangeIndex, rows) {
950
+ const range = this.block.ranges[rangeIndex];
951
+ const previous = this.instances[rangeIndex];
952
+ const oldIndices = /* @__PURE__ */ new Map();
953
+ [...previous.keys()].forEach((key, index) => oldIndices.set(key, index));
954
+ const nextKeys = new Set(rows.keys);
955
+ for (const [key, instance] of previous) {
956
+ if (nextKeys.has(key)) continue;
957
+ instance.scope?.cleanup();
958
+ instance.element.remove();
959
+ }
960
+ const sequence = rows.keys.map((key) => oldIndices.get(key) ?? -1);
961
+ const stablePositions = longestIncreasingSubsequencePositions(sequence);
962
+ const nextInstances = [];
963
+ for (let index = 0; index < rows.items.length; index += 1) {
964
+ const key = rows.keys[index];
965
+ const existing = previous.get(key);
966
+ if (existing) {
967
+ const descriptor2 = range.create(rows.items[index], index);
968
+ if (!existing.scope?.update(descriptor2)) return false;
969
+ applyKeyedRowBindings(range, existing, rows.items[index], index);
970
+ existing.item = rows.items[index];
971
+ existing.index = index;
972
+ nextInstances.push(existing);
973
+ continue;
974
+ }
975
+ const descriptor = range.create(rows.items[index], index);
976
+ const element = createCompilerHostElement(this.root.ownerDocument, descriptor);
977
+ const scope = mountCompilerHostTree(this.owner, element, descriptor, this.onFallback);
978
+ if (!scope) return false;
979
+ nextInstances.push({
980
+ key,
981
+ element,
982
+ scope,
983
+ values: readKeyedRowBindingValues(range, rows.items[index], index),
984
+ item: rows.items[index],
985
+ index,
986
+ conditionalValues: /* @__PURE__ */ new Map()
987
+ });
988
+ }
989
+ let anchor = this.anchorAfter(rangeIndex);
990
+ for (let index = nextInstances.length - 1; index >= 0; index -= 1) {
991
+ const instance = nextInstances[index];
992
+ if (sequence[index] < 0 || !stablePositions.has(index) && instance.element.nextSibling !== anchor) {
993
+ this.root.insertBefore(instance.element, anchor);
994
+ }
995
+ anchor = instance.element;
996
+ }
997
+ this.instances[rangeIndex] = new Map(nextInstances.map((instance) => [instance.key, instance]));
998
+ return true;
999
+ }
1000
+ updateStaticScopes(descriptor, rowsByRange) {
1001
+ const descriptors = flattenCompilerHostElements(materializeCompilerHostChildren(descriptor));
1002
+ let descriptorIndex = 0;
1003
+ let scopeIndex = 0;
1004
+ for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
1005
+ const range = this.block.ranges[rangeIndex];
1006
+ for (let index = 0; index < range.before; index += 1) {
1007
+ const scope = this.staticScopes[scopeIndex++];
1008
+ const child = descriptors[descriptorIndex++];
1009
+ if (!scope || !child || !scope.update(child)) return false;
1010
+ }
1011
+ descriptorIndex += rowsByRange[rangeIndex].items.length;
1012
+ }
1013
+ for (let index = 0; index < this.block.trailing; index += 1) {
1014
+ const scope = this.staticScopes[scopeIndex++];
1015
+ const child = descriptors[descriptorIndex++];
1016
+ if (!scope || !child || !scope.update(child)) return false;
1017
+ }
1018
+ return scopeIndex === this.staticScopes.length && descriptorIndex === descriptors.length;
1019
+ }
1020
+ update(descriptor) {
1021
+ const block = descriptor.block;
1022
+ if (!this.active || block?.kind !== "keyed-ranges" || block.id !== this.block.id || block.ranges.length !== this.block.ranges.length || block.trailing !== this.block.trailing || block.ranges.some((range, index) => range.before !== this.block.ranges[index].before)) {
1023
+ return false;
1024
+ }
1025
+ this.host = descriptor;
1026
+ this.block = block;
1027
+ const rowsByRange = this.readRanges();
1028
+ if (!rowsByRange || rowsByRange.length !== this.instances.length || !this.updateStaticScopes(descriptor, rowsByRange) || !applyStaticRangeBindings(this.block.bindings, this.staticSegments, this.staticValues)) {
1029
+ return false;
1030
+ }
1031
+ for (let index = rowsByRange.length - 1; index >= 0; index -= 1) {
1032
+ if (!this.reconcileRange(index, rowsByRange[index])) return false;
1033
+ }
1034
+ return true;
1035
+ }
1036
+ cleanup() {
1037
+ if (!this.active) return;
1038
+ this.active = false;
1039
+ this.unsubscribe?.();
1040
+ for (const instances of this.instances) {
1041
+ for (const instance of instances.values()) instance.scope?.cleanup();
1042
+ }
1043
+ for (const scope of this.staticScopes) scope.cleanup();
1044
+ this.instances.length = 0;
1045
+ this.staticSegments.length = 0;
1046
+ this.staticScopes.length = 0;
1047
+ this.staticValues.length = 0;
1048
+ }
1049
+ };
1050
+ var CompilerNestedMixedRanges = class {
1051
+ constructor(owner, root, host, block, onFallback) {
1052
+ this.owner = owner;
1053
+ this.root = root;
1054
+ this.host = host;
1055
+ this.block = block;
1056
+ this.onFallback = onFallback;
1057
+ this.instances = [];
1058
+ this.staticSegments = [];
1059
+ this.staticScopes = [];
1060
+ this.staticValues = [];
1061
+ this.active = true;
1062
+ this.refresh = (afterCommit) => {
1063
+ if (!this.active) {
1064
+ afterCommit?.();
1065
+ return;
1066
+ }
1067
+ const snapshots = this.readSnapshots();
1068
+ if (!snapshots || snapshots.length !== this.instances.length) {
1069
+ this.onFallback();
1070
+ afterCommit?.();
1071
+ return;
1072
+ }
1073
+ if (!applyStaticRangeBindings(this.block.bindings, this.staticSegments, this.staticValues)) {
1074
+ this.onFallback();
1075
+ afterCommit?.();
1076
+ return;
1077
+ }
1078
+ const activeElement = this.root.ownerDocument.activeElement;
1079
+ const restoreFocus = Boolean(activeElement && this.root.contains(activeElement));
1080
+ for (let index = snapshots.length - 1; index >= 0; index -= 1) {
1081
+ if (!this.reconcileRange(index, snapshots[index])) {
1082
+ this.onFallback();
1083
+ afterCommit?.();
1084
+ return;
1085
+ }
1086
+ }
1087
+ if (restoreFocus && activeElement?.isConnected && activeElement.ownerDocument.activeElement !== activeElement && "focus" in activeElement) {
1088
+ activeElement.focus({ preventScroll: true });
1089
+ }
1090
+ afterCommit?.();
1091
+ };
1092
+ }
1093
+ readSnapshots() {
1094
+ const snapshots = [];
1095
+ for (const range of this.block.ranges) {
1096
+ if (range.kind === "conditional") {
1097
+ const selection = hostConditionalSelection(range);
1098
+ if (selection.kind === "fallback") return null;
1099
+ snapshots.push({ kind: "conditional", selection });
1100
+ continue;
1101
+ }
1102
+ const items = materializeIterable(range.items());
1103
+ const keys = items.map((item, index) => keyedRowIdentity(range.rowKey(item, index)));
1104
+ if (new Set(keys).size !== keys.length) return null;
1105
+ snapshots.push({ kind: "keyed", rows: { items, keys } });
1106
+ }
1107
+ return snapshots;
1108
+ }
1109
+ mountStatic(elements, descriptors) {
1110
+ if (elements.length !== descriptors.length) return false;
1111
+ for (let index = 0; index < elements.length; index += 1) {
1112
+ const scope = mountCompilerHostTree(
1113
+ this.owner,
1114
+ elements[index],
1115
+ descriptors[index],
1116
+ this.onFallback
1117
+ );
1118
+ if (!scope) return false;
1119
+ this.staticScopes.push(scope);
1120
+ }
1121
+ return true;
1122
+ }
1123
+ adopt() {
1124
+ if (!Number.isSafeInteger(this.block.trailing) || this.block.trailing < 0) return false;
1125
+ const snapshots = this.readSnapshots();
1126
+ if (!snapshots) return false;
1127
+ const elements = [...this.root.children];
1128
+ const descriptors = flattenCompilerHostElements(this.host.children);
1129
+ if (elements.length !== descriptors.length) return false;
1130
+ let cursor = 0;
1131
+ for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
1132
+ const range = this.block.ranges[rangeIndex];
1133
+ const snapshot = snapshots[rangeIndex];
1134
+ if (!Number.isSafeInteger(range.before) || range.before < 0 || range.kind !== snapshot.kind) {
1135
+ this.cleanup();
1136
+ return false;
1137
+ }
1138
+ const staticEnd = cursor + range.before;
1139
+ if (staticEnd > elements.length || !this.mountStatic(elements.slice(cursor, staticEnd), descriptors.slice(cursor, staticEnd))) {
1140
+ this.cleanup();
1141
+ return false;
1142
+ }
1143
+ this.staticSegments.push(elements.slice(cursor, staticEnd));
1144
+ cursor = staticEnd;
1145
+ if (range.kind === "conditional" && snapshot.kind === "conditional") {
1146
+ if (snapshot.selection.kind === "empty") {
1147
+ this.instances.push({ kind: "conditional", value: null });
1148
+ continue;
1149
+ }
1150
+ const element = elements[cursor];
1151
+ if (!element) {
1152
+ this.cleanup();
1153
+ return false;
1154
+ }
1155
+ const descriptor = snapshot.selection.branch.create();
1156
+ const host = mountCompilerHostInstance(
1157
+ this.owner,
1158
+ element,
1159
+ descriptor,
1160
+ snapshot.selection.branch,
1161
+ this.onFallback
1162
+ );
1163
+ if (!host) {
1164
+ this.cleanup();
1165
+ return false;
1166
+ }
1167
+ this.instances.push({
1168
+ kind: "conditional",
1169
+ value: { key: snapshot.selection.key, host }
1170
+ });
1171
+ cursor += 1;
1172
+ continue;
1173
+ }
1174
+ if (range.kind !== "keyed" || snapshot.kind !== "keyed") {
1175
+ this.cleanup();
1176
+ return false;
1177
+ }
1178
+ const keyedInstances = /* @__PURE__ */ new Map();
1179
+ for (let index = 0; index < snapshot.rows.items.length; index += 1) {
1180
+ const element = elements[cursor + index];
1181
+ if (!element) {
1182
+ this.cleanup();
1183
+ return false;
1184
+ }
1185
+ const descriptor = range.create(snapshot.rows.items[index], index);
1186
+ const scope = mountCompilerHostTree(this.owner, element, descriptor, this.onFallback);
1187
+ if (!scope) {
1188
+ this.cleanup();
1189
+ return false;
1190
+ }
1191
+ const instance = {
1192
+ key: snapshot.rows.keys[index],
1193
+ element,
1194
+ scope,
1195
+ values: range.bindings.map(() => UNSET_KEYED_ROW_BINDING),
1196
+ item: snapshot.rows.items[index],
1197
+ index,
1198
+ conditionalValues: /* @__PURE__ */ new Map()
1199
+ };
1200
+ try {
1201
+ applyKeyedRowBindings(range, instance, snapshot.rows.items[index], index);
1202
+ } catch (error) {
1203
+ scope.cleanup();
1204
+ throw error;
1205
+ }
1206
+ keyedInstances.set(snapshot.rows.keys[index], instance);
1207
+ }
1208
+ this.instances.push({ kind: "keyed", value: keyedInstances });
1209
+ cursor += snapshot.rows.items.length;
1210
+ }
1211
+ const trailingEnd = cursor + this.block.trailing;
1212
+ if (trailingEnd !== elements.length || !this.mountStatic(elements.slice(cursor), descriptors.slice(cursor))) {
1213
+ this.cleanup();
1214
+ return false;
1215
+ }
1216
+ this.staticSegments.push(elements.slice(cursor));
1217
+ if (!applyStaticRangeBindings(this.block.bindings, this.staticSegments, this.staticValues)) {
1218
+ this.cleanup();
1219
+ return false;
1220
+ }
1221
+ this.unsubscribe = this.owner.subscribe(this.block.id, this.refresh);
1222
+ return true;
1223
+ }
1224
+ firstInstanceElement(instance) {
1225
+ if (instance.kind === "conditional") return instance.value?.host.element || null;
1226
+ return instance.value.values().next().value?.element || null;
1227
+ }
1228
+ anchorAfter(rangeIndex) {
1229
+ for (let next = rangeIndex + 1; next < this.instances.length; next += 1) {
1230
+ const staticAnchor = this.staticSegments[next]?.[0];
1231
+ if (staticAnchor) return staticAnchor;
1232
+ const rangeAnchor = this.firstInstanceElement(this.instances[next]);
1233
+ if (rangeAnchor) return rangeAnchor;
1234
+ }
1235
+ return this.staticSegments[this.instances.length]?.[0] || null;
1236
+ }
1237
+ reconcileConditional(rangeIndex, range, selection) {
1238
+ const instance = this.instances[rangeIndex];
1239
+ if (instance.kind !== "conditional") return false;
1240
+ const previous = instance.value;
1241
+ if (selection.kind === "empty") {
1242
+ previous?.host.scope?.cleanup();
1243
+ previous?.host.element.remove();
1244
+ instance.value = null;
1245
+ return true;
1246
+ }
1247
+ if (previous?.key === selection.key) {
1248
+ const descriptor2 = selection.branch.create();
1249
+ if (!previous.host.scope?.update(descriptor2)) return false;
1250
+ applyHostConditionalBindings(selection.branch, previous.host);
1251
+ return true;
1252
+ }
1253
+ const descriptor = selection.branch.create();
1254
+ const element = createCompilerHostElement(this.root.ownerDocument, descriptor);
1255
+ const host = mountCompilerHostInstance(
1256
+ this.owner,
1257
+ element,
1258
+ descriptor,
1259
+ selection.branch,
1260
+ this.onFallback
1261
+ );
1262
+ if (!host) return false;
1263
+ previous?.host.scope?.cleanup();
1264
+ if (previous) previous.host.element.replaceWith(element);
1265
+ else this.root.insertBefore(element, this.anchorAfter(rangeIndex));
1266
+ instance.value = { key: selection.key, host };
1267
+ return true;
1268
+ }
1269
+ reconcileKeyed(rangeIndex, range, rows) {
1270
+ const instance = this.instances[rangeIndex];
1271
+ if (instance.kind !== "keyed") return false;
1272
+ const previous = instance.value;
1273
+ const oldIndices = /* @__PURE__ */ new Map();
1274
+ [...previous.keys()].forEach((key, index) => oldIndices.set(key, index));
1275
+ const nextKeys = new Set(rows.keys);
1276
+ for (const [key, row] of previous) {
1277
+ if (nextKeys.has(key)) continue;
1278
+ row.scope?.cleanup();
1279
+ row.element.remove();
1280
+ }
1281
+ const sequence = rows.keys.map((key) => oldIndices.get(key) ?? -1);
1282
+ const stablePositions = longestIncreasingSubsequencePositions(sequence);
1283
+ const nextInstances = [];
1284
+ for (let index = 0; index < rows.items.length; index += 1) {
1285
+ const key = rows.keys[index];
1286
+ const existing = previous.get(key);
1287
+ if (existing) {
1288
+ const descriptor2 = range.create(rows.items[index], index);
1289
+ if (!existing.scope?.update(descriptor2)) return false;
1290
+ applyKeyedRowBindings(range, existing, rows.items[index], index);
1291
+ existing.item = rows.items[index];
1292
+ existing.index = index;
1293
+ nextInstances.push(existing);
1294
+ continue;
1295
+ }
1296
+ const descriptor = range.create(rows.items[index], index);
1297
+ const element = createCompilerHostElement(this.root.ownerDocument, descriptor);
1298
+ const scope = mountCompilerHostTree(this.owner, element, descriptor, this.onFallback);
1299
+ if (!scope) return false;
1300
+ let values;
1301
+ try {
1302
+ values = readKeyedRowBindingValues(range, rows.items[index], index);
1303
+ } catch (error) {
1304
+ scope.cleanup();
1305
+ throw error;
1306
+ }
1307
+ nextInstances.push({
1308
+ key,
1309
+ element,
1310
+ scope,
1311
+ values,
1312
+ item: rows.items[index],
1313
+ index,
1314
+ conditionalValues: /* @__PURE__ */ new Map()
1315
+ });
1316
+ }
1317
+ let anchor = this.anchorAfter(rangeIndex);
1318
+ for (let index = nextInstances.length - 1; index >= 0; index -= 1) {
1319
+ const row = nextInstances[index];
1320
+ if (sequence[index] < 0 || !stablePositions.has(index) && row.element.nextSibling !== anchor) {
1321
+ this.root.insertBefore(row.element, anchor);
1322
+ }
1323
+ anchor = row.element;
1324
+ }
1325
+ instance.value = new Map(nextInstances.map((row) => [row.key, row]));
1326
+ return true;
1327
+ }
1328
+ reconcileRange(rangeIndex, snapshot) {
1329
+ const range = this.block.ranges[rangeIndex];
1330
+ if (range.kind !== snapshot.kind) return false;
1331
+ return range.kind === "conditional" && snapshot.kind === "conditional" ? this.reconcileConditional(rangeIndex, range, snapshot.selection) : range.kind === "keyed" && snapshot.kind === "keyed" ? this.reconcileKeyed(rangeIndex, range, snapshot.rows) : false;
1332
+ }
1333
+ updateStaticScopes(descriptor, snapshots) {
1334
+ const descriptors = flattenCompilerHostElements(descriptor.children);
1335
+ let descriptorIndex = 0;
1336
+ let scopeIndex = 0;
1337
+ for (let rangeIndex = 0; rangeIndex < this.block.ranges.length; rangeIndex += 1) {
1338
+ const range = this.block.ranges[rangeIndex];
1339
+ for (let index = 0; index < range.before; index += 1) {
1340
+ const scope = this.staticScopes[scopeIndex++];
1341
+ const child = descriptors[descriptorIndex++];
1342
+ if (!scope || !child || !scope.update(child)) return false;
1343
+ }
1344
+ const snapshot = snapshots[rangeIndex];
1345
+ if (snapshot.kind === "conditional") {
1346
+ if (snapshot.selection.kind === "branch") descriptorIndex += 1;
1347
+ } else {
1348
+ descriptorIndex += snapshot.rows.items.length;
1349
+ }
1350
+ }
1351
+ for (let index = 0; index < this.block.trailing; index += 1) {
1352
+ const scope = this.staticScopes[scopeIndex++];
1353
+ const child = descriptors[descriptorIndex++];
1354
+ if (!scope || !child || !scope.update(child)) return false;
1355
+ }
1356
+ return scopeIndex === this.staticScopes.length && descriptorIndex === descriptors.length;
1357
+ }
1358
+ update(descriptor) {
1359
+ const block = descriptor.block;
1360
+ if (!this.active || block?.kind !== "mixed-ranges" || block.id !== this.block.id || block.ranges.length !== this.block.ranges.length || block.trailing !== this.block.trailing || block.ranges.some(
1361
+ (range, index) => range.kind !== this.block.ranges[index].kind || range.before !== this.block.ranges[index].before
1362
+ )) {
1363
+ return false;
1364
+ }
1365
+ this.host = descriptor;
1366
+ this.block = block;
1367
+ const snapshots = this.readSnapshots();
1368
+ if (!snapshots || snapshots.length !== this.instances.length || !this.updateStaticScopes(descriptor, snapshots) || !applyStaticRangeBindings(this.block.bindings, this.staticSegments, this.staticValues)) {
1369
+ return false;
1370
+ }
1371
+ for (let index = snapshots.length - 1; index >= 0; index -= 1) {
1372
+ if (!this.reconcileRange(index, snapshots[index])) return false;
1373
+ }
1374
+ return true;
1375
+ }
1376
+ cleanup() {
1377
+ if (!this.active) return;
1378
+ this.active = false;
1379
+ this.unsubscribe?.();
1380
+ for (const instance of this.instances) {
1381
+ if (instance.kind === "conditional") {
1382
+ instance.value?.host.scope?.cleanup();
1383
+ } else {
1384
+ for (const row of instance.value.values()) row.scope?.cleanup();
1385
+ }
1386
+ }
1387
+ for (const scope of this.staticScopes) scope.cleanup();
1388
+ this.instances.length = 0;
1389
+ this.staticSegments.length = 0;
1390
+ this.staticScopes.length = 0;
1391
+ this.staticValues.length = 0;
1392
+ }
1393
+ };
378
1394
  function createHostConditionalBlockComponent(owner) {
379
1395
  class FarmHostConditionalBlock extends React.Component {
380
1396
  constructor() {
@@ -386,8 +1402,13 @@ function createHostConditionalBlockComponent(owner) {
386
1402
  this.fallbackVersion = 0;
387
1403
  this.propSyncQueued = false;
388
1404
  this.currentProps = this.props;
1405
+ this.fallbackUnsubscribers = [];
389
1406
  this.activeBranch = null;
390
1407
  this.instance = null;
1408
+ this.requestNestedFallback = () => {
1409
+ this.instance?.scope?.cleanup();
1410
+ this.activateFallback();
1411
+ };
391
1412
  this.captureRoot = (root) => {
392
1413
  this.root = root;
393
1414
  };
@@ -395,6 +1416,26 @@ function createHostConditionalBlockComponent(owner) {
395
1416
  this.reconcile(afterCommit);
396
1417
  };
397
1418
  }
1419
+ subscribeFallbackDescendants() {
1420
+ for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
1421
+ this.fallbackUnsubscribers = [];
1422
+ const ids = /* @__PURE__ */ new Set();
1423
+ if (this.currentProps.truthy) {
1424
+ collectCompilerHostBlockIds(this.currentProps.truthy.create(), ids);
1425
+ }
1426
+ if (this.currentProps.falsy) {
1427
+ collectCompilerHostBlockIds(this.currentProps.falsy.create(), ids);
1428
+ }
1429
+ ids.delete(this.currentProps.id);
1430
+ for (const id of ids) {
1431
+ this.fallbackUnsubscribers.push(
1432
+ owner.subscribe(id, (afterCommit) => {
1433
+ this.fallbackVersion += 1;
1434
+ this.forceUpdate(afterCommit);
1435
+ })
1436
+ );
1437
+ }
1438
+ }
398
1439
  adopt() {
399
1440
  if (!this.root) return false;
400
1441
  const selection = hostConditionalSelection(this.currentProps);
@@ -411,11 +1452,16 @@ function createHostConditionalBlockComponent(owner) {
411
1452
  const descriptor = selection.branch.create();
412
1453
  const element = this.root.firstElementChild;
413
1454
  if (!matchesCompilerHostElement(element, descriptor)) return false;
414
- this.activeBranch = selection.key;
415
- this.instance = {
1455
+ const instance = mountCompilerHostInstance(
1456
+ owner,
416
1457
  element,
417
- values: readHostConditionalBindingValues(selection.branch)
418
- };
1458
+ descriptor,
1459
+ selection.branch,
1460
+ this.requestNestedFallback
1461
+ );
1462
+ if (!instance) return false;
1463
+ this.activeBranch = selection.key;
1464
+ this.instance = instance;
419
1465
  return true;
420
1466
  }
421
1467
  activateFallback(afterCommit) {
@@ -424,6 +1470,10 @@ function createHostConditionalBlockComponent(owner) {
424
1470
  return;
425
1471
  }
426
1472
  this.fallbackRequested = true;
1473
+ this.instance?.scope?.cleanup();
1474
+ this.instance = null;
1475
+ this.activeBranch = null;
1476
+ this.subscribeFallbackDescendants();
427
1477
  this.fallbackVersion += 1;
428
1478
  this.setState({ fallback: true }, afterCommit);
429
1479
  }
@@ -442,6 +1492,7 @@ function createHostConditionalBlockComponent(owner) {
442
1492
  return;
443
1493
  }
444
1494
  if (selection.kind === "empty") {
1495
+ this.instance?.scope?.cleanup();
445
1496
  if (this.instance) this.instance.element.remove();
446
1497
  this.activeBranch = null;
447
1498
  this.instance = null;
@@ -449,17 +1500,40 @@ function createHostConditionalBlockComponent(owner) {
449
1500
  return;
450
1501
  }
451
1502
  if (this.activeBranch === selection.key && this.instance) {
1503
+ const descriptor2 = selection.branch.create();
1504
+ const scope = mountCompilerHostTree(
1505
+ owner,
1506
+ this.instance.element,
1507
+ descriptor2,
1508
+ this.requestNestedFallback
1509
+ );
1510
+ if (!scope) {
1511
+ this.activateFallback(afterCommit);
1512
+ return;
1513
+ }
1514
+ this.instance.scope?.cleanup();
1515
+ this.instance.scope = scope;
452
1516
  applyHostConditionalBindings(selection.branch, this.instance);
453
1517
  afterCommit?.();
454
1518
  return;
455
1519
  }
456
- const element = createCompilerHostElement(this.root.ownerDocument, selection.branch.create());
1520
+ const descriptor = selection.branch.create();
1521
+ const element = createCompilerHostElement(this.root.ownerDocument, descriptor);
1522
+ const instance = mountCompilerHostInstance(
1523
+ owner,
1524
+ element,
1525
+ descriptor,
1526
+ selection.branch,
1527
+ this.requestNestedFallback
1528
+ );
1529
+ if (!instance) {
1530
+ this.activateFallback(afterCommit);
1531
+ return;
1532
+ }
1533
+ this.instance?.scope?.cleanup();
457
1534
  this.root.replaceChildren(element);
458
1535
  this.activeBranch = selection.key;
459
- this.instance = {
460
- element,
461
- values: readHostConditionalBindingValues(selection.branch)
462
- };
1536
+ this.instance = instance;
463
1537
  afterCommit?.();
464
1538
  }
465
1539
  schedulePropSync() {
@@ -484,6 +1558,9 @@ function createHostConditionalBlockComponent(owner) {
484
1558
  componentWillUnmount() {
485
1559
  this.mounted = false;
486
1560
  this.unsubscribe?.();
1561
+ for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
1562
+ this.fallbackUnsubscribers = [];
1563
+ this.instance?.scope?.cleanup();
487
1564
  this.root = null;
488
1565
  this.activeBranch = null;
489
1566
  this.instance = null;
@@ -504,6 +1581,279 @@ function createHostConditionalBlockComponent(owner) {
504
1581
  FarmHostConditionalBlock.displayName = "FarmCompiledHostConditional";
505
1582
  return FarmHostConditionalBlock;
506
1583
  }
1584
+ function createConditionalRangesBlockComponent(owner) {
1585
+ class FarmConditionalRangesBlock extends React.Component {
1586
+ constructor() {
1587
+ super(...arguments);
1588
+ this.state = { fallback: false };
1589
+ this.root = null;
1590
+ this.mounted = false;
1591
+ this.fallbackRequested = false;
1592
+ this.fallbackVersion = 0;
1593
+ this.propFallbackQueued = false;
1594
+ this.currentProps = this.props;
1595
+ this.fallbackUnsubscribers = [];
1596
+ this.rangeInstances = [];
1597
+ this.staticSegments = [];
1598
+ this.staticValues = [];
1599
+ this.requestNestedFallback = () => {
1600
+ for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
1601
+ this.activateFallback();
1602
+ };
1603
+ this.captureRoot = (root) => {
1604
+ this.root = root;
1605
+ this.currentProps.rootRef?.(root);
1606
+ };
1607
+ this.refresh = (afterCommit) => {
1608
+ this.reconcile(afterCommit);
1609
+ };
1610
+ }
1611
+ subscribeFallbackDescendants() {
1612
+ for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
1613
+ this.fallbackUnsubscribers = [];
1614
+ const ids = /* @__PURE__ */ new Set();
1615
+ for (const range of this.currentProps.ranges) {
1616
+ if (range.truthy) collectCompilerHostBlockIds(range.truthy.create(), ids);
1617
+ if (range.falsy) collectCompilerHostBlockIds(range.falsy.create(), ids);
1618
+ }
1619
+ ids.delete(this.currentProps.id);
1620
+ for (const id of ids) {
1621
+ this.fallbackUnsubscribers.push(
1622
+ owner.subscribe(id, (afterCommit) => {
1623
+ this.fallbackVersion += 1;
1624
+ this.forceUpdate(afterCommit);
1625
+ })
1626
+ );
1627
+ }
1628
+ }
1629
+ readSelections(props) {
1630
+ const selections = [];
1631
+ for (const range of props.ranges) {
1632
+ const selection = hostConditionalSelection(range);
1633
+ if (selection.kind === "fallback") return null;
1634
+ selections.push(selection);
1635
+ }
1636
+ return selections;
1637
+ }
1638
+ adopt(props = this.currentProps) {
1639
+ if (!this.root || !Number.isSafeInteger(props.trailing) || props.trailing < 0) return false;
1640
+ const selections = this.readSelections(props);
1641
+ if (!selections) return false;
1642
+ const elements = [...this.root.children];
1643
+ const staticSegments = [];
1644
+ const instances = [];
1645
+ const cleanupInstances = () => {
1646
+ for (const instance of instances) instance?.host.scope?.cleanup();
1647
+ };
1648
+ let cursor = 0;
1649
+ for (let rangeIndex = 0; rangeIndex < props.ranges.length; rangeIndex += 1) {
1650
+ const range = props.ranges[rangeIndex];
1651
+ if (!Number.isSafeInteger(range.before) || range.before < 0) {
1652
+ cleanupInstances();
1653
+ return false;
1654
+ }
1655
+ const staticEnd = cursor + range.before;
1656
+ if (staticEnd > elements.length) {
1657
+ cleanupInstances();
1658
+ return false;
1659
+ }
1660
+ staticSegments.push(elements.slice(cursor, staticEnd));
1661
+ cursor = staticEnd;
1662
+ const selection = selections[rangeIndex];
1663
+ if (selection.kind === "empty") {
1664
+ instances.push(null);
1665
+ continue;
1666
+ }
1667
+ const element = elements[cursor];
1668
+ if (!element) {
1669
+ cleanupInstances();
1670
+ return false;
1671
+ }
1672
+ const descriptor = selection.branch.create();
1673
+ if (!matchesCompilerHostElement(element, descriptor)) {
1674
+ cleanupInstances();
1675
+ return false;
1676
+ }
1677
+ const host = mountCompilerHostInstance(
1678
+ owner,
1679
+ element,
1680
+ descriptor,
1681
+ selection.branch,
1682
+ this.requestNestedFallback
1683
+ );
1684
+ if (!host) {
1685
+ cleanupInstances();
1686
+ return false;
1687
+ }
1688
+ instances.push({
1689
+ key: selection.key,
1690
+ host
1691
+ });
1692
+ cursor += 1;
1693
+ }
1694
+ if (cursor + props.trailing !== elements.length) {
1695
+ cleanupInstances();
1696
+ return false;
1697
+ }
1698
+ staticSegments.push(elements.slice(cursor));
1699
+ this.staticSegments = staticSegments;
1700
+ this.rangeInstances = instances;
1701
+ if (!applyStaticRangeBindings(props.bindings, this.staticSegments, this.staticValues)) {
1702
+ cleanupInstances();
1703
+ this.rangeInstances = [];
1704
+ this.staticSegments = [];
1705
+ return false;
1706
+ }
1707
+ return true;
1708
+ }
1709
+ anchorAfter(rangeIndex) {
1710
+ for (let next = rangeIndex + 1; next < this.rangeInstances.length; next += 1) {
1711
+ const staticAnchor = this.staticSegments[next]?.[0];
1712
+ if (staticAnchor) return staticAnchor;
1713
+ const rangeAnchor = this.rangeInstances[next]?.host.element;
1714
+ if (rangeAnchor) return rangeAnchor;
1715
+ }
1716
+ return this.staticSegments[this.rangeInstances.length]?.[0] || null;
1717
+ }
1718
+ reconcileRange(rangeIndex, selection) {
1719
+ if (!this.root) return false;
1720
+ const previous = this.rangeInstances[rangeIndex];
1721
+ if (selection.kind === "empty") {
1722
+ previous?.host.scope?.cleanup();
1723
+ previous?.host.element.remove();
1724
+ this.rangeInstances[rangeIndex] = null;
1725
+ return true;
1726
+ }
1727
+ if (previous?.key === selection.key) {
1728
+ const descriptor2 = selection.branch.create();
1729
+ const scope = mountCompilerHostTree(
1730
+ owner,
1731
+ previous.host.element,
1732
+ descriptor2,
1733
+ this.requestNestedFallback
1734
+ );
1735
+ if (!scope) {
1736
+ this.requestNestedFallback();
1737
+ return false;
1738
+ }
1739
+ previous.host.scope?.cleanup();
1740
+ previous.host.scope = scope;
1741
+ applyHostConditionalBindings(selection.branch, previous.host);
1742
+ return true;
1743
+ }
1744
+ const descriptor = selection.branch.create();
1745
+ const element = createCompilerHostElement(this.root.ownerDocument, descriptor);
1746
+ const host = mountCompilerHostInstance(
1747
+ owner,
1748
+ element,
1749
+ descriptor,
1750
+ selection.branch,
1751
+ this.requestNestedFallback
1752
+ );
1753
+ if (!host) {
1754
+ this.requestNestedFallback();
1755
+ return false;
1756
+ }
1757
+ previous?.host.scope?.cleanup();
1758
+ if (previous) previous.host.element.replaceWith(element);
1759
+ else this.root.insertBefore(element, this.anchorAfter(rangeIndex));
1760
+ this.rangeInstances[rangeIndex] = {
1761
+ key: selection.key,
1762
+ host
1763
+ };
1764
+ return true;
1765
+ }
1766
+ reconcile(afterCommit) {
1767
+ if (!this.mounted || !this.root) {
1768
+ afterCommit?.();
1769
+ return;
1770
+ }
1771
+ if (this.state.fallback) {
1772
+ this.fallbackVersion += 1;
1773
+ this.forceUpdate(afterCommit);
1774
+ return;
1775
+ }
1776
+ if (this.currentProps.ranges.length !== this.rangeInstances.length) {
1777
+ this.activateFallback(afterCommit);
1778
+ return;
1779
+ }
1780
+ const selections = this.readSelections(this.currentProps);
1781
+ if (!selections) {
1782
+ this.activateFallback(afterCommit);
1783
+ return;
1784
+ }
1785
+ if (!applyStaticRangeBindings(
1786
+ this.currentProps.bindings,
1787
+ this.staticSegments,
1788
+ this.staticValues
1789
+ )) {
1790
+ this.activateFallback(afterCommit);
1791
+ return;
1792
+ }
1793
+ for (let rangeIndex = this.rangeInstances.length - 1; rangeIndex >= 0; rangeIndex -= 1) {
1794
+ if (!this.reconcileRange(rangeIndex, selections[rangeIndex])) {
1795
+ afterCommit?.();
1796
+ return;
1797
+ }
1798
+ }
1799
+ afterCommit?.();
1800
+ }
1801
+ activateFallback(afterCommit) {
1802
+ if (!this.mounted || this.state.fallback || this.fallbackRequested) {
1803
+ afterCommit?.();
1804
+ return;
1805
+ }
1806
+ this.fallbackRequested = true;
1807
+ for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
1808
+ this.subscribeFallbackDescendants();
1809
+ this.setState({ fallback: true }, afterCommit);
1810
+ }
1811
+ schedulePropFallback() {
1812
+ if (this.propFallbackQueued) return;
1813
+ this.propFallbackQueued = true;
1814
+ queueMicrotask(() => {
1815
+ this.propFallbackQueued = false;
1816
+ if (this.mounted && !this.state.fallback) this.activateFallback();
1817
+ });
1818
+ }
1819
+ shouldComponentUpdate(nextProps, nextState) {
1820
+ this.currentProps = nextProps;
1821
+ if (nextState.fallback || this.state.fallback) return true;
1822
+ this.schedulePropFallback();
1823
+ return false;
1824
+ }
1825
+ componentDidMount() {
1826
+ this.mounted = true;
1827
+ this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
1828
+ if (!this.adopt()) this.activateFallback();
1829
+ }
1830
+ componentWillUnmount() {
1831
+ this.mounted = false;
1832
+ this.unsubscribe?.();
1833
+ for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
1834
+ this.fallbackUnsubscribers = [];
1835
+ for (const instance of this.rangeInstances) instance?.host.scope?.cleanup();
1836
+ this.root = null;
1837
+ this.rangeInstances = [];
1838
+ this.staticSegments = [];
1839
+ this.staticValues.length = 0;
1840
+ }
1841
+ render() {
1842
+ const container = this.currentProps.render();
1843
+ if (!React.isValidElement(container) || typeof container.type !== "string") {
1844
+ throw new TypeError(
1845
+ `Compiled conditional ranges ${this.currentProps.id} must own one host container.`
1846
+ );
1847
+ }
1848
+ return React.cloneElement(container, {
1849
+ key: this.state.fallback ? `react-${this.fallbackVersion}` : "compiled",
1850
+ ref: this.captureRoot
1851
+ });
1852
+ }
1853
+ }
1854
+ FarmConditionalRangesBlock.displayName = "FarmCompiledConditionalRanges";
1855
+ return FarmConditionalRangesBlock;
1856
+ }
507
1857
  function longestIncreasingSubsequencePositions(sequence) {
508
1858
  const tails = [];
509
1859
  const previous = Array.from({ length: sequence.length }, () => -1);
@@ -528,6 +1878,10 @@ function longestIncreasingSubsequencePositions(sequence) {
528
1878
  return positions;
529
1879
  }
530
1880
  function createKeyedRowsBlockComponent(owner) {
1881
+ const rowHostScopeOwner = {
1882
+ subscribe: () => () => {
1883
+ }
1884
+ };
531
1885
  class FarmKeyedRowConditional extends React.Component {
532
1886
  constructor() {
533
1887
  super(...arguments);
@@ -584,16 +1938,23 @@ function createKeyedRowsBlockComponent(owner) {
584
1938
  this.renderVersion = 0;
585
1939
  this.eventHandlers = /* @__PURE__ */ new Map();
586
1940
  this.conditionalListeners = /* @__PURE__ */ new Map();
1941
+ this.instancesByElement = /* @__PURE__ */ new WeakMap();
587
1942
  this.conditionalOwner = {
588
1943
  subscribe: (key, id, refresh) => this.subscribeToRowConditional(key, id, refresh)
589
1944
  };
590
1945
  this.captureRoot = (root) => {
591
1946
  this.root = root;
592
1947
  };
1948
+ this.requestHostScopeFallback = () => {
1949
+ this.activateFallback();
1950
+ };
593
1951
  this.rowEvent = (item, index, eventId) => {
594
1952
  if (this.state.fallback) {
595
1953
  return (event) => this.currentProps.events?.[eventId]?.invoke(item, index, event);
596
1954
  }
1955
+ if (this.usesDelegatedEvents()) {
1956
+ return void 0;
1957
+ }
597
1958
  const key = keyedRowIdentity(this.currentProps.rowKey(item, index));
598
1959
  let handlers = this.eventHandlers.get(key);
599
1960
  if (!handlers) {
@@ -611,6 +1972,26 @@ function createKeyedRowsBlockComponent(owner) {
611
1972
  handlers.set(eventId, handler);
612
1973
  return handler;
613
1974
  };
1975
+ this.dispatchDelegatedEvent = (name, event) => {
1976
+ const instance = this.eventRowInstance(event);
1977
+ const eventTarget = event.target;
1978
+ if (!instance || !eventTarget) return;
1979
+ const capture = name.endsWith("Capture");
1980
+ const matches = (this.currentProps.events || []).filter((descriptor) => descriptor.name === name && descriptor.path !== void 0).map((descriptor) => ({
1981
+ descriptor,
1982
+ target: findCompilerHostTarget(instance.element, descriptor.path || [])
1983
+ })).filter(
1984
+ (match) => Boolean(
1985
+ match.target && (match.target === eventTarget || match.target.contains(eventTarget))
1986
+ )
1987
+ ).sort(
1988
+ (left, right) => capture ? (left.descriptor.path?.length || 0) - (right.descriptor.path?.length || 0) : (right.descriptor.path?.length || 0) - (left.descriptor.path?.length || 0)
1989
+ );
1990
+ for (const match of matches) {
1991
+ this.invokeDelegatedEvent(match.descriptor, instance, event, match.target);
1992
+ if (event.isPropagationStopped()) break;
1993
+ }
1994
+ };
614
1995
  this.rowConditional = (item, index, conditionalId, render) => {
615
1996
  if (this.state.fallback) return render(item, index);
616
1997
  const key = keyedRowIdentity(this.currentProps.rowKey(item, index));
@@ -625,17 +2006,65 @@ function createKeyedRowsBlockComponent(owner) {
625
2006
  render
626
2007
  });
627
2008
  };
628
- this.refresh = (afterCommit) => {
2009
+ this.refresh = (afterCommit, dirtyState) => {
2010
+ if (dirtyState && this.refreshDirtyBindings(dirtyState, afterCommit)) return;
629
2011
  this.reconcile(afterCommit);
630
2012
  };
631
2013
  }
632
2014
  readRows(props) {
633
- const source = props.items();
634
- const items = source ? Array.from(source) : [];
2015
+ const items = materializeIterable(props.items());
635
2016
  const keys = items.map((item, index) => keyedRowIdentity(props.rowKey(item, index)));
636
2017
  if (new Set(keys).size !== keys.length) return null;
637
2018
  return { items, keys };
638
2019
  }
2020
+ usesDelegatedEvents(props = this.currentProps) {
2021
+ return Boolean(
2022
+ props.delegateEvents && props.events?.length && props.events.every((event) => event.path !== void 0)
2023
+ );
2024
+ }
2025
+ rebuildElementIndex(instances) {
2026
+ this.instancesByElement = /* @__PURE__ */ new WeakMap();
2027
+ for (const instance of instances.values()) {
2028
+ this.instancesByElement.set(instance.element, instance);
2029
+ }
2030
+ }
2031
+ eventRowInstance(event) {
2032
+ if (!this.root) return void 0;
2033
+ const target = event.target;
2034
+ if (!target) return void 0;
2035
+ let element = target.nodeType === 1 ? target : target.parentElement;
2036
+ while (element && element.parentElement !== this.root) element = element.parentElement;
2037
+ return element?.parentElement === this.root ? this.instancesByElement.get(element) : void 0;
2038
+ }
2039
+ invokeDelegatedEvent(descriptor, instance, event, currentTarget) {
2040
+ const ownCurrentTarget = Object.getOwnPropertyDescriptor(event, "currentTarget");
2041
+ try {
2042
+ Object.defineProperty(event, "currentTarget", {
2043
+ configurable: true,
2044
+ value: currentTarget
2045
+ });
2046
+ descriptor.invoke(instance.item, instance.index, event);
2047
+ } finally {
2048
+ if (ownCurrentTarget) Object.defineProperty(event, "currentTarget", ownCurrentTarget);
2049
+ else Reflect.deleteProperty(event, "currentTarget");
2050
+ }
2051
+ }
2052
+ delegatedContainerProps(container) {
2053
+ if (this.state.fallback || !this.usesDelegatedEvents()) return {};
2054
+ const props = container.props;
2055
+ return Object.fromEntries(
2056
+ [...new Set((this.currentProps.events || []).map((event) => event.name))].map((name) => {
2057
+ const existing = props[name];
2058
+ const capture = name.endsWith("Capture");
2059
+ const handler = (event) => {
2060
+ if (capture) existing?.(event);
2061
+ if (!event.isPropagationStopped()) this.dispatchDelegatedEvent(name, event);
2062
+ if (!capture && !event.isPropagationStopped()) existing?.(event);
2063
+ };
2064
+ return [name, handler];
2065
+ })
2066
+ );
2067
+ }
639
2068
  subscribeToRowConditional(key, id, refresh) {
640
2069
  let listeners = this.conditionalListeners.get(key);
641
2070
  if (!listeners) {
@@ -651,7 +2080,21 @@ function createKeyedRowsBlockComponent(owner) {
651
2080
  };
652
2081
  }
653
2082
  hasReactOwnedRows(props = this.currentProps) {
654
- return Boolean(props.events?.length || props.conditionals?.length);
2083
+ return Boolean(
2084
+ props.conditionals?.length || props.events?.length && !this.usesDelegatedEvents(props)
2085
+ );
2086
+ }
2087
+ cleanupHostScopes(instances = this.instances) {
2088
+ for (const instance of instances.values()) instance.scope?.cleanup();
2089
+ }
2090
+ mountRowHostScope(element, descriptor, props = this.currentProps) {
2091
+ if (!props.hostBlocks) return void 0;
2092
+ return mountCompilerHostTree(
2093
+ rowHostScopeOwner,
2094
+ element,
2095
+ descriptor,
2096
+ this.requestHostScopeFallback
2097
+ );
655
2098
  }
656
2099
  pruneEventHandlers(keys) {
657
2100
  const active = new Set(keys);
@@ -675,16 +2118,20 @@ function createKeyedRowsBlockComponent(owner) {
675
2118
  );
676
2119
  const instances = /* @__PURE__ */ new Map();
677
2120
  for (let index = 0; index < rows.items.length; index += 1) {
678
- if (this.hasReactOwnedRows() && !matchesCompilerHostElement(
679
- elements[index],
680
- this.currentProps.create(rows.items[index], index),
681
- opaqueConditionalPaths
682
- )) {
2121
+ const descriptor = this.currentProps.create(rows.items[index], index);
2122
+ if (this.hasReactOwnedRows() && !matchesCompilerHostElement(elements[index], descriptor, opaqueConditionalPaths)) {
2123
+ this.cleanupHostScopes(instances);
2124
+ return false;
2125
+ }
2126
+ const scope = this.mountRowHostScope(elements[index], descriptor);
2127
+ if (this.currentProps.hostBlocks && !scope) {
2128
+ this.cleanupHostScopes(instances);
683
2129
  return false;
684
2130
  }
685
2131
  const instance = {
686
2132
  key: rows.keys[index],
687
2133
  element: elements[index],
2134
+ scope: scope || void 0,
688
2135
  values: this.hasReactOwnedRows() ? this.currentProps.bindings.map(() => UNSET_KEYED_ROW_BINDING) : readKeyedRowBindingValues(this.currentProps, rows.items[index], index),
689
2136
  item: rows.items[index],
690
2137
  index,
@@ -699,7 +2146,9 @@ function createKeyedRowsBlockComponent(owner) {
699
2146
  }
700
2147
  instances.set(rows.keys[index], instance);
701
2148
  }
2149
+ this.cleanupHostScopes();
702
2150
  this.instances = instances;
2151
+ this.rebuildElementIndex(instances);
703
2152
  this.pruneEventHandlers(rows.keys);
704
2153
  this.pruneConditionalListeners(rows.keys);
705
2154
  return true;
@@ -718,6 +2167,7 @@ function createKeyedRowsBlockComponent(owner) {
718
2167
  }
719
2168
  this.fallbackRequested = true;
720
2169
  this.fallbackKeysWereUnsafe = this.hasUnsafeFallbackKeys();
2170
+ this.cleanupHostScopes();
721
2171
  this.fallbackVersion += 1;
722
2172
  this.setState({ fallback: true }, afterCommit);
723
2173
  }
@@ -752,6 +2202,116 @@ function createKeyedRowsBlockComponent(owner) {
752
2202
  }
753
2203
  });
754
2204
  }
2205
+ refreshDirtyBindings(dirtyState, afterCommit) {
2206
+ if (!this.mounted || !this.root || this.state.fallback || this.hasReactOwnedRows() || this.currentProps.hostBlocks || !this.currentProps.structureDependencies || this.currentProps.structureDependencies.some((dependency) => dirtyState.has(dependency)) || this.currentProps.bindings.some((binding) => binding.dependencies === void 0)) {
2207
+ return false;
2208
+ }
2209
+ const affectedBindingIndices = [];
2210
+ for (let bindingIndex = 0; bindingIndex < this.currentProps.bindings.length; bindingIndex += 1) {
2211
+ const dependencies = this.currentProps.bindings[bindingIndex].dependencies || [];
2212
+ if (dependencies.some((dependency) => dirtyState.has(dependency))) {
2213
+ affectedBindingIndices.push(bindingIndex);
2214
+ }
2215
+ }
2216
+ for (const instance of this.instances.values()) {
2217
+ for (const bindingIndex of affectedBindingIndices) {
2218
+ applyKeyedRowBinding(
2219
+ this.currentProps,
2220
+ instance,
2221
+ instance.item,
2222
+ instance.index,
2223
+ bindingIndex
2224
+ );
2225
+ }
2226
+ }
2227
+ afterCommit?.();
2228
+ return true;
2229
+ }
2230
+ reconcileStableRows(rows, afterCommit) {
2231
+ if (rows.keys.length !== this.instances.size) return false;
2232
+ let index = 0;
2233
+ for (const key of this.instances.keys()) {
2234
+ if (rows.keys[index] !== key) return false;
2235
+ index += 1;
2236
+ }
2237
+ const conditionalChanges = [];
2238
+ for (index = 0; index < rows.items.length; index += 1) {
2239
+ const key = rows.keys[index];
2240
+ const existing = this.instances.get(key);
2241
+ if (!existing) return false;
2242
+ if (this.currentProps.hostBlocks) {
2243
+ const descriptor = this.currentProps.create(rows.items[index], index);
2244
+ if (!existing.scope?.update(descriptor)) {
2245
+ this.activateFallback(afterCommit);
2246
+ return true;
2247
+ }
2248
+ }
2249
+ applyKeyedRowBindings(this.currentProps, existing, rows.items[index], index);
2250
+ const conditionalValues = readKeyedRowConditionalValues(
2251
+ this.currentProps,
2252
+ rows.items[index],
2253
+ index
2254
+ );
2255
+ for (const [id, values] of conditionalValues) {
2256
+ if (keyedRowConditionalChanged(existing.conditionalValues.get(id), values)) {
2257
+ conditionalChanges.push({ key, id, item: rows.items[index], index });
2258
+ }
2259
+ }
2260
+ existing.conditionalValues = conditionalValues;
2261
+ existing.item = rows.items[index];
2262
+ existing.index = index;
2263
+ }
2264
+ this.notifyConditionalChanges(conditionalChanges, afterCommit);
2265
+ return true;
2266
+ }
2267
+ reconcileSingleRemoval(rows, afterCommit) {
2268
+ if (this.hasReactOwnedRows() || rows.keys.length + 1 !== this.instances.size) return false;
2269
+ const previousKeys = [...this.instances.keys()];
2270
+ let removedIndex = 0;
2271
+ while (removedIndex < rows.keys.length && previousKeys[removedIndex] === rows.keys[removedIndex]) {
2272
+ removedIndex += 1;
2273
+ }
2274
+ for (let index = removedIndex; index < rows.keys.length; index += 1) {
2275
+ if (previousKeys[index + 1] !== rows.keys[index]) return false;
2276
+ }
2277
+ const removedKey = previousKeys[removedIndex];
2278
+ const removed = this.instances.get(removedKey);
2279
+ if (!removed) return false;
2280
+ const conditionalChanges = [];
2281
+ for (let index = 0; index < rows.items.length; index += 1) {
2282
+ const key = rows.keys[index];
2283
+ const existing = this.instances.get(key);
2284
+ if (!existing) return false;
2285
+ if (this.currentProps.hostBlocks) {
2286
+ const descriptor = this.currentProps.create(rows.items[index], index);
2287
+ if (!existing.scope?.update(descriptor)) {
2288
+ this.activateFallback(afterCommit);
2289
+ return true;
2290
+ }
2291
+ }
2292
+ applyKeyedRowBindings(this.currentProps, existing, rows.items[index], index);
2293
+ const conditionalValues = readKeyedRowConditionalValues(
2294
+ this.currentProps,
2295
+ rows.items[index],
2296
+ index
2297
+ );
2298
+ for (const [id, values] of conditionalValues) {
2299
+ if (keyedRowConditionalChanged(existing.conditionalValues.get(id), values)) {
2300
+ conditionalChanges.push({ key, id, item: rows.items[index], index });
2301
+ }
2302
+ }
2303
+ existing.conditionalValues = conditionalValues;
2304
+ existing.item = rows.items[index];
2305
+ existing.index = index;
2306
+ }
2307
+ removed.scope?.cleanup();
2308
+ removed.element.remove();
2309
+ this.instances.delete(removedKey);
2310
+ this.eventHandlers.delete(removedKey);
2311
+ this.conditionalListeners.delete(removedKey);
2312
+ this.notifyConditionalChanges(conditionalChanges, afterCommit);
2313
+ return true;
2314
+ }
755
2315
  reconcile(afterCommit) {
756
2316
  if (!this.mounted || !this.root) {
757
2317
  afterCommit?.();
@@ -771,27 +2331,54 @@ function createKeyedRowsBlockComponent(owner) {
771
2331
  this.activateFallback(afterCommit);
772
2332
  return;
773
2333
  }
774
- const previousKeys = [...this.instances.keys()];
775
- if (this.hasReactOwnedRows() && (rows.keys.length !== previousKeys.length || rows.keys.some((key, index) => key !== previousKeys[index]))) {
776
- this.synchronizeReactOwnedRows(afterCommit);
2334
+ if (this.hasReactOwnedRows()) {
2335
+ const previousKeys = [...this.instances.keys()];
2336
+ if (rows.keys.length !== previousKeys.length || rows.keys.some((key, index) => key !== previousKeys[index])) {
2337
+ this.synchronizeReactOwnedRows(afterCommit);
2338
+ return;
2339
+ }
2340
+ }
2341
+ if (rows.items.length === 0) {
2342
+ this.cleanupHostScopes();
2343
+ this.root.replaceChildren();
2344
+ this.instances = /* @__PURE__ */ new Map();
2345
+ this.instancesByElement = /* @__PURE__ */ new WeakMap();
2346
+ this.eventHandlers.clear();
2347
+ this.conditionalListeners.clear();
2348
+ afterCommit?.();
777
2349
  return;
778
2350
  }
779
- const oldIndices = /* @__PURE__ */ new Map();
2351
+ if (this.reconcileStableRows(rows, afterCommit)) return;
2352
+ if (this.reconcileSingleRemoval(rows, afterCommit)) return;
780
2353
  const activeElement = this.root.ownerDocument.activeElement;
781
2354
  const restoreFocus = Boolean(activeElement && this.root.contains(activeElement));
782
- [...this.instances].forEach(([key], index) => oldIndices.set(key, index));
783
2355
  const nextKeys = new Set(rows.keys);
2356
+ const hasSurvivingRows = rows.keys.some((key) => this.instances.has(key));
2357
+ const oldIndices = /* @__PURE__ */ new Map();
2358
+ if (hasSurvivingRows) {
2359
+ [...this.instances].forEach(([key], index) => oldIndices.set(key, index));
2360
+ }
784
2361
  for (const [key, instance] of this.instances) {
785
- if (!nextKeys.has(key)) instance.element.remove();
2362
+ if (!nextKeys.has(key)) {
2363
+ instance.scope?.cleanup();
2364
+ if (hasSurvivingRows) instance.element.remove();
2365
+ }
786
2366
  }
787
- const sequence = rows.keys.map((key) => oldIndices.get(key) ?? -1);
788
- const stablePositions = longestIncreasingSubsequencePositions(sequence);
2367
+ const sequence = hasSurvivingRows ? rows.keys.map((key) => oldIndices.get(key) ?? -1) : rows.keys.map(() => -1);
2368
+ const stablePositions = hasSurvivingRows ? longestIncreasingSubsequencePositions(sequence) : /* @__PURE__ */ new Set();
789
2369
  const nextInstances = [];
790
2370
  const conditionalChanges = [];
791
2371
  for (let index = 0; index < rows.items.length; index += 1) {
792
2372
  const key = rows.keys[index];
793
2373
  const existing = this.instances.get(key);
794
2374
  if (existing) {
2375
+ if (this.currentProps.hostBlocks) {
2376
+ const descriptor2 = this.currentProps.create(rows.items[index], index);
2377
+ if (!existing.scope?.update(descriptor2)) {
2378
+ this.activateFallback(afterCommit);
2379
+ return;
2380
+ }
2381
+ }
795
2382
  applyKeyedRowBindings(this.currentProps, existing, rows.items[index], index);
796
2383
  const conditionalValues = readKeyedRowConditionalValues(
797
2384
  this.currentProps,
@@ -809,13 +2396,20 @@ function createKeyedRowsBlockComponent(owner) {
809
2396
  nextInstances.push(existing);
810
2397
  continue;
811
2398
  }
812
- const element = createCompilerHostElement(
813
- this.root.ownerDocument,
814
- this.currentProps.create(rows.items[index], index)
815
- );
2399
+ const descriptor = this.currentProps.create(rows.items[index], index);
2400
+ const element = createCompilerHostElement(this.root.ownerDocument, descriptor);
2401
+ const scope = this.mountRowHostScope(element, descriptor);
2402
+ if (this.currentProps.hostBlocks && !scope) {
2403
+ for (const instance of nextInstances) {
2404
+ if (!this.instances.has(instance.key)) instance.scope?.cleanup();
2405
+ }
2406
+ this.activateFallback(afterCommit);
2407
+ return;
2408
+ }
816
2409
  nextInstances.push({
817
2410
  key,
818
2411
  element,
2412
+ scope: scope || void 0,
819
2413
  values: readKeyedRowBindingValues(this.currentProps, rows.items[index], index),
820
2414
  item: rows.items[index],
821
2415
  index,
@@ -826,17 +2420,34 @@ function createKeyedRowsBlockComponent(owner) {
826
2420
  )
827
2421
  });
828
2422
  }
829
- let anchor = null;
830
- for (let index = nextInstances.length - 1; index >= 0; index -= 1) {
831
- const instance = nextInstances[index];
832
- if (sequence[index] < 0) {
833
- this.root.insertBefore(instance.element, anchor);
834
- } else if (!stablePositions.has(index) && instance.element.nextSibling !== anchor) {
835
- this.root.insertBefore(instance.element, anchor);
2423
+ if (!hasSurvivingRows) {
2424
+ const fragment = this.root.ownerDocument.createDocumentFragment();
2425
+ for (const instance of nextInstances) fragment.append(instance.element);
2426
+ this.root.replaceChildren(fragment);
2427
+ } else {
2428
+ let anchor = null;
2429
+ for (let index = nextInstances.length - 1; index >= 0; index -= 1) {
2430
+ const instance = nextInstances[index];
2431
+ if (sequence[index] < 0) {
2432
+ let start = index;
2433
+ while (start > 0 && sequence[start - 1] < 0) start -= 1;
2434
+ const fragment = this.root.ownerDocument.createDocumentFragment();
2435
+ for (let itemIndex = start; itemIndex <= index; itemIndex += 1) {
2436
+ fragment.append(nextInstances[itemIndex].element);
2437
+ }
2438
+ this.root.insertBefore(fragment, anchor);
2439
+ anchor = nextInstances[start].element;
2440
+ index = start;
2441
+ } else {
2442
+ if (!stablePositions.has(index) && instance.element.nextSibling !== anchor) {
2443
+ this.root.insertBefore(instance.element, anchor);
2444
+ }
2445
+ anchor = instance.element;
2446
+ }
836
2447
  }
837
- anchor = instance.element;
838
2448
  }
839
2449
  this.instances = new Map(nextInstances.map((instance) => [instance.key, instance]));
2450
+ this.rebuildElementIndex(this.instances);
840
2451
  this.pruneEventHandlers(rows.keys);
841
2452
  this.pruneConditionalListeners(rows.keys);
842
2453
  if (restoreFocus && activeElement?.isConnected && activeElement.ownerDocument.activeElement !== activeElement && "focus" in activeElement) {
@@ -879,7 +2490,9 @@ function createKeyedRowsBlockComponent(owner) {
879
2490
  this.mounted = false;
880
2491
  this.unsubscribe?.();
881
2492
  this.root = null;
2493
+ this.cleanupHostScopes();
882
2494
  this.instances.clear();
2495
+ this.instancesByElement = /* @__PURE__ */ new WeakMap();
883
2496
  this.eventHandlers.clear();
884
2497
  this.conditionalListeners.clear();
885
2498
  }
@@ -892,6 +2505,7 @@ function createKeyedRowsBlockComponent(owner) {
892
2505
  );
893
2506
  }
894
2507
  return React.cloneElement(container, {
2508
+ ...this.delegatedContainerProps(container),
895
2509
  key: this.state.fallback ? `react-${this.fallbackVersion}` : "compiled",
896
2510
  ref: this.captureRoot
897
2511
  });
@@ -913,6 +2527,7 @@ function createKeyedRangesBlockComponent(owner) {
913
2527
  this.currentProps = this.props;
914
2528
  this.rangeInstances = [];
915
2529
  this.staticSegments = [];
2530
+ this.staticValues = [];
916
2531
  this.captureRoot = (root) => {
917
2532
  this.root = root;
918
2533
  this.currentProps.rootRef?.(root);
@@ -922,8 +2537,7 @@ function createKeyedRangesBlockComponent(owner) {
922
2537
  };
923
2538
  }
924
2539
  readRange(range) {
925
- const source = range.items();
926
- const items = source ? Array.from(source) : [];
2540
+ const items = materializeIterable(range.items());
927
2541
  const keys = items.map((item, index) => keyedRowIdentity(range.rowKey(item, index)));
928
2542
  if (new Set(keys).size !== keys.length) return null;
929
2543
  return { items, keys };
@@ -977,6 +2591,11 @@ function createKeyedRangesBlockComponent(owner) {
977
2591
  staticSegments.push(elements.slice(cursor));
978
2592
  this.staticSegments = staticSegments;
979
2593
  this.rangeInstances = instancesByRange;
2594
+ if (!applyStaticRangeBindings(props.bindings, this.staticSegments, this.staticValues)) {
2595
+ this.rangeInstances = [];
2596
+ this.staticSegments = [];
2597
+ return false;
2598
+ }
980
2599
  return true;
981
2600
  }
982
2601
  anchorAfter(rangeIndex) {
@@ -1053,6 +2672,14 @@ function createKeyedRangesBlockComponent(owner) {
1053
2672
  this.activateFallback(afterCommit);
1054
2673
  return;
1055
2674
  }
2675
+ if (!applyStaticRangeBindings(
2676
+ this.currentProps.bindings,
2677
+ this.staticSegments,
2678
+ this.staticValues
2679
+ )) {
2680
+ this.activateFallback(afterCommit);
2681
+ return;
2682
+ }
1056
2683
  const activeElement = this.root.ownerDocument.activeElement;
1057
2684
  const restoreFocus = Boolean(activeElement && this.root.contains(activeElement));
1058
2685
  for (let rangeIndex = rowsByRange.length - 1; rangeIndex >= 0; rangeIndex -= 1) {
@@ -1096,6 +2723,7 @@ function createKeyedRangesBlockComponent(owner) {
1096
2723
  this.root = null;
1097
2724
  this.rangeInstances = [];
1098
2725
  this.staticSegments = [];
2726
+ this.staticValues.length = 0;
1099
2727
  }
1100
2728
  render() {
1101
2729
  const container = this.currentProps.render();
@@ -1113,6 +2741,128 @@ function createKeyedRangesBlockComponent(owner) {
1113
2741
  FarmKeyedRangesBlock.displayName = "FarmCompiledKeyedRanges";
1114
2742
  return FarmKeyedRangesBlock;
1115
2743
  }
2744
+ function createMixedRangesBlockComponent(owner) {
2745
+ class FarmMixedRangesBlock extends React.Component {
2746
+ constructor() {
2747
+ super(...arguments);
2748
+ this.state = { fallback: false };
2749
+ this.root = null;
2750
+ this.mounted = false;
2751
+ this.fallbackRequested = false;
2752
+ this.fallbackVersion = 0;
2753
+ this.propFallbackQueued = false;
2754
+ this.currentProps = this.props;
2755
+ this.controller = null;
2756
+ this.fallbackUnsubscribers = [];
2757
+ this.captureRoot = (root) => {
2758
+ this.root = root;
2759
+ this.currentProps.rootRef?.(root);
2760
+ };
2761
+ this.activateFallback = (afterCommit) => {
2762
+ if (!this.mounted || this.state.fallback || this.fallbackRequested) {
2763
+ afterCommit?.();
2764
+ return;
2765
+ }
2766
+ this.fallbackRequested = true;
2767
+ this.controller?.cleanup();
2768
+ this.controller = null;
2769
+ this.fallbackVersion += 1;
2770
+ this.setState({ fallback: true }, () => {
2771
+ this.subscribeFallbackBlocks();
2772
+ afterCommit?.();
2773
+ });
2774
+ };
2775
+ }
2776
+ clearFallbackSubscriptions() {
2777
+ for (const unsubscribe of this.fallbackUnsubscribers) unsubscribe();
2778
+ this.fallbackUnsubscribers = [];
2779
+ }
2780
+ subscribeFallbackBlocks() {
2781
+ this.clearFallbackSubscriptions();
2782
+ const descriptor = this.currentProps.create();
2783
+ const ids = /* @__PURE__ */ new Set();
2784
+ collectCompilerHostBlockIds(descriptor, ids);
2785
+ for (const id of ids) {
2786
+ this.fallbackUnsubscribers.push(
2787
+ owner.subscribe(id, (afterCommit) => {
2788
+ if (!this.mounted || !this.state.fallback) {
2789
+ afterCommit?.();
2790
+ return;
2791
+ }
2792
+ this.fallbackVersion += 1;
2793
+ this.forceUpdate(afterCommit);
2794
+ })
2795
+ );
2796
+ }
2797
+ }
2798
+ adopt() {
2799
+ if (!this.root) return false;
2800
+ const descriptor = this.currentProps.create();
2801
+ const block = descriptor.block;
2802
+ if (block?.kind !== "mixed-ranges" || block.id !== this.currentProps.id) return false;
2803
+ const controller = new CompilerNestedMixedRanges(
2804
+ owner,
2805
+ this.root,
2806
+ descriptor,
2807
+ block,
2808
+ this.activateFallback
2809
+ );
2810
+ try {
2811
+ if (!controller.adopt()) {
2812
+ controller.cleanup();
2813
+ return false;
2814
+ }
2815
+ } catch (error) {
2816
+ controller.cleanup();
2817
+ throw error;
2818
+ }
2819
+ this.controller = controller;
2820
+ return true;
2821
+ }
2822
+ schedulePropFallback() {
2823
+ if (this.propFallbackQueued) return;
2824
+ this.propFallbackQueued = true;
2825
+ queueMicrotask(() => {
2826
+ this.propFallbackQueued = false;
2827
+ if (this.mounted && !this.state.fallback) this.activateFallback();
2828
+ });
2829
+ }
2830
+ shouldComponentUpdate(nextProps, nextState) {
2831
+ this.currentProps = nextProps;
2832
+ if (nextState.fallback || this.state.fallback) return true;
2833
+ this.schedulePropFallback();
2834
+ return false;
2835
+ }
2836
+ componentDidMount() {
2837
+ this.mounted = true;
2838
+ if (!this.adopt()) this.activateFallback();
2839
+ }
2840
+ componentDidUpdate() {
2841
+ if (this.state.fallback) this.subscribeFallbackBlocks();
2842
+ }
2843
+ componentWillUnmount() {
2844
+ this.mounted = false;
2845
+ this.controller?.cleanup();
2846
+ this.controller = null;
2847
+ this.clearFallbackSubscriptions();
2848
+ this.root = null;
2849
+ }
2850
+ render() {
2851
+ const container = this.currentProps.render();
2852
+ if (!React.isValidElement(container) || typeof container.type !== "string") {
2853
+ throw new TypeError(
2854
+ `Compiled mixed ranges ${this.currentProps.id} must own one host container.`
2855
+ );
2856
+ }
2857
+ return React.cloneElement(container, {
2858
+ key: this.state.fallback ? `react-${this.fallbackVersion}` : "compiled",
2859
+ ref: this.captureRoot
2860
+ });
2861
+ }
2862
+ }
2863
+ FarmMixedRangesBlock.displayName = "FarmCompiledMixedRanges";
2864
+ return FarmMixedRangesBlock;
2865
+ }
1116
2866
  function createComponentBlockComponent(owner) {
1117
2867
  class FarmComponentBlock extends React.Component {
1118
2868
  constructor() {
@@ -1165,6 +2915,17 @@ function createCompiledComponent(definition) {
1165
2915
  this.hasBindingError = false;
1166
2916
  this.inputSelection = null;
1167
2917
  this.dirtyState = /* @__PURE__ */ new Set();
2918
+ this.indexedDefinition = null;
2919
+ this.staticBindingsByDependency = [];
2920
+ this.blockBindingsByDependency = [];
2921
+ this.blockBindings = /* @__PURE__ */ new Map();
2922
+ this.trackedBindingsByDependency = [];
2923
+ this.trackedDependenciesByBinding = /* @__PURE__ */ new Map();
2924
+ this.bindingValues = /* @__PURE__ */ new Map();
2925
+ this.activeBinding = null;
2926
+ this.activeDependencies = null;
2927
+ this.renderedDefinition = null;
2928
+ this.renderedElement = null;
1168
2929
  this.blockRefreshListeners = /* @__PURE__ */ new Map();
1169
2930
  this.blockRoots = /* @__PURE__ */ new Map();
1170
2931
  this.blockRootElements = /* @__PURE__ */ new Set();
@@ -1176,20 +2937,35 @@ function createCompiledComponent(definition) {
1176
2937
  this.refreshDefinition = () => {
1177
2938
  if (this.mounted) this.forceUpdate();
1178
2939
  };
1179
- this.cells = definitionReference.current.initialize(props).map((initialValue, index) => {
2940
+ const initialState = definitionReference.current.initialize(props);
2941
+ const initialProps = definitionReference.current.readProps?.(props) || [];
2942
+ this.propCellOffset = initialState.length;
2943
+ this.cells = [...initialState, ...initialProps].map((initialValue, index) => {
1180
2944
  let value = initialValue;
1181
2945
  const pending = [];
1182
2946
  return {
1183
- get: () => value,
2947
+ get: () => {
2948
+ if (this.activeBinding && this.activeDependencies) {
2949
+ this.activeDependencies.add(index);
2950
+ }
2951
+ return value;
2952
+ },
1184
2953
  set: (next) => {
1185
- pending.push(next);
2954
+ pending.push({ kind: "state", update: next });
1186
2955
  this.scheduleBindingFlush(index);
1187
2956
  },
2957
+ replace: (next) => {
2958
+ pending.push({ kind: "value", value: next });
2959
+ },
1188
2960
  flush: () => {
1189
2961
  if (pending.length === 0) return false;
1190
2962
  const previous = value;
1191
2963
  for (const next of pending.splice(0)) {
1192
- value = typeof next === "function" ? next(value) : next;
2964
+ if (next.kind === "value") {
2965
+ value = next.value;
2966
+ } else {
2967
+ value = typeof next.update === "function" ? next.update(value) : next.update;
2968
+ }
1193
2969
  }
1194
2970
  return !Object.is(previous, value);
1195
2971
  }
@@ -1203,6 +2979,9 @@ function createCompiledComponent(definition) {
1203
2979
  HostConditional: createHostConditionalBlockComponent({
1204
2980
  subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
1205
2981
  }),
2982
+ ConditionalRanges: createConditionalRangesBlockComponent({
2983
+ subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
2984
+ }),
1206
2985
  KeyedList: createKeyedListBlockComponent({
1207
2986
  subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
1208
2987
  }),
@@ -1212,12 +2991,113 @@ function createCompiledComponent(definition) {
1212
2991
  KeyedRanges: createKeyedRangesBlockComponent({
1213
2992
  subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
1214
2993
  }),
2994
+ MixedRanges: createMixedRangesBlockComponent({
2995
+ subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
2996
+ }),
1215
2997
  Component: createComponentBlockComponent({
1216
2998
  subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
1217
2999
  }),
1218
3000
  target: (id) => this.bindingTarget(id)
1219
3001
  };
1220
3002
  }
3003
+ usesHybridReactivity() {
3004
+ return definitionReference.current.reactivity === "hybrid";
3005
+ }
3006
+ canReuseRenderedElement(currentDefinition, propValues) {
3007
+ return Boolean(
3008
+ this.mounted && propValues && propValues.every(isCompilerPrimitive) && this.renderedDefinition === currentDefinition && this.renderedElement
3009
+ );
3010
+ }
3011
+ renderCellsForProps(propValues) {
3012
+ if (!propValues) return { cells: this.cells, commit: () => void 0 };
3013
+ let committed = false;
3014
+ const cells = this.cells.slice(0, this.propCellOffset);
3015
+ for (let propIndex = 0; propIndex < propValues.length; propIndex += 1) {
3016
+ const cell = this.cells[this.propCellOffset + propIndex];
3017
+ if (!cell) continue;
3018
+ cells.push({
3019
+ get: () => committed ? cell.get() : propValues[propIndex],
3020
+ set: (next) => cell.set(next)
3021
+ });
3022
+ }
3023
+ return {
3024
+ cells,
3025
+ commit: () => {
3026
+ committed = true;
3027
+ }
3028
+ };
3029
+ }
3030
+ tracksBinding(binding) {
3031
+ return this.usesHybridReactivity() && binding.tracking === "dynamic";
3032
+ }
3033
+ ensureBindingIndex() {
3034
+ const currentDefinition = definitionReference.current;
3035
+ if (this.indexedDefinition === currentDefinition) return;
3036
+ this.indexedDefinition = currentDefinition;
3037
+ this.staticBindingsByDependency = Array.from({ length: this.cells.length }, () => []);
3038
+ this.blockBindingsByDependency = Array.from({ length: this.cells.length }, () => []);
3039
+ this.trackedBindingsByDependency = Array.from(
3040
+ { length: this.cells.length },
3041
+ () => /* @__PURE__ */ new Set()
3042
+ );
3043
+ this.blockBindings.clear();
3044
+ this.trackedDependenciesByBinding.clear();
3045
+ this.bindingValues.clear();
3046
+ for (const binding of currentDefinition.bindings) {
3047
+ if (binding.kind === "block") this.blockBindings.set(binding.id, binding);
3048
+ for (const dependency of binding.dependencies) {
3049
+ if (dependency < 0 || dependency >= this.cells.length) continue;
3050
+ if (binding.kind === "block") {
3051
+ this.blockBindingsByDependency[dependency].push(binding);
3052
+ } else if (!this.tracksBinding(binding)) {
3053
+ this.staticBindingsByDependency[dependency].push(binding);
3054
+ }
3055
+ }
3056
+ }
3057
+ }
3058
+ updateTrackedDependencies(binding, nextDependencies) {
3059
+ const previousDependencies = this.trackedDependenciesByBinding.get(binding);
3060
+ if (previousDependencies) {
3061
+ for (const dependency of previousDependencies) {
3062
+ if (!nextDependencies.has(dependency)) {
3063
+ this.trackedBindingsByDependency[dependency]?.delete(binding);
3064
+ }
3065
+ }
3066
+ }
3067
+ for (const dependency of nextDependencies) {
3068
+ if (!previousDependencies?.has(dependency)) {
3069
+ this.trackedBindingsByDependency[dependency]?.add(binding);
3070
+ }
3071
+ }
3072
+ this.trackedDependenciesByBinding.set(binding, nextDependencies);
3073
+ }
3074
+ readBinding(binding) {
3075
+ if (!this.tracksBinding(binding)) return binding.read(this.props, this.cells);
3076
+ const previousBinding = this.activeBinding;
3077
+ const previousDependencies = this.activeDependencies;
3078
+ const nextDependencies = /* @__PURE__ */ new Set();
3079
+ this.activeBinding = binding;
3080
+ this.activeDependencies = nextDependencies;
3081
+ try {
3082
+ return binding.read(this.props, this.cells);
3083
+ } finally {
3084
+ this.activeBinding = previousBinding;
3085
+ this.activeDependencies = previousDependencies;
3086
+ this.updateTrackedDependencies(binding, nextDependencies);
3087
+ }
3088
+ }
3089
+ bindingValue(binding, value) {
3090
+ return binding.kind === "text" ? renderTextValue(value) : value;
3091
+ }
3092
+ primeHybridBindings() {
3093
+ if (!this.usesHybridReactivity()) return;
3094
+ for (const binding of definitionReference.current.bindings) {
3095
+ if (binding.kind === "block") continue;
3096
+ if (!this.tracksBinding(binding)) continue;
3097
+ const value = this.readBinding(binding);
3098
+ this.bindingValues.set(binding, this.bindingValue(binding, value));
3099
+ }
3100
+ }
1221
3101
  bindingTarget(id) {
1222
3102
  const existing = this.bindingTargetRefs.get(id);
1223
3103
  if (existing) return existing;
@@ -1274,83 +3154,118 @@ function createCompiledComponent(definition) {
1274
3154
  this.flushQueued = true;
1275
3155
  queueMicrotask(() => {
1276
3156
  this.flushQueued = false;
1277
- const inputSelection = this.inputSelection;
1278
- this.inputSelection = null;
1279
- if (!this.mounted) return;
1280
- const dirty = /* @__PURE__ */ new Set();
1281
- for (const index2 of this.dirtyState) {
1282
- if (this.cells[index2]?.flush()) dirty.add(index2);
1283
- }
1284
- this.dirtyState.clear();
1285
- if (dirty.size === 0) return;
1286
- try {
1287
- const bindings = definitionReference.current.bindings;
1288
- const blockBindings = /* @__PURE__ */ new Map();
1289
- const affectedBlockIds = /* @__PURE__ */ new Set();
1290
- for (const binding of bindings) {
1291
- if (binding.kind !== "block") continue;
1292
- blockBindings.set(binding.id, binding);
1293
- if (binding.dependencies.some((dependency) => dirty.has(dependency))) {
1294
- affectedBlockIds.add(binding.id);
1295
- }
3157
+ this.flushBindingUpdates();
3158
+ });
3159
+ }
3160
+ flushBindingUpdates() {
3161
+ const inputSelection = this.inputSelection;
3162
+ this.inputSelection = null;
3163
+ if (!this.mounted) return;
3164
+ const dirty = /* @__PURE__ */ new Set();
3165
+ for (const index of this.dirtyState) {
3166
+ if (this.cells[index]?.flush()) dirty.add(index);
3167
+ }
3168
+ this.dirtyState.clear();
3169
+ if (dirty.size === 0) return;
3170
+ try {
3171
+ this.ensureBindingIndex();
3172
+ const affectedBlockIds = /* @__PURE__ */ new Set();
3173
+ const affectedBindings = /* @__PURE__ */ new Set();
3174
+ for (const dependency of dirty) {
3175
+ for (const binding of this.blockBindingsByDependency[dependency] || []) {
3176
+ affectedBlockIds.add(binding.id);
1296
3177
  }
1297
- const hasAffectedMountedAncestor = (binding) => {
1298
- let parent = binding.parent;
1299
- while (parent !== void 0) {
1300
- if (affectedBlockIds.has(parent) && this.blockRefreshListeners.has(parent)) {
1301
- return true;
1302
- }
1303
- parent = blockBindings.get(parent)?.parent;
1304
- }
1305
- return false;
1306
- };
1307
- const blockRefreshes = [...affectedBlockIds].map((id) => {
1308
- const binding = blockBindings.get(id);
1309
- const refresh = this.blockRefreshListeners.get(id);
1310
- return binding && refresh && !hasAffectedMountedAncestor(binding) ? refresh : void 0;
1311
- }).filter(
1312
- (refresh) => refresh !== void 0
1313
- );
1314
- for (const binding of bindings) {
1315
- if (binding.kind !== "block" && binding.dependencies.some((dependency) => dirty.has(dependency))) {
1316
- this.applyBinding(binding);
3178
+ for (const binding of this.staticBindingsByDependency[dependency] || []) {
3179
+ affectedBindings.add(binding);
3180
+ }
3181
+ if (this.usesHybridReactivity()) {
3182
+ for (const binding of this.trackedBindingsByDependency[dependency] || []) {
3183
+ affectedBindings.add(binding);
1317
3184
  }
1318
3185
  }
1319
- let pendingBlockCommits = blockRefreshes.length;
1320
- for (const refresh of blockRefreshes) {
1321
- refresh(() => {
1322
- pendingBlockCommits -= 1;
1323
- if (pendingBlockCommits === 0) this.restoreInputSelection(inputSelection);
1324
- });
3186
+ }
3187
+ const hasAffectedMountedAncestor = (binding) => {
3188
+ let parent = binding.parent;
3189
+ while (parent !== void 0) {
3190
+ if (affectedBlockIds.has(parent) && this.blockRefreshListeners.has(parent)) {
3191
+ return true;
3192
+ }
3193
+ parent = this.blockBindings.get(parent)?.parent;
1325
3194
  }
1326
- if (blockRefreshes.length === 0) this.restoreInputSelection(inputSelection);
1327
- } catch (error) {
1328
- this.bindingError = error;
1329
- this.hasBindingError = true;
1330
- this.forceUpdate();
3195
+ return false;
3196
+ };
3197
+ const blockRefreshes = [...affectedBlockIds].map((id) => {
3198
+ const binding = this.blockBindings.get(id);
3199
+ const refresh = this.blockRefreshListeners.get(id);
3200
+ return binding && refresh && !hasAffectedMountedAncestor(binding) ? refresh : void 0;
3201
+ }).filter((refresh) => refresh !== void 0);
3202
+ for (const binding of affectedBindings) {
3203
+ if (binding.kind !== "block") this.applyBinding(binding);
1331
3204
  }
1332
- });
3205
+ let pendingBlockCommits = blockRefreshes.length;
3206
+ for (const refresh of blockRefreshes) {
3207
+ refresh(() => {
3208
+ pendingBlockCommits -= 1;
3209
+ if (pendingBlockCommits === 0) this.restoreInputSelection(inputSelection);
3210
+ }, dirty);
3211
+ }
3212
+ if (blockRefreshes.length === 0) this.restoreInputSelection(inputSelection);
3213
+ } catch (error) {
3214
+ this.bindingError = error;
3215
+ this.hasBindingError = true;
3216
+ this.forceUpdate();
3217
+ }
1333
3218
  }
1334
- applyBinding(binding) {
3219
+ applyBinding(binding, force = false) {
1335
3220
  if (!this.root || binding.kind === "block") return;
1336
3221
  const target = binding.target === void 0 ? findBindingTarget(this.root, binding.path, this.blockRootElements) : binding.path.length === 0 ? this.root : this.bindingTargets.get(binding.target) || null;
1337
3222
  if (!target) return;
1338
- const value = binding.read(this.props, this.cells);
3223
+ const value = this.readBinding(binding);
3224
+ const comparableValue = this.bindingValue(binding, value);
3225
+ if (!force && this.bindingValues.has(binding)) {
3226
+ if (Object.is(this.bindingValues.get(binding), comparableValue)) return;
3227
+ }
1339
3228
  if (binding.kind === "text") {
1340
- target.textContent = renderTextValue(value);
3229
+ target.textContent = comparableValue;
1341
3230
  } else if (binding.kind === "style") {
1342
3231
  updateStyle(target, binding.name, value);
1343
3232
  } else {
1344
3233
  updateAttribute(target, binding.name, value);
1345
3234
  }
3235
+ this.bindingValues.set(binding, comparableValue);
1346
3236
  }
1347
3237
  componentDidMount() {
1348
3238
  this.mounted = true;
1349
3239
  refreshListeners.add(this.refreshDefinition);
3240
+ this.ensureBindingIndex();
3241
+ this.primeHybridBindings();
1350
3242
  }
1351
- componentDidUpdate() {
3243
+ getSnapshotBeforeUpdate() {
3244
+ const currentDefinition = definitionReference.current;
3245
+ const propValues = currentDefinition.readProps?.(this.props) || null;
3246
+ return this.canReuseRenderedElement(currentDefinition, propValues);
3247
+ }
3248
+ componentDidUpdate(_previousProps, _previousState, reusedRenderedElement = false) {
3249
+ const propValues = definitionReference.current.readProps?.(this.props) || null;
3250
+ if (propValues) {
3251
+ if (reusedRenderedElement) this.captureInputSelection();
3252
+ for (let propIndex = 0; propIndex < propValues.length; propIndex += 1) {
3253
+ const cellIndex = this.propCellOffset + propIndex;
3254
+ const cell = this.cells[cellIndex];
3255
+ if (!cell) continue;
3256
+ cell.replace(propValues[propIndex]);
3257
+ if (reusedRenderedElement) {
3258
+ this.dirtyState.add(cellIndex);
3259
+ } else {
3260
+ cell.flush();
3261
+ }
3262
+ }
3263
+ this.flushBindingUpdates();
3264
+ return;
3265
+ }
3266
+ this.ensureBindingIndex();
1352
3267
  for (const binding of definitionReference.current.bindings) {
1353
- if (binding.kind !== "block") this.applyBinding(binding);
3268
+ if (binding.kind !== "block") this.applyBinding(binding, true);
1354
3269
  }
1355
3270
  }
1356
3271
  componentWillUnmount() {
@@ -1363,30 +3278,68 @@ function createCompiledComponent(definition) {
1363
3278
  this.blockRootElements.clear();
1364
3279
  this.bindingTargets.clear();
1365
3280
  this.bindingTargetRefs.clear();
3281
+ this.indexedDefinition = null;
3282
+ this.staticBindingsByDependency = [];
3283
+ this.blockBindingsByDependency = [];
3284
+ this.blockBindings.clear();
3285
+ this.trackedBindingsByDependency = [];
3286
+ this.trackedDependenciesByBinding.clear();
3287
+ this.bindingValues.clear();
3288
+ this.activeBinding = null;
3289
+ this.activeDependencies = null;
1366
3290
  refreshListeners.delete(this.refreshDefinition);
1367
3291
  }
1368
3292
  render() {
1369
3293
  if (this.hasBindingError) throw this.bindingError;
1370
3294
  const currentDefinition = definitionReference.current;
1371
- const element = currentDefinition.render(this.props, this.cells, this.blockRuntime);
3295
+ const propValues = currentDefinition.readProps?.(this.props) || null;
3296
+ if (this.canReuseRenderedElement(currentDefinition, propValues)) {
3297
+ return this.renderedElement;
3298
+ }
3299
+ const renderCells = this.renderCellsForProps(propValues);
3300
+ const element = currentDefinition.render(this.props, renderCells.cells, this.blockRuntime);
1372
3301
  if (!React.isValidElement(element)) {
1373
3302
  throw new TypeError(
1374
3303
  `Compiled component ${currentDefinition.displayName} must return one host element.`
1375
3304
  );
1376
3305
  }
3306
+ let renderedElement;
3307
+ const captureCommittedRoot = (root) => {
3308
+ this.captureRoot(root);
3309
+ if (!root) return;
3310
+ renderCells.commit();
3311
+ this.renderedDefinition = currentDefinition;
3312
+ this.renderedElement = renderedElement;
3313
+ };
1377
3314
  if (element.type === this.blockRuntime.KeyedRanges) {
1378
- return React.cloneElement(element, {
1379
- rootRef: this.captureRoot
1380
- });
1381
- }
1382
- if (typeof element.type !== "string") {
3315
+ renderedElement = React.cloneElement(
3316
+ element,
3317
+ {
3318
+ rootRef: captureCommittedRoot
3319
+ }
3320
+ );
3321
+ } else if (element.type === this.blockRuntime.ConditionalRanges) {
3322
+ renderedElement = React.cloneElement(
3323
+ element,
3324
+ { rootRef: captureCommittedRoot }
3325
+ );
3326
+ } else if (element.type === this.blockRuntime.MixedRanges) {
3327
+ renderedElement = React.cloneElement(
3328
+ element,
3329
+ {
3330
+ rootRef: captureCommittedRoot
3331
+ }
3332
+ );
3333
+ } else if (typeof element.type !== "string") {
1383
3334
  throw new TypeError(
1384
3335
  `Compiled component ${currentDefinition.displayName} must return one host element.`
1385
3336
  );
3337
+ } else {
3338
+ renderedElement = React.cloneElement(element, {
3339
+ ref: captureCommittedRoot
3340
+ });
1386
3341
  }
1387
- return React.cloneElement(element, {
1388
- ref: this.captureRoot
1389
- });
3342
+ return renderedElement;
1390
3343
  }
1391
3344
  }
1392
3345
  FarmCompiledComponent.displayName = `FarmCompiled(${definition.displayName})`;