@sigx/terminal 0.1.26 → 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 +908 -28
- 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,23 +1480,57 @@ 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
|
-
|
|
961
|
-
|
|
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");
|
|
962
1534
|
function normalizeChildren(children) {
|
|
963
1535
|
if (children == null || children === false || children === true) return [];
|
|
964
1536
|
if (isComputed(children)) return normalizeChildren(children.value);
|
|
@@ -1023,6 +1595,9 @@ function normalizeChildren(children) {
|
|
|
1023
1595
|
if (children.type) return [children];
|
|
1024
1596
|
return [];
|
|
1025
1597
|
}
|
|
1598
|
+
/**
|
|
1599
|
+
* Create a JSX element - this is the core function called by TSX transpilation
|
|
1600
|
+
*/
|
|
1026
1601
|
function jsx(type, props, key) {
|
|
1027
1602
|
const processedProps = { ...props };
|
|
1028
1603
|
const models = {};
|
|
@@ -1123,11 +1698,26 @@ function jsx(type, props, key) {
|
|
|
1123
1698
|
dom: null
|
|
1124
1699
|
};
|
|
1125
1700
|
}
|
|
1701
|
+
/**
|
|
1702
|
+
* JSX Factory for fragments
|
|
1703
|
+
*/
|
|
1126
1704
|
function jsxs(type, props, key) {
|
|
1127
1705
|
return jsx(type, props, key);
|
|
1128
1706
|
}
|
|
1129
|
-
|
|
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
|
+
*/
|
|
1130
1716
|
var currentSuspenseBoundary = null;
|
|
1717
|
+
/**
|
|
1718
|
+
* Register a promise with the current Suspense boundary
|
|
1719
|
+
* @internal
|
|
1720
|
+
*/
|
|
1131
1721
|
function registerPendingPromise(promise) {
|
|
1132
1722
|
const boundary = getCurrentSuspenseBoundarySafe() ?? currentSuspenseBoundary;
|
|
1133
1723
|
if (boundary) {
|
|
@@ -1140,6 +1730,33 @@ function registerPendingPromise(promise) {
|
|
|
1140
1730
|
}
|
|
1141
1731
|
return false;
|
|
1142
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
|
+
*/
|
|
1143
1760
|
function lazy(loader) {
|
|
1144
1761
|
let Component = null;
|
|
1145
1762
|
let promise = null;
|
|
@@ -1223,7 +1840,30 @@ function lazy(loader) {
|
|
|
1223
1840
|
};
|
|
1224
1841
|
return LazyWrapper;
|
|
1225
1842
|
}
|
|
1226
|
-
|
|
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) => {
|
|
1227
1867
|
const { props, slots } = ctx;
|
|
1228
1868
|
const state = ctx.signal({
|
|
1229
1869
|
isReady: false,
|
|
@@ -1273,9 +1913,48 @@ const Suspense = component((ctx) => {
|
|
|
1273
1913
|
}
|
|
1274
1914
|
};
|
|
1275
1915
|
}, { name: "Suspense" });
|
|
1916
|
+
/**
|
|
1917
|
+
* Check if a component is a lazy-loaded component
|
|
1918
|
+
*/
|
|
1276
1919
|
function isLazyComponent(component) {
|
|
1277
1920
|
return component && component.__lazy === true;
|
|
1278
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
|
+
*/
|
|
1279
1958
|
function useAsync(loader) {
|
|
1280
1959
|
const state = signal({
|
|
1281
1960
|
value: null,
|
|
@@ -1295,7 +1974,38 @@ function useAsync(loader) {
|
|
|
1295
1974
|
});
|
|
1296
1975
|
return state;
|
|
1297
1976
|
}
|
|
1298
|
-
|
|
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) => {
|
|
1299
2009
|
const { fallback } = ctx.props;
|
|
1300
2010
|
const { slots } = ctx;
|
|
1301
2011
|
const state = ctx.signal({
|
|
@@ -1323,6 +2033,8 @@ const ErrorBoundary = component((ctx) => {
|
|
|
1323
2033
|
}
|
|
1324
2034
|
};
|
|
1325
2035
|
}, { name: "ErrorBoundary" });
|
|
2036
|
+
//#endregion
|
|
2037
|
+
//#region ../runtime-core/src/utils/index.ts
|
|
1326
2038
|
var Utils = class {
|
|
1327
2039
|
static isPromise(value) {
|
|
1328
2040
|
return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
@@ -1334,13 +2046,17 @@ function guid$1() {
|
|
|
1334
2046
|
return (c == "x" ? r : r & 3 | 8).toString(16);
|
|
1335
2047
|
});
|
|
1336
2048
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
2049
|
+
//#endregion
|
|
2050
|
+
//#region ../runtime-core/src/models/index.ts
|
|
2051
|
+
var guid = guid$1;
|
|
2052
|
+
var InstanceLifetimes = /* @__PURE__ */ function(InstanceLifetimes) {
|
|
1339
2053
|
InstanceLifetimes[InstanceLifetimes["Transient"] = 0] = "Transient";
|
|
1340
2054
|
InstanceLifetimes[InstanceLifetimes["Scoped"] = 1] = "Scoped";
|
|
1341
2055
|
InstanceLifetimes[InstanceLifetimes["Singleton"] = 2] = "Singleton";
|
|
1342
2056
|
return InstanceLifetimes;
|
|
1343
2057
|
}({});
|
|
2058
|
+
//#endregion
|
|
2059
|
+
//#region ../runtime-core/src/messaging/index.ts
|
|
1344
2060
|
function createTopic(_options) {
|
|
1345
2061
|
let subscribers = [];
|
|
1346
2062
|
const publish = (data) => {
|
|
@@ -1369,6 +2085,8 @@ function createTopic(_options) {
|
|
|
1369
2085
|
function toSubscriber(topic) {
|
|
1370
2086
|
return { subscribe: (handler) => topic.subscribe(handler) };
|
|
1371
2087
|
}
|
|
2088
|
+
//#endregion
|
|
2089
|
+
//#region ../runtime-core/src/di/factory.ts
|
|
1372
2090
|
var SubscriptionHandler = class {
|
|
1373
2091
|
constructor() {
|
|
1374
2092
|
this.unsubs = [];
|
|
@@ -1408,6 +2126,21 @@ function defineFactory(setup, _lifetime, _typeIdentifier) {
|
|
|
1408
2126
|
if (setup.length <= 1) return defineInjectable(() => factoryCreator());
|
|
1409
2127
|
return factoryCreator;
|
|
1410
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
|
+
*/
|
|
1411
2144
|
function createPropsAccessor(reactiveProps) {
|
|
1412
2145
|
return new Proxy(reactiveProps, {
|
|
1413
2146
|
get(target, key) {
|
|
@@ -1431,6 +2164,39 @@ function createPropsAccessor(reactiveProps) {
|
|
|
1431
2164
|
}
|
|
1432
2165
|
});
|
|
1433
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
|
+
*/
|
|
1434
2200
|
function createSlots(children, slotsFromProps) {
|
|
1435
2201
|
const versionSignal = signal({ v: 0 });
|
|
1436
2202
|
function extractNamedSlotsFromChildren(c) {
|
|
@@ -1451,7 +2217,7 @@ function createSlots(children, slotsFromProps) {
|
|
|
1451
2217
|
namedSlots
|
|
1452
2218
|
};
|
|
1453
2219
|
}
|
|
1454
|
-
|
|
2220
|
+
return new Proxy({
|
|
1455
2221
|
_children: children,
|
|
1456
2222
|
_slotsFromProps: slotsFromProps || {},
|
|
1457
2223
|
_version: versionSignal,
|
|
@@ -1462,8 +2228,7 @@ function createSlots(children, slotsFromProps) {
|
|
|
1462
2228
|
const { defaultChildren } = extractNamedSlotsFromChildren(c);
|
|
1463
2229
|
return defaultChildren.filter((child) => child != null && child !== false && child !== true);
|
|
1464
2230
|
}
|
|
1465
|
-
}
|
|
1466
|
-
return new Proxy(slotsObj, { get(target, prop) {
|
|
2231
|
+
}, { get(target, prop) {
|
|
1467
2232
|
if (prop in target) return target[prop];
|
|
1468
2233
|
if (typeof prop === "string") return function(scopedProps) {
|
|
1469
2234
|
target._version.v;
|
|
@@ -1477,6 +2242,39 @@ function createSlots(children, slotsFromProps) {
|
|
|
1477
2242
|
};
|
|
1478
2243
|
} });
|
|
1479
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
|
+
*/
|
|
1480
2278
|
function normalizeSubTree(result) {
|
|
1481
2279
|
if (result == null || result === false || result === true) return {
|
|
1482
2280
|
type: Text,
|
|
@@ -1504,14 +2302,41 @@ function normalizeSubTree(result) {
|
|
|
1504
2302
|
};
|
|
1505
2303
|
return result;
|
|
1506
2304
|
}
|
|
1507
|
-
|
|
1508
|
-
|
|
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 = [
|
|
1509
2324
|
"client:load",
|
|
1510
2325
|
"client:idle",
|
|
1511
2326
|
"client:visible",
|
|
1512
2327
|
"client:media",
|
|
1513
2328
|
"client:only"
|
|
1514
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
|
+
*/
|
|
1515
2340
|
function createEmit(reactiveProps) {
|
|
1516
2341
|
return (event, ...args) => {
|
|
1517
2342
|
const eventName = `on${event[0].toUpperCase() + event.slice(1)}`;
|
|
@@ -1519,6 +2344,8 @@ function createEmit(reactiveProps) {
|
|
|
1519
2344
|
if (handler && typeof handler === "function") handler(...args);
|
|
1520
2345
|
};
|
|
1521
2346
|
}
|
|
2347
|
+
//#endregion
|
|
2348
|
+
//#region ../runtime-core/src/renderer.ts
|
|
1522
2349
|
function createRenderer(options) {
|
|
1523
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;
|
|
1524
2351
|
let currentAppContext = null;
|
|
@@ -1801,6 +2628,9 @@ function createRenderer(options) {
|
|
|
1801
2628
|
newChildren.forEach((c) => c.parent = newVNode);
|
|
1802
2629
|
reconcileChildrenArray(container, oldChildren, newChildren, parentIsSVG);
|
|
1803
2630
|
}
|
|
2631
|
+
/**
|
|
2632
|
+
* Check for duplicate keys in an array of VNodes and warn in development.
|
|
2633
|
+
*/
|
|
1804
2634
|
function checkDuplicateKeys(children) {
|
|
1805
2635
|
if (process.env.NODE_ENV === "production") return;
|
|
1806
2636
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
@@ -2020,8 +2850,10 @@ function createRenderer(options) {
|
|
|
2020
2850
|
mountComponent
|
|
2021
2851
|
};
|
|
2022
2852
|
}
|
|
2853
|
+
//#endregion
|
|
2854
|
+
//#region ../runtime-terminal/src/focus.ts
|
|
2023
2855
|
var focusableIds = /* @__PURE__ */ new Set();
|
|
2024
|
-
|
|
2856
|
+
var focusState = signal({ activeId: null });
|
|
2025
2857
|
function registerFocusable(id) {
|
|
2026
2858
|
focusableIds.add(id);
|
|
2027
2859
|
if (focusState.activeId === null) focusState.activeId = id;
|
|
@@ -2046,6 +2878,8 @@ function focusPrev() {
|
|
|
2046
2878
|
const ids = Array.from(focusableIds);
|
|
2047
2879
|
focusState.activeId = ids[((focusState.activeId ? ids.indexOf(focusState.activeId) : -1) - 1 + ids.length) % ids.length];
|
|
2048
2880
|
}
|
|
2881
|
+
//#endregion
|
|
2882
|
+
//#region ../runtime-terminal/src/utils.ts
|
|
2049
2883
|
function getColorCode(color) {
|
|
2050
2884
|
switch (color) {
|
|
2051
2885
|
case "red": return "\x1B[31m";
|
|
@@ -2073,7 +2907,10 @@ function getBackgroundColorCode(color) {
|
|
|
2073
2907
|
function stripAnsi(str) {
|
|
2074
2908
|
return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
|
|
2075
2909
|
}
|
|
2076
|
-
|
|
2910
|
+
//#endregion
|
|
2911
|
+
//#region ../runtime-terminal/src/components/Input.tsx
|
|
2912
|
+
/** @jsxImportSource @sigx/runtime-core */
|
|
2913
|
+
var Input = component(({ props, emit }) => {
|
|
2077
2914
|
const id = Math.random().toString(36).slice(2);
|
|
2078
2915
|
let isReady = false;
|
|
2079
2916
|
const isFocused = () => focusState.activeId === id;
|
|
@@ -2128,7 +2965,10 @@ const Input = component(({ props, emit }) => {
|
|
|
2128
2965
|
});
|
|
2129
2966
|
};
|
|
2130
2967
|
}, { name: "Input" });
|
|
2131
|
-
|
|
2968
|
+
//#endregion
|
|
2969
|
+
//#region ../runtime-terminal/src/components/ProgressBar.tsx
|
|
2970
|
+
/** @jsxImportSource @sigx/runtime-core */
|
|
2971
|
+
var ProgressBar = component(({ props }) => {
|
|
2132
2972
|
return () => {
|
|
2133
2973
|
const value = props.value || 0;
|
|
2134
2974
|
const max = props.max || 100;
|
|
@@ -2144,7 +2984,10 @@ const ProgressBar = component(({ props }) => {
|
|
|
2144
2984
|
return /* @__PURE__ */ jsx("box", { children: /* @__PURE__ */ jsx("text", { children: colorCode + barChar.repeat(filledLen) + emptyChar.repeat(emptyLen) + reset + ` ${Math.round(percentage * 100)}%` }) });
|
|
2145
2985
|
};
|
|
2146
2986
|
}, { name: "ProgressBar" });
|
|
2147
|
-
|
|
2987
|
+
//#endregion
|
|
2988
|
+
//#region ../runtime-terminal/src/components/Button.tsx
|
|
2989
|
+
/** @jsxImportSource @sigx/runtime-core */
|
|
2990
|
+
var Button = component(({ props, emit }) => {
|
|
2148
2991
|
const id = Math.random().toString(36).slice(2);
|
|
2149
2992
|
const isFocused = () => focusState.activeId === id;
|
|
2150
2993
|
const pressed = signal({ value: false });
|
|
@@ -2187,7 +3030,10 @@ const Button = component(({ props, emit }) => {
|
|
|
2187
3030
|
});
|
|
2188
3031
|
};
|
|
2189
3032
|
}, { name: "Button" });
|
|
2190
|
-
|
|
3033
|
+
//#endregion
|
|
3034
|
+
//#region ../runtime-terminal/src/components/Checkbox.tsx
|
|
3035
|
+
/** @jsxImportSource @sigx/runtime-core */
|
|
3036
|
+
var Checkbox = component(({ props, emit }) => {
|
|
2191
3037
|
const id = Math.random().toString(36).slice(2);
|
|
2192
3038
|
const isFocused = () => focusState.activeId === id;
|
|
2193
3039
|
const checked = () => !!props.model?.value;
|
|
@@ -2235,7 +3081,10 @@ const Checkbox = component(({ props, emit }) => {
|
|
|
2235
3081
|
] });
|
|
2236
3082
|
};
|
|
2237
3083
|
}, { name: "Checkbox" });
|
|
2238
|
-
|
|
3084
|
+
//#endregion
|
|
3085
|
+
//#region ../runtime-terminal/src/components/Select.tsx
|
|
3086
|
+
/** @jsxImportSource @sigx/runtime-core */
|
|
3087
|
+
var Select = component(({ props, emit }) => {
|
|
2239
3088
|
const id = Math.random().toString(36).slice(2);
|
|
2240
3089
|
let isReady = false;
|
|
2241
3090
|
const isFocused = () => focusState.activeId === id;
|
|
@@ -2308,7 +3157,7 @@ const Select = component(({ props, emit }) => {
|
|
|
2308
3157
|
}), descriptionElement] });
|
|
2309
3158
|
};
|
|
2310
3159
|
}, { name: "Select" });
|
|
2311
|
-
|
|
3160
|
+
var { render } = createRenderer({
|
|
2312
3161
|
patchProp: (el, key, prev, next) => {
|
|
2313
3162
|
el.props[key] = next;
|
|
2314
3163
|
scheduleRender();
|
|
@@ -2396,6 +3245,10 @@ function flushRender() {
|
|
|
2396
3245
|
process.stdout.write(lines.join("\x1B[K\n") + "\x1B[K");
|
|
2397
3246
|
process.stdout.write("\x1B[J");
|
|
2398
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
|
+
*/
|
|
2399
3252
|
function hasBoxChild(node) {
|
|
2400
3253
|
for (const child of node.children) if (child.tag === "box") return true;
|
|
2401
3254
|
return false;
|
|
@@ -2532,6 +3385,15 @@ function renderTerminal(app, options = {}) {
|
|
|
2532
3385
|
} };
|
|
2533
3386
|
}
|
|
2534
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
|
+
*/
|
|
2535
3397
|
function mountTerminal(options = { clearConsole: true }) {
|
|
2536
3398
|
return {
|
|
2537
3399
|
mount: terminalMount,
|
|
@@ -2541,6 +3403,9 @@ function mountTerminal(options = { clearConsole: true }) {
|
|
|
2541
3403
|
}
|
|
2542
3404
|
};
|
|
2543
3405
|
}
|
|
3406
|
+
/**
|
|
3407
|
+
* Exit the terminal app cleanly, restoring terminal state.
|
|
3408
|
+
*/
|
|
2544
3409
|
function exitTerminal() {
|
|
2545
3410
|
if (unmountFn) {
|
|
2546
3411
|
unmountFn();
|
|
@@ -2549,7 +3414,21 @@ function exitTerminal() {
|
|
|
2549
3414
|
process.stdout.write("\x1B[?25h");
|
|
2550
3415
|
process.stdout.write("\x1B[2J\x1B[H");
|
|
2551
3416
|
}
|
|
2552
|
-
|
|
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) => {
|
|
2553
3432
|
rootNode = {
|
|
2554
3433
|
type: "root",
|
|
2555
3434
|
props: {},
|
|
@@ -2577,6 +3456,7 @@ const terminalMount = (component, options, appContext) => {
|
|
|
2577
3456
|
};
|
|
2578
3457
|
};
|
|
2579
3458
|
setDefaultMount(terminalMount);
|
|
3459
|
+
//#endregion
|
|
2580
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 };
|
|
2581
3461
|
|
|
2582
3462
|
//# sourceMappingURL=index.js.map
|