@sigx/runtime-terminal 0.1.5 → 0.1.7

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 CHANGED
@@ -1,1002 +1,8 @@
1
- //#region ../runtime-core/src/plugins.ts
2
- const plugins$1 = [];
3
- /**
4
- * Get all registered plugins (internal use)
5
- */
6
- function getComponentPlugins$1() {
7
- return plugins$1;
8
- }
9
- const contextExtensions = [];
10
- /**
11
- * Apply all registered context extensions to a context object.
12
- * Called internally by the renderer when creating component contexts.
13
- */
14
- function applyContextExtensions(ctx) {
15
- for (const extension of contextExtensions) extension(ctx);
16
- }
17
-
18
- //#endregion
19
- //#region ../runtime-core/src/app.ts
20
- let defaultMountFn = null;
21
- /**
22
- * Set the default mount function for the platform.
23
- * Called by platform packages (runtime-dom, runtime-terminal) on import.
24
- *
25
- * @example
26
- * ```typescript
27
- * // In @sigx/runtime-dom
28
- * import { setDefaultMount } from '@sigx/runtime-core';
29
- * setDefaultMount(domMount);
30
- * ```
31
- */
32
- function setDefaultMount(mountFn) {
33
- defaultMountFn = mountFn;
34
- }
35
- /**
36
- * Notify all app hooks that a component was created.
37
- * Called by the renderer after setup() returns.
38
- */
39
- function notifyComponentCreated(context, instance) {
40
- if (!context) return;
41
- for (const hooks of context.hooks) try {
42
- hooks.onComponentCreated?.(instance);
43
- } catch (err) {
44
- handleHookError(context, err, instance, "onComponentCreated");
45
- }
46
- }
47
- /**
48
- * Notify all app hooks that a component was mounted.
49
- * Called by the renderer after mount hooks run.
50
- */
51
- function notifyComponentMounted(context, instance) {
52
- if (!context) return;
53
- for (const hooks of context.hooks) try {
54
- hooks.onComponentMounted?.(instance);
55
- } catch (err) {
56
- handleHookError(context, err, instance, "onComponentMounted");
57
- }
58
- }
59
- /**
60
- * Notify all app hooks that a component was unmounted.
61
- * Called by the renderer before cleanup.
62
- */
63
- function notifyComponentUnmounted(context, instance) {
64
- if (!context) return;
65
- for (const hooks of context.hooks) try {
66
- hooks.onComponentUnmounted?.(instance);
67
- } catch (err) {
68
- handleHookError(context, err, instance, "onComponentUnmounted");
69
- }
70
- }
71
- /**
72
- * Notify all app hooks that a component updated.
73
- * Called by the renderer after re-render.
74
- */
75
- function notifyComponentUpdated(context, instance) {
76
- if (!context) return;
77
- for (const hooks of context.hooks) try {
78
- hooks.onComponentUpdated?.(instance);
79
- } catch (err) {
80
- handleHookError(context, err, instance, "onComponentUpdated");
81
- }
82
- }
83
- /**
84
- * Handle an error in a component. Returns true if the error was handled.
85
- * Called by the renderer when an error occurs in setup or render.
86
- */
87
- function handleComponentError(context, err, instance, info) {
88
- if (!context) return false;
89
- for (const hooks of context.hooks) try {
90
- if (hooks.onComponentError?.(err, instance, info) === true) return true;
91
- } catch (hookErr) {
92
- console.error("Error in onComponentError hook:", hookErr);
93
- }
94
- if (context.config.errorHandler) try {
95
- if (context.config.errorHandler(err, instance, info) === true) return true;
96
- } catch (handlerErr) {
97
- console.error("Error in app.config.errorHandler:", handlerErr);
98
- }
99
- return false;
100
- }
101
- /**
102
- * Handle errors that occur in hooks themselves
103
- */
104
- function handleHookError(context, err, instance, hookName) {
105
- console.error(`Error in ${hookName} hook:`, err);
106
- if (context.config.errorHandler) try {
107
- context.config.errorHandler(err, instance, `plugin hook: ${hookName}`);
108
- } catch {}
109
- }
110
-
111
- //#endregion
112
- //#region ../runtime-core/src/component.ts
113
- let currentComponentContext = null;
114
- function getCurrentInstance() {
115
- return currentComponentContext;
116
- }
117
- function setCurrentInstance(ctx) {
118
- const prev = currentComponentContext;
119
- currentComponentContext = ctx;
120
- return prev;
121
- }
122
- function onMount(fn) {
123
- if (currentComponentContext) currentComponentContext.onMount(fn);
124
- else console.warn("onMount called outside of component setup");
125
- }
126
- function onCleanup(fn) {
127
- if (currentComponentContext) currentComponentContext.onCleanup(fn);
128
- else console.warn("onCleanup called outside of component setup");
129
- }
130
- const componentRegistry$1 = /* @__PURE__ */ new Map();
131
- /**
132
- * Define a component. Returns a JSX factory function.
133
- *
134
- * @param setup - Setup function that receives context and returns a render function
135
- * @param options - Optional configuration (e.g., name for DevTools)
136
- *
137
- * @example
138
- * ```tsx
139
- * type CardProps = DefineProp<"title", string> & DefineSlot<"header">;
140
- *
141
- * export const Card = defineComponent<CardProps>((ctx) => {
142
- * const { title } = ctx.props;
143
- * const { slots } = ctx;
144
- *
145
- * return () => (
146
- * <div class="card">
147
- * {slots.header?.() ?? <h2>{title}</h2>}
148
- * {slots.default()}
149
- * </div>
150
- * );
151
- * });
152
- * ```
153
- */
154
- function defineComponent(setup, options) {
155
- const factory = function(props) {
156
- return {
157
- type: factory,
158
- props: props || {},
159
- key: props?.key || null,
160
- children: [],
161
- dom: null
162
- };
163
- };
164
- factory.__setup = setup;
165
- factory.__name = options?.name;
166
- factory.__props = null;
167
- factory.__events = null;
168
- factory.__ref = null;
169
- factory.__slots = null;
170
- componentRegistry$1.set(factory, {
171
- name: options?.name,
172
- setup
173
- });
174
- getComponentPlugins$1().forEach((p) => p.onDefine?.(options?.name, factory, setup));
175
- return factory;
176
- }
177
-
178
- //#endregion
179
- //#region ../reactivity/src/index.ts
180
- let activeEffect = null;
181
- let batchDepth = 0;
182
- const pendingEffects = /* @__PURE__ */ new Set();
183
- function batch(fn) {
184
- batchDepth++;
185
- try {
186
- fn();
187
- } finally {
188
- batchDepth--;
189
- if (batchDepth === 0) {
190
- const effects = Array.from(pendingEffects);
191
- pendingEffects.clear();
192
- for (const effect$1 of effects) effect$1();
193
- }
194
- }
195
- }
196
- function runEffect(fn) {
197
- const effectFn = function() {
198
- cleanup(effectFn);
199
- activeEffect = effectFn;
200
- fn();
201
- activeEffect = null;
202
- };
203
- effectFn.deps = [];
204
- effectFn();
205
- const runner = (() => effectFn());
206
- runner.stop = () => cleanup(effectFn);
207
- return runner;
208
- }
209
- function cleanup(effect$1) {
210
- if (!effect$1.deps) return;
211
- for (const dep of effect$1.deps) dep.delete(effect$1);
212
- effect$1.deps.length = 0;
213
- }
214
- function track(depSet) {
215
- if (!activeEffect) return;
216
- depSet.add(activeEffect);
217
- activeEffect.deps.push(depSet);
218
- }
219
- function trigger(depSet) {
220
- const effects = Array.from(depSet);
221
- for (const effect$1 of effects) if (batchDepth > 0) pendingEffects.add(effect$1);
222
- else effect$1();
223
- }
224
- let accessObserver = null;
225
- function detectAccess(selector) {
226
- let result = null;
227
- const prev = accessObserver;
228
- accessObserver = (target, key) => {
229
- result = [target, key];
230
- };
231
- try {
232
- selector();
233
- } finally {
234
- accessObserver = prev;
235
- }
236
- return result;
237
- }
238
- function untrack(fn) {
239
- const prev = activeEffect;
240
- activeEffect = null;
241
- try {
242
- return fn();
243
- } finally {
244
- activeEffect = prev;
245
- }
246
- }
247
- function signal(target) {
248
- const depsMap = /* @__PURE__ */ new Map();
249
- const reactiveCache = /* @__PURE__ */ new WeakMap();
250
- return new Proxy(target, {
251
- get(obj, prop, receiver) {
252
- if (prop === "$set") return (newValue) => {
253
- batch(() => {
254
- if (Array.isArray(obj) && Array.isArray(newValue)) {
255
- const len = newValue.length;
256
- for (let i = 0; i < len; i++) Reflect.set(receiver, String(i), newValue[i]);
257
- Reflect.set(receiver, "length", len);
258
- } else {
259
- const newKeys = Object.keys(newValue);
260
- const oldKeys = Object.keys(obj);
261
- for (const key of newKeys) Reflect.set(receiver, key, newValue[key]);
262
- for (const key of oldKeys) if (!(key in newValue)) Reflect.deleteProperty(receiver, key);
263
- }
264
- });
265
- };
266
- if (Array.isArray(obj) && typeof prop === "string" && arrayInstrumentations.hasOwnProperty(prop)) return arrayInstrumentations[prop];
267
- const value = Reflect.get(obj, prop);
268
- if (accessObserver) accessObserver(receiver, prop);
269
- let dep = depsMap.get(prop);
270
- if (!dep) {
271
- dep = /* @__PURE__ */ new Set();
272
- depsMap.set(prop, dep);
273
- }
274
- track(dep);
275
- if (value && typeof value === "object") {
276
- let cached = reactiveCache.get(value);
277
- if (!cached) {
278
- cached = signal(value);
279
- reactiveCache.set(value, cached);
280
- }
281
- return cached;
282
- }
283
- return value;
284
- },
285
- set(obj, prop, newValue) {
286
- const oldLength = Array.isArray(obj) ? obj.length : 0;
287
- const oldValue = Reflect.get(obj, prop);
288
- const result = Reflect.set(obj, prop, newValue);
289
- if (!Object.is(oldValue, newValue)) {
290
- const dep = depsMap.get(prop);
291
- if (dep) trigger(dep);
292
- if (Array.isArray(obj)) {
293
- if (prop !== "length" && obj.length !== oldLength) {
294
- const lengthDep = depsMap.get("length");
295
- if (lengthDep) trigger(lengthDep);
296
- }
297
- if (prop === "length" && typeof newValue === "number" && newValue < oldLength) for (let i = newValue; i < oldLength; i++) {
298
- const idxDep = depsMap.get(String(i));
299
- if (idxDep) trigger(idxDep);
300
- }
301
- }
302
- }
303
- return result;
304
- },
305
- deleteProperty(obj, prop) {
306
- const hasKey = Object.prototype.hasOwnProperty.call(obj, prop);
307
- const result = Reflect.deleteProperty(obj, prop);
308
- if (result && hasKey) {
309
- const dep = depsMap.get(prop);
310
- if (dep) trigger(dep);
311
- }
312
- return result;
313
- }
314
- });
315
- }
316
- function effect(fn) {
317
- return runEffect(fn);
318
- }
319
- const arrayInstrumentations = {};
320
- [
321
- "push",
322
- "pop",
323
- "shift",
324
- "unshift",
325
- "splice",
326
- "sort",
327
- "reverse"
328
- ].forEach((method) => {
329
- arrayInstrumentations[method] = function(...args) {
330
- let res;
331
- batch(() => {
332
- res = Array.prototype[method].apply(this, args);
333
- });
334
- return res;
335
- };
336
- });
337
-
338
- //#endregion
339
- //#region ../runtime-core/src/jsx-runtime.ts
340
- const Fragment$1 = Symbol.for("sigx.Fragment");
341
- const Text$1 = Symbol.for("sigx.Text");
342
-
343
- //#endregion
344
- //#region ../runtime-core/src/lazy.tsx
345
- /**
346
- * Lazy loading utilities for sigx components.
347
- *
348
- * Provides runtime-only lazy loading with no build dependencies.
349
- * Works with any bundler that supports dynamic import().
350
- */
351
- let currentSuspenseBoundary$1 = null;
352
- /**
353
- * Register a promise with the current Suspense boundary
354
- * @internal
355
- */
356
- function registerPendingPromise$1(promise) {
357
- const boundary = currentSuspenseBoundary$1;
358
- if (boundary) {
359
- boundary.pending.add(promise);
360
- promise.finally(() => {
361
- boundary.pending.delete(promise);
362
- if (boundary.pending.size === 0) boundary.onResolve();
363
- });
364
- return true;
365
- }
366
- return false;
367
- }
368
- /**
369
- * Suspense boundary component for handling async loading states.
370
- *
371
- * Wraps lazy-loaded components and shows a fallback while they load.
372
- *
373
- * @example
374
- * ```tsx
375
- * import { lazy, Suspense } from 'sigx';
376
- *
377
- * const LazyDashboard = lazy(() => import('./Dashboard'));
378
- *
379
- * // Basic usage
380
- * <Suspense fallback={<div>Loading...</div>}>
381
- * <LazyDashboard />
382
- * </Suspense>
383
- *
384
- * // With spinner component
385
- * <Suspense fallback={<Spinner size="large" />}>
386
- * <LazyDashboard />
387
- * <LazyCharts />
388
- * </Suspense>
389
- * ```
390
- */
391
- const Suspense$1 = defineComponent((ctx) => {
392
- const { props, slots } = ctx;
393
- const state = ctx.signal({
394
- isReady: false,
395
- pendingCount: 0
396
- });
397
- const boundary = {
398
- pending: /* @__PURE__ */ new Set(),
399
- onResolve: () => {
400
- state.pendingCount = boundary.pending.size;
401
- if (boundary.pending.size === 0) state.isReady = true;
402
- }
403
- };
404
- ctx.onMount(() => {
405
- if (boundary.pending.size === 0) state.isReady = true;
406
- });
407
- return () => {
408
- state.isReady;
409
- state.pendingCount;
410
- const prevBoundary = currentSuspenseBoundary$1;
411
- currentSuspenseBoundary$1 = boundary;
412
- try {
413
- const children = slots.default();
414
- if (boundary.pending.size > 0) {
415
- const fallback = props.fallback;
416
- if (typeof fallback === "function") return fallback();
417
- return fallback ?? null;
418
- }
419
- if (Array.isArray(children)) {
420
- const filtered = children.filter((c) => c != null && c !== false && c !== true);
421
- if (filtered.length === 0) return null;
422
- if (filtered.length === 1) return filtered[0];
423
- return filtered;
424
- }
425
- return children;
426
- } catch (err) {
427
- if (err instanceof Promise) {
428
- registerPendingPromise$1(err);
429
- const fallback = props.fallback;
430
- if (typeof fallback === "function") return fallback();
431
- return fallback ?? null;
432
- }
433
- throw err;
434
- } finally {
435
- currentSuspenseBoundary$1 = prevBoundary;
436
- }
437
- };
438
- }, { name: "Suspense" });
439
-
440
- //#endregion
441
- //#region ../runtime-core/src/utils/props-accessor.ts
442
- /**
443
- * Creates a props accessor that can be called with defaults or accessed directly.
444
- * After calling with defaults, direct property access uses those defaults.
445
- *
446
- * @example
447
- * ```ts
448
- * // In component setup:
449
- * const props = createPropsAccessor(reactiveProps);
450
- *
451
- * // Set defaults
452
- * props({ count: 0, label: 'Default' });
453
- *
454
- * // Access props (falls back to defaults if not provided)
455
- * const count = props.count;
456
- * ```
457
- */
458
- function createPropsAccessor(reactiveProps) {
459
- let defaults = {};
460
- const proxy = new Proxy(function propsAccessor() {}, {
461
- get(_, key) {
462
- if (typeof key === "symbol") return void 0;
463
- const value = reactiveProps[key];
464
- return value != null ? value : defaults[key];
465
- },
466
- apply(_, __, args) {
467
- if (args[0] && typeof args[0] === "object") defaults = {
468
- ...defaults,
469
- ...args[0]
470
- };
471
- return proxy;
472
- },
473
- has(_, key) {
474
- if (typeof key === "symbol") return false;
475
- return key in reactiveProps || key in defaults;
476
- },
477
- ownKeys() {
478
- return [...new Set([...Object.keys(reactiveProps), ...Object.keys(defaults)])];
479
- },
480
- getOwnPropertyDescriptor(_, key) {
481
- if (typeof key === "symbol") return void 0;
482
- if (key in reactiveProps || key in defaults) return {
483
- enumerable: true,
484
- configurable: true,
485
- writable: false
486
- };
487
- }
488
- });
489
- return proxy;
490
- }
491
-
492
- //#endregion
493
- //#region ../runtime-core/src/utils/slots.ts
494
- /**
495
- * Slots system for component children.
496
- * Supports default and named slots with reactivity.
497
- */
498
- /**
499
- * Create slots object from children and slots prop.
500
- * Uses a version signal to trigger re-renders when children change.
501
- *
502
- * Supports named slots via:
503
- * - `slots` prop object (e.g., `slots={{ header: () => <div>...</div> }}`)
504
- * - `slot` prop on children (e.g., `<div slot="header">...</div>`)
505
- *
506
- * @example
507
- * ```tsx
508
- * // Parent component
509
- * <Card slots={{ header: () => <h1>Title</h1> }}>
510
- * <p>Default content</p>
511
- * <span slot="footer">Footer text</span>
512
- * </Card>
513
- *
514
- * // Card component setup
515
- * const slots = createSlots(children, slotsFromProps);
516
- * return () => (
517
- * <div>
518
- * {slots.header()}
519
- * {slots.default()}
520
- * {slots.footer()}
521
- * </div>
522
- * );
523
- * ```
524
- */
525
- function createSlots(children, slotsFromProps) {
526
- const versionSignal = signal({ v: 0 });
527
- function extractNamedSlotsFromChildren(c) {
528
- const defaultChildren = [];
529
- const namedSlots = {};
530
- if (c == null) return {
531
- defaultChildren,
532
- namedSlots
533
- };
534
- const items = Array.isArray(c) ? c : [c];
535
- for (const child of items) if (child && typeof child === "object" && child.props && child.props.slot) {
536
- const slotName = child.props.slot;
537
- if (!namedSlots[slotName]) namedSlots[slotName] = [];
538
- namedSlots[slotName].push(child);
539
- } else defaultChildren.push(child);
540
- return {
541
- defaultChildren,
542
- namedSlots
543
- };
544
- }
545
- const slotsObj = {
546
- _children: children,
547
- _slotsFromProps: slotsFromProps || {},
548
- _version: versionSignal,
549
- _isPatching: false,
550
- default: function() {
551
- this._version.v;
552
- const c = this._children;
553
- const { defaultChildren } = extractNamedSlotsFromChildren(c);
554
- return defaultChildren.filter((child) => child != null && child !== false && child !== true);
555
- }
556
- };
557
- return new Proxy(slotsObj, { get(target, prop) {
558
- if (prop in target) return target[prop];
559
- if (typeof prop === "string") return function(scopedProps) {
560
- target._version.v;
561
- if (target._slotsFromProps && typeof target._slotsFromProps[prop] === "function") {
562
- const result = target._slotsFromProps[prop](scopedProps);
563
- if (result == null) return [];
564
- return Array.isArray(result) ? result : [result];
565
- }
566
- const { namedSlots } = extractNamedSlotsFromChildren(target._children);
567
- return namedSlots[prop] || [];
568
- };
569
- } });
570
- }
571
-
572
- //#endregion
573
- //#region ../runtime-core/src/utils/normalize.ts
574
- /**
575
- * VNode normalization utilities.
576
- * Converts render results into proper VNode structures.
577
- */
578
- /**
579
- * Normalize render result to a VNode (wrapping arrays in Fragment).
580
- * Handles null, undefined, false, true by returning an empty Text node.
581
- *
582
- * This is used to normalize the return value of component render functions
583
- * into a consistent VNode structure for the renderer to process.
584
- *
585
- * @example
586
- * ```ts
587
- * // Conditional rendering returns null/false
588
- * normalizeSubTree(null) // → empty Text node
589
- * normalizeSubTree(false) // → empty Text node
590
- *
591
- * // Arrays become Fragments
592
- * normalizeSubTree([<A/>, <B/>]) // → Fragment with children
593
- *
594
- * // Primitives become Text nodes
595
- * normalizeSubTree("hello") // → Text node
596
- * normalizeSubTree(42) // → Text node
597
- *
598
- * // VNodes pass through
599
- * normalizeSubTree(<div/>) // → same VNode
600
- * ```
601
- */
602
- function normalizeSubTree(result) {
603
- if (result == null || result === false || result === true) return {
604
- type: Text$1,
605
- props: {},
606
- key: null,
607
- children: [],
608
- dom: null,
609
- text: ""
610
- };
611
- if (Array.isArray(result)) return {
612
- type: Fragment$1,
613
- props: {},
614
- key: null,
615
- children: result,
616
- dom: null
617
- };
618
- if (typeof result === "string" || typeof result === "number") return {
619
- type: Text$1,
620
- props: {},
621
- key: null,
622
- children: [],
623
- dom: null,
624
- text: result
625
- };
626
- return result;
627
- }
628
-
629
- //#endregion
630
- //#region ../runtime-core/src/renderer.ts
631
- /**
632
- * Check if a vnode type is a component (has __setup)
633
- */
634
- function isComponent(type) {
635
- return typeof type === "function" && "__setup" in type;
636
- }
637
- function createRenderer(options) {
638
- 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 } = options;
639
- let currentAppContext = null;
640
- function render$1(element, container, appContext) {
641
- if (appContext) currentAppContext = appContext;
642
- const oldVNode = container._vnode;
643
- let vnode = null;
644
- if (element != null && element !== false && element !== true) if (typeof element === "string" || typeof element === "number") vnode = {
645
- type: Text$1,
646
- props: {},
647
- key: null,
648
- children: [],
649
- dom: null,
650
- text: element
651
- };
652
- else if (isComponent(element)) vnode = {
653
- type: element,
654
- props: {},
655
- key: null,
656
- children: [],
657
- dom: null
658
- };
659
- else vnode = element;
660
- if (vnode) {
661
- if (oldVNode) patch(oldVNode, vnode, container);
662
- else mount(vnode, container);
663
- container._vnode = vnode;
664
- } else if (oldVNode) {
665
- unmount(oldVNode, container);
666
- container._vnode = null;
667
- }
668
- }
669
- function mount(vnode, container, before = null) {
670
- if (vnode == null || vnode === false || vnode === true) return;
671
- if (vnode.type === Text$1) {
672
- const node = hostCreateText(String(vnode.text));
673
- vnode.dom = node;
674
- node.__vnode = vnode;
675
- hostInsert(node, container, before);
676
- return;
677
- }
678
- if (vnode.type === Fragment$1) {
679
- const anchor = hostCreateComment("");
680
- vnode.dom = anchor;
681
- hostInsert(anchor, container, before);
682
- if (vnode.children) vnode.children.forEach((child) => mount(child, container, anchor));
683
- return;
684
- }
685
- if (isComponent(vnode.type)) {
686
- mountComponent(vnode, container, before, vnode.type.__setup);
687
- return;
688
- }
689
- const element = hostCreateElement(vnode.type);
690
- vnode.dom = element;
691
- element.__vnode = vnode;
692
- if (vnode.props) {
693
- for (const key in vnode.props) if (key !== "children" && key !== "key" && key !== "ref") hostPatchProp(element, key, null, vnode.props[key]);
694
- if (vnode.props.ref) {
695
- if (typeof vnode.props.ref === "function") vnode.props.ref(element);
696
- else if (typeof vnode.props.ref === "object") vnode.props.ref.current = element;
697
- }
698
- }
699
- if (vnode.children) vnode.children.forEach((child) => {
700
- child.parent = vnode;
701
- mount(child, element);
702
- });
703
- hostInsert(element, container, before);
704
- }
705
- function unmount(vnode, container) {
706
- const internalVNode = vnode;
707
- if (internalVNode._effect) internalVNode._effect.stop();
708
- if (vnode.cleanup) vnode.cleanup();
709
- if (isComponent(vnode.type)) {
710
- const subTree = internalVNode._subTree;
711
- if (subTree) unmount(subTree, container);
712
- if (vnode.dom) hostRemove(vnode.dom);
713
- if (vnode.props?.ref) {
714
- if (typeof vnode.props.ref === "function") vnode.props.ref(null);
715
- else if (typeof vnode.props.ref === "object") vnode.props.ref.current = null;
716
- }
717
- return;
718
- }
719
- if (vnode.type === Fragment$1) {
720
- if (vnode.children) vnode.children.forEach((child) => unmount(child, container));
721
- if (vnode.dom) hostRemove(vnode.dom);
722
- return;
723
- }
724
- if (vnode.props?.ref) {
725
- if (typeof vnode.props.ref === "function") vnode.props.ref(null);
726
- else if (vnode.props.ref && typeof vnode.props.ref === "object") vnode.props.ref.current = null;
727
- }
728
- if (vnode.children && vnode.children.length > 0) vnode.children.forEach((child) => unmount(child, vnode.dom));
729
- if (vnode.dom) hostRemove(vnode.dom);
730
- }
731
- function patch(oldVNode, newVNode, container) {
732
- if (oldVNode === newVNode) return;
733
- if (!isSameVNode(oldVNode, newVNode)) {
734
- const parent = hostParentNode(oldVNode.dom) || container;
735
- const nextSibling = hostNextSibling(oldVNode.dom);
736
- unmount(oldVNode, parent);
737
- mount(newVNode, parent, nextSibling);
738
- return;
739
- }
740
- const oldInternal = oldVNode;
741
- const newInternal = newVNode;
742
- if (oldInternal._effect) {
743
- newVNode.dom = oldVNode.dom;
744
- newInternal._effect = oldInternal._effect;
745
- newInternal._subTree = oldInternal._subTree;
746
- newInternal._slots = oldInternal._slots;
747
- const props = oldInternal._componentProps;
748
- newInternal._componentProps = props;
749
- if (props) {
750
- const newProps$1 = newVNode.props || {};
751
- untrack(() => {
752
- for (const key in newProps$1) if (key !== "children" && key !== "key" && key !== "ref") {
753
- if (props[key] !== newProps$1[key]) props[key] = newProps$1[key];
754
- }
755
- for (const key in props) if (!(key in newProps$1) && key !== "children" && key !== "key" && key !== "ref") delete props[key];
756
- });
757
- }
758
- const slotsRef = oldInternal._slots;
759
- const newChildren = newVNode.props?.children;
760
- const newSlotsFromProps = newVNode.props?.slots;
761
- if (slotsRef) {
762
- if (newChildren !== void 0) slotsRef._children = newChildren;
763
- if (newSlotsFromProps !== void 0) slotsRef._slotsFromProps = newSlotsFromProps;
764
- if (!slotsRef._isPatching) {
765
- slotsRef._isPatching = true;
766
- try {
767
- untrack(() => {
768
- slotsRef._version.v++;
769
- });
770
- } finally {
771
- slotsRef._isPatching = false;
772
- }
773
- }
774
- }
775
- return;
776
- }
777
- if (newVNode.type === Text$1) {
778
- newVNode.dom = oldVNode.dom;
779
- if (oldVNode.text !== newVNode.text) hostSetText(newVNode.dom, String(newVNode.text));
780
- return;
781
- }
782
- if (newVNode.type === Fragment$1) {
783
- patchChildren(oldVNode, newVNode, container);
784
- return;
785
- }
786
- const element = newVNode.dom = oldVNode.dom;
787
- const oldProps = oldVNode.props || {};
788
- const newProps = newVNode.props || {};
789
- for (const key in oldProps) if (!(key in newProps) && key !== "children" && key !== "key" && key !== "ref") hostPatchProp(element, key, oldProps[key], null);
790
- for (const key in newProps) {
791
- const oldValue = oldProps[key];
792
- const newValue = newProps[key];
793
- if (key !== "children" && key !== "key" && key !== "ref" && oldValue !== newValue) hostPatchProp(element, key, oldValue, newValue);
794
- }
795
- patchChildren(oldVNode, newVNode, element);
796
- }
797
- function patchChildren(oldVNode, newVNode, container) {
798
- const oldChildren = oldVNode.children;
799
- const newChildren = newVNode.children;
800
- newChildren.forEach((c) => c.parent = newVNode);
801
- reconcileChildrenArray(container, oldChildren, newChildren);
802
- }
803
- function reconcileChildrenArray(parent, oldChildren, newChildren) {
804
- let oldStartIdx = 0;
805
- let oldEndIdx = oldChildren.length - 1;
806
- let oldStartVNode = oldChildren[0];
807
- let oldEndVNode = oldChildren[oldEndIdx];
808
- let newStartIdx = 0;
809
- let newEndIdx = newChildren.length - 1;
810
- let newStartVNode = newChildren[0];
811
- let newEndVNode = newChildren[newEndIdx];
812
- let oldKeyToIdx;
813
- while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) if (oldStartVNode == null) oldStartVNode = oldChildren[++oldStartIdx];
814
- else if (oldEndVNode == null) oldEndVNode = oldChildren[--oldEndIdx];
815
- else if (isSameVNode(oldStartVNode, newStartVNode)) {
816
- patch(oldStartVNode, newStartVNode, parent);
817
- oldStartVNode = oldChildren[++oldStartIdx];
818
- newStartVNode = newChildren[++newStartIdx];
819
- } else if (isSameVNode(oldEndVNode, newEndVNode)) {
820
- patch(oldEndVNode, newEndVNode, parent);
821
- oldEndVNode = oldChildren[--oldEndIdx];
822
- newEndVNode = newChildren[--newEndIdx];
823
- } else if (isSameVNode(oldStartVNode, newEndVNode)) {
824
- patch(oldStartVNode, newEndVNode, parent);
825
- const nodeToMove = oldStartVNode.dom;
826
- const anchor = hostNextSibling(oldEndVNode.dom);
827
- if (nodeToMove) hostInsert(nodeToMove, parent, anchor);
828
- oldStartVNode = oldChildren[++oldStartIdx];
829
- newEndVNode = newChildren[--newEndIdx];
830
- } else if (isSameVNode(oldEndVNode, newStartVNode)) {
831
- patch(oldEndVNode, newStartVNode, parent);
832
- const nodeToMove = oldEndVNode.dom;
833
- const anchor = oldStartVNode.dom;
834
- if (nodeToMove) hostInsert(nodeToMove, parent, anchor);
835
- oldEndVNode = oldChildren[--oldEndIdx];
836
- newStartVNode = newChildren[++newStartIdx];
837
- } else {
838
- if (!oldKeyToIdx) oldKeyToIdx = createKeyToKeyIndexMap(oldChildren, oldStartIdx, oldEndIdx);
839
- const idxInOld = newStartVNode.key != null ? oldKeyToIdx.get(String(newStartVNode.key)) : findIndexInOld(oldChildren, newStartVNode, oldStartIdx, oldEndIdx);
840
- if (idxInOld != null) {
841
- const vnodeToMove = oldChildren[idxInOld];
842
- patch(vnodeToMove, newStartVNode, parent);
843
- oldChildren[idxInOld] = void 0;
844
- if (vnodeToMove.dom && oldStartVNode.dom) hostInsert(vnodeToMove.dom, parent, oldStartVNode.dom);
845
- } else mount(newStartVNode, parent, oldStartVNode.dom);
846
- newStartVNode = newChildren[++newStartIdx];
847
- }
848
- if (oldStartIdx > oldEndIdx) {
849
- if (newStartIdx <= newEndIdx) {
850
- const anchor = newChildren[newEndIdx + 1] == null ? null : newChildren[newEndIdx + 1].dom;
851
- for (let i = newStartIdx; i <= newEndIdx; i++) mount(newChildren[i], parent, anchor);
852
- }
853
- } else if (newStartIdx > newEndIdx) {
854
- for (let i = oldStartIdx; i <= oldEndIdx; i++) if (oldChildren[i]) unmount(oldChildren[i], parent);
855
- }
856
- }
857
- function isSameVNode(n1, n2) {
858
- const k1 = n1.key == null ? null : n1.key;
859
- const k2 = n2.key == null ? null : n2.key;
860
- if (n1.type !== n2.type) return false;
861
- if (k1 === k2) return true;
862
- return String(k1) === String(k2);
863
- }
864
- function createKeyToKeyIndexMap(children, beginIdx, endIdx) {
865
- const map = /* @__PURE__ */ new Map();
866
- for (let i = beginIdx; i <= endIdx; i++) {
867
- const key = children[i]?.key;
868
- if (key != null) map.set(String(key), i);
869
- }
870
- return map;
871
- }
872
- function findIndexInOld(children, newChild, beginIdx, endIdx) {
873
- for (let i = beginIdx; i <= endIdx; i++) if (children[i] && isSameVNode(children[i], newChild)) return i;
874
- return null;
875
- }
876
- function mountComponent(vnode, container, before, setup) {
877
- const anchor = hostCreateComment("");
878
- vnode.dom = anchor;
879
- anchor.__vnode = vnode;
880
- hostInsert(anchor, container, before);
881
- let exposed = null;
882
- let exposeCalled = false;
883
- const { children, slots: slotsFromProps, ...propsData } = vnode.props || {};
884
- const reactiveProps = signal(propsData);
885
- const internalVNode = vnode;
886
- internalVNode._componentProps = reactiveProps;
887
- const slots = createSlots(children, slotsFromProps);
888
- internalVNode._slots = slots;
889
- const mountHooks = [];
890
- const cleanupHooks = [];
891
- const parentInstance = getCurrentInstance();
892
- const componentName = vnode.type.__name;
893
- const ctx = {
894
- el: container,
895
- signal,
896
- props: createPropsAccessor(reactiveProps),
897
- slots,
898
- emit: (event, ...args) => {
899
- const handler = reactiveProps[`on${event[0].toUpperCase() + event.slice(1)}`];
900
- if (handler && typeof handler === "function") handler(...args);
901
- },
902
- parent: parentInstance,
903
- onMount: (fn) => {
904
- mountHooks.push(fn);
905
- },
906
- onCleanup: (fn) => {
907
- cleanupHooks.push(fn);
908
- },
909
- expose: (exposedValue) => {
910
- exposed = exposedValue;
911
- exposeCalled = true;
912
- },
913
- renderFn: null,
914
- update: () => {}
915
- };
916
- applyContextExtensions(ctx);
917
- ctx.__name = componentName;
918
- if (currentAppContext) ctx._appContext = currentAppContext;
919
- const componentInstance = {
920
- name: componentName,
921
- ctx,
922
- vnode
923
- };
924
- const prev = setCurrentInstance(ctx);
925
- let renderFn;
926
- try {
927
- const setupResult = setup(ctx);
928
- if (setupResult && typeof setupResult.then === "function") throw new Error(`Async setup in component "${componentName}" is only supported during SSR. On the client, use pre-loaded data from hydration or fetch in onMount.`);
929
- renderFn = setupResult;
930
- notifyComponentCreated(currentAppContext, componentInstance);
931
- } catch (err) {
932
- if (!handleComponentError(currentAppContext, err, componentInstance, "setup")) throw err;
933
- } finally {
934
- setCurrentInstance(prev);
935
- }
936
- if (vnode.props?.ref) {
937
- const refValue = exposeCalled ? exposed : null;
938
- if (typeof vnode.props.ref === "function") vnode.props.ref(refValue);
939
- else if (vnode.props.ref && typeof vnode.props.ref === "object") vnode.props.ref.current = refValue;
940
- }
941
- if (renderFn) {
942
- ctx.renderFn = renderFn;
943
- const componentEffect = effect(() => {
944
- const prevInstance = setCurrentInstance(ctx);
945
- try {
946
- const subTreeResult = ctx.renderFn();
947
- if (subTreeResult == null) return;
948
- const subTree = normalizeSubTree(subTreeResult);
949
- const prevSubTree = internalVNode._subTree;
950
- if (prevSubTree) {
951
- patch(prevSubTree, subTree, container);
952
- notifyComponentUpdated(currentAppContext, componentInstance);
953
- } else mount(subTree, container, anchor);
954
- internalVNode._subTree = subTree;
955
- } catch (err) {
956
- if (!handleComponentError(currentAppContext, err, componentInstance, "render")) throw err;
957
- } finally {
958
- setCurrentInstance(prevInstance);
959
- }
960
- });
961
- internalVNode._effect = componentEffect;
962
- ctx.update = () => {
963
- componentEffect();
964
- };
965
- }
966
- const mountCtx = { el: container };
967
- mountHooks.forEach((hook) => hook(mountCtx));
968
- notifyComponentMounted(currentAppContext, componentInstance);
969
- vnode.cleanup = () => {
970
- notifyComponentUnmounted(currentAppContext, componentInstance);
971
- cleanupHooks.forEach((hook) => hook(mountCtx));
972
- };
973
- }
974
- return {
975
- render: render$1,
976
- patch,
977
- mount,
978
- unmount,
979
- mountComponent,
980
- createApp: (rootComponent) => {
981
- return { mount(selectorOrContainer) {
982
- let container = null;
983
- if (typeof selectorOrContainer === "string") {
984
- if (options.querySelector) container = options.querySelector(selectorOrContainer);
985
- } else container = selectorOrContainer;
986
- if (!container) {
987
- console.warn(`Container not found: ${selectorOrContainer}`);
988
- return;
989
- }
990
- render$1(rootComponent, container);
991
- } };
992
- }
993
- };
994
- }
995
-
996
- //#endregion
997
- //#region src/focus.ts
998
- const focusableIds = /* @__PURE__ */ new Set();
999
- const focusState = signal({ activeId: null });
1
+ import { component as component$1, createRenderer, onMounted, onUnmounted, setDefaultMount, signal } from "@sigx/runtime-core";
2
+ import { signal as signal$1 } from "@sigx/reactivity";
3
+ import { jsx, jsxs } from "@sigx/runtime-core/jsx-runtime";
4
+ var focusableIds = /* @__PURE__ */ new Set();
5
+ const focusState = signal$1({ activeId: null });
1000
6
  function registerFocusable(id) {
1001
7
  focusableIds.add(id);
1002
8
  if (focusState.activeId === null) focusState.activeId = id;
@@ -1021,9 +27,6 @@ function focusPrev() {
1021
27
  const ids = Array.from(focusableIds);
1022
28
  focusState.activeId = ids[((focusState.activeId ? ids.indexOf(focusState.activeId) : -1) - 1 + ids.length) % ids.length];
1023
29
  }
1024
-
1025
- //#endregion
1026
- //#region src/utils.ts
1027
30
  function getColorCode(color) {
1028
31
  switch (color) {
1029
32
  case "red": return "\x1B[31m";
@@ -1051,298 +54,48 @@ function getBackgroundColorCode(color) {
1051
54
  function stripAnsi(str) {
1052
55
  return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
1053
56
  }
1054
-
1055
- //#endregion
1056
- //#region ../runtime-core/dist/index.js
1057
- let platformSyncProcessor = null;
1058
- /**
1059
- * Get the current platform sync processor (for internal use).
1060
- */
1061
- function getPlatformSyncProcessor() {
1062
- return platformSyncProcessor;
1063
- }
1064
- const plugins = [];
1065
- /**
1066
- * Get all registered plugins (internal use)
1067
- */
1068
- function getComponentPlugins() {
1069
- return plugins;
1070
- }
1071
- const componentRegistry = /* @__PURE__ */ new Map();
1072
- /**
1073
- * Define a component. Returns a JSX factory function.
1074
- *
1075
- * @param setup - Setup function that receives context and returns a render function
1076
- * @param options - Optional configuration (e.g., name for DevTools)
1077
- *
1078
- * @example
1079
- * ```tsx
1080
- * type CardProps = DefineProp<"title", string> & DefineSlot<"header">;
1081
- *
1082
- * export const Card = defineComponent<CardProps>((ctx) => {
1083
- * const { title } = ctx.props;
1084
- * const { slots } = ctx;
1085
- *
1086
- * return () => (
1087
- * <div class="card">
1088
- * {slots.header?.() ?? <h2>{title}</h2>}
1089
- * {slots.default()}
1090
- * </div>
1091
- * );
1092
- * });
1093
- * ```
1094
- */
1095
- function defineComponent$1(setup, options) {
1096
- const factory = function(props) {
1097
- return {
1098
- type: factory,
1099
- props: props || {},
1100
- key: props?.key || null,
1101
- children: [],
1102
- dom: null
1103
- };
1104
- };
1105
- factory.__setup = setup;
1106
- factory.__name = options?.name;
1107
- factory.__props = null;
1108
- factory.__events = null;
1109
- factory.__ref = null;
1110
- factory.__slots = null;
1111
- componentRegistry.set(factory, {
1112
- name: options?.name,
1113
- setup
1114
- });
1115
- getComponentPlugins().forEach((p) => p.onDefine?.(options?.name, factory, setup));
1116
- return factory;
1117
- }
1118
- const Fragment = Symbol.for("sigx.Fragment");
1119
- const Text = Symbol.for("sigx.Text");
1120
- function normalizeChildren(children) {
1121
- if (children == null || children === false || children === true) return [];
1122
- if (Array.isArray(children)) return children.flatMap((c) => normalizeChildren(c));
1123
- if (typeof children === "string" || typeof children === "number") return [{
1124
- type: Text,
1125
- props: {},
1126
- key: null,
1127
- children: [],
1128
- dom: null,
1129
- text: children
1130
- }];
1131
- if (children.type) return [children];
1132
- return [];
1133
- }
1134
- /**
1135
- * Check if a type is a sigx component (has __setup)
1136
- */
1137
- function isComponent$1(type) {
1138
- return typeof type === "function" && "__setup" in type;
1139
- }
1140
- /**
1141
- * Create a JSX element - this is the core function called by TSX transpilation
1142
- */
1143
- function jsx(type, props, key) {
1144
- const processedProps = { ...props || {} };
1145
- if (props) {
1146
- for (const propKey in props) if (propKey === "sync") {
1147
- let syncBinding = props[propKey];
1148
- if (typeof syncBinding === "function") {
1149
- const detected = detectAccess(syncBinding);
1150
- if (detected) syncBinding = detected;
1151
- }
1152
- if (Array.isArray(syncBinding) && syncBinding.length === 2) {
1153
- const [stateObj, key$1] = syncBinding;
1154
- let handled = false;
1155
- const platformProcessor = getPlatformSyncProcessor();
1156
- if (typeof type === "string" && platformProcessor) handled = platformProcessor(type, processedProps, [stateObj, key$1], props);
1157
- if (!handled) {
1158
- processedProps.value = stateObj[key$1];
1159
- const existingHandler = processedProps["onUpdate:value"];
1160
- processedProps["onUpdate:value"] = (v) => {
1161
- stateObj[key$1] = v;
1162
- if (existingHandler) existingHandler(v);
1163
- };
1164
- }
1165
- delete processedProps.sync;
1166
- }
1167
- } else if (propKey.startsWith("sync:")) {
1168
- const syncBinding = props[propKey];
1169
- if (Array.isArray(syncBinding) && syncBinding.length === 2) {
1170
- const [stateObj, key$1] = syncBinding;
1171
- const name = propKey.slice(5);
1172
- processedProps[name] = stateObj[key$1];
1173
- const eventName = `onUpdate:${name}`;
1174
- const existingHandler = processedProps[eventName];
1175
- processedProps[eventName] = (v) => {
1176
- stateObj[key$1] = v;
1177
- if (existingHandler) existingHandler(v);
1178
- };
1179
- delete processedProps[propKey];
1180
- }
1181
- }
1182
- }
1183
- if (isComponent$1(type)) {
1184
- const { children: children$1, ...rest$1 } = processedProps;
1185
- return {
1186
- type,
1187
- props: {
1188
- ...rest$1,
1189
- children: children$1
1190
- },
1191
- key: key || rest$1.key || null,
1192
- children: [],
1193
- dom: null
1194
- };
1195
- }
1196
- if (typeof type === "function" && type !== Fragment) return type(processedProps);
1197
- const { children, ...rest } = processedProps;
1198
- return {
1199
- type,
1200
- props: rest,
1201
- key: key || rest.key || null,
1202
- children: normalizeChildren(children),
1203
- dom: null
1204
- };
1205
- }
1206
- /**
1207
- * JSX Factory for fragments
1208
- */
1209
- function jsxs(type, props, key) {
1210
- return jsx(type, props, key);
1211
- }
1212
- /**
1213
- * Lazy loading utilities for sigx components.
1214
- *
1215
- * Provides runtime-only lazy loading with no build dependencies.
1216
- * Works with any bundler that supports dynamic import().
1217
- */
1218
- let currentSuspenseBoundary = null;
1219
- /**
1220
- * Register a promise with the current Suspense boundary
1221
- * @internal
1222
- */
1223
- function registerPendingPromise(promise) {
1224
- const boundary = currentSuspenseBoundary;
1225
- if (boundary) {
1226
- boundary.pending.add(promise);
1227
- promise.finally(() => {
1228
- boundary.pending.delete(promise);
1229
- if (boundary.pending.size === 0) boundary.onResolve();
1230
- });
1231
- return true;
1232
- }
1233
- return false;
1234
- }
1235
- /**
1236
- * Suspense boundary component for handling async loading states.
1237
- *
1238
- * Wraps lazy-loaded components and shows a fallback while they load.
1239
- *
1240
- * @example
1241
- * ```tsx
1242
- * import { lazy, Suspense } from 'sigx';
1243
- *
1244
- * const LazyDashboard = lazy(() => import('./Dashboard'));
1245
- *
1246
- * // Basic usage
1247
- * <Suspense fallback={<div>Loading...</div>}>
1248
- * <LazyDashboard />
1249
- * </Suspense>
1250
- *
1251
- * // With spinner component
1252
- * <Suspense fallback={<Spinner size="large" />}>
1253
- * <LazyDashboard />
1254
- * <LazyCharts />
1255
- * </Suspense>
1256
- * ```
1257
- */
1258
- const Suspense = defineComponent$1((ctx) => {
1259
- const { props, slots } = ctx;
1260
- const state = ctx.signal({
1261
- isReady: false,
1262
- pendingCount: 0
1263
- });
1264
- const boundary = {
1265
- pending: /* @__PURE__ */ new Set(),
1266
- onResolve: () => {
1267
- state.pendingCount = boundary.pending.size;
1268
- if (boundary.pending.size === 0) state.isReady = true;
1269
- }
1270
- };
1271
- ctx.onMount(() => {
1272
- if (boundary.pending.size === 0) state.isReady = true;
1273
- });
1274
- return () => {
1275
- state.isReady;
1276
- state.pendingCount;
1277
- const prevBoundary = currentSuspenseBoundary;
1278
- currentSuspenseBoundary = boundary;
1279
- try {
1280
- const children = slots.default();
1281
- if (boundary.pending.size > 0) {
1282
- const fallback = props.fallback;
1283
- if (typeof fallback === "function") return fallback();
1284
- return fallback ?? null;
1285
- }
1286
- if (Array.isArray(children)) {
1287
- const filtered = children.filter((c) => c != null && c !== false && c !== true);
1288
- if (filtered.length === 0) return null;
1289
- if (filtered.length === 1) return filtered[0];
1290
- return filtered;
1291
- }
1292
- return children;
1293
- } catch (err) {
1294
- if (err instanceof Promise) {
1295
- registerPendingPromise(err);
1296
- const fallback = props.fallback;
1297
- if (typeof fallback === "function") return fallback();
1298
- return fallback ?? null;
1299
- }
1300
- throw err;
1301
- } finally {
1302
- currentSuspenseBoundary = prevBoundary;
1303
- }
1304
- };
1305
- }, { name: "Suspense" });
1306
-
1307
- //#endregion
1308
- //#region src/components/Input.tsx
1309
- /** @jsxImportSource @sigx/runtime-core */
1310
- const Input = defineComponent(({ props, emit }) => {
57
+ const Input = component$1(({ props, emit }) => {
1311
58
  const id = Math.random().toString(36).slice(2);
59
+ let isReady = false;
1312
60
  const isFocused = () => focusState.activeId === id;
61
+ const getValue = () => props.model?.value || "";
1313
62
  const handleKey = (key) => {
1314
63
  if (!isFocused()) return;
64
+ if (!isReady) return;
1315
65
  if (key === "\r") {
1316
- emit("submit", props.value || "");
66
+ emit("submit", getValue());
1317
67
  return;
1318
68
  }
1319
69
  if (key === "\n") return;
1320
70
  if (key === "" || key === "\b") {
1321
- const val = props.value || "";
71
+ const val = getValue();
1322
72
  if (val.length > 0) {
1323
- const newValue$1 = val.slice(0, -1);
1324
- emit("update:value", newValue$1);
1325
- emit("input", newValue$1);
73
+ const newValue = val.slice(0, -1);
74
+ if (props.model) props.model.value = newValue;
75
+ emit("input", newValue);
1326
76
  }
1327
77
  return;
1328
78
  }
1329
79
  if (key.length > 1) return;
1330
- const newValue = (props.value || "") + key;
1331
- emit("update:value", newValue);
80
+ const newValue = getValue() + key;
81
+ if (props.model) props.model.value = newValue;
1332
82
  emit("input", newValue);
1333
83
  };
1334
84
  let keyCleanup = null;
1335
- onMount(() => {
85
+ onMounted(() => {
1336
86
  registerFocusable(id);
1337
87
  if (props.autofocus) focus(id);
1338
88
  keyCleanup = onKey(handleKey);
89
+ setTimeout(() => {
90
+ isReady = true;
91
+ }, 50);
1339
92
  });
1340
- onCleanup(() => {
93
+ onUnmounted(() => {
1341
94
  if (keyCleanup) keyCleanup();
1342
95
  unregisterFocusable(id);
1343
96
  });
1344
97
  return () => {
1345
- const val = (props.value || "").replace(/[\r\n]+/g, " ");
98
+ const val = getValue().replace(/[\r\n]+/g, " ");
1346
99
  const placeholder = (props.placeholder || "").replace(/[\r\n]+/g, " ");
1347
100
  const showCursor = isFocused();
1348
101
  return /* @__PURE__ */ jsxs("box", {
@@ -1356,11 +109,7 @@ const Input = defineComponent(({ props, emit }) => {
1356
109
  });
1357
110
  };
1358
111
  }, { name: "Input" });
1359
-
1360
- //#endregion
1361
- //#region src/components/ProgressBar.tsx
1362
- /** @jsxImportSource @sigx/runtime-core */
1363
- const ProgressBar = defineComponent(({ props }) => {
112
+ const ProgressBar = component$1(({ props }) => {
1364
113
  return () => {
1365
114
  const value = props.value || 0;
1366
115
  const max = props.max || 100;
@@ -1376,11 +125,7 @@ const ProgressBar = defineComponent(({ props }) => {
1376
125
  return /* @__PURE__ */ jsx("box", { children: /* @__PURE__ */ jsx("text", { children: colorCode + barChar.repeat(filledLen) + emptyChar.repeat(emptyLen) + reset + ` ${Math.round(percentage * 100)}%` }) });
1377
126
  };
1378
127
  }, { name: "ProgressBar" });
1379
-
1380
- //#endregion
1381
- //#region src/components/Button.tsx
1382
- /** @jsxImportSource @sigx/runtime-core */
1383
- const Button = defineComponent(({ props, emit }) => {
128
+ const Button = component$1(({ props, emit }) => {
1384
129
  const id = Math.random().toString(36).slice(2);
1385
130
  const isFocused = () => focusState.activeId === id;
1386
131
  const pressed = signal({ value: false });
@@ -1398,11 +143,11 @@ const Button = defineComponent(({ props, emit }) => {
1398
143
  };
1399
144
  let keyCleanup = null;
1400
145
  let pressTimer = null;
1401
- onMount(() => {
146
+ onMounted(() => {
1402
147
  registerFocusable(id);
1403
148
  keyCleanup = onKey(handleKey);
1404
149
  });
1405
- onCleanup(() => {
150
+ onUnmounted(() => {
1406
151
  if (keyCleanup) keyCleanup();
1407
152
  unregisterFocusable(id);
1408
153
  if (pressTimer) clearTimeout(pressTimer);
@@ -1423,30 +168,26 @@ const Button = defineComponent(({ props, emit }) => {
1423
168
  });
1424
169
  };
1425
170
  }, { name: "Button" });
1426
-
1427
- //#endregion
1428
- //#region src/components/Checkbox.tsx
1429
- /** @jsxImportSource @sigx/runtime-core */
1430
- const Checkbox = defineComponent(({ props, emit }) => {
171
+ const Checkbox = component$1(({ props, emit }) => {
1431
172
  const id = Math.random().toString(36).slice(2);
1432
173
  const isFocused = () => focusState.activeId === id;
1433
- const checked = () => !!props.value;
174
+ const checked = () => !!props.model?.value;
1434
175
  const handleKey = (key) => {
1435
176
  if (!isFocused()) return;
1436
177
  if (props.disabled) return;
1437
178
  if (key === "\r" || key === " ") {
1438
179
  const next = !checked();
1439
- emit("update:value", next);
180
+ if (props.model) props.model.value = next;
1440
181
  emit("change", next);
1441
182
  }
1442
183
  };
1443
184
  let keyCleanup = null;
1444
- onMount(() => {
185
+ onMounted(() => {
1445
186
  registerFocusable(id);
1446
187
  if (props.autofocus) focus(id);
1447
188
  keyCleanup = onKey(handleKey);
1448
189
  });
1449
- onCleanup(() => {
190
+ onUnmounted(() => {
1450
191
  if (keyCleanup) keyCleanup();
1451
192
  unregisterFocusable(id);
1452
193
  });
@@ -1475,79 +216,80 @@ const Checkbox = defineComponent(({ props, emit }) => {
1475
216
  ] });
1476
217
  };
1477
218
  }, { name: "Checkbox" });
1478
-
1479
- //#endregion
1480
- //#region src/components/Select.tsx
1481
- /** @jsxImportSource @sigx/runtime-core */
1482
- const Select = defineComponent(({ props, emit }) => {
219
+ const Select = component$1(({ props, emit }) => {
1483
220
  const id = Math.random().toString(36).slice(2);
221
+ let isReady = false;
1484
222
  const isFocused = () => focusState.activeId === id;
1485
223
  const getCurrentIndex = () => {
1486
- const idx = (props.options || []).findIndex((o) => o.value === props.value);
224
+ const idx = (props.options || []).findIndex((o) => o.value === props.model?.value);
1487
225
  return idx >= 0 ? idx : 0;
1488
226
  };
1489
227
  const handleKey = (key) => {
1490
228
  if (!isFocused()) return;
229
+ if (!isReady) return;
1491
230
  const options = props.options || [];
1492
231
  if (options.length === 0) return;
1493
232
  const currentIndex = getCurrentIndex();
1494
233
  if (key === "\x1B[A" || key === "k") {
1495
234
  const newValue = options[currentIndex > 0 ? currentIndex - 1 : options.length - 1].value;
1496
- emit("update:value", newValue);
235
+ if (props.model) props.model.value = newValue;
1497
236
  emit("change", newValue);
1498
237
  return;
1499
238
  }
1500
239
  if (key === "\x1B[B" || key === "j") {
1501
240
  const newValue = options[currentIndex < options.length - 1 ? currentIndex + 1 : 0].value;
1502
- emit("update:value", newValue);
241
+ if (props.model) props.model.value = newValue;
1503
242
  emit("change", newValue);
1504
243
  return;
1505
244
  }
1506
245
  if (key === "\r") {
1507
- emit("submit", props.value || options[0]?.value || "");
246
+ emit("submit", props.model?.value || options[0]?.value || "");
1508
247
  return;
1509
248
  }
1510
249
  };
1511
250
  let keyCleanup = null;
1512
- onMount(() => {
251
+ onMounted(() => {
1513
252
  registerFocusable(id);
1514
253
  if (props.autofocus) focus(id);
1515
254
  keyCleanup = onKey(handleKey);
255
+ setTimeout(() => {
256
+ isReady = true;
257
+ }, 50);
1516
258
  });
1517
- onCleanup(() => {
259
+ onUnmounted(() => {
1518
260
  if (keyCleanup) keyCleanup();
1519
261
  unregisterFocusable(id);
1520
262
  });
1521
263
  return () => {
1522
264
  const options = props.options || [];
1523
265
  const focused = isFocused();
1524
- const currentValue = props.value || options[0]?.value || "";
266
+ const currentValue = props.model?.value || options[0]?.value || "";
1525
267
  const label = props.label;
1526
- return /* @__PURE__ */ jsx("box", {
268
+ const selectedOption = options.find((o) => o.value === currentValue);
269
+ const optionElements = options.map((option) => {
270
+ const isSelected = option.value === currentValue;
271
+ return /* @__PURE__ */ jsx("box", { children: /* @__PURE__ */ jsxs("text", {
272
+ color: isSelected ? "cyan" : "white",
273
+ children: [
274
+ isSelected ? "❯" : " ",
275
+ " ",
276
+ option.label
277
+ ]
278
+ }) });
279
+ });
280
+ const descriptionElement = props.showDescription && selectedOption?.description ? /* @__PURE__ */ jsx("box", { children: /* @__PURE__ */ jsxs("text", {
281
+ color: "#666666",
282
+ children: [" ↳ ", selectedOption.description]
283
+ }) }) : null;
284
+ return /* @__PURE__ */ jsxs("box", { children: [/* @__PURE__ */ jsx("box", {
1527
285
  border: "single",
1528
286
  borderColor: focused ? "green" : "white",
1529
287
  label,
1530
- children: options.map((option) => {
1531
- const isSelected = option.value === currentValue;
1532
- return /* @__PURE__ */ jsxs("box", { children: [/* @__PURE__ */ jsxs("text", {
1533
- color: isSelected ? "cyan" : "white",
1534
- children: [
1535
- isSelected ? "❯" : " ",
1536
- " ",
1537
- option.label
1538
- ]
1539
- }), option.description && isSelected && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("br", {}), /* @__PURE__ */ jsxs("text", {
1540
- color: "white",
1541
- children: [" ", option.description]
1542
- })] })] });
1543
- })
1544
- });
288
+ children: optionElements
289
+ }), descriptionElement] });
1545
290
  };
1546
291
  }, { name: "Select" });
1547
-
1548
- //#endregion
1549
- //#region src/index.ts
1550
- const renderer = createRenderer({
292
+ const { render } = createRenderer({
1551
293
  patchProp: (el, key, prev, next) => {
1552
294
  el.props[key] = next;
1553
295
  scheduleRender();
@@ -1618,9 +360,8 @@ const renderer = createRenderer({
1618
360
  };
1619
361
  }
1620
362
  });
1621
- const { render, createApp } = renderer;
1622
- let rootNode = null;
1623
- let isRendering = false;
363
+ var rootNode = null;
364
+ var isRendering = false;
1624
365
  function scheduleRender() {
1625
366
  if (isRendering) return;
1626
367
  isRendering = true;
@@ -1636,10 +377,6 @@ function flushRender() {
1636
377
  process.stdout.write(lines.join("\x1B[K\n") + "\x1B[K");
1637
378
  process.stdout.write("\x1B[J");
1638
379
  }
1639
- /**
1640
- * Check if a node has a box element as an immediate child.
1641
- * This is used to determine if a component wrapper should be treated as a block element.
1642
- */
1643
380
  function hasBoxChild(node) {
1644
381
  for (const child of node.children) if (child.tag === "box") return true;
1645
382
  return false;
@@ -1728,7 +465,7 @@ function getBorderChars(style) {
1728
465
  v: "│"
1729
466
  };
1730
467
  }
1731
- const keyHandlers = /* @__PURE__ */ new Set();
468
+ var keyHandlers = /* @__PURE__ */ new Set();
1732
469
  function onKey(handler) {
1733
470
  keyHandlers.add(handler);
1734
471
  return () => keyHandlers.delete(handler);
@@ -1775,16 +512,7 @@ function renderTerminal(app, options = {}) {
1775
512
  }
1776
513
  } };
1777
514
  }
1778
- let unmountFn = null;
1779
- /**
1780
- * Helper function to mount the terminal for CLI apps.
1781
- * Returns a mount target that can be passed to defineApp().mount().
1782
- *
1783
- * @example
1784
- * ```tsx
1785
- * defineApp(MyApp).mount(mountTerminal());
1786
- * ```
1787
- */
515
+ var unmountFn = null;
1788
516
  function mountTerminal(options = { clearConsole: true }) {
1789
517
  return {
1790
518
  mount: terminalMount,
@@ -1794,9 +522,6 @@ function mountTerminal(options = { clearConsole: true }) {
1794
522
  }
1795
523
  };
1796
524
  }
1797
- /**
1798
- * Exit the terminal app cleanly, restoring terminal state.
1799
- */
1800
525
  function exitTerminal() {
1801
526
  if (unmountFn) {
1802
527
  unmountFn();
@@ -1805,20 +530,6 @@ function exitTerminal() {
1805
530
  process.stdout.write("\x1B[?25h");
1806
531
  process.stdout.write("\x1B[2J\x1B[H");
1807
532
  }
1808
- /**
1809
- * Mount function for Terminal environments.
1810
- * Use this with defineApp().mount() to render to the terminal.
1811
- *
1812
- * @example
1813
- * ```tsx
1814
- * import { defineApp } from '@sigx/runtime-core';
1815
- * import { terminalMount } from '@sigx/runtime-terminal';
1816
- *
1817
- * const app = defineApp(<Counter />);
1818
- * app.use(loggingPlugin)
1819
- * .mount({ clearConsole: true }, terminalMount);
1820
- * ```
1821
- */
1822
533
  const terminalMount = (component, options, appContext) => {
1823
534
  rootNode = {
1824
535
  type: "root",
@@ -1847,7 +558,6 @@ const terminalMount = (component, options, appContext) => {
1847
558
  };
1848
559
  };
1849
560
  setDefaultMount(terminalMount);
561
+ export { Button, Checkbox, Input, ProgressBar, Select, exitTerminal, focus, focusNext, focusPrev, focusState, mountTerminal, onKey, registerFocusable, render, renderNodeToLines, renderTerminal, terminalMount, unregisterFocusable };
1850
562
 
1851
- //#endregion
1852
- export { Button, Checkbox, Input, ProgressBar, Select, createApp, exitTerminal, focus, focusNext, focusPrev, focusState, mountTerminal, onKey, registerFocusable, render, renderNodeToLines, renderTerminal, terminalMount, unregisterFocusable };
1853
563
  //# sourceMappingURL=index.js.map