@sigx/runtime-terminal 0.1.4 → 0.1.5
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/dist/index.d.ts +2 -2
- package/dist/index.js +205 -114
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -13,8 +13,8 @@ export interface TerminalNode {
|
|
|
13
13
|
children: TerminalNode[];
|
|
14
14
|
parentNode?: TerminalNode | null;
|
|
15
15
|
}
|
|
16
|
-
export declare const render:
|
|
17
|
-
mount(selectorOrContainer: string | TerminalNode)
|
|
16
|
+
export declare const render: import("@sigx/runtime-core").RootRenderFunction<TerminalNode, TerminalNode>, createApp: (rootComponent: any) => {
|
|
17
|
+
mount: (selectorOrContainer: string | TerminalNode) => void;
|
|
18
18
|
};
|
|
19
19
|
export declare function renderNodeToLines(node: TerminalNode): string[];
|
|
20
20
|
type KeyHandler = (key: string) => void;
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,14 @@ const plugins$1 = [];
|
|
|
6
6
|
function getComponentPlugins$1() {
|
|
7
7
|
return plugins$1;
|
|
8
8
|
}
|
|
9
|
+
const contextExtensions = [];
|
|
10
|
+
/**
|
|
11
|
+
* Apply all registered context extensions to a context object.
|
|
12
|
+
* Called internally by the renderer when creating component contexts.
|
|
13
|
+
*/
|
|
14
|
+
function applyContextExtensions(ctx) {
|
|
15
|
+
for (const extension of contextExtensions) extension(ctx);
|
|
16
|
+
}
|
|
9
17
|
|
|
10
18
|
//#endregion
|
|
11
19
|
//#region ../runtime-core/src/app.ts
|
|
@@ -429,6 +437,195 @@ const Suspense$1 = defineComponent((ctx) => {
|
|
|
429
437
|
};
|
|
430
438
|
}, { name: "Suspense" });
|
|
431
439
|
|
|
440
|
+
//#endregion
|
|
441
|
+
//#region ../runtime-core/src/utils/props-accessor.ts
|
|
442
|
+
/**
|
|
443
|
+
* Creates a props accessor that can be called with defaults or accessed directly.
|
|
444
|
+
* After calling with defaults, direct property access uses those defaults.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```ts
|
|
448
|
+
* // In component setup:
|
|
449
|
+
* const props = createPropsAccessor(reactiveProps);
|
|
450
|
+
*
|
|
451
|
+
* // Set defaults
|
|
452
|
+
* props({ count: 0, label: 'Default' });
|
|
453
|
+
*
|
|
454
|
+
* // Access props (falls back to defaults if not provided)
|
|
455
|
+
* const count = props.count;
|
|
456
|
+
* ```
|
|
457
|
+
*/
|
|
458
|
+
function createPropsAccessor(reactiveProps) {
|
|
459
|
+
let defaults = {};
|
|
460
|
+
const proxy = new Proxy(function propsAccessor() {}, {
|
|
461
|
+
get(_, key) {
|
|
462
|
+
if (typeof key === "symbol") return void 0;
|
|
463
|
+
const value = reactiveProps[key];
|
|
464
|
+
return value != null ? value : defaults[key];
|
|
465
|
+
},
|
|
466
|
+
apply(_, __, args) {
|
|
467
|
+
if (args[0] && typeof args[0] === "object") defaults = {
|
|
468
|
+
...defaults,
|
|
469
|
+
...args[0]
|
|
470
|
+
};
|
|
471
|
+
return proxy;
|
|
472
|
+
},
|
|
473
|
+
has(_, key) {
|
|
474
|
+
if (typeof key === "symbol") return false;
|
|
475
|
+
return key in reactiveProps || key in defaults;
|
|
476
|
+
},
|
|
477
|
+
ownKeys() {
|
|
478
|
+
return [...new Set([...Object.keys(reactiveProps), ...Object.keys(defaults)])];
|
|
479
|
+
},
|
|
480
|
+
getOwnPropertyDescriptor(_, key) {
|
|
481
|
+
if (typeof key === "symbol") return void 0;
|
|
482
|
+
if (key in reactiveProps || key in defaults) return {
|
|
483
|
+
enumerable: true,
|
|
484
|
+
configurable: true,
|
|
485
|
+
writable: false
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
return proxy;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
//#endregion
|
|
493
|
+
//#region ../runtime-core/src/utils/slots.ts
|
|
494
|
+
/**
|
|
495
|
+
* Slots system for component children.
|
|
496
|
+
* Supports default and named slots with reactivity.
|
|
497
|
+
*/
|
|
498
|
+
/**
|
|
499
|
+
* Create slots object from children and slots prop.
|
|
500
|
+
* Uses a version signal to trigger re-renders when children change.
|
|
501
|
+
*
|
|
502
|
+
* Supports named slots via:
|
|
503
|
+
* - `slots` prop object (e.g., `slots={{ header: () => <div>...</div> }}`)
|
|
504
|
+
* - `slot` prop on children (e.g., `<div slot="header">...</div>`)
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* ```tsx
|
|
508
|
+
* // Parent component
|
|
509
|
+
* <Card slots={{ header: () => <h1>Title</h1> }}>
|
|
510
|
+
* <p>Default content</p>
|
|
511
|
+
* <span slot="footer">Footer text</span>
|
|
512
|
+
* </Card>
|
|
513
|
+
*
|
|
514
|
+
* // Card component setup
|
|
515
|
+
* const slots = createSlots(children, slotsFromProps);
|
|
516
|
+
* return () => (
|
|
517
|
+
* <div>
|
|
518
|
+
* {slots.header()}
|
|
519
|
+
* {slots.default()}
|
|
520
|
+
* {slots.footer()}
|
|
521
|
+
* </div>
|
|
522
|
+
* );
|
|
523
|
+
* ```
|
|
524
|
+
*/
|
|
525
|
+
function createSlots(children, slotsFromProps) {
|
|
526
|
+
const versionSignal = signal({ v: 0 });
|
|
527
|
+
function extractNamedSlotsFromChildren(c) {
|
|
528
|
+
const defaultChildren = [];
|
|
529
|
+
const namedSlots = {};
|
|
530
|
+
if (c == null) return {
|
|
531
|
+
defaultChildren,
|
|
532
|
+
namedSlots
|
|
533
|
+
};
|
|
534
|
+
const items = Array.isArray(c) ? c : [c];
|
|
535
|
+
for (const child of items) if (child && typeof child === "object" && child.props && child.props.slot) {
|
|
536
|
+
const slotName = child.props.slot;
|
|
537
|
+
if (!namedSlots[slotName]) namedSlots[slotName] = [];
|
|
538
|
+
namedSlots[slotName].push(child);
|
|
539
|
+
} else defaultChildren.push(child);
|
|
540
|
+
return {
|
|
541
|
+
defaultChildren,
|
|
542
|
+
namedSlots
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
const slotsObj = {
|
|
546
|
+
_children: children,
|
|
547
|
+
_slotsFromProps: slotsFromProps || {},
|
|
548
|
+
_version: versionSignal,
|
|
549
|
+
_isPatching: false,
|
|
550
|
+
default: function() {
|
|
551
|
+
this._version.v;
|
|
552
|
+
const c = this._children;
|
|
553
|
+
const { defaultChildren } = extractNamedSlotsFromChildren(c);
|
|
554
|
+
return defaultChildren.filter((child) => child != null && child !== false && child !== true);
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
return new Proxy(slotsObj, { get(target, prop) {
|
|
558
|
+
if (prop in target) return target[prop];
|
|
559
|
+
if (typeof prop === "string") return function(scopedProps) {
|
|
560
|
+
target._version.v;
|
|
561
|
+
if (target._slotsFromProps && typeof target._slotsFromProps[prop] === "function") {
|
|
562
|
+
const result = target._slotsFromProps[prop](scopedProps);
|
|
563
|
+
if (result == null) return [];
|
|
564
|
+
return Array.isArray(result) ? result : [result];
|
|
565
|
+
}
|
|
566
|
+
const { namedSlots } = extractNamedSlotsFromChildren(target._children);
|
|
567
|
+
return namedSlots[prop] || [];
|
|
568
|
+
};
|
|
569
|
+
} });
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
//#endregion
|
|
573
|
+
//#region ../runtime-core/src/utils/normalize.ts
|
|
574
|
+
/**
|
|
575
|
+
* VNode normalization utilities.
|
|
576
|
+
* Converts render results into proper VNode structures.
|
|
577
|
+
*/
|
|
578
|
+
/**
|
|
579
|
+
* Normalize render result to a VNode (wrapping arrays in Fragment).
|
|
580
|
+
* Handles null, undefined, false, true by returning an empty Text node.
|
|
581
|
+
*
|
|
582
|
+
* This is used to normalize the return value of component render functions
|
|
583
|
+
* into a consistent VNode structure for the renderer to process.
|
|
584
|
+
*
|
|
585
|
+
* @example
|
|
586
|
+
* ```ts
|
|
587
|
+
* // Conditional rendering returns null/false
|
|
588
|
+
* normalizeSubTree(null) // → empty Text node
|
|
589
|
+
* normalizeSubTree(false) // → empty Text node
|
|
590
|
+
*
|
|
591
|
+
* // Arrays become Fragments
|
|
592
|
+
* normalizeSubTree([<A/>, <B/>]) // → Fragment with children
|
|
593
|
+
*
|
|
594
|
+
* // Primitives become Text nodes
|
|
595
|
+
* normalizeSubTree("hello") // → Text node
|
|
596
|
+
* normalizeSubTree(42) // → Text node
|
|
597
|
+
*
|
|
598
|
+
* // VNodes pass through
|
|
599
|
+
* normalizeSubTree(<div/>) // → same VNode
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
function normalizeSubTree(result) {
|
|
603
|
+
if (result == null || result === false || result === true) return {
|
|
604
|
+
type: Text$1,
|
|
605
|
+
props: {},
|
|
606
|
+
key: null,
|
|
607
|
+
children: [],
|
|
608
|
+
dom: null,
|
|
609
|
+
text: ""
|
|
610
|
+
};
|
|
611
|
+
if (Array.isArray(result)) return {
|
|
612
|
+
type: Fragment$1,
|
|
613
|
+
props: {},
|
|
614
|
+
key: null,
|
|
615
|
+
children: result,
|
|
616
|
+
dom: null
|
|
617
|
+
};
|
|
618
|
+
if (typeof result === "string" || typeof result === "number") return {
|
|
619
|
+
type: Text$1,
|
|
620
|
+
props: {},
|
|
621
|
+
key: null,
|
|
622
|
+
children: [],
|
|
623
|
+
dom: null,
|
|
624
|
+
text: result
|
|
625
|
+
};
|
|
626
|
+
return result;
|
|
627
|
+
}
|
|
628
|
+
|
|
432
629
|
//#endregion
|
|
433
630
|
//#region ../runtime-core/src/renderer.ts
|
|
434
631
|
/**
|
|
@@ -676,43 +873,6 @@ function createRenderer(options) {
|
|
|
676
873
|
for (let i = beginIdx; i <= endIdx; i++) if (children[i] && isSameVNode(children[i], newChild)) return i;
|
|
677
874
|
return null;
|
|
678
875
|
}
|
|
679
|
-
/**
|
|
680
|
-
* Creates a props accessor that can be called with defaults or accessed directly.
|
|
681
|
-
* After calling with defaults, direct property access uses those defaults.
|
|
682
|
-
*/
|
|
683
|
-
function createPropsAccessor(reactiveProps) {
|
|
684
|
-
let defaults = {};
|
|
685
|
-
const proxy = new Proxy(function propsAccessor() {}, {
|
|
686
|
-
get(_, key) {
|
|
687
|
-
if (typeof key === "symbol") return void 0;
|
|
688
|
-
const value = reactiveProps[key];
|
|
689
|
-
return value != null ? value : defaults[key];
|
|
690
|
-
},
|
|
691
|
-
apply(_, __, args) {
|
|
692
|
-
if (args[0] && typeof args[0] === "object") defaults = {
|
|
693
|
-
...defaults,
|
|
694
|
-
...args[0]
|
|
695
|
-
};
|
|
696
|
-
return proxy;
|
|
697
|
-
},
|
|
698
|
-
has(_, key) {
|
|
699
|
-
if (typeof key === "symbol") return false;
|
|
700
|
-
return key in reactiveProps || key in defaults;
|
|
701
|
-
},
|
|
702
|
-
ownKeys() {
|
|
703
|
-
return [...new Set([...Object.keys(reactiveProps), ...Object.keys(defaults)])];
|
|
704
|
-
},
|
|
705
|
-
getOwnPropertyDescriptor(_, key) {
|
|
706
|
-
if (typeof key === "symbol") return void 0;
|
|
707
|
-
if (key in reactiveProps || key in defaults) return {
|
|
708
|
-
enumerable: true,
|
|
709
|
-
configurable: true,
|
|
710
|
-
writable: false
|
|
711
|
-
};
|
|
712
|
-
}
|
|
713
|
-
});
|
|
714
|
-
return proxy;
|
|
715
|
-
}
|
|
716
876
|
function mountComponent(vnode, container, before, setup) {
|
|
717
877
|
const anchor = hostCreateComment("");
|
|
718
878
|
vnode.dom = anchor;
|
|
@@ -753,6 +913,7 @@ function createRenderer(options) {
|
|
|
753
913
|
renderFn: null,
|
|
754
914
|
update: () => {}
|
|
755
915
|
};
|
|
916
|
+
applyContextExtensions(ctx);
|
|
756
917
|
ctx.__name = componentName;
|
|
757
918
|
if (currentAppContext) ctx._appContext = currentAppContext;
|
|
758
919
|
const componentInstance = {
|
|
@@ -763,7 +924,9 @@ function createRenderer(options) {
|
|
|
763
924
|
const prev = setCurrentInstance(ctx);
|
|
764
925
|
let renderFn;
|
|
765
926
|
try {
|
|
766
|
-
|
|
927
|
+
const setupResult = setup(ctx);
|
|
928
|
+
if (setupResult && typeof setupResult.then === "function") throw new Error(`Async setup in component "${componentName}" is only supported during SSR. On the client, use pre-loaded data from hydration or fetch in onMount.`);
|
|
929
|
+
renderFn = setupResult;
|
|
767
930
|
notifyComponentCreated(currentAppContext, componentInstance);
|
|
768
931
|
} catch (err) {
|
|
769
932
|
if (!handleComponentError(currentAppContext, err, componentInstance, "setup")) throw err;
|
|
@@ -808,84 +971,12 @@ function createRenderer(options) {
|
|
|
808
971
|
cleanupHooks.forEach((hook) => hook(mountCtx));
|
|
809
972
|
};
|
|
810
973
|
}
|
|
811
|
-
/**
|
|
812
|
-
* Create slots object from children and slots prop.
|
|
813
|
-
* Uses a version signal to trigger re-renders when children change.
|
|
814
|
-
* Supports named slots via:
|
|
815
|
-
* - `slots` prop object (e.g., slots={{ header: () => <div>...</div> }})
|
|
816
|
-
* - `slot` prop on children (e.g., <div slot="header">...</div>)
|
|
817
|
-
*/
|
|
818
|
-
function createSlots(children, slotsFromProps) {
|
|
819
|
-
const versionSignal = signal({ v: 0 });
|
|
820
|
-
function extractNamedSlotsFromChildren(c) {
|
|
821
|
-
const defaultChildren = [];
|
|
822
|
-
const namedSlots = {};
|
|
823
|
-
if (c == null) return {
|
|
824
|
-
defaultChildren,
|
|
825
|
-
namedSlots
|
|
826
|
-
};
|
|
827
|
-
const items = Array.isArray(c) ? c : [c];
|
|
828
|
-
for (const child of items) if (child && typeof child === "object" && child.props && child.props.slot) {
|
|
829
|
-
const slotName = child.props.slot;
|
|
830
|
-
if (!namedSlots[slotName]) namedSlots[slotName] = [];
|
|
831
|
-
namedSlots[slotName].push(child);
|
|
832
|
-
} else defaultChildren.push(child);
|
|
833
|
-
return {
|
|
834
|
-
defaultChildren,
|
|
835
|
-
namedSlots
|
|
836
|
-
};
|
|
837
|
-
}
|
|
838
|
-
const slotsObj = {
|
|
839
|
-
_children: children,
|
|
840
|
-
_slotsFromProps: slotsFromProps || {},
|
|
841
|
-
_version: versionSignal,
|
|
842
|
-
_isPatching: false,
|
|
843
|
-
default: function() {
|
|
844
|
-
this._version.v;
|
|
845
|
-
const c = this._children;
|
|
846
|
-
const { defaultChildren } = extractNamedSlotsFromChildren(c);
|
|
847
|
-
return defaultChildren.filter((child) => child != null && child !== false && child !== true);
|
|
848
|
-
}
|
|
849
|
-
};
|
|
850
|
-
return new Proxy(slotsObj, { get(target, prop) {
|
|
851
|
-
if (prop in target) return target[prop];
|
|
852
|
-
if (typeof prop === "string") return function(scopedProps) {
|
|
853
|
-
target._version.v;
|
|
854
|
-
if (target._slotsFromProps && typeof target._slotsFromProps[prop] === "function") {
|
|
855
|
-
const result = target._slotsFromProps[prop](scopedProps);
|
|
856
|
-
if (result == null) return [];
|
|
857
|
-
return Array.isArray(result) ? result : [result];
|
|
858
|
-
}
|
|
859
|
-
const { namedSlots } = extractNamedSlotsFromChildren(target._children);
|
|
860
|
-
return namedSlots[prop] || [];
|
|
861
|
-
};
|
|
862
|
-
} });
|
|
863
|
-
}
|
|
864
|
-
/**
|
|
865
|
-
* Normalize render result to a VNode (wrapping arrays in Fragment)
|
|
866
|
-
* Note: Falsy values (null, undefined, false, true) from conditional rendering
|
|
867
|
-
* are handled by mount() which guards against them, so no filtering needed here.
|
|
868
|
-
*/
|
|
869
|
-
function normalizeSubTree(result) {
|
|
870
|
-
if (Array.isArray(result)) return {
|
|
871
|
-
type: Fragment$1,
|
|
872
|
-
props: {},
|
|
873
|
-
key: null,
|
|
874
|
-
children: result,
|
|
875
|
-
dom: null
|
|
876
|
-
};
|
|
877
|
-
if (typeof result === "string" || typeof result === "number") return {
|
|
878
|
-
type: Text$1,
|
|
879
|
-
props: {},
|
|
880
|
-
key: null,
|
|
881
|
-
children: [],
|
|
882
|
-
dom: null,
|
|
883
|
-
text: result
|
|
884
|
-
};
|
|
885
|
-
return result;
|
|
886
|
-
}
|
|
887
974
|
return {
|
|
888
975
|
render: render$1,
|
|
976
|
+
patch,
|
|
977
|
+
mount,
|
|
978
|
+
unmount,
|
|
979
|
+
mountComponent,
|
|
889
980
|
createApp: (rootComponent) => {
|
|
890
981
|
return { mount(selectorOrContainer) {
|
|
891
982
|
let container = null;
|