@farm.js/react 0.1.0-beta.2 → 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 +34 -11
- package/dist/compiler-runtime.cjs +184 -0
- package/dist/compiler-runtime.cjs.map +1 -1
- package/dist/compiler-runtime.d.mts +19 -1
- package/dist/compiler-runtime.d.ts +19 -1
- package/dist/compiler-runtime.mjs +184 -0
- package/dist/compiler-runtime.mjs.map +1 -1
- package/dist/vite.cjs +166 -3
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.mjs +166 -3
- 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[];
|
|
@@ -134,6 +151,7 @@ interface CompilerComponentBlockProps {
|
|
|
134
151
|
interface CompilerBlockRuntime {
|
|
135
152
|
Conditional: React.ComponentType<CompilerConditionalBlockProps>;
|
|
136
153
|
HostConditional: React.ComponentType<CompilerHostConditionalBlockProps>;
|
|
154
|
+
ConditionalRanges: React.ComponentType<CompilerConditionalRangesBlockProps>;
|
|
137
155
|
KeyedList: React.ComponentType<CompilerKeyedListBlockProps>;
|
|
138
156
|
KeyedRows: React.ComponentType<CompilerKeyedRowsBlockProps>;
|
|
139
157
|
KeyedRanges: React.ComponentType<CompilerKeyedRangesBlockProps>;
|
|
@@ -160,4 +178,4 @@ interface CompiledComponentDefinition<Props> {
|
|
|
160
178
|
*/
|
|
161
179
|
declare function createCompiledComponent<Props>(definition: CompiledComponentDefinition<Props>): React.ComponentType<Props>;
|
|
162
180
|
|
|
163
|
-
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 CompilerKeyedRange, type CompilerKeyedRangesBlockProps, 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[];
|
|
@@ -134,6 +151,7 @@ interface CompilerComponentBlockProps {
|
|
|
134
151
|
interface CompilerBlockRuntime {
|
|
135
152
|
Conditional: React.ComponentType<CompilerConditionalBlockProps>;
|
|
136
153
|
HostConditional: React.ComponentType<CompilerHostConditionalBlockProps>;
|
|
154
|
+
ConditionalRanges: React.ComponentType<CompilerConditionalRangesBlockProps>;
|
|
137
155
|
KeyedList: React.ComponentType<CompilerKeyedListBlockProps>;
|
|
138
156
|
KeyedRows: React.ComponentType<CompilerKeyedRowsBlockProps>;
|
|
139
157
|
KeyedRanges: React.ComponentType<CompilerKeyedRangesBlockProps>;
|
|
@@ -160,4 +178,4 @@ interface CompiledComponentDefinition<Props> {
|
|
|
160
178
|
*/
|
|
161
179
|
declare function createCompiledComponent<Props>(definition: CompiledComponentDefinition<Props>): React.ComponentType<Props>;
|
|
162
180
|
|
|
163
|
-
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 CompilerKeyedRange, type CompilerKeyedRangesBlockProps, 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);
|
|
@@ -1203,6 +1378,9 @@ function createCompiledComponent(definition) {
|
|
|
1203
1378
|
HostConditional: createHostConditionalBlockComponent({
|
|
1204
1379
|
subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
|
|
1205
1380
|
}),
|
|
1381
|
+
ConditionalRanges: createConditionalRangesBlockComponent({
|
|
1382
|
+
subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
|
|
1383
|
+
}),
|
|
1206
1384
|
KeyedList: createKeyedListBlockComponent({
|
|
1207
1385
|
subscribe: (id, refresh) => this.subscribeToBlock(id, refresh)
|
|
1208
1386
|
}),
|
|
@@ -1379,6 +1557,12 @@ function createCompiledComponent(definition) {
|
|
|
1379
1557
|
rootRef: this.captureRoot
|
|
1380
1558
|
});
|
|
1381
1559
|
}
|
|
1560
|
+
if (element.type === this.blockRuntime.ConditionalRanges) {
|
|
1561
|
+
return React.cloneElement(
|
|
1562
|
+
element,
|
|
1563
|
+
{ rootRef: this.captureRoot }
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1382
1566
|
if (typeof element.type !== "string") {
|
|
1383
1567
|
throw new TypeError(
|
|
1384
1568
|
`Compiled component ${currentDefinition.displayName} must return one host element.`
|