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