@farm.js/react 0.1.0-beta.1 → 0.1.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -20
- package/dist/compiler-runtime.cjs +411 -1
- package/dist/compiler-runtime.cjs.map +1 -1
- package/dist/compiler-runtime.d.mts +36 -1
- package/dist/compiler-runtime.d.ts +36 -1
- package/dist/compiler-runtime.mjs +411 -1
- package/dist/compiler-runtime.mjs.map +1 -1
- package/dist/vite.cjs +489 -20
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.mjs +489 -20
- package/dist/vite.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -95,6 +95,23 @@ interface CompilerHostConditionalBlockProps {
|
|
|
95
95
|
truthy?: CompilerHostConditionalBranch;
|
|
96
96
|
falsy?: CompilerHostConditionalBranch;
|
|
97
97
|
}
|
|
98
|
+
interface CompilerConditionalRange {
|
|
99
|
+
/** Number of static direct host siblings between this slot and the previous slot. */
|
|
100
|
+
before: number;
|
|
101
|
+
test(): unknown;
|
|
102
|
+
/** Logical && can produce a visible number instead of an empty branch. */
|
|
103
|
+
logical?: boolean;
|
|
104
|
+
truthy?: CompilerHostConditionalBranch;
|
|
105
|
+
falsy?: CompilerHostConditionalBranch;
|
|
106
|
+
}
|
|
107
|
+
interface CompilerConditionalRangesBlockProps {
|
|
108
|
+
id: number;
|
|
109
|
+
render(): React.ReactElement;
|
|
110
|
+
rootRef?: React.RefCallback<Element>;
|
|
111
|
+
ranges: readonly CompilerConditionalRange[];
|
|
112
|
+
/** Number of static direct host siblings after the final conditional slot. */
|
|
113
|
+
trailing: number;
|
|
114
|
+
}
|
|
98
115
|
interface CompilerKeyedRowBinding {
|
|
99
116
|
kind: "text" | "attribute" | "style";
|
|
100
117
|
path: readonly number[];
|
|
@@ -111,6 +128,22 @@ interface CompilerKeyedRowsBlockProps {
|
|
|
111
128
|
events?: readonly CompilerKeyedRowEvent[];
|
|
112
129
|
conditionals?: readonly CompilerKeyedRowConditional[];
|
|
113
130
|
}
|
|
131
|
+
interface CompilerKeyedRange {
|
|
132
|
+
/** Number of static direct host siblings between this range and the previous range. */
|
|
133
|
+
before: number;
|
|
134
|
+
items(): Iterable<unknown> | null | undefined;
|
|
135
|
+
rowKey(item: unknown, index: number): React.Key;
|
|
136
|
+
create(item: unknown, index: number): CompilerKeyedRowElement;
|
|
137
|
+
bindings: readonly CompilerKeyedRowBinding[];
|
|
138
|
+
}
|
|
139
|
+
interface CompilerKeyedRangesBlockProps {
|
|
140
|
+
id: number;
|
|
141
|
+
render(): React.ReactElement;
|
|
142
|
+
rootRef?: React.RefCallback<Element>;
|
|
143
|
+
ranges: readonly CompilerKeyedRange[];
|
|
144
|
+
/** Number of static direct host siblings after the final keyed range. */
|
|
145
|
+
trailing: number;
|
|
146
|
+
}
|
|
114
147
|
interface CompilerComponentBlockProps {
|
|
115
148
|
id: number;
|
|
116
149
|
render(): React.ReactNode;
|
|
@@ -118,8 +151,10 @@ interface CompilerComponentBlockProps {
|
|
|
118
151
|
interface CompilerBlockRuntime {
|
|
119
152
|
Conditional: React.ComponentType<CompilerConditionalBlockProps>;
|
|
120
153
|
HostConditional: React.ComponentType<CompilerHostConditionalBlockProps>;
|
|
154
|
+
ConditionalRanges: React.ComponentType<CompilerConditionalRangesBlockProps>;
|
|
121
155
|
KeyedList: React.ComponentType<CompilerKeyedListBlockProps>;
|
|
122
156
|
KeyedRows: React.ComponentType<CompilerKeyedRowsBlockProps>;
|
|
157
|
+
KeyedRanges: React.ComponentType<CompilerKeyedRangesBlockProps>;
|
|
123
158
|
Component: React.ComponentType<CompilerComponentBlockProps>;
|
|
124
159
|
target(id: number): React.RefCallback<Element>;
|
|
125
160
|
}
|
|
@@ -143,4 +178,4 @@ interface CompiledComponentDefinition<Props> {
|
|
|
143
178
|
*/
|
|
144
179
|
declare function createCompiledComponent<Props>(definition: CompiledComponentDefinition<Props>): React.ComponentType<Props>;
|
|
145
180
|
|
|
146
|
-
export { type CompiledComponentDefinition, type CompilerAttributeBinding, type CompilerBinding, type CompilerBlockRuntime, type CompilerCell, type CompilerComponentBlockProps, type CompilerConditionalBlockBinding, type CompilerConditionalBlockProps, type CompilerHostConditionalBinding, type CompilerHostConditionalBlockProps, type CompilerHostConditionalBranch, type CompilerHostElement, type CompilerKeyedListBlockProps, type CompilerKeyedRowBinding, type CompilerKeyedRowConditional, type CompilerKeyedRowConditionalBranch, type CompilerKeyedRowElement, type CompilerKeyedRowEvent, type CompilerKeyedRowsBlockProps, type CompilerStateUpdater, type CompilerStyleBinding, type CompilerTextBinding, createCompiledComponent };
|
|
181
|
+
export { type CompiledComponentDefinition, type CompilerAttributeBinding, type CompilerBinding, type CompilerBlockRuntime, type CompilerCell, type CompilerComponentBlockProps, type CompilerConditionalBlockBinding, type CompilerConditionalBlockProps, type CompilerConditionalRange, type CompilerConditionalRangesBlockProps, type CompilerHostConditionalBinding, type CompilerHostConditionalBlockProps, type CompilerHostConditionalBranch, type CompilerHostElement, type CompilerKeyedListBlockProps, type CompilerKeyedRange, type CompilerKeyedRangesBlockProps, type CompilerKeyedRowBinding, type CompilerKeyedRowConditional, type CompilerKeyedRowConditionalBranch, type CompilerKeyedRowElement, type CompilerKeyedRowEvent, type CompilerKeyedRowsBlockProps, type CompilerStateUpdater, type CompilerStyleBinding, type CompilerTextBinding, createCompiledComponent };
|
|
@@ -95,6 +95,23 @@ interface CompilerHostConditionalBlockProps {
|
|
|
95
95
|
truthy?: CompilerHostConditionalBranch;
|
|
96
96
|
falsy?: CompilerHostConditionalBranch;
|
|
97
97
|
}
|
|
98
|
+
interface CompilerConditionalRange {
|
|
99
|
+
/** Number of static direct host siblings between this slot and the previous slot. */
|
|
100
|
+
before: number;
|
|
101
|
+
test(): unknown;
|
|
102
|
+
/** Logical && can produce a visible number instead of an empty branch. */
|
|
103
|
+
logical?: boolean;
|
|
104
|
+
truthy?: CompilerHostConditionalBranch;
|
|
105
|
+
falsy?: CompilerHostConditionalBranch;
|
|
106
|
+
}
|
|
107
|
+
interface CompilerConditionalRangesBlockProps {
|
|
108
|
+
id: number;
|
|
109
|
+
render(): React.ReactElement;
|
|
110
|
+
rootRef?: React.RefCallback<Element>;
|
|
111
|
+
ranges: readonly CompilerConditionalRange[];
|
|
112
|
+
/** Number of static direct host siblings after the final conditional slot. */
|
|
113
|
+
trailing: number;
|
|
114
|
+
}
|
|
98
115
|
interface CompilerKeyedRowBinding {
|
|
99
116
|
kind: "text" | "attribute" | "style";
|
|
100
117
|
path: readonly number[];
|
|
@@ -111,6 +128,22 @@ interface CompilerKeyedRowsBlockProps {
|
|
|
111
128
|
events?: readonly CompilerKeyedRowEvent[];
|
|
112
129
|
conditionals?: readonly CompilerKeyedRowConditional[];
|
|
113
130
|
}
|
|
131
|
+
interface CompilerKeyedRange {
|
|
132
|
+
/** Number of static direct host siblings between this range and the previous range. */
|
|
133
|
+
before: number;
|
|
134
|
+
items(): Iterable<unknown> | null | undefined;
|
|
135
|
+
rowKey(item: unknown, index: number): React.Key;
|
|
136
|
+
create(item: unknown, index: number): CompilerKeyedRowElement;
|
|
137
|
+
bindings: readonly CompilerKeyedRowBinding[];
|
|
138
|
+
}
|
|
139
|
+
interface CompilerKeyedRangesBlockProps {
|
|
140
|
+
id: number;
|
|
141
|
+
render(): React.ReactElement;
|
|
142
|
+
rootRef?: React.RefCallback<Element>;
|
|
143
|
+
ranges: readonly CompilerKeyedRange[];
|
|
144
|
+
/** Number of static direct host siblings after the final keyed range. */
|
|
145
|
+
trailing: number;
|
|
146
|
+
}
|
|
114
147
|
interface CompilerComponentBlockProps {
|
|
115
148
|
id: number;
|
|
116
149
|
render(): React.ReactNode;
|
|
@@ -118,8 +151,10 @@ interface CompilerComponentBlockProps {
|
|
|
118
151
|
interface CompilerBlockRuntime {
|
|
119
152
|
Conditional: React.ComponentType<CompilerConditionalBlockProps>;
|
|
120
153
|
HostConditional: React.ComponentType<CompilerHostConditionalBlockProps>;
|
|
154
|
+
ConditionalRanges: React.ComponentType<CompilerConditionalRangesBlockProps>;
|
|
121
155
|
KeyedList: React.ComponentType<CompilerKeyedListBlockProps>;
|
|
122
156
|
KeyedRows: React.ComponentType<CompilerKeyedRowsBlockProps>;
|
|
157
|
+
KeyedRanges: React.ComponentType<CompilerKeyedRangesBlockProps>;
|
|
123
158
|
Component: React.ComponentType<CompilerComponentBlockProps>;
|
|
124
159
|
target(id: number): React.RefCallback<Element>;
|
|
125
160
|
}
|
|
@@ -143,4 +178,4 @@ interface CompiledComponentDefinition<Props> {
|
|
|
143
178
|
*/
|
|
144
179
|
declare function createCompiledComponent<Props>(definition: CompiledComponentDefinition<Props>): React.ComponentType<Props>;
|
|
145
180
|
|
|
146
|
-
export { type CompiledComponentDefinition, type CompilerAttributeBinding, type CompilerBinding, type CompilerBlockRuntime, type CompilerCell, type CompilerComponentBlockProps, type CompilerConditionalBlockBinding, type CompilerConditionalBlockProps, type CompilerHostConditionalBinding, type CompilerHostConditionalBlockProps, type CompilerHostConditionalBranch, type CompilerHostElement, type CompilerKeyedListBlockProps, type CompilerKeyedRowBinding, type CompilerKeyedRowConditional, type CompilerKeyedRowConditionalBranch, type CompilerKeyedRowElement, type CompilerKeyedRowEvent, type CompilerKeyedRowsBlockProps, type CompilerStateUpdater, type CompilerStyleBinding, type CompilerTextBinding, createCompiledComponent };
|
|
181
|
+
export { type CompiledComponentDefinition, type CompilerAttributeBinding, type CompilerBinding, type CompilerBlockRuntime, type CompilerCell, type CompilerComponentBlockProps, type CompilerConditionalBlockBinding, type CompilerConditionalBlockProps, type CompilerConditionalRange, type CompilerConditionalRangesBlockProps, type CompilerHostConditionalBinding, type CompilerHostConditionalBlockProps, type CompilerHostConditionalBranch, type CompilerHostElement, type CompilerKeyedListBlockProps, type CompilerKeyedRange, type CompilerKeyedRangesBlockProps, type CompilerKeyedRowBinding, type CompilerKeyedRowConditional, type CompilerKeyedRowConditionalBranch, type CompilerKeyedRowElement, type CompilerKeyedRowEvent, type CompilerKeyedRowsBlockProps, type CompilerStateUpdater, type CompilerStyleBinding, type CompilerTextBinding, createCompiledComponent };
|
|
@@ -504,6 +504,181 @@ function createHostConditionalBlockComponent(owner) {
|
|
|
504
504
|
FarmHostConditionalBlock.displayName = "FarmCompiledHostConditional";
|
|
505
505
|
return FarmHostConditionalBlock;
|
|
506
506
|
}
|
|
507
|
+
function createConditionalRangesBlockComponent(owner) {
|
|
508
|
+
class FarmConditionalRangesBlock extends React.Component {
|
|
509
|
+
constructor() {
|
|
510
|
+
super(...arguments);
|
|
511
|
+
this.state = { fallback: false };
|
|
512
|
+
this.root = null;
|
|
513
|
+
this.mounted = false;
|
|
514
|
+
this.fallbackRequested = false;
|
|
515
|
+
this.fallbackVersion = 0;
|
|
516
|
+
this.propFallbackQueued = false;
|
|
517
|
+
this.currentProps = this.props;
|
|
518
|
+
this.rangeInstances = [];
|
|
519
|
+
this.staticSegments = [];
|
|
520
|
+
this.captureRoot = (root) => {
|
|
521
|
+
this.root = root;
|
|
522
|
+
this.currentProps.rootRef?.(root);
|
|
523
|
+
};
|
|
524
|
+
this.refresh = (afterCommit) => {
|
|
525
|
+
this.reconcile(afterCommit);
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
readSelections(props) {
|
|
529
|
+
const selections = [];
|
|
530
|
+
for (const range of props.ranges) {
|
|
531
|
+
const selection = hostConditionalSelection(range);
|
|
532
|
+
if (selection.kind === "fallback") return null;
|
|
533
|
+
selections.push(selection);
|
|
534
|
+
}
|
|
535
|
+
return selections;
|
|
536
|
+
}
|
|
537
|
+
adopt(props = this.currentProps) {
|
|
538
|
+
if (!this.root || !Number.isSafeInteger(props.trailing) || props.trailing < 0) return false;
|
|
539
|
+
const selections = this.readSelections(props);
|
|
540
|
+
if (!selections) return false;
|
|
541
|
+
const elements = [...this.root.children];
|
|
542
|
+
const staticSegments = [];
|
|
543
|
+
const instances = [];
|
|
544
|
+
let cursor = 0;
|
|
545
|
+
for (let rangeIndex = 0; rangeIndex < props.ranges.length; rangeIndex += 1) {
|
|
546
|
+
const range = props.ranges[rangeIndex];
|
|
547
|
+
if (!Number.isSafeInteger(range.before) || range.before < 0) return false;
|
|
548
|
+
const staticEnd = cursor + range.before;
|
|
549
|
+
if (staticEnd > elements.length) return false;
|
|
550
|
+
staticSegments.push(elements.slice(cursor, staticEnd));
|
|
551
|
+
cursor = staticEnd;
|
|
552
|
+
const selection = selections[rangeIndex];
|
|
553
|
+
if (selection.kind === "empty") {
|
|
554
|
+
instances.push(null);
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
const element = elements[cursor];
|
|
558
|
+
if (!element) return false;
|
|
559
|
+
const descriptor = selection.branch.create();
|
|
560
|
+
if (!matchesCompilerHostElement(element, descriptor)) return false;
|
|
561
|
+
instances.push({
|
|
562
|
+
key: selection.key,
|
|
563
|
+
host: {
|
|
564
|
+
element,
|
|
565
|
+
values: readHostConditionalBindingValues(selection.branch)
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
cursor += 1;
|
|
569
|
+
}
|
|
570
|
+
if (cursor + props.trailing !== elements.length) return false;
|
|
571
|
+
staticSegments.push(elements.slice(cursor));
|
|
572
|
+
this.staticSegments = staticSegments;
|
|
573
|
+
this.rangeInstances = instances;
|
|
574
|
+
return true;
|
|
575
|
+
}
|
|
576
|
+
anchorAfter(rangeIndex) {
|
|
577
|
+
for (let next = rangeIndex + 1; next < this.rangeInstances.length; next += 1) {
|
|
578
|
+
const staticAnchor = this.staticSegments[next]?.[0];
|
|
579
|
+
if (staticAnchor) return staticAnchor;
|
|
580
|
+
const rangeAnchor = this.rangeInstances[next]?.host.element;
|
|
581
|
+
if (rangeAnchor) return rangeAnchor;
|
|
582
|
+
}
|
|
583
|
+
return this.staticSegments[this.rangeInstances.length]?.[0] || null;
|
|
584
|
+
}
|
|
585
|
+
reconcileRange(rangeIndex, selection) {
|
|
586
|
+
if (!this.root) return;
|
|
587
|
+
const previous = this.rangeInstances[rangeIndex];
|
|
588
|
+
if (selection.kind === "empty") {
|
|
589
|
+
previous?.host.element.remove();
|
|
590
|
+
this.rangeInstances[rangeIndex] = null;
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
if (previous?.key === selection.key) {
|
|
594
|
+
applyHostConditionalBindings(selection.branch, previous.host);
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
const element = createCompilerHostElement(this.root.ownerDocument, selection.branch.create());
|
|
598
|
+
if (previous) previous.host.element.replaceWith(element);
|
|
599
|
+
else this.root.insertBefore(element, this.anchorAfter(rangeIndex));
|
|
600
|
+
this.rangeInstances[rangeIndex] = {
|
|
601
|
+
key: selection.key,
|
|
602
|
+
host: {
|
|
603
|
+
element,
|
|
604
|
+
values: readHostConditionalBindingValues(selection.branch)
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
reconcile(afterCommit) {
|
|
609
|
+
if (!this.mounted || !this.root) {
|
|
610
|
+
afterCommit?.();
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
if (this.state.fallback) {
|
|
614
|
+
this.fallbackVersion += 1;
|
|
615
|
+
this.forceUpdate(afterCommit);
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (this.currentProps.ranges.length !== this.rangeInstances.length) {
|
|
619
|
+
this.activateFallback(afterCommit);
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
const selections = this.readSelections(this.currentProps);
|
|
623
|
+
if (!selections) {
|
|
624
|
+
this.activateFallback(afterCommit);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
for (let rangeIndex = this.rangeInstances.length - 1; rangeIndex >= 0; rangeIndex -= 1) {
|
|
628
|
+
this.reconcileRange(rangeIndex, selections[rangeIndex]);
|
|
629
|
+
}
|
|
630
|
+
afterCommit?.();
|
|
631
|
+
}
|
|
632
|
+
activateFallback(afterCommit) {
|
|
633
|
+
if (!this.mounted || this.state.fallback || this.fallbackRequested) {
|
|
634
|
+
afterCommit?.();
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
this.fallbackRequested = true;
|
|
638
|
+
this.setState({ fallback: true }, afterCommit);
|
|
639
|
+
}
|
|
640
|
+
schedulePropFallback() {
|
|
641
|
+
if (this.propFallbackQueued) return;
|
|
642
|
+
this.propFallbackQueued = true;
|
|
643
|
+
queueMicrotask(() => {
|
|
644
|
+
this.propFallbackQueued = false;
|
|
645
|
+
if (this.mounted && !this.state.fallback) this.activateFallback();
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
shouldComponentUpdate(nextProps, nextState) {
|
|
649
|
+
this.currentProps = nextProps;
|
|
650
|
+
if (nextState.fallback || this.state.fallback) return true;
|
|
651
|
+
this.schedulePropFallback();
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
componentDidMount() {
|
|
655
|
+
this.mounted = true;
|
|
656
|
+
this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
|
|
657
|
+
if (!this.adopt()) this.activateFallback();
|
|
658
|
+
}
|
|
659
|
+
componentWillUnmount() {
|
|
660
|
+
this.mounted = false;
|
|
661
|
+
this.unsubscribe?.();
|
|
662
|
+
this.root = null;
|
|
663
|
+
this.rangeInstances = [];
|
|
664
|
+
this.staticSegments = [];
|
|
665
|
+
}
|
|
666
|
+
render() {
|
|
667
|
+
const container = this.currentProps.render();
|
|
668
|
+
if (!React.isValidElement(container) || typeof container.type !== "string") {
|
|
669
|
+
throw new TypeError(
|
|
670
|
+
`Compiled conditional ranges ${this.currentProps.id} must own one host container.`
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
return React.cloneElement(container, {
|
|
674
|
+
key: this.state.fallback ? `react-${this.fallbackVersion}` : "compiled",
|
|
675
|
+
ref: this.captureRoot
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
FarmConditionalRangesBlock.displayName = "FarmCompiledConditionalRanges";
|
|
680
|
+
return FarmConditionalRangesBlock;
|
|
681
|
+
}
|
|
507
682
|
function longestIncreasingSubsequencePositions(sequence) {
|
|
508
683
|
const tails = [];
|
|
509
684
|
const previous = Array.from({ length: sequence.length }, () => -1);
|
|
@@ -900,6 +1075,219 @@ function createKeyedRowsBlockComponent(owner) {
|
|
|
900
1075
|
FarmKeyedRowsBlock.displayName = "FarmCompiledKeyedRows";
|
|
901
1076
|
return FarmKeyedRowsBlock;
|
|
902
1077
|
}
|
|
1078
|
+
function createKeyedRangesBlockComponent(owner) {
|
|
1079
|
+
class FarmKeyedRangesBlock extends React.Component {
|
|
1080
|
+
constructor() {
|
|
1081
|
+
super(...arguments);
|
|
1082
|
+
this.state = { fallback: false };
|
|
1083
|
+
this.root = null;
|
|
1084
|
+
this.mounted = false;
|
|
1085
|
+
this.fallbackRequested = false;
|
|
1086
|
+
this.fallbackVersion = 0;
|
|
1087
|
+
this.propFallbackQueued = false;
|
|
1088
|
+
this.currentProps = this.props;
|
|
1089
|
+
this.rangeInstances = [];
|
|
1090
|
+
this.staticSegments = [];
|
|
1091
|
+
this.captureRoot = (root) => {
|
|
1092
|
+
this.root = root;
|
|
1093
|
+
this.currentProps.rootRef?.(root);
|
|
1094
|
+
};
|
|
1095
|
+
this.refresh = (afterCommit) => {
|
|
1096
|
+
this.reconcile(afterCommit);
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
readRange(range) {
|
|
1100
|
+
const source = range.items();
|
|
1101
|
+
const items = source ? Array.from(source) : [];
|
|
1102
|
+
const keys = items.map((item, index) => keyedRowIdentity(range.rowKey(item, index)));
|
|
1103
|
+
if (new Set(keys).size !== keys.length) return null;
|
|
1104
|
+
return { items, keys };
|
|
1105
|
+
}
|
|
1106
|
+
readRanges(props) {
|
|
1107
|
+
const ranges = [];
|
|
1108
|
+
for (const range of props.ranges) {
|
|
1109
|
+
const rows = this.readRange(range);
|
|
1110
|
+
if (!rows) return null;
|
|
1111
|
+
ranges.push(rows);
|
|
1112
|
+
}
|
|
1113
|
+
return ranges;
|
|
1114
|
+
}
|
|
1115
|
+
adopt(props = this.currentProps) {
|
|
1116
|
+
if (!this.root || !Number.isSafeInteger(props.trailing) || props.trailing < 0) return false;
|
|
1117
|
+
const rowsByRange = this.readRanges(props);
|
|
1118
|
+
if (!rowsByRange) return false;
|
|
1119
|
+
const elements = [...this.root.children];
|
|
1120
|
+
const staticSegments = [];
|
|
1121
|
+
const instancesByRange = [];
|
|
1122
|
+
let cursor = 0;
|
|
1123
|
+
for (let rangeIndex = 0; rangeIndex < props.ranges.length; rangeIndex += 1) {
|
|
1124
|
+
const range = props.ranges[rangeIndex];
|
|
1125
|
+
const rows = rowsByRange[rangeIndex];
|
|
1126
|
+
if (!Number.isSafeInteger(range.before) || range.before < 0) return false;
|
|
1127
|
+
const staticEnd = cursor + range.before;
|
|
1128
|
+
if (staticEnd > elements.length) return false;
|
|
1129
|
+
staticSegments.push(elements.slice(cursor, staticEnd));
|
|
1130
|
+
cursor = staticEnd;
|
|
1131
|
+
const rowEnd = cursor + rows.items.length;
|
|
1132
|
+
if (rowEnd > elements.length) return false;
|
|
1133
|
+
const instances = /* @__PURE__ */ new Map();
|
|
1134
|
+
for (let index = 0; index < rows.items.length; index += 1) {
|
|
1135
|
+
const element = elements[cursor + index];
|
|
1136
|
+
if (!matchesCompilerHostElement(element, range.create(rows.items[index], index))) {
|
|
1137
|
+
return false;
|
|
1138
|
+
}
|
|
1139
|
+
instances.set(rows.keys[index], {
|
|
1140
|
+
key: rows.keys[index],
|
|
1141
|
+
element,
|
|
1142
|
+
values: readKeyedRowBindingValues(range, rows.items[index], index),
|
|
1143
|
+
item: rows.items[index],
|
|
1144
|
+
index,
|
|
1145
|
+
conditionalValues: /* @__PURE__ */ new Map()
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
instancesByRange.push(instances);
|
|
1149
|
+
cursor = rowEnd;
|
|
1150
|
+
}
|
|
1151
|
+
if (cursor + props.trailing !== elements.length) return false;
|
|
1152
|
+
staticSegments.push(elements.slice(cursor));
|
|
1153
|
+
this.staticSegments = staticSegments;
|
|
1154
|
+
this.rangeInstances = instancesByRange;
|
|
1155
|
+
return true;
|
|
1156
|
+
}
|
|
1157
|
+
anchorAfter(rangeIndex) {
|
|
1158
|
+
for (let next = rangeIndex + 1; next < this.rangeInstances.length; next += 1) {
|
|
1159
|
+
const staticAnchor = this.staticSegments[next]?.[0];
|
|
1160
|
+
if (staticAnchor) return staticAnchor;
|
|
1161
|
+
const rowAnchor = this.rangeInstances[next].values().next().value?.element;
|
|
1162
|
+
if (rowAnchor) return rowAnchor;
|
|
1163
|
+
}
|
|
1164
|
+
return this.staticSegments[this.rangeInstances.length]?.[0] || null;
|
|
1165
|
+
}
|
|
1166
|
+
reconcileRange(rangeIndex, rows) {
|
|
1167
|
+
if (!this.root) return;
|
|
1168
|
+
const range = this.currentProps.ranges[rangeIndex];
|
|
1169
|
+
const previous = this.rangeInstances[rangeIndex];
|
|
1170
|
+
const oldIndices = /* @__PURE__ */ new Map();
|
|
1171
|
+
[...previous.keys()].forEach((key, index) => oldIndices.set(key, index));
|
|
1172
|
+
const nextKeys = new Set(rows.keys);
|
|
1173
|
+
for (const [key, instance] of previous) {
|
|
1174
|
+
if (!nextKeys.has(key)) instance.element.remove();
|
|
1175
|
+
}
|
|
1176
|
+
const sequence = rows.keys.map((key) => oldIndices.get(key) ?? -1);
|
|
1177
|
+
const stablePositions = longestIncreasingSubsequencePositions(sequence);
|
|
1178
|
+
const nextInstances = [];
|
|
1179
|
+
for (let index = 0; index < rows.items.length; index += 1) {
|
|
1180
|
+
const key = rows.keys[index];
|
|
1181
|
+
const existing = previous.get(key);
|
|
1182
|
+
if (existing) {
|
|
1183
|
+
applyKeyedRowBindings(range, existing, rows.items[index], index);
|
|
1184
|
+
existing.item = rows.items[index];
|
|
1185
|
+
existing.index = index;
|
|
1186
|
+
nextInstances.push(existing);
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
const element = createCompilerHostElement(
|
|
1190
|
+
this.root.ownerDocument,
|
|
1191
|
+
range.create(rows.items[index], index)
|
|
1192
|
+
);
|
|
1193
|
+
nextInstances.push({
|
|
1194
|
+
key,
|
|
1195
|
+
element,
|
|
1196
|
+
values: readKeyedRowBindingValues(range, rows.items[index], index),
|
|
1197
|
+
item: rows.items[index],
|
|
1198
|
+
index,
|
|
1199
|
+
conditionalValues: /* @__PURE__ */ new Map()
|
|
1200
|
+
});
|
|
1201
|
+
}
|
|
1202
|
+
let anchor = this.anchorAfter(rangeIndex);
|
|
1203
|
+
for (let index = nextInstances.length - 1; index >= 0; index -= 1) {
|
|
1204
|
+
const instance = nextInstances[index];
|
|
1205
|
+
if (sequence[index] < 0) {
|
|
1206
|
+
this.root.insertBefore(instance.element, anchor);
|
|
1207
|
+
} else if (!stablePositions.has(index) && instance.element.nextSibling !== anchor) {
|
|
1208
|
+
this.root.insertBefore(instance.element, anchor);
|
|
1209
|
+
}
|
|
1210
|
+
anchor = instance.element;
|
|
1211
|
+
}
|
|
1212
|
+
this.rangeInstances[rangeIndex] = new Map(
|
|
1213
|
+
nextInstances.map((instance) => [instance.key, instance])
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1216
|
+
reconcile(afterCommit) {
|
|
1217
|
+
if (!this.mounted || !this.root) {
|
|
1218
|
+
afterCommit?.();
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
if (this.state.fallback) {
|
|
1222
|
+
this.fallbackVersion += 1;
|
|
1223
|
+
this.forceUpdate(afterCommit);
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
const rowsByRange = this.readRanges(this.currentProps);
|
|
1227
|
+
if (!rowsByRange || rowsByRange.length !== this.rangeInstances.length) {
|
|
1228
|
+
this.activateFallback(afterCommit);
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
const activeElement = this.root.ownerDocument.activeElement;
|
|
1232
|
+
const restoreFocus = Boolean(activeElement && this.root.contains(activeElement));
|
|
1233
|
+
for (let rangeIndex = rowsByRange.length - 1; rangeIndex >= 0; rangeIndex -= 1) {
|
|
1234
|
+
this.reconcileRange(rangeIndex, rowsByRange[rangeIndex]);
|
|
1235
|
+
}
|
|
1236
|
+
if (restoreFocus && activeElement?.isConnected && activeElement.ownerDocument.activeElement !== activeElement && "focus" in activeElement) {
|
|
1237
|
+
activeElement.focus({ preventScroll: true });
|
|
1238
|
+
}
|
|
1239
|
+
afterCommit?.();
|
|
1240
|
+
}
|
|
1241
|
+
activateFallback(afterCommit) {
|
|
1242
|
+
if (!this.mounted || this.state.fallback || this.fallbackRequested) {
|
|
1243
|
+
afterCommit?.();
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
this.fallbackRequested = true;
|
|
1247
|
+
this.setState({ fallback: true }, afterCommit);
|
|
1248
|
+
}
|
|
1249
|
+
schedulePropFallback() {
|
|
1250
|
+
if (this.propFallbackQueued) return;
|
|
1251
|
+
this.propFallbackQueued = true;
|
|
1252
|
+
queueMicrotask(() => {
|
|
1253
|
+
this.propFallbackQueued = false;
|
|
1254
|
+
if (this.mounted && !this.state.fallback) this.activateFallback();
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
shouldComponentUpdate(nextProps, nextState) {
|
|
1258
|
+
this.currentProps = nextProps;
|
|
1259
|
+
if (nextState.fallback || this.state.fallback) return true;
|
|
1260
|
+
this.schedulePropFallback();
|
|
1261
|
+
return false;
|
|
1262
|
+
}
|
|
1263
|
+
componentDidMount() {
|
|
1264
|
+
this.mounted = true;
|
|
1265
|
+
this.unsubscribe = owner.subscribe(this.props.id, this.refresh);
|
|
1266
|
+
if (!this.adopt()) this.activateFallback();
|
|
1267
|
+
}
|
|
1268
|
+
componentWillUnmount() {
|
|
1269
|
+
this.mounted = false;
|
|
1270
|
+
this.unsubscribe?.();
|
|
1271
|
+
this.root = null;
|
|
1272
|
+
this.rangeInstances = [];
|
|
1273
|
+
this.staticSegments = [];
|
|
1274
|
+
}
|
|
1275
|
+
render() {
|
|
1276
|
+
const container = this.currentProps.render();
|
|
1277
|
+
if (!React.isValidElement(container) || typeof container.type !== "string") {
|
|
1278
|
+
throw new TypeError(
|
|
1279
|
+
`Compiled keyed ranges ${this.currentProps.id} must own one host container.`
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
return React.cloneElement(container, {
|
|
1283
|
+
key: this.state.fallback ? `react-${this.fallbackVersion}` : "compiled",
|
|
1284
|
+
ref: this.captureRoot
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
FarmKeyedRangesBlock.displayName = "FarmCompiledKeyedRanges";
|
|
1289
|
+
return FarmKeyedRangesBlock;
|
|
1290
|
+
}
|
|
903
1291
|
function createComponentBlockComponent(owner) {
|
|
904
1292
|
class FarmComponentBlock extends React.Component {
|
|
905
1293
|
constructor() {
|
|
@@ -990,12 +1378,18 @@ function createCompiledComponent(definition) {
|
|
|
990
1378
|
HostConditional: createHostConditionalBlockComponent({
|
|
991
1379
|
subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
|
|
992
1380
|
}),
|
|
1381
|
+
ConditionalRanges: createConditionalRangesBlockComponent({
|
|
1382
|
+
subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
|
|
1383
|
+
}),
|
|
993
1384
|
KeyedList: createKeyedListBlockComponent({
|
|
994
1385
|
subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
|
|
995
1386
|
}),
|
|
996
1387
|
KeyedRows: createKeyedRowsBlockComponent({
|
|
997
1388
|
subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
|
|
998
1389
|
}),
|
|
1390
|
+
KeyedRanges: createKeyedRangesBlockComponent({
|
|
1391
|
+
subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
|
|
1392
|
+
}),
|
|
999
1393
|
Component: createComponentBlockComponent({
|
|
1000
1394
|
subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
|
|
1001
1395
|
}),
|
|
@@ -1153,7 +1547,23 @@ function createCompiledComponent(definition) {
|
|
|
1153
1547
|
if (this.hasBindingError) throw this.bindingError;
|
|
1154
1548
|
const currentDefinition = definitionReference.current;
|
|
1155
1549
|
const element = currentDefinition.render(this.props, this.cells, this.blockRuntime);
|
|
1156
|
-
if (!React.isValidElement(element)
|
|
1550
|
+
if (!React.isValidElement(element)) {
|
|
1551
|
+
throw new TypeError(
|
|
1552
|
+
`Compiled component ${currentDefinition.displayName} must return one host element.`
|
|
1553
|
+
);
|
|
1554
|
+
}
|
|
1555
|
+
if (element.type === this.blockRuntime.KeyedRanges) {
|
|
1556
|
+
return React.cloneElement(element, {
|
|
1557
|
+
rootRef: this.captureRoot
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
if (element.type === this.blockRuntime.ConditionalRanges) {
|
|
1561
|
+
return React.cloneElement(
|
|
1562
|
+
element,
|
|
1563
|
+
{ rootRef: this.captureRoot }
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
if (typeof element.type !== "string") {
|
|
1157
1567
|
throw new TypeError(
|
|
1158
1568
|
`Compiled component ${currentDefinition.displayName} must return one host element.`
|
|
1159
1569
|
);
|