@sigx/terminal 0.1.25 → 0.2.0
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.js +973 -29
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
1
2
|
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
//#endregion
|
|
4
|
+
//#region ../reactivity/src/types.ts
|
|
5
|
+
/** Symbol to identify computed values */
|
|
6
|
+
var ComputedSymbol = Symbol("computed");
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region ../reactivity/src/effect.ts
|
|
9
|
+
var activeEffect = null;
|
|
4
10
|
var batchDepth = 0;
|
|
5
11
|
var pendingEffects = /* @__PURE__ */ new Set();
|
|
6
12
|
function setActiveEffect(effect) {
|
|
@@ -9,6 +15,18 @@ function setActiveEffect(effect) {
|
|
|
9
15
|
function getActiveEffect() {
|
|
10
16
|
return activeEffect;
|
|
11
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Batch multiple reactive updates into a single flush.
|
|
20
|
+
* Effects are deferred until the batch completes, avoiding redundant re-renders.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* batch(() => {
|
|
25
|
+
* count.value++;
|
|
26
|
+
* name.value = 'Alice';
|
|
27
|
+
* }); // effects run once after both updates
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
12
30
|
function batch(fn) {
|
|
13
31
|
batchDepth++;
|
|
14
32
|
try {
|
|
@@ -59,9 +77,32 @@ function runEffect(fn) {
|
|
|
59
77
|
};
|
|
60
78
|
return runner;
|
|
61
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Create a reactive effect that re-runs whenever its tracked dependencies change.
|
|
82
|
+
* Returns a runner with a `.stop()` method to dispose the effect.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* const count = signal(0);
|
|
87
|
+
* const runner = effect(() => console.log(count.value));
|
|
88
|
+
* count.value++; // logs: 1
|
|
89
|
+
* runner.stop();
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
62
92
|
function effect(fn) {
|
|
63
93
|
return runEffect(fn);
|
|
64
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Execute a function without tracking any reactive dependencies.
|
|
97
|
+
* Useful for reading signals inside an effect without creating a subscription.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* effect(() => {
|
|
102
|
+
* const val = untrack(() => someSignal.value); // not tracked
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
65
106
|
function untrack(fn) {
|
|
66
107
|
const prev = activeEffect;
|
|
67
108
|
activeEffect = null;
|
|
@@ -71,6 +112,19 @@ function untrack(fn) {
|
|
|
71
112
|
activeEffect = prev;
|
|
72
113
|
}
|
|
73
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Create an effect scope that collects reactive effects for bulk disposal.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* const scope = effectScope();
|
|
121
|
+
* scope.run(() => {
|
|
122
|
+
* effect(() => console.log(count.value));
|
|
123
|
+
* effect(() => console.log(name.value));
|
|
124
|
+
* });
|
|
125
|
+
* scope.stop(); // disposes both effects
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
74
128
|
function effectScope(_detached) {
|
|
75
129
|
const effects = [];
|
|
76
130
|
let active = true;
|
|
@@ -85,26 +139,49 @@ function effectScope(_detached) {
|
|
|
85
139
|
}
|
|
86
140
|
};
|
|
87
141
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region ../reactivity/src/collections.ts
|
|
144
|
+
/** Symbol for tracking iteration dependencies (forEach, keys, values, entries, size) */
|
|
145
|
+
var ITERATE_KEY = Symbol("iterate");
|
|
146
|
+
/** WeakMap to get raw object from reactive proxy */
|
|
147
|
+
var reactiveToRaw = /* @__PURE__ */ new WeakMap();
|
|
148
|
+
/** WeakMap to get reactive proxy from raw object */
|
|
149
|
+
var rawToReactive = /* @__PURE__ */ new WeakMap();
|
|
150
|
+
/**
|
|
151
|
+
* Returns the raw, original object from a reactive proxy.
|
|
152
|
+
* If the value is not a proxy, returns it as-is.
|
|
153
|
+
*/
|
|
91
154
|
function toRaw(observed) {
|
|
92
155
|
const raw = reactiveToRaw.get(observed);
|
|
93
156
|
return raw ? toRaw(raw) : observed;
|
|
94
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Checks if a value is a reactive proxy created by signal().
|
|
160
|
+
*/
|
|
95
161
|
function isReactive(value) {
|
|
96
162
|
return reactiveToRaw.has(value);
|
|
97
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Checks if a value is a collection type (Set, Map, WeakSet, WeakMap).
|
|
166
|
+
*/
|
|
98
167
|
function isCollection(value) {
|
|
99
168
|
if (!value || typeof value !== "object") return false;
|
|
100
169
|
const ctor = value.constructor;
|
|
101
170
|
return ctor === Set || ctor === Map || ctor === WeakSet || ctor === WeakMap;
|
|
102
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Checks if a value is an iterable collection (Set or Map, not Weak variants).
|
|
174
|
+
*/
|
|
103
175
|
function isIterableCollection(value) {
|
|
104
176
|
if (!value || typeof value !== "object") return false;
|
|
105
177
|
const ctor = value.constructor;
|
|
106
178
|
return ctor === Set || ctor === Map;
|
|
107
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Checks if a value is an "exotic" built-in object that should NOT be proxied.
|
|
182
|
+
* These objects have internal slots that cannot be accessed through Proxy.
|
|
183
|
+
* Proxying them causes errors like "Method X called on incompatible receiver".
|
|
184
|
+
*/
|
|
108
185
|
function shouldNotProxy(value) {
|
|
109
186
|
if (!value || typeof value !== "object") return false;
|
|
110
187
|
const proto = Object.prototype.toString.call(value);
|
|
@@ -128,6 +205,11 @@ function shouldNotProxy(value) {
|
|
|
128
205
|
"[object BigUint64Array]"
|
|
129
206
|
].includes(proto);
|
|
130
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Creates instrumented collection methods that properly handle reactivity.
|
|
210
|
+
* These methods call the real collection methods on the raw object while
|
|
211
|
+
* tracking dependencies and triggering updates.
|
|
212
|
+
*/
|
|
131
213
|
function createCollectionInstrumentations(depsMap, getOrCreateDep) {
|
|
132
214
|
const instrumentations = {};
|
|
133
215
|
instrumentations.has = function(key) {
|
|
@@ -230,6 +312,9 @@ function createCollectionInstrumentations(depsMap, getOrCreateDep) {
|
|
|
230
312
|
};
|
|
231
313
|
return instrumentations;
|
|
232
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* Creates a reactive iterator that wraps values in reactive proxies.
|
|
317
|
+
*/
|
|
233
318
|
function createReactiveIterator(innerIterator, wrapValues) {
|
|
234
319
|
return {
|
|
235
320
|
next() {
|
|
@@ -248,6 +333,9 @@ function createReactiveIterator(innerIterator, wrapValues) {
|
|
|
248
333
|
}
|
|
249
334
|
};
|
|
250
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Creates a reactive entries iterator that wraps both keys and values.
|
|
338
|
+
*/
|
|
251
339
|
function createReactiveEntriesIterator(innerIterator) {
|
|
252
340
|
return {
|
|
253
341
|
next() {
|
|
@@ -267,18 +355,37 @@ function createReactiveEntriesIterator(innerIterator) {
|
|
|
267
355
|
}
|
|
268
356
|
};
|
|
269
357
|
}
|
|
358
|
+
//#endregion
|
|
359
|
+
//#region ../reactivity/src/signal.ts
|
|
360
|
+
/** Check if a value is a primitive type */
|
|
270
361
|
function isPrimitive(value) {
|
|
271
362
|
if (value === null || value === void 0) return true;
|
|
272
363
|
const type = typeof value;
|
|
273
364
|
return type === "string" || type === "number" || type === "boolean" || type === "symbol" || type === "bigint";
|
|
274
365
|
}
|
|
275
366
|
var accessObserver = null;
|
|
367
|
+
/** @internal Get the current access observer for computed/model integration */
|
|
276
368
|
function getAccessObserver() {
|
|
277
369
|
return accessObserver;
|
|
278
370
|
}
|
|
371
|
+
/** @internal Temporarily suspend the access observer (used by computed to prevent leakage) */
|
|
279
372
|
function setAccessObserver(observer) {
|
|
280
373
|
accessObserver = observer;
|
|
281
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* Detect which reactive property a selector function accesses.
|
|
377
|
+
*
|
|
378
|
+
* Runs `selector()` while observing property accesses and returns the
|
|
379
|
+
* last `[target, key]` pair accessed, or `null` if nothing was read.
|
|
380
|
+
* Used internally by the model/two-way-binding system.
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* ```ts
|
|
384
|
+
* const state = signal({ form: { name: 'Alice' } });
|
|
385
|
+
* const result = detectAccess(() => state.form.name);
|
|
386
|
+
* // result === [state.form, 'name']
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
282
389
|
function detectAccess(selector) {
|
|
283
390
|
let result = null;
|
|
284
391
|
const prev = accessObserver;
|
|
@@ -415,6 +522,14 @@ function signal(target) {
|
|
|
415
522
|
rawToReactive.set(objectTarget, proxy);
|
|
416
523
|
return proxy;
|
|
417
524
|
}
|
|
525
|
+
//#endregion
|
|
526
|
+
//#region ../reactivity/src/watch.ts
|
|
527
|
+
/**
|
|
528
|
+
* Deeply traverses an object to trigger reactive tracking on all nested properties.
|
|
529
|
+
* @param value The value to traverse
|
|
530
|
+
* @param depth Maximum depth to traverse (Infinity for unlimited, number for limited)
|
|
531
|
+
* @param seen Set of already visited objects to prevent circular references
|
|
532
|
+
*/
|
|
418
533
|
function traverse(value, depth = Infinity, seen = /* @__PURE__ */ new Set()) {
|
|
419
534
|
if (depth <= 0) return value;
|
|
420
535
|
if (value === null || typeof value !== "object") return value;
|
|
@@ -431,6 +546,19 @@ function traverse(value, depth = Infinity, seen = /* @__PURE__ */ new Set()) {
|
|
|
431
546
|
else for (const key of Object.keys(value)) traverse(value[key], depth - 1, seen);
|
|
432
547
|
return value;
|
|
433
548
|
}
|
|
549
|
+
/**
|
|
550
|
+
* Watch a reactive source and run a callback when it changes.
|
|
551
|
+
* Supports deep watching, immediate invocation, and pause/resume.
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
* ```ts
|
|
555
|
+
* const count = signal(0);
|
|
556
|
+
* const handle = watch(() => count.value, (newVal, oldVal) => {
|
|
557
|
+
* console.log(`${oldVal} → ${newVal}`);
|
|
558
|
+
* });
|
|
559
|
+
* handle.stop(); // stop watching
|
|
560
|
+
* ```
|
|
561
|
+
*/
|
|
434
562
|
function watch(source, cb, options) {
|
|
435
563
|
let oldValue;
|
|
436
564
|
let isFirst = true;
|
|
@@ -495,6 +623,8 @@ function watch(source, cb, options) {
|
|
|
495
623
|
resume
|
|
496
624
|
});
|
|
497
625
|
}
|
|
626
|
+
//#endregion
|
|
627
|
+
//#region ../reactivity/src/computed.ts
|
|
498
628
|
function computed(getterOrOptions) {
|
|
499
629
|
let getter;
|
|
500
630
|
let setter;
|
|
@@ -562,20 +692,47 @@ function computed(getterOrOptions) {
|
|
|
562
692
|
}
|
|
563
693
|
return computedObj;
|
|
564
694
|
}
|
|
695
|
+
/**
|
|
696
|
+
* Type guard to check if a value is a computed signal.
|
|
697
|
+
*
|
|
698
|
+
* @example
|
|
699
|
+
* ```ts
|
|
700
|
+
* const doubled = computed(() => count.value * 2);
|
|
701
|
+
* console.log(isComputed(doubled)); // true
|
|
702
|
+
* console.log(isComputed({ value: 1 })); // false
|
|
703
|
+
* ```
|
|
704
|
+
*/
|
|
565
705
|
function isComputed(value) {
|
|
566
706
|
return value !== null && typeof value === "object" && ComputedSymbol in value;
|
|
567
707
|
}
|
|
708
|
+
//#endregion
|
|
709
|
+
//#region ../runtime-core/src/plugins.ts
|
|
568
710
|
var plugins = [];
|
|
711
|
+
/**
|
|
712
|
+
* Get all registered plugins (internal use)
|
|
713
|
+
*/
|
|
569
714
|
function getComponentPlugins() {
|
|
570
715
|
return plugins;
|
|
571
716
|
}
|
|
572
717
|
var contextExtensions = [];
|
|
718
|
+
/**
|
|
719
|
+
* Apply all registered context extensions to a context object.
|
|
720
|
+
* Called internally by the renderer when creating component contexts.
|
|
721
|
+
*/
|
|
573
722
|
function applyContextExtensions(ctx) {
|
|
574
723
|
for (const extension of contextExtensions) extension(ctx);
|
|
575
724
|
}
|
|
725
|
+
//#endregion
|
|
726
|
+
//#region __vite-browser-external
|
|
576
727
|
var require___vite_browser_external = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
577
728
|
module.exports = {};
|
|
578
729
|
}));
|
|
730
|
+
//#endregion
|
|
731
|
+
//#region ../runtime-core/src/async-context.ts
|
|
732
|
+
/**
|
|
733
|
+
* Try to load AsyncLocalStorage from Node.js.
|
|
734
|
+
* Returns null in browser environments.
|
|
735
|
+
*/
|
|
579
736
|
var asyncLocalStorage = null;
|
|
580
737
|
try {
|
|
581
738
|
if (typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined") {
|
|
@@ -587,6 +744,10 @@ var _fallbackContext = {
|
|
|
587
744
|
currentComponentContext: null,
|
|
588
745
|
currentSuspenseBoundary: null
|
|
589
746
|
};
|
|
747
|
+
/**
|
|
748
|
+
* Get the current request context.
|
|
749
|
+
* Returns the AsyncLocalStorage store if available, otherwise the module-level fallback.
|
|
750
|
+
*/
|
|
590
751
|
function getRequestContext() {
|
|
591
752
|
if (asyncLocalStorage) {
|
|
592
753
|
const store = asyncLocalStorage.getStore();
|
|
@@ -594,25 +755,56 @@ function getRequestContext() {
|
|
|
594
755
|
}
|
|
595
756
|
return _fallbackContext;
|
|
596
757
|
}
|
|
758
|
+
/**
|
|
759
|
+
* Get the current component context (request-safe).
|
|
760
|
+
*/
|
|
597
761
|
function getCurrentInstanceSafe() {
|
|
598
762
|
return getRequestContext().currentComponentContext;
|
|
599
763
|
}
|
|
764
|
+
/**
|
|
765
|
+
* Set the current component context (request-safe).
|
|
766
|
+
* Returns the previous value.
|
|
767
|
+
*/
|
|
600
768
|
function setCurrentInstanceSafe(ctx) {
|
|
601
769
|
const reqCtx = getRequestContext();
|
|
602
770
|
const prev = reqCtx.currentComponentContext;
|
|
603
771
|
reqCtx.currentComponentContext = ctx;
|
|
604
772
|
return prev;
|
|
605
773
|
}
|
|
774
|
+
/**
|
|
775
|
+
* Get the current suspense boundary (request-safe).
|
|
776
|
+
*/
|
|
606
777
|
function getCurrentSuspenseBoundarySafe() {
|
|
607
778
|
return getRequestContext().currentSuspenseBoundary;
|
|
608
779
|
}
|
|
780
|
+
/**
|
|
781
|
+
* Set the current suspense boundary (request-safe).
|
|
782
|
+
* Returns the previous value.
|
|
783
|
+
*/
|
|
609
784
|
function setCurrentSuspenseBoundarySafe(boundary) {
|
|
610
785
|
const reqCtx = getRequestContext();
|
|
611
786
|
const prev = reqCtx.currentSuspenseBoundary;
|
|
612
787
|
reqCtx.currentSuspenseBoundary = boundary;
|
|
613
788
|
return prev;
|
|
614
789
|
}
|
|
790
|
+
//#endregion
|
|
791
|
+
//#region ../runtime-core/src/component.ts
|
|
615
792
|
var currentComponentContext = null;
|
|
793
|
+
/**
|
|
794
|
+
* Returns the setup context of the currently executing component, or `null` if called outside setup.
|
|
795
|
+
*
|
|
796
|
+
* Use this to access the component context (props, emit, etc.) from composable functions
|
|
797
|
+
* or lifecycle hooks that run during component setup.
|
|
798
|
+
*
|
|
799
|
+
* @example
|
|
800
|
+
* ```ts
|
|
801
|
+
* function useMyComposable() {
|
|
802
|
+
* const ctx = getCurrentInstance();
|
|
803
|
+
* if (!ctx) throw new Error('Must be called during component setup');
|
|
804
|
+
* ctx.onMounted(({ el }) => console.log('Mounted to', el));
|
|
805
|
+
* }
|
|
806
|
+
* ```
|
|
807
|
+
*/
|
|
616
808
|
function getCurrentInstance() {
|
|
617
809
|
return getCurrentInstanceSafe() ?? currentComponentContext;
|
|
618
810
|
}
|
|
@@ -622,26 +814,108 @@ function setCurrentInstance(ctx) {
|
|
|
622
814
|
currentComponentContext = ctx;
|
|
623
815
|
return prevSafe ?? prevModule;
|
|
624
816
|
}
|
|
817
|
+
/**
|
|
818
|
+
* Register a callback to run after the component is mounted to the DOM.
|
|
819
|
+
* Must be called during component setup.
|
|
820
|
+
*
|
|
821
|
+
* @param fn - Callback receiving a {@link MountContext} with the component's root element.
|
|
822
|
+
*
|
|
823
|
+
* @example
|
|
824
|
+
* ```ts
|
|
825
|
+
* const MyComponent = component(() => {
|
|
826
|
+
* onMounted(({ el }) => {
|
|
827
|
+
* console.log('Mounted to', el);
|
|
828
|
+
* });
|
|
829
|
+
* return () => <div>Hello</div>;
|
|
830
|
+
* });
|
|
831
|
+
* ```
|
|
832
|
+
*/
|
|
625
833
|
function onMounted(fn) {
|
|
626
834
|
if (currentComponentContext) currentComponentContext.onMounted(fn);
|
|
627
835
|
else console.warn("onMounted called outside of component setup");
|
|
628
836
|
}
|
|
837
|
+
/**
|
|
838
|
+
* Register a callback to run when the component is unmounted from the DOM.
|
|
839
|
+
* Must be called during component setup. Use for cleanup (event listeners, timers, subscriptions).
|
|
840
|
+
*
|
|
841
|
+
* @param fn - Callback receiving a {@link MountContext} with the component's root element.
|
|
842
|
+
*
|
|
843
|
+
* @example
|
|
844
|
+
* ```ts
|
|
845
|
+
* const MyComponent = component(() => {
|
|
846
|
+
* const timer = setInterval(() => tick(), 1000);
|
|
847
|
+
* onUnmounted(() => clearInterval(timer));
|
|
848
|
+
* return () => <div>Tick</div>;
|
|
849
|
+
* });
|
|
850
|
+
* ```
|
|
851
|
+
*/
|
|
629
852
|
function onUnmounted(fn) {
|
|
630
853
|
if (currentComponentContext) currentComponentContext.onUnmounted(fn);
|
|
631
854
|
else console.warn("onUnmounted called outside of component setup");
|
|
632
855
|
}
|
|
856
|
+
/**
|
|
857
|
+
* Register a callback to run immediately after component setup completes,
|
|
858
|
+
* before the first render. Must be called during component setup.
|
|
859
|
+
*
|
|
860
|
+
* @example
|
|
861
|
+
* ```ts
|
|
862
|
+
* const MyComponent = component(() => {
|
|
863
|
+
* onCreated(() => console.log('Setup done, about to render'));
|
|
864
|
+
* return () => <div>Hello</div>;
|
|
865
|
+
* });
|
|
866
|
+
* ```
|
|
867
|
+
*/
|
|
633
868
|
function onCreated(fn) {
|
|
634
869
|
if (currentComponentContext) currentComponentContext.onCreated(fn);
|
|
635
870
|
else console.warn("onCreated called outside of component setup");
|
|
636
871
|
}
|
|
872
|
+
/**
|
|
873
|
+
* Register a callback to run after every reactive re-render of the component.
|
|
874
|
+
* Must be called during component setup.
|
|
875
|
+
*
|
|
876
|
+
* @example
|
|
877
|
+
* ```ts
|
|
878
|
+
* const Counter = component(() => {
|
|
879
|
+
* const state = signal({ count: 0 });
|
|
880
|
+
* onUpdated(() => console.log('Re-rendered with count:', state.count));
|
|
881
|
+
* return () => <button onClick={() => state.count++}>{state.count}</button>;
|
|
882
|
+
* });
|
|
883
|
+
* ```
|
|
884
|
+
*/
|
|
637
885
|
function onUpdated(fn) {
|
|
638
886
|
if (currentComponentContext) currentComponentContext.onUpdated(fn);
|
|
639
887
|
else console.warn("onUpdated called outside of component setup");
|
|
640
888
|
}
|
|
641
889
|
var componentRegistry = /* @__PURE__ */ new Map();
|
|
890
|
+
/**
|
|
891
|
+
* Get component metadata (for DevTools)
|
|
892
|
+
*/
|
|
642
893
|
function getComponentMeta(factory) {
|
|
643
894
|
return componentRegistry.get(factory);
|
|
644
895
|
}
|
|
896
|
+
/**
|
|
897
|
+
* Define a component. Returns a JSX factory function.
|
|
898
|
+
*
|
|
899
|
+
* @param setup - Setup function that receives context and returns a render function
|
|
900
|
+
* @param options - Optional configuration (e.g., name for DevTools)
|
|
901
|
+
*
|
|
902
|
+
* @example
|
|
903
|
+
* ```tsx
|
|
904
|
+
* type CardProps = DefineProp<"title", string> & DefineSlot<"header">;
|
|
905
|
+
*
|
|
906
|
+
* export const Card = component<CardProps>((ctx) => {
|
|
907
|
+
* const { title } = ctx.props;
|
|
908
|
+
* const { slots } = ctx;
|
|
909
|
+
*
|
|
910
|
+
* return () => (
|
|
911
|
+
* <div class="card">
|
|
912
|
+
* {slots.header?.() ?? <h2>{title}</h2>}
|
|
913
|
+
* {slots.default()}
|
|
914
|
+
* </div>
|
|
915
|
+
* );
|
|
916
|
+
* });
|
|
917
|
+
* ```
|
|
918
|
+
*/
|
|
645
919
|
function component(setup, options) {
|
|
646
920
|
const factory = function(props) {
|
|
647
921
|
return {
|
|
@@ -665,6 +939,28 @@ function component(setup, options) {
|
|
|
665
939
|
getComponentPlugins().forEach((p) => p.onDefine?.(options?.name, factory, setup));
|
|
666
940
|
return factory;
|
|
667
941
|
}
|
|
942
|
+
//#endregion
|
|
943
|
+
//#region ../runtime-core/src/errors.ts
|
|
944
|
+
/**
|
|
945
|
+
* Structured error system for SignalX runtime.
|
|
946
|
+
*
|
|
947
|
+
* Every runtime error has a unique code (SIGX001–SIGX999) so users can
|
|
948
|
+
* programmatically handle errors and look them up in documentation.
|
|
949
|
+
*
|
|
950
|
+
* @example
|
|
951
|
+
* ```ts
|
|
952
|
+
* try {
|
|
953
|
+
* app.mount('#app');
|
|
954
|
+
* } catch (e) {
|
|
955
|
+
* if (e instanceof SigxError && e.code === 'SIGX101') {
|
|
956
|
+
* // handle missing mount target
|
|
957
|
+
* }
|
|
958
|
+
* }
|
|
959
|
+
* ```
|
|
960
|
+
*/
|
|
961
|
+
/**
|
|
962
|
+
* Base error class for all SignalX runtime errors.
|
|
963
|
+
*/
|
|
668
964
|
var SigxError = class extends Error {
|
|
669
965
|
constructor(message, options) {
|
|
670
966
|
super(message);
|
|
@@ -674,7 +970,15 @@ var SigxError = class extends Error {
|
|
|
674
970
|
if (options.cause) this.cause = options.cause;
|
|
675
971
|
}
|
|
676
972
|
};
|
|
677
|
-
|
|
973
|
+
/**
|
|
974
|
+
* Error codes for the SignalX runtime.
|
|
975
|
+
*
|
|
976
|
+
* Ranges:
|
|
977
|
+
* - SIGX001–SIGX099: App lifecycle
|
|
978
|
+
* - SIGX100–SIGX199: Rendering / mounting
|
|
979
|
+
* - SIGX200–SIGX299: Dependency injection
|
|
980
|
+
*/
|
|
981
|
+
var SigxErrorCode = {
|
|
678
982
|
NO_MOUNT_FUNCTION: "SIGX001",
|
|
679
983
|
RENDER_TARGET_NOT_FOUND: "SIGX100",
|
|
680
984
|
MOUNT_TARGET_NOT_FOUND: "SIGX101",
|
|
@@ -718,8 +1022,23 @@ function provideInvalidInjectableError() {
|
|
|
718
1022
|
suggestion: "Create an injectable first:\n const useMyService = defineInjectable(() => new MyService());\n defineProvide(useMyService);"
|
|
719
1023
|
});
|
|
720
1024
|
}
|
|
1025
|
+
//#endregion
|
|
1026
|
+
//#region ../runtime-core/src/di/injectable.ts
|
|
1027
|
+
/**
|
|
1028
|
+
* Global singleton instances (fallback when no provider found)
|
|
1029
|
+
*/
|
|
721
1030
|
var globalInstances = /* @__PURE__ */ new Map();
|
|
1031
|
+
/**
|
|
1032
|
+
* Token for the AppContext injectable.
|
|
1033
|
+
* Used to provide/lookup the AppContext in the component tree.
|
|
1034
|
+
*/
|
|
722
1035
|
var appContextToken = Symbol("sigx:appContext");
|
|
1036
|
+
/**
|
|
1037
|
+
* Lookup a provided value by token, traversing component tree.
|
|
1038
|
+
* The AppContext is provided at the root component level, so it's found
|
|
1039
|
+
* just like any other provided value.
|
|
1040
|
+
* @internal
|
|
1041
|
+
*/
|
|
723
1042
|
function lookupProvided(token) {
|
|
724
1043
|
const ctx = getCurrentInstance();
|
|
725
1044
|
if (!ctx) return;
|
|
@@ -729,6 +1048,10 @@ function lookupProvided(token) {
|
|
|
729
1048
|
current = current.parent;
|
|
730
1049
|
}
|
|
731
1050
|
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Provide a value at the current component level
|
|
1053
|
+
* @internal
|
|
1054
|
+
*/
|
|
732
1055
|
function provideAtComponent(token, value) {
|
|
733
1056
|
const ctx = getCurrentInstance();
|
|
734
1057
|
if (!ctx) throw provideOutsideSetupError();
|
|
@@ -736,6 +1059,26 @@ function provideAtComponent(token, value) {
|
|
|
736
1059
|
if (!node.provides) node.provides = /* @__PURE__ */ new Map();
|
|
737
1060
|
node.provides.set(token, value);
|
|
738
1061
|
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Define an injectable service/value that can be provided at app or component level.
|
|
1064
|
+
*
|
|
1065
|
+
* The returned function can be called to get the current instance:
|
|
1066
|
+
* - If provided at component level via `defineProvide()`, returns that instance
|
|
1067
|
+
* - If provided at app level via `app.defineProvide()`, returns that instance
|
|
1068
|
+
* - Otherwise falls back to a global singleton created by the factory
|
|
1069
|
+
*
|
|
1070
|
+
* @example
|
|
1071
|
+
* ```typescript
|
|
1072
|
+
* // Define a service
|
|
1073
|
+
* const useApiConfig = defineInjectable(() => ({
|
|
1074
|
+
* baseUrl: 'https://api.example.com'
|
|
1075
|
+
* }));
|
|
1076
|
+
*
|
|
1077
|
+
* // Use it in any component - gets nearest provided instance or global singleton
|
|
1078
|
+
* const config = useApiConfig();
|
|
1079
|
+
* console.log(config.baseUrl);
|
|
1080
|
+
* ```
|
|
1081
|
+
*/
|
|
739
1082
|
function defineInjectable(factory) {
|
|
740
1083
|
const token = Symbol();
|
|
741
1084
|
const useFn = (() => {
|
|
@@ -748,6 +1091,34 @@ function defineInjectable(factory) {
|
|
|
748
1091
|
useFn._token = token;
|
|
749
1092
|
return useFn;
|
|
750
1093
|
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Provide a new instance of an injectable at the current component level.
|
|
1096
|
+
* Child components will receive this instance when calling the injectable function.
|
|
1097
|
+
*
|
|
1098
|
+
* @param useFn - The injectable function created by defineInjectable
|
|
1099
|
+
* @param factory - Optional custom factory to create the instance (overrides default)
|
|
1100
|
+
*
|
|
1101
|
+
* @example
|
|
1102
|
+
* ```typescript
|
|
1103
|
+
* const useApiConfig = defineInjectable(() => ({ baseUrl: 'https://api.example.com' }));
|
|
1104
|
+
*
|
|
1105
|
+
* const MyComponent = component(() => {
|
|
1106
|
+
* // Create and provide a new instance for this subtree
|
|
1107
|
+
* const config = defineProvide(useApiConfig);
|
|
1108
|
+
* config.baseUrl = 'https://custom.api.com';
|
|
1109
|
+
*
|
|
1110
|
+
* return () => <ChildComponent />;
|
|
1111
|
+
* });
|
|
1112
|
+
*
|
|
1113
|
+
* // Or provide a pre-constructed instance:
|
|
1114
|
+
* const MyComponent2 = component(() => {
|
|
1115
|
+
* const customService = createMyService({ custom: 'options' });
|
|
1116
|
+
* defineProvide(useMyService, () => customService);
|
|
1117
|
+
*
|
|
1118
|
+
* return () => <ChildComponent />;
|
|
1119
|
+
* });
|
|
1120
|
+
* ```
|
|
1121
|
+
*/
|
|
751
1122
|
function defineProvide(useFn, factory) {
|
|
752
1123
|
const actualFactory = factory ?? useFn._factory;
|
|
753
1124
|
const token = useFn._token;
|
|
@@ -756,31 +1127,110 @@ function defineProvide(useFn, factory) {
|
|
|
756
1127
|
provideAtComponent(token, instance);
|
|
757
1128
|
return instance;
|
|
758
1129
|
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Get the current AppContext from the component tree.
|
|
1132
|
+
* The AppContext is provided at the root component level during mount/hydrate/SSR.
|
|
1133
|
+
*
|
|
1134
|
+
* @example
|
|
1135
|
+
* ```typescript
|
|
1136
|
+
* const appContext = useAppContext();
|
|
1137
|
+
* console.log(appContext?.app);
|
|
1138
|
+
* ```
|
|
1139
|
+
*/
|
|
759
1140
|
function useAppContext() {
|
|
760
1141
|
return lookupProvided(appContextToken) ?? null;
|
|
761
1142
|
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Get the AppContext token.
|
|
1145
|
+
* Used by renderers to provide the AppContext at the root component level.
|
|
1146
|
+
* @internal
|
|
1147
|
+
*/
|
|
762
1148
|
function getAppContextToken() {
|
|
763
1149
|
return appContextToken;
|
|
764
1150
|
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Provide the AppContext on a component's provides Map.
|
|
1153
|
+
* Called by the renderer for the ROOT component only.
|
|
1154
|
+
* @internal
|
|
1155
|
+
*/
|
|
765
1156
|
function provideAppContext(ctx, appContext) {
|
|
766
1157
|
const node = ctx;
|
|
767
1158
|
if (!node.provides) node.provides = /* @__PURE__ */ new Map();
|
|
768
1159
|
node.provides.set(appContextToken, appContext);
|
|
769
1160
|
if (appContext.provides) for (const [token, value] of appContext.provides) node.provides.set(token, value);
|
|
770
1161
|
}
|
|
771
|
-
|
|
1162
|
+
//#endregion
|
|
1163
|
+
//#region ../runtime-core/src/directives.ts
|
|
1164
|
+
/**
|
|
1165
|
+
* Marker symbol to identify directive definitions.
|
|
1166
|
+
* @internal
|
|
1167
|
+
*/
|
|
1168
|
+
var __DIRECTIVE__ = Symbol.for("sigx.directive");
|
|
1169
|
+
/**
|
|
1170
|
+
* Define a directive. This is an identity function that marks the definition
|
|
1171
|
+
* for type inference and runtime identification.
|
|
1172
|
+
*
|
|
1173
|
+
* @example
|
|
1174
|
+
* ```ts
|
|
1175
|
+
* const highlight = defineDirective<string>({
|
|
1176
|
+
* mounted(el, { value }) {
|
|
1177
|
+
* el.style.backgroundColor = value;
|
|
1178
|
+
* },
|
|
1179
|
+
* updated(el, { value }) {
|
|
1180
|
+
* el.style.backgroundColor = value;
|
|
1181
|
+
* }
|
|
1182
|
+
* });
|
|
1183
|
+
* ```
|
|
1184
|
+
*/
|
|
772
1185
|
function defineDirective(definition) {
|
|
773
1186
|
definition[__DIRECTIVE__] = true;
|
|
774
1187
|
return definition;
|
|
775
1188
|
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Check if a value is a directive definition.
|
|
1191
|
+
*/
|
|
776
1192
|
function isDirective(value) {
|
|
777
1193
|
return value != null && typeof value === "object" && value[__DIRECTIVE__] === true;
|
|
778
1194
|
}
|
|
1195
|
+
//#endregion
|
|
1196
|
+
//#region ../runtime-core/src/app.ts
|
|
779
1197
|
var isDev = typeof process !== "undefined" && process.env.NODE_ENV !== "production" || true;
|
|
780
1198
|
var defaultMountFn = null;
|
|
1199
|
+
/**
|
|
1200
|
+
* Set the default mount function for the platform.
|
|
1201
|
+
* Called by platform packages (runtime-dom, runtime-terminal) on import.
|
|
1202
|
+
*
|
|
1203
|
+
* @example
|
|
1204
|
+
* ```typescript
|
|
1205
|
+
* // In @sigx/runtime-dom
|
|
1206
|
+
* import { setDefaultMount } from '@sigx/runtime-core';
|
|
1207
|
+
* setDefaultMount(domMount);
|
|
1208
|
+
* ```
|
|
1209
|
+
*/
|
|
781
1210
|
function setDefaultMount(mountFn) {
|
|
782
1211
|
defaultMountFn = mountFn;
|
|
783
1212
|
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Create an application instance.
|
|
1215
|
+
*
|
|
1216
|
+
* @example
|
|
1217
|
+
* ```tsx
|
|
1218
|
+
* import { defineApp, defineInjectable } from '@sigx/runtime-core';
|
|
1219
|
+
*
|
|
1220
|
+
* // Define an injectable service
|
|
1221
|
+
* const useApiConfig = defineInjectable(() => ({ baseUrl: 'https://api.example.com' }));
|
|
1222
|
+
*
|
|
1223
|
+
* const app = defineApp(<App />);
|
|
1224
|
+
*
|
|
1225
|
+
* app.use(myPlugin, { option: 'value' });
|
|
1226
|
+
*
|
|
1227
|
+
* // Provide custom instance at app level
|
|
1228
|
+
* const config = app.defineProvide(useApiConfig);
|
|
1229
|
+
* config.baseUrl = 'https://custom.api.com';
|
|
1230
|
+
*
|
|
1231
|
+
* app.mount(document.getElementById('app')!);
|
|
1232
|
+
* ```
|
|
1233
|
+
*/
|
|
784
1234
|
function defineApp(rootComponent) {
|
|
785
1235
|
const installedPlugins = /* @__PURE__ */ new Set();
|
|
786
1236
|
const context = {
|
|
@@ -867,6 +1317,10 @@ function defineApp(rootComponent) {
|
|
|
867
1317
|
context.provides.set(appContextToken, context);
|
|
868
1318
|
return app;
|
|
869
1319
|
}
|
|
1320
|
+
/**
|
|
1321
|
+
* Notify all app hooks that a component was created.
|
|
1322
|
+
* Called by the renderer after setup() returns.
|
|
1323
|
+
*/
|
|
870
1324
|
function notifyComponentCreated(context, instance) {
|
|
871
1325
|
if (!context) return;
|
|
872
1326
|
for (const hooks of context.hooks) try {
|
|
@@ -875,6 +1329,10 @@ function notifyComponentCreated(context, instance) {
|
|
|
875
1329
|
handleHookError(context, err, instance, "onComponentCreated");
|
|
876
1330
|
}
|
|
877
1331
|
}
|
|
1332
|
+
/**
|
|
1333
|
+
* Notify all app hooks that a component was mounted.
|
|
1334
|
+
* Called by the renderer after mount hooks run.
|
|
1335
|
+
*/
|
|
878
1336
|
function notifyComponentMounted(context, instance) {
|
|
879
1337
|
if (!context) return;
|
|
880
1338
|
for (const hooks of context.hooks) try {
|
|
@@ -883,6 +1341,10 @@ function notifyComponentMounted(context, instance) {
|
|
|
883
1341
|
handleHookError(context, err, instance, "onComponentMounted");
|
|
884
1342
|
}
|
|
885
1343
|
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Notify all app hooks that a component was unmounted.
|
|
1346
|
+
* Called by the renderer before cleanup.
|
|
1347
|
+
*/
|
|
886
1348
|
function notifyComponentUnmounted(context, instance) {
|
|
887
1349
|
if (!context) return;
|
|
888
1350
|
for (const hooks of context.hooks) try {
|
|
@@ -891,6 +1353,10 @@ function notifyComponentUnmounted(context, instance) {
|
|
|
891
1353
|
handleHookError(context, err, instance, "onComponentUnmounted");
|
|
892
1354
|
}
|
|
893
1355
|
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Notify all app hooks that a component updated.
|
|
1358
|
+
* Called by the renderer after re-render.
|
|
1359
|
+
*/
|
|
894
1360
|
function notifyComponentUpdated(context, instance) {
|
|
895
1361
|
if (!context) return;
|
|
896
1362
|
for (const hooks of context.hooks) try {
|
|
@@ -899,6 +1365,10 @@ function notifyComponentUpdated(context, instance) {
|
|
|
899
1365
|
handleHookError(context, err, instance, "onComponentUpdated");
|
|
900
1366
|
}
|
|
901
1367
|
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Handle an error in a component. Returns true if the error was handled.
|
|
1370
|
+
* Called by the renderer when an error occurs in setup or render.
|
|
1371
|
+
*/
|
|
902
1372
|
function handleComponentError(context, err, instance, info) {
|
|
903
1373
|
if (!context) return false;
|
|
904
1374
|
for (const hooks of context.hooks) try {
|
|
@@ -913,16 +1383,84 @@ function handleComponentError(context, err, instance, info) {
|
|
|
913
1383
|
}
|
|
914
1384
|
return false;
|
|
915
1385
|
}
|
|
1386
|
+
/**
|
|
1387
|
+
* Handle errors that occur in hooks themselves
|
|
1388
|
+
*/
|
|
916
1389
|
function handleHookError(context, err, instance, hookName) {
|
|
917
1390
|
console.error(`Error in ${hookName} hook:`, err);
|
|
918
1391
|
if (context.config.errorHandler) try {
|
|
919
1392
|
context.config.errorHandler(err, instance, `plugin hook: ${hookName}`);
|
|
920
1393
|
} catch {}
|
|
921
1394
|
}
|
|
1395
|
+
//#endregion
|
|
1396
|
+
//#region ../runtime-core/src/compound.ts
|
|
1397
|
+
/**
|
|
1398
|
+
* Creates a compound component by attaching sub-components as static properties.
|
|
1399
|
+
*
|
|
1400
|
+
* This enables the pattern of `Parent.Child` components (e.g., `Menu.Item`, `Card.Body`)
|
|
1401
|
+
* while preserving full TypeScript type inference for both the parent and children.
|
|
1402
|
+
*
|
|
1403
|
+
* @param main - The main/parent component factory
|
|
1404
|
+
* @param sub - An object containing sub-components to attach
|
|
1405
|
+
* @returns The main component with sub-components attached as static properties
|
|
1406
|
+
*
|
|
1407
|
+
* @example
|
|
1408
|
+
* ```tsx
|
|
1409
|
+
* // Define individual components
|
|
1410
|
+
* const _Menu = component<MenuProps>(ctx => { ... });
|
|
1411
|
+
* const _MenuItem = component<MenuItemProps>(ctx => { ... });
|
|
1412
|
+
* const _MenuTitle = component<MenuTitleProps>(ctx => { ... });
|
|
1413
|
+
*
|
|
1414
|
+
* // Create compound component
|
|
1415
|
+
* export const Menu = compound(_Menu, {
|
|
1416
|
+
* Item: _MenuItem,
|
|
1417
|
+
* Title: _MenuTitle,
|
|
1418
|
+
* });
|
|
1419
|
+
*
|
|
1420
|
+
* // Usage in JSX
|
|
1421
|
+
* <Menu>
|
|
1422
|
+
* <Menu.Title>Navigation</Menu.Title>
|
|
1423
|
+
* <Menu.Item value="home">Home</Menu.Item>
|
|
1424
|
+
* <Menu.Item value="about">About</Menu.Item>
|
|
1425
|
+
* </Menu>
|
|
1426
|
+
* ```
|
|
1427
|
+
*/
|
|
922
1428
|
function compound(main, sub) {
|
|
923
1429
|
return Object.assign(main, sub);
|
|
924
1430
|
}
|
|
1431
|
+
//#endregion
|
|
1432
|
+
//#region ../runtime-core/src/model.ts
|
|
1433
|
+
/**
|
|
1434
|
+
* Model<T> - Unified two-way binding type for SignalX components.
|
|
1435
|
+
*
|
|
1436
|
+
* Provides a single interface for reading, writing, and forwarding model bindings.
|
|
1437
|
+
*
|
|
1438
|
+
* @example
|
|
1439
|
+
* ```tsx
|
|
1440
|
+
* const Input = component<InputProps>(({ props }) => {
|
|
1441
|
+
* // Read
|
|
1442
|
+
* console.log(props.model.value);
|
|
1443
|
+
*
|
|
1444
|
+
* // Write
|
|
1445
|
+
* props.model.value = "new value";
|
|
1446
|
+
*
|
|
1447
|
+
* // Forward to child
|
|
1448
|
+
* <Child model={props.model} />
|
|
1449
|
+
*
|
|
1450
|
+
* // Forward via context
|
|
1451
|
+
* defineProvide(inputContext, () => props.model);
|
|
1452
|
+
* });
|
|
1453
|
+
* ```
|
|
1454
|
+
*/
|
|
1455
|
+
/** Symbol to identify Model objects */
|
|
925
1456
|
var MODEL_SYMBOL = Symbol.for("sigx.model");
|
|
1457
|
+
/**
|
|
1458
|
+
* Creates a Model<T> from a binding tuple and update handler.
|
|
1459
|
+
*
|
|
1460
|
+
* @param tuple - The [sourceObject, key] tuple from reactivity detection
|
|
1461
|
+
* @param updateHandler - Function called when value is set (enables parent interception)
|
|
1462
|
+
* @returns A Model<T> with .value getter/setter and .binding for forwarding
|
|
1463
|
+
*/
|
|
926
1464
|
function createModel(tuple, updateHandler) {
|
|
927
1465
|
const [obj, key] = tuple;
|
|
928
1466
|
return {
|
|
@@ -942,26 +1480,110 @@ function createModel(tuple, updateHandler) {
|
|
|
942
1480
|
[MODEL_SYMBOL]: true
|
|
943
1481
|
};
|
|
944
1482
|
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Creates a Model<T> from an existing binding (for forwarding scenarios).
|
|
1485
|
+
*
|
|
1486
|
+
* @param binding - The full binding tuple [obj, key, handler]
|
|
1487
|
+
* @returns A new Model<T> wrapping the same binding
|
|
1488
|
+
*/
|
|
945
1489
|
function createModelFromBinding(binding) {
|
|
946
1490
|
const [obj, key, handler] = binding;
|
|
947
1491
|
return createModel([obj, key], handler);
|
|
948
1492
|
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Type guard to check if a value is a Model<T>.
|
|
1495
|
+
*
|
|
1496
|
+
* Used by JSX runtime to detect forwarded models and extract their bindings.
|
|
1497
|
+
*/
|
|
949
1498
|
function isModel(value) {
|
|
950
1499
|
return value !== null && typeof value === "object" && MODEL_SYMBOL in value && value[MODEL_SYMBOL] === true;
|
|
951
1500
|
}
|
|
1501
|
+
//#endregion
|
|
1502
|
+
//#region ../runtime-core/src/platform.ts
|
|
952
1503
|
var platformModelProcessor = null;
|
|
1504
|
+
/**
|
|
1505
|
+
* Get the current platform model processor (for internal use).
|
|
1506
|
+
*/
|
|
953
1507
|
function getPlatformModelProcessor() {
|
|
954
1508
|
return platformModelProcessor;
|
|
955
1509
|
}
|
|
1510
|
+
//#endregion
|
|
1511
|
+
//#region ../runtime-core/src/utils/is-component.ts
|
|
1512
|
+
/**
|
|
1513
|
+
* Check if a value is a SignalX component (has __setup).
|
|
1514
|
+
*
|
|
1515
|
+
* SignalX components are created with component() and have a __setup
|
|
1516
|
+
* property containing the setup function.
|
|
1517
|
+
*
|
|
1518
|
+
* @example
|
|
1519
|
+
* ```ts
|
|
1520
|
+
* const MyComponent = component((ctx) => () => <div/>);
|
|
1521
|
+
* isComponent(MyComponent); // true
|
|
1522
|
+
* isComponent(() => <div/>); // false (plain function component)
|
|
1523
|
+
* isComponent('div'); // false
|
|
1524
|
+
* ```
|
|
1525
|
+
*/
|
|
956
1526
|
function isComponent(type) {
|
|
957
1527
|
return typeof type === "function" && "__setup" in type;
|
|
958
1528
|
}
|
|
959
|
-
|
|
960
|
-
|
|
1529
|
+
//#endregion
|
|
1530
|
+
//#region ../runtime-core/src/jsx-runtime.ts
|
|
1531
|
+
var Fragment = Symbol.for("sigx.Fragment");
|
|
1532
|
+
var Text = Symbol.for("sigx.Text");
|
|
1533
|
+
var Comment = Symbol.for("sigx.Comment");
|
|
961
1534
|
function normalizeChildren(children) {
|
|
962
1535
|
if (children == null || children === false || children === true) return [];
|
|
963
1536
|
if (isComputed(children)) return normalizeChildren(children.value);
|
|
964
|
-
if (Array.isArray(children)) return children.
|
|
1537
|
+
if (Array.isArray(children)) return children.map((c) => {
|
|
1538
|
+
if (c == null || c === false || c === true) return {
|
|
1539
|
+
type: Comment,
|
|
1540
|
+
props: {},
|
|
1541
|
+
key: null,
|
|
1542
|
+
children: [],
|
|
1543
|
+
dom: null
|
|
1544
|
+
};
|
|
1545
|
+
if (isComputed(c)) return normalizeChildren(c.value)[0] ?? {
|
|
1546
|
+
type: Comment,
|
|
1547
|
+
props: {},
|
|
1548
|
+
key: null,
|
|
1549
|
+
children: [],
|
|
1550
|
+
dom: null
|
|
1551
|
+
};
|
|
1552
|
+
if (typeof c === "string" || typeof c === "number") return {
|
|
1553
|
+
type: Text,
|
|
1554
|
+
props: {},
|
|
1555
|
+
key: null,
|
|
1556
|
+
children: [],
|
|
1557
|
+
dom: null,
|
|
1558
|
+
text: c
|
|
1559
|
+
};
|
|
1560
|
+
if (Array.isArray(c)) {
|
|
1561
|
+
const nested = normalizeChildren(c);
|
|
1562
|
+
if (nested.length === 0) return {
|
|
1563
|
+
type: Comment,
|
|
1564
|
+
props: {},
|
|
1565
|
+
key: null,
|
|
1566
|
+
children: [],
|
|
1567
|
+
dom: null
|
|
1568
|
+
};
|
|
1569
|
+
if (nested.length === 1) return nested[0];
|
|
1570
|
+
return {
|
|
1571
|
+
type: Fragment,
|
|
1572
|
+
props: {},
|
|
1573
|
+
key: null,
|
|
1574
|
+
children: nested,
|
|
1575
|
+
dom: null
|
|
1576
|
+
};
|
|
1577
|
+
}
|
|
1578
|
+
if (c.type) return c;
|
|
1579
|
+
return {
|
|
1580
|
+
type: Comment,
|
|
1581
|
+
props: {},
|
|
1582
|
+
key: null,
|
|
1583
|
+
children: [],
|
|
1584
|
+
dom: null
|
|
1585
|
+
};
|
|
1586
|
+
});
|
|
965
1587
|
if (typeof children === "string" || typeof children === "number") return [{
|
|
966
1588
|
type: Text,
|
|
967
1589
|
props: {},
|
|
@@ -973,6 +1595,9 @@ function normalizeChildren(children) {
|
|
|
973
1595
|
if (children.type) return [children];
|
|
974
1596
|
return [];
|
|
975
1597
|
}
|
|
1598
|
+
/**
|
|
1599
|
+
* Create a JSX element - this is the core function called by TSX transpilation
|
|
1600
|
+
*/
|
|
976
1601
|
function jsx(type, props, key) {
|
|
977
1602
|
const processedProps = { ...props };
|
|
978
1603
|
const models = {};
|
|
@@ -1073,11 +1698,26 @@ function jsx(type, props, key) {
|
|
|
1073
1698
|
dom: null
|
|
1074
1699
|
};
|
|
1075
1700
|
}
|
|
1701
|
+
/**
|
|
1702
|
+
* JSX Factory for fragments
|
|
1703
|
+
*/
|
|
1076
1704
|
function jsxs(type, props, key) {
|
|
1077
1705
|
return jsx(type, props, key);
|
|
1078
1706
|
}
|
|
1079
|
-
|
|
1707
|
+
var jsxDEV = jsx;
|
|
1708
|
+
//#endregion
|
|
1709
|
+
//#region ../runtime-core/src/lazy.tsx
|
|
1710
|
+
/**
|
|
1711
|
+
* Lazy loading utilities for sigx components.
|
|
1712
|
+
*
|
|
1713
|
+
* Provides runtime-only lazy loading with no build dependencies.
|
|
1714
|
+
* Works with any bundler that supports dynamic import().
|
|
1715
|
+
*/
|
|
1080
1716
|
var currentSuspenseBoundary = null;
|
|
1717
|
+
/**
|
|
1718
|
+
* Register a promise with the current Suspense boundary
|
|
1719
|
+
* @internal
|
|
1720
|
+
*/
|
|
1081
1721
|
function registerPendingPromise(promise) {
|
|
1082
1722
|
const boundary = getCurrentSuspenseBoundarySafe() ?? currentSuspenseBoundary;
|
|
1083
1723
|
if (boundary) {
|
|
@@ -1090,6 +1730,33 @@ function registerPendingPromise(promise) {
|
|
|
1090
1730
|
}
|
|
1091
1731
|
return false;
|
|
1092
1732
|
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Create a lazy-loaded component wrapper.
|
|
1735
|
+
*
|
|
1736
|
+
* The component will be loaded on first render. Use with `<Suspense>` to show
|
|
1737
|
+
* a fallback while loading.
|
|
1738
|
+
*
|
|
1739
|
+
* @param loader - Function that returns a Promise resolving to the component
|
|
1740
|
+
* @returns A component factory that loads the real component on demand
|
|
1741
|
+
*
|
|
1742
|
+
* @example
|
|
1743
|
+
* ```tsx
|
|
1744
|
+
* import { lazy, Suspense } from 'sigx';
|
|
1745
|
+
*
|
|
1746
|
+
* // Component will be in a separate chunk
|
|
1747
|
+
* const HeavyChart = lazy(() => import('./components/HeavyChart'));
|
|
1748
|
+
*
|
|
1749
|
+
* // Usage
|
|
1750
|
+
* <Suspense fallback={<Spinner />}>
|
|
1751
|
+
* <HeavyChart data={chartData} />
|
|
1752
|
+
* </Suspense>
|
|
1753
|
+
*
|
|
1754
|
+
* // Preload on hover
|
|
1755
|
+
* <button onMouseEnter={() => HeavyChart.preload()}>
|
|
1756
|
+
* Show Chart
|
|
1757
|
+
* </button>
|
|
1758
|
+
* ```
|
|
1759
|
+
*/
|
|
1093
1760
|
function lazy(loader) {
|
|
1094
1761
|
let Component = null;
|
|
1095
1762
|
let promise = null;
|
|
@@ -1173,7 +1840,30 @@ function lazy(loader) {
|
|
|
1173
1840
|
};
|
|
1174
1841
|
return LazyWrapper;
|
|
1175
1842
|
}
|
|
1176
|
-
|
|
1843
|
+
/**
|
|
1844
|
+
* Suspense boundary component for handling async loading states.
|
|
1845
|
+
*
|
|
1846
|
+
* Wraps lazy-loaded components and shows a fallback while they load.
|
|
1847
|
+
*
|
|
1848
|
+
* @example
|
|
1849
|
+
* ```tsx
|
|
1850
|
+
* import { lazy, Suspense } from 'sigx';
|
|
1851
|
+
*
|
|
1852
|
+
* const LazyDashboard = lazy(() => import('./Dashboard'));
|
|
1853
|
+
*
|
|
1854
|
+
* // Basic usage
|
|
1855
|
+
* <Suspense fallback={<div>Loading...</div>}>
|
|
1856
|
+
* <LazyDashboard />
|
|
1857
|
+
* </Suspense>
|
|
1858
|
+
*
|
|
1859
|
+
* // With spinner component
|
|
1860
|
+
* <Suspense fallback={<Spinner size="large" />}>
|
|
1861
|
+
* <LazyDashboard />
|
|
1862
|
+
* <LazyCharts />
|
|
1863
|
+
* </Suspense>
|
|
1864
|
+
* ```
|
|
1865
|
+
*/
|
|
1866
|
+
var Suspense = component((ctx) => {
|
|
1177
1867
|
const { props, slots } = ctx;
|
|
1178
1868
|
const state = ctx.signal({
|
|
1179
1869
|
isReady: false,
|
|
@@ -1223,9 +1913,48 @@ const Suspense = component((ctx) => {
|
|
|
1223
1913
|
}
|
|
1224
1914
|
};
|
|
1225
1915
|
}, { name: "Suspense" });
|
|
1916
|
+
/**
|
|
1917
|
+
* Check if a component is a lazy-loaded component
|
|
1918
|
+
*/
|
|
1226
1919
|
function isLazyComponent(component) {
|
|
1227
1920
|
return component && component.__lazy === true;
|
|
1228
1921
|
}
|
|
1922
|
+
//#endregion
|
|
1923
|
+
//#region ../runtime-core/src/use-async.ts
|
|
1924
|
+
/**
|
|
1925
|
+
* useAsync — composable for loading async dependencies in components.
|
|
1926
|
+
*
|
|
1927
|
+
* Wraps an async loader in a reactive signal with loading/error states.
|
|
1928
|
+
* No renderer changes required — works with sigx's existing effect system.
|
|
1929
|
+
*
|
|
1930
|
+
* @example
|
|
1931
|
+
* ```tsx
|
|
1932
|
+
* import { component, useAsync } from 'sigx';
|
|
1933
|
+
*
|
|
1934
|
+
* const CodeEditor = component(({ signal: s }) => {
|
|
1935
|
+
* const libs = useAsync(async () => {
|
|
1936
|
+
* const { EditorView } = await import('@codemirror/view');
|
|
1937
|
+
* const { json } = await import('@codemirror/lang-json');
|
|
1938
|
+
* return { EditorView, json };
|
|
1939
|
+
* });
|
|
1940
|
+
*
|
|
1941
|
+
* return () => {
|
|
1942
|
+
* if (libs.loading) return <div class="skeleton" />;
|
|
1943
|
+
* if (libs.error) return <div class="error">{libs.error.message}</div>;
|
|
1944
|
+
* return <div ref={el => new libs.value!.EditorView({ parent: el })} />;
|
|
1945
|
+
* };
|
|
1946
|
+
* });
|
|
1947
|
+
* ```
|
|
1948
|
+
*/
|
|
1949
|
+
/**
|
|
1950
|
+
* Load an async resource inside a component's setup function.
|
|
1951
|
+
*
|
|
1952
|
+
* Returns a reactive object with `value`, `loading`, and `error` fields.
|
|
1953
|
+
* The component's render function re-runs automatically when the state changes.
|
|
1954
|
+
*
|
|
1955
|
+
* @param loader — async function that returns the resource
|
|
1956
|
+
* @returns reactive AsyncState
|
|
1957
|
+
*/
|
|
1229
1958
|
function useAsync(loader) {
|
|
1230
1959
|
const state = signal({
|
|
1231
1960
|
value: null,
|
|
@@ -1245,7 +1974,38 @@ function useAsync(loader) {
|
|
|
1245
1974
|
});
|
|
1246
1975
|
return state;
|
|
1247
1976
|
}
|
|
1248
|
-
|
|
1977
|
+
//#endregion
|
|
1978
|
+
//#region ../runtime-core/src/error-boundary.ts
|
|
1979
|
+
/**
|
|
1980
|
+
* ErrorBoundary component for catching render errors.
|
|
1981
|
+
*
|
|
1982
|
+
* Catches errors thrown during child component rendering and displays
|
|
1983
|
+
* a fallback UI. Works during both SSR and client-side rendering.
|
|
1984
|
+
*
|
|
1985
|
+
* @example
|
|
1986
|
+
* ```tsx
|
|
1987
|
+
* import { ErrorBoundary } from 'sigx';
|
|
1988
|
+
*
|
|
1989
|
+
* <ErrorBoundary
|
|
1990
|
+
* fallback={(error, retry) => (
|
|
1991
|
+
* <div>
|
|
1992
|
+
* <p>Something went wrong: {error.message}</p>
|
|
1993
|
+
* <button onClick={retry}>Retry</button>
|
|
1994
|
+
* </div>
|
|
1995
|
+
* )}
|
|
1996
|
+
* >
|
|
1997
|
+
* <RiskyComponent />
|
|
1998
|
+
* </ErrorBoundary>
|
|
1999
|
+
* ```
|
|
2000
|
+
*/
|
|
2001
|
+
/**
|
|
2002
|
+
* ErrorBoundary component.
|
|
2003
|
+
*
|
|
2004
|
+
* Wraps children and catches errors thrown during rendering.
|
|
2005
|
+
* When an error occurs, displays the `fallback` UI.
|
|
2006
|
+
* Provides a `retry` function to reset and re-render children.
|
|
2007
|
+
*/
|
|
2008
|
+
var ErrorBoundary = component((ctx) => {
|
|
1249
2009
|
const { fallback } = ctx.props;
|
|
1250
2010
|
const { slots } = ctx;
|
|
1251
2011
|
const state = ctx.signal({
|
|
@@ -1273,6 +2033,8 @@ const ErrorBoundary = component((ctx) => {
|
|
|
1273
2033
|
}
|
|
1274
2034
|
};
|
|
1275
2035
|
}, { name: "ErrorBoundary" });
|
|
2036
|
+
//#endregion
|
|
2037
|
+
//#region ../runtime-core/src/utils/index.ts
|
|
1276
2038
|
var Utils = class {
|
|
1277
2039
|
static isPromise(value) {
|
|
1278
2040
|
return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
@@ -1284,13 +2046,17 @@ function guid$1() {
|
|
|
1284
2046
|
return (c == "x" ? r : r & 3 | 8).toString(16);
|
|
1285
2047
|
});
|
|
1286
2048
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
2049
|
+
//#endregion
|
|
2050
|
+
//#region ../runtime-core/src/models/index.ts
|
|
2051
|
+
var guid = guid$1;
|
|
2052
|
+
var InstanceLifetimes = /* @__PURE__ */ function(InstanceLifetimes) {
|
|
1289
2053
|
InstanceLifetimes[InstanceLifetimes["Transient"] = 0] = "Transient";
|
|
1290
2054
|
InstanceLifetimes[InstanceLifetimes["Scoped"] = 1] = "Scoped";
|
|
1291
2055
|
InstanceLifetimes[InstanceLifetimes["Singleton"] = 2] = "Singleton";
|
|
1292
2056
|
return InstanceLifetimes;
|
|
1293
2057
|
}({});
|
|
2058
|
+
//#endregion
|
|
2059
|
+
//#region ../runtime-core/src/messaging/index.ts
|
|
1294
2060
|
function createTopic(_options) {
|
|
1295
2061
|
let subscribers = [];
|
|
1296
2062
|
const publish = (data) => {
|
|
@@ -1319,6 +2085,8 @@ function createTopic(_options) {
|
|
|
1319
2085
|
function toSubscriber(topic) {
|
|
1320
2086
|
return { subscribe: (handler) => topic.subscribe(handler) };
|
|
1321
2087
|
}
|
|
2088
|
+
//#endregion
|
|
2089
|
+
//#region ../runtime-core/src/di/factory.ts
|
|
1322
2090
|
var SubscriptionHandler = class {
|
|
1323
2091
|
constructor() {
|
|
1324
2092
|
this.unsubs = [];
|
|
@@ -1358,6 +2126,21 @@ function defineFactory(setup, _lifetime, _typeIdentifier) {
|
|
|
1358
2126
|
if (setup.length <= 1) return defineInjectable(() => factoryCreator());
|
|
1359
2127
|
return factoryCreator;
|
|
1360
2128
|
}
|
|
2129
|
+
//#endregion
|
|
2130
|
+
//#region ../runtime-core/src/utils/props-accessor.ts
|
|
2131
|
+
/**
|
|
2132
|
+
* Creates a props accessor - a simple reactive proxy for props.
|
|
2133
|
+
* Use destructuring with defaults for optional props.
|
|
2134
|
+
*
|
|
2135
|
+
* @example
|
|
2136
|
+
* ```ts
|
|
2137
|
+
* // In component setup:
|
|
2138
|
+
* const { count = 0, label = 'Default' } = ctx.props;
|
|
2139
|
+
*
|
|
2140
|
+
* // Or spread to forward props
|
|
2141
|
+
* <ChildComponent {...ctx.props} />
|
|
2142
|
+
* ```
|
|
2143
|
+
*/
|
|
1361
2144
|
function createPropsAccessor(reactiveProps) {
|
|
1362
2145
|
return new Proxy(reactiveProps, {
|
|
1363
2146
|
get(target, key) {
|
|
@@ -1381,6 +2164,39 @@ function createPropsAccessor(reactiveProps) {
|
|
|
1381
2164
|
}
|
|
1382
2165
|
});
|
|
1383
2166
|
}
|
|
2167
|
+
//#endregion
|
|
2168
|
+
//#region ../runtime-core/src/utils/slots.ts
|
|
2169
|
+
/**
|
|
2170
|
+
* Slots system for component children.
|
|
2171
|
+
* Supports default and named slots with reactivity.
|
|
2172
|
+
*/
|
|
2173
|
+
/**
|
|
2174
|
+
* Create slots object from children and slots prop.
|
|
2175
|
+
* Uses a version signal to trigger re-renders when children change.
|
|
2176
|
+
*
|
|
2177
|
+
* Supports named slots via:
|
|
2178
|
+
* - `slots` prop object (e.g., `slots={{ header: () => <div>...</div> }}`)
|
|
2179
|
+
* - `slot` prop on children (e.g., `<div slot="header">...</div>`)
|
|
2180
|
+
*
|
|
2181
|
+
* @example
|
|
2182
|
+
* ```tsx
|
|
2183
|
+
* // Parent component
|
|
2184
|
+
* <Card slots={{ header: () => <h1>Title</h1> }}>
|
|
2185
|
+
* <p>Default content</p>
|
|
2186
|
+
* <span slot="footer">Footer text</span>
|
|
2187
|
+
* </Card>
|
|
2188
|
+
*
|
|
2189
|
+
* // Card component setup
|
|
2190
|
+
* const slots = createSlots(children, slotsFromProps);
|
|
2191
|
+
* return () => (
|
|
2192
|
+
* <div>
|
|
2193
|
+
* {slots.header()}
|
|
2194
|
+
* {slots.default()}
|
|
2195
|
+
* {slots.footer()}
|
|
2196
|
+
* </div>
|
|
2197
|
+
* );
|
|
2198
|
+
* ```
|
|
2199
|
+
*/
|
|
1384
2200
|
function createSlots(children, slotsFromProps) {
|
|
1385
2201
|
const versionSignal = signal({ v: 0 });
|
|
1386
2202
|
function extractNamedSlotsFromChildren(c) {
|
|
@@ -1401,7 +2217,7 @@ function createSlots(children, slotsFromProps) {
|
|
|
1401
2217
|
namedSlots
|
|
1402
2218
|
};
|
|
1403
2219
|
}
|
|
1404
|
-
|
|
2220
|
+
return new Proxy({
|
|
1405
2221
|
_children: children,
|
|
1406
2222
|
_slotsFromProps: slotsFromProps || {},
|
|
1407
2223
|
_version: versionSignal,
|
|
@@ -1412,8 +2228,7 @@ function createSlots(children, slotsFromProps) {
|
|
|
1412
2228
|
const { defaultChildren } = extractNamedSlotsFromChildren(c);
|
|
1413
2229
|
return defaultChildren.filter((child) => child != null && child !== false && child !== true);
|
|
1414
2230
|
}
|
|
1415
|
-
}
|
|
1416
|
-
return new Proxy(slotsObj, { get(target, prop) {
|
|
2231
|
+
}, { get(target, prop) {
|
|
1417
2232
|
if (prop in target) return target[prop];
|
|
1418
2233
|
if (typeof prop === "string") return function(scopedProps) {
|
|
1419
2234
|
target._version.v;
|
|
@@ -1427,6 +2242,39 @@ function createSlots(children, slotsFromProps) {
|
|
|
1427
2242
|
};
|
|
1428
2243
|
} });
|
|
1429
2244
|
}
|
|
2245
|
+
//#endregion
|
|
2246
|
+
//#region ../runtime-core/src/utils/normalize.ts
|
|
2247
|
+
/**
|
|
2248
|
+
* VNode normalization utilities.
|
|
2249
|
+
* Converts render results into proper VNode structures.
|
|
2250
|
+
*/
|
|
2251
|
+
/**
|
|
2252
|
+
* Normalize render result to a VNode (wrapping arrays in Fragment).
|
|
2253
|
+
* Handles null, undefined, false, true by returning an empty Text node.
|
|
2254
|
+
*
|
|
2255
|
+
* This is used to normalize the return value of component render functions
|
|
2256
|
+
* into a consistent VNode structure for the renderer to process.
|
|
2257
|
+
*
|
|
2258
|
+
* @example
|
|
2259
|
+
* ```ts
|
|
2260
|
+
* // Conditional rendering returns null/false
|
|
2261
|
+
* normalizeSubTree(null) // → empty Text node
|
|
2262
|
+
* normalizeSubTree(false) // → empty Text node
|
|
2263
|
+
*
|
|
2264
|
+
* // Arrays become Fragments
|
|
2265
|
+
* normalizeSubTree([<A/>, <B/>]) // → Fragment with children
|
|
2266
|
+
*
|
|
2267
|
+
* // Primitives become Text nodes
|
|
2268
|
+
* normalizeSubTree("hello") // → Text node
|
|
2269
|
+
* normalizeSubTree(42) // → Text node
|
|
2270
|
+
*
|
|
2271
|
+
* // Computed signals are auto-unwrapped
|
|
2272
|
+
* normalizeSubTree(computed(() => "hi")) // → Text node with "hi"
|
|
2273
|
+
*
|
|
2274
|
+
* // VNodes pass through
|
|
2275
|
+
* normalizeSubTree(<div/>) // → same VNode
|
|
2276
|
+
* ```
|
|
2277
|
+
*/
|
|
1430
2278
|
function normalizeSubTree(result) {
|
|
1431
2279
|
if (result == null || result === false || result === true) return {
|
|
1432
2280
|
type: Text,
|
|
@@ -1454,14 +2302,41 @@ function normalizeSubTree(result) {
|
|
|
1454
2302
|
};
|
|
1455
2303
|
return result;
|
|
1456
2304
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
2305
|
+
//#endregion
|
|
2306
|
+
//#region ../runtime-core/src/hydration/index.ts
|
|
2307
|
+
/**
|
|
2308
|
+
* Hydration utilities for SSR
|
|
2309
|
+
*
|
|
2310
|
+
* These utilities are shared between server-side rendering (stream.ts)
|
|
2311
|
+
* and client-side hydration (hydrate.ts). They are placed in runtime-core
|
|
2312
|
+
* to allow any SSR implementation to use them.
|
|
2313
|
+
*
|
|
2314
|
+
* @module
|
|
2315
|
+
*/
|
|
2316
|
+
/**
|
|
2317
|
+
* Client directive prefix used for selective hydration
|
|
2318
|
+
*/
|
|
2319
|
+
var CLIENT_DIRECTIVE_PREFIX = "client:";
|
|
2320
|
+
/**
|
|
2321
|
+
* Valid client directive names
|
|
2322
|
+
*/
|
|
2323
|
+
var CLIENT_DIRECTIVES = [
|
|
1459
2324
|
"client:load",
|
|
1460
2325
|
"client:idle",
|
|
1461
2326
|
"client:visible",
|
|
1462
2327
|
"client:media",
|
|
1463
2328
|
"client:only"
|
|
1464
2329
|
];
|
|
2330
|
+
/**
|
|
2331
|
+
* Create an emit function for component context.
|
|
2332
|
+
* This is a common pattern used in both mountComponent and hydrateComponent.
|
|
2333
|
+
*
|
|
2334
|
+
* @example
|
|
2335
|
+
* ```ts
|
|
2336
|
+
* const emit = createEmit(reactiveProps);
|
|
2337
|
+
* emit('click', eventData); // Calls props.onClick(eventData)
|
|
2338
|
+
* ```
|
|
2339
|
+
*/
|
|
1465
2340
|
function createEmit(reactiveProps) {
|
|
1466
2341
|
return (event, ...args) => {
|
|
1467
2342
|
const eventName = `on${event[0].toUpperCase() + event.slice(1)}`;
|
|
@@ -1469,6 +2344,8 @@ function createEmit(reactiveProps) {
|
|
|
1469
2344
|
if (handler && typeof handler === "function") handler(...args);
|
|
1470
2345
|
};
|
|
1471
2346
|
}
|
|
2347
|
+
//#endregion
|
|
2348
|
+
//#region ../runtime-core/src/renderer.ts
|
|
1472
2349
|
function createRenderer(options) {
|
|
1473
2350
|
const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, createElement: hostCreateElement, createText: hostCreateText, createComment: hostCreateComment, setText: hostSetText, setElementText: _hostSetElementText, parentNode: hostParentNode, nextSibling: hostNextSibling, cloneNode: _hostCloneNode, insertStaticContent: _hostInsertStaticContent, patchDirective: hostPatchDirective, onElementMounted: hostOnElementMounted, onElementUnmounted: hostOnElementUnmounted, getActiveElement: hostGetActiveElement, restoreFocus: hostRestoreFocus } = options;
|
|
1474
2351
|
let currentAppContext = null;
|
|
@@ -1575,6 +2452,12 @@ function createRenderer(options) {
|
|
|
1575
2452
|
hostInsert(node, container, before);
|
|
1576
2453
|
return;
|
|
1577
2454
|
}
|
|
2455
|
+
if (vnode.type === Comment) {
|
|
2456
|
+
const node = hostCreateComment("");
|
|
2457
|
+
vnode.dom = node;
|
|
2458
|
+
hostInsert(node, container, before);
|
|
2459
|
+
return;
|
|
2460
|
+
}
|
|
1578
2461
|
if (vnode.type === Fragment) {
|
|
1579
2462
|
const anchor = hostCreateComment("");
|
|
1580
2463
|
vnode.dom = anchor;
|
|
@@ -1627,6 +2510,10 @@ function createRenderer(options) {
|
|
|
1627
2510
|
if (vnode.dom) hostRemove(vnode.dom);
|
|
1628
2511
|
return;
|
|
1629
2512
|
}
|
|
2513
|
+
if (vnode.type === Comment) {
|
|
2514
|
+
if (vnode.dom) hostRemove(vnode.dom);
|
|
2515
|
+
return;
|
|
2516
|
+
}
|
|
1630
2517
|
if (vnode.props?.ref) untrack(() => {
|
|
1631
2518
|
if (typeof vnode.props.ref === "function") vnode.props.ref(null);
|
|
1632
2519
|
else if (vnode.props.ref && typeof vnode.props.ref === "object") vnode.props.ref.current = null;
|
|
@@ -1706,6 +2593,10 @@ function createRenderer(options) {
|
|
|
1706
2593
|
if (oldVNode.text !== newVNode.text) hostSetText(newVNode.dom, String(newVNode.text));
|
|
1707
2594
|
return;
|
|
1708
2595
|
}
|
|
2596
|
+
if (newVNode.type === Comment) {
|
|
2597
|
+
newVNode.dom = oldVNode.dom;
|
|
2598
|
+
return;
|
|
2599
|
+
}
|
|
1709
2600
|
if (newVNode.type === Fragment) {
|
|
1710
2601
|
patchChildren(oldVNode, newVNode, container, false);
|
|
1711
2602
|
return;
|
|
@@ -1737,6 +2628,9 @@ function createRenderer(options) {
|
|
|
1737
2628
|
newChildren.forEach((c) => c.parent = newVNode);
|
|
1738
2629
|
reconcileChildrenArray(container, oldChildren, newChildren, parentIsSVG);
|
|
1739
2630
|
}
|
|
2631
|
+
/**
|
|
2632
|
+
* Check for duplicate keys in an array of VNodes and warn in development.
|
|
2633
|
+
*/
|
|
1740
2634
|
function checkDuplicateKeys(children) {
|
|
1741
2635
|
if (process.env.NODE_ENV === "production") return;
|
|
1742
2636
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
@@ -1956,8 +2850,10 @@ function createRenderer(options) {
|
|
|
1956
2850
|
mountComponent
|
|
1957
2851
|
};
|
|
1958
2852
|
}
|
|
2853
|
+
//#endregion
|
|
2854
|
+
//#region ../runtime-terminal/src/focus.ts
|
|
1959
2855
|
var focusableIds = /* @__PURE__ */ new Set();
|
|
1960
|
-
|
|
2856
|
+
var focusState = signal({ activeId: null });
|
|
1961
2857
|
function registerFocusable(id) {
|
|
1962
2858
|
focusableIds.add(id);
|
|
1963
2859
|
if (focusState.activeId === null) focusState.activeId = id;
|
|
@@ -1982,6 +2878,8 @@ function focusPrev() {
|
|
|
1982
2878
|
const ids = Array.from(focusableIds);
|
|
1983
2879
|
focusState.activeId = ids[((focusState.activeId ? ids.indexOf(focusState.activeId) : -1) - 1 + ids.length) % ids.length];
|
|
1984
2880
|
}
|
|
2881
|
+
//#endregion
|
|
2882
|
+
//#region ../runtime-terminal/src/utils.ts
|
|
1985
2883
|
function getColorCode(color) {
|
|
1986
2884
|
switch (color) {
|
|
1987
2885
|
case "red": return "\x1B[31m";
|
|
@@ -2009,7 +2907,10 @@ function getBackgroundColorCode(color) {
|
|
|
2009
2907
|
function stripAnsi(str) {
|
|
2010
2908
|
return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
|
|
2011
2909
|
}
|
|
2012
|
-
|
|
2910
|
+
//#endregion
|
|
2911
|
+
//#region ../runtime-terminal/src/components/Input.tsx
|
|
2912
|
+
/** @jsxImportSource @sigx/runtime-core */
|
|
2913
|
+
var Input = component(({ props, emit }) => {
|
|
2013
2914
|
const id = Math.random().toString(36).slice(2);
|
|
2014
2915
|
let isReady = false;
|
|
2015
2916
|
const isFocused = () => focusState.activeId === id;
|
|
@@ -2064,7 +2965,10 @@ const Input = component(({ props, emit }) => {
|
|
|
2064
2965
|
});
|
|
2065
2966
|
};
|
|
2066
2967
|
}, { name: "Input" });
|
|
2067
|
-
|
|
2968
|
+
//#endregion
|
|
2969
|
+
//#region ../runtime-terminal/src/components/ProgressBar.tsx
|
|
2970
|
+
/** @jsxImportSource @sigx/runtime-core */
|
|
2971
|
+
var ProgressBar = component(({ props }) => {
|
|
2068
2972
|
return () => {
|
|
2069
2973
|
const value = props.value || 0;
|
|
2070
2974
|
const max = props.max || 100;
|
|
@@ -2080,7 +2984,10 @@ const ProgressBar = component(({ props }) => {
|
|
|
2080
2984
|
return /* @__PURE__ */ jsx("box", { children: /* @__PURE__ */ jsx("text", { children: colorCode + barChar.repeat(filledLen) + emptyChar.repeat(emptyLen) + reset + ` ${Math.round(percentage * 100)}%` }) });
|
|
2081
2985
|
};
|
|
2082
2986
|
}, { name: "ProgressBar" });
|
|
2083
|
-
|
|
2987
|
+
//#endregion
|
|
2988
|
+
//#region ../runtime-terminal/src/components/Button.tsx
|
|
2989
|
+
/** @jsxImportSource @sigx/runtime-core */
|
|
2990
|
+
var Button = component(({ props, emit }) => {
|
|
2084
2991
|
const id = Math.random().toString(36).slice(2);
|
|
2085
2992
|
const isFocused = () => focusState.activeId === id;
|
|
2086
2993
|
const pressed = signal({ value: false });
|
|
@@ -2123,7 +3030,10 @@ const Button = component(({ props, emit }) => {
|
|
|
2123
3030
|
});
|
|
2124
3031
|
};
|
|
2125
3032
|
}, { name: "Button" });
|
|
2126
|
-
|
|
3033
|
+
//#endregion
|
|
3034
|
+
//#region ../runtime-terminal/src/components/Checkbox.tsx
|
|
3035
|
+
/** @jsxImportSource @sigx/runtime-core */
|
|
3036
|
+
var Checkbox = component(({ props, emit }) => {
|
|
2127
3037
|
const id = Math.random().toString(36).slice(2);
|
|
2128
3038
|
const isFocused = () => focusState.activeId === id;
|
|
2129
3039
|
const checked = () => !!props.model?.value;
|
|
@@ -2171,7 +3081,10 @@ const Checkbox = component(({ props, emit }) => {
|
|
|
2171
3081
|
] });
|
|
2172
3082
|
};
|
|
2173
3083
|
}, { name: "Checkbox" });
|
|
2174
|
-
|
|
3084
|
+
//#endregion
|
|
3085
|
+
//#region ../runtime-terminal/src/components/Select.tsx
|
|
3086
|
+
/** @jsxImportSource @sigx/runtime-core */
|
|
3087
|
+
var Select = component(({ props, emit }) => {
|
|
2175
3088
|
const id = Math.random().toString(36).slice(2);
|
|
2176
3089
|
let isReady = false;
|
|
2177
3090
|
const isFocused = () => focusState.activeId === id;
|
|
@@ -2244,7 +3157,7 @@ const Select = component(({ props, emit }) => {
|
|
|
2244
3157
|
}), descriptionElement] });
|
|
2245
3158
|
};
|
|
2246
3159
|
}, { name: "Select" });
|
|
2247
|
-
|
|
3160
|
+
var { render } = createRenderer({
|
|
2248
3161
|
patchProp: (el, key, prev, next) => {
|
|
2249
3162
|
el.props[key] = next;
|
|
2250
3163
|
scheduleRender();
|
|
@@ -2332,6 +3245,10 @@ function flushRender() {
|
|
|
2332
3245
|
process.stdout.write(lines.join("\x1B[K\n") + "\x1B[K");
|
|
2333
3246
|
process.stdout.write("\x1B[J");
|
|
2334
3247
|
}
|
|
3248
|
+
/**
|
|
3249
|
+
* Check if a node has a box element as an immediate child.
|
|
3250
|
+
* This is used to determine if a component wrapper should be treated as a block element.
|
|
3251
|
+
*/
|
|
2335
3252
|
function hasBoxChild(node) {
|
|
2336
3253
|
for (const child of node.children) if (child.tag === "box") return true;
|
|
2337
3254
|
return false;
|
|
@@ -2468,6 +3385,15 @@ function renderTerminal(app, options = {}) {
|
|
|
2468
3385
|
} };
|
|
2469
3386
|
}
|
|
2470
3387
|
var unmountFn = null;
|
|
3388
|
+
/**
|
|
3389
|
+
* Helper function to mount the terminal for CLI apps.
|
|
3390
|
+
* Returns a mount target that can be passed to defineApp().mount().
|
|
3391
|
+
*
|
|
3392
|
+
* @example
|
|
3393
|
+
* ```tsx
|
|
3394
|
+
* defineApp(MyApp).mount(mountTerminal());
|
|
3395
|
+
* ```
|
|
3396
|
+
*/
|
|
2471
3397
|
function mountTerminal(options = { clearConsole: true }) {
|
|
2472
3398
|
return {
|
|
2473
3399
|
mount: terminalMount,
|
|
@@ -2477,6 +3403,9 @@ function mountTerminal(options = { clearConsole: true }) {
|
|
|
2477
3403
|
}
|
|
2478
3404
|
};
|
|
2479
3405
|
}
|
|
3406
|
+
/**
|
|
3407
|
+
* Exit the terminal app cleanly, restoring terminal state.
|
|
3408
|
+
*/
|
|
2480
3409
|
function exitTerminal() {
|
|
2481
3410
|
if (unmountFn) {
|
|
2482
3411
|
unmountFn();
|
|
@@ -2485,7 +3414,21 @@ function exitTerminal() {
|
|
|
2485
3414
|
process.stdout.write("\x1B[?25h");
|
|
2486
3415
|
process.stdout.write("\x1B[2J\x1B[H");
|
|
2487
3416
|
}
|
|
2488
|
-
|
|
3417
|
+
/**
|
|
3418
|
+
* Mount function for Terminal environments.
|
|
3419
|
+
* Use this with defineApp().mount() to render to the terminal.
|
|
3420
|
+
*
|
|
3421
|
+
* @example
|
|
3422
|
+
* ```tsx
|
|
3423
|
+
* import { defineApp } from '@sigx/runtime-core';
|
|
3424
|
+
* import { terminalMount } from '@sigx/runtime-terminal';
|
|
3425
|
+
*
|
|
3426
|
+
* const app = defineApp(<Counter />);
|
|
3427
|
+
* app.use(loggingPlugin)
|
|
3428
|
+
* .mount({ clearConsole: true }, terminalMount);
|
|
3429
|
+
* ```
|
|
3430
|
+
*/
|
|
3431
|
+
var terminalMount = (component, options, appContext) => {
|
|
2489
3432
|
rootNode = {
|
|
2490
3433
|
type: "root",
|
|
2491
3434
|
props: {},
|
|
@@ -2513,6 +3456,7 @@ const terminalMount = (component, options, appContext) => {
|
|
|
2513
3456
|
};
|
|
2514
3457
|
};
|
|
2515
3458
|
setDefaultMount(terminalMount);
|
|
2516
|
-
|
|
3459
|
+
//#endregion
|
|
3460
|
+
export { Button, CLIENT_DIRECTIVES, CLIENT_DIRECTIVE_PREFIX, Checkbox, Comment, ComputedSymbol, ErrorBoundary, Fragment, Input, InstanceLifetimes, ProgressBar, Select, SigxError, SigxErrorCode, SubscriptionHandler, Suspense, Text, Utils, asyncSetupClientError, batch, component, compound, computed, createModel, createModelFromBinding, createTopic, defineApp, defineDirective, defineFactory, defineInjectable, defineProvide, detectAccess, effect, effectScope, exitTerminal, focus, focusNext, focusPrev, focusState, getComponentMeta, getCurrentInstance, guid, isComponent, isComputed, isDirective, isLazyComponent, isModel, isReactive, jsx, jsxDEV, jsxs, lazy, mountTargetNotFoundError, mountTerminal, noMountFunctionError, onCreated, onKey, onMounted, onUnmounted, onUpdated, provideInvalidInjectableError, provideOutsideSetupError, registerFocusable, render, renderNodeToLines, renderTargetNotFoundError, renderTerminal, signal, terminalMount, toRaw, toSubscriber, unregisterFocusable, untrack, useAppContext, useAsync, watch };
|
|
2517
3461
|
|
|
2518
3462
|
//# sourceMappingURL=index.js.map
|