@cascadetui/solid 0.1.1

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/index.js ADDED
@@ -0,0 +1,1030 @@
1
+ // @bun
2
+ // index.ts
3
+ import { CliRenderer, createCliRenderer, engine as engine2 } from "@cascadetui/core";
4
+ import { createTestRenderer } from "@cascadetui/core/testing";
5
+
6
+ // src/elements/index.ts
7
+ import {
8
+ ASCIIFontRenderable,
9
+ BoxRenderable,
10
+ CodeRenderable,
11
+ DiffRenderable,
12
+ InputRenderable as InputRenderable2,
13
+ LineNumberRenderable,
14
+ MarkdownRenderable,
15
+ ScrollBoxRenderable as ScrollBoxRenderable2,
16
+ SelectRenderable as SelectRenderable2,
17
+ TabSelectRenderable as TabSelectRenderable2,
18
+ TextareaRenderable,
19
+ TextAttributes,
20
+ TextNodeRenderable as TextNodeRenderable3,
21
+ TextRenderable as TextRenderable3
22
+ } from "@cascadetui/core";
23
+
24
+ // src/elements/hooks.ts
25
+ import {
26
+ engine,
27
+ Timeline
28
+ } from "@cascadetui/core";
29
+ import { createContext, createSignal, onCleanup, onMount, useContext } from "solid-js";
30
+ var RendererContext = createContext();
31
+ var useRenderer = () => {
32
+ const renderer = useContext(RendererContext);
33
+ if (!renderer) {
34
+ throw new Error("No renderer found");
35
+ }
36
+ return renderer;
37
+ };
38
+ var onResize = (callback) => {
39
+ const renderer = useRenderer();
40
+ onMount(() => {
41
+ renderer.on("resize", callback);
42
+ });
43
+ onCleanup(() => {
44
+ renderer.off("resize", callback);
45
+ });
46
+ };
47
+ var useTerminalDimensions = () => {
48
+ const renderer = useRenderer();
49
+ const [terminalDimensions, setTerminalDimensions] = createSignal({ width: renderer.width, height: renderer.height });
50
+ const callback = (width, height) => {
51
+ setTerminalDimensions({ width, height });
52
+ };
53
+ onResize(callback);
54
+ return terminalDimensions;
55
+ };
56
+ var useKeyboard = (callback, options) => {
57
+ const renderer = useRenderer();
58
+ const keyHandler = renderer.keyInput;
59
+ onMount(() => {
60
+ keyHandler.on("keypress", callback);
61
+ if (options?.release) {
62
+ keyHandler.on("keyrelease", callback);
63
+ }
64
+ });
65
+ onCleanup(() => {
66
+ keyHandler.off("keypress", callback);
67
+ if (options?.release) {
68
+ keyHandler.off("keyrelease", callback);
69
+ }
70
+ });
71
+ };
72
+ var usePaste = (callback) => {
73
+ const renderer = useRenderer();
74
+ const keyHandler = renderer.keyInput;
75
+ onMount(() => {
76
+ keyHandler.on("paste", callback);
77
+ });
78
+ onCleanup(() => {
79
+ keyHandler.off("paste", callback);
80
+ });
81
+ };
82
+ var useKeyHandler = useKeyboard;
83
+ var useSelectionHandler = (callback) => {
84
+ const renderer = useRenderer();
85
+ onMount(() => {
86
+ renderer.on("selection", callback);
87
+ });
88
+ onCleanup(() => {
89
+ renderer.off("selection", callback);
90
+ });
91
+ };
92
+ var useTimeline = (options = {}) => {
93
+ const timeline = new Timeline(options);
94
+ onMount(() => {
95
+ if (options.autoplay !== false) {
96
+ timeline.play();
97
+ }
98
+ engine.register(timeline);
99
+ });
100
+ onCleanup(() => {
101
+ timeline.pause();
102
+ engine.unregister(timeline);
103
+ });
104
+ return timeline;
105
+ };
106
+ // src/elements/extras.ts
107
+ import { createEffect, createMemo as createMemo2, getOwner, onCleanup as onCleanup2, runWithOwner, splitProps, untrack as untrack2 } from "solid-js";
108
+
109
+ // src/reconciler.ts
110
+ import {
111
+ BaseRenderable,
112
+ createTextAttributes,
113
+ InputRenderable,
114
+ InputRenderableEvents,
115
+ isTextNodeRenderable,
116
+ parseColor,
117
+ Renderable,
118
+ RootTextNodeRenderable,
119
+ ScrollBoxRenderable,
120
+ SelectRenderable,
121
+ SelectRenderableEvents,
122
+ TabSelectRenderable,
123
+ TabSelectRenderableEvents,
124
+ TextNodeRenderable,
125
+ TextRenderable
126
+ } from "@cascadetui/core";
127
+ import { useContext as useContext2 } from "solid-js";
128
+
129
+ // src/renderer/universal.js
130
+ import { createRoot, createRenderEffect, createMemo, createComponent, untrack, mergeProps } from "solid-js";
131
+ var memo = (fn) => createMemo(() => fn());
132
+ function createRenderer({
133
+ createElement,
134
+ createTextNode,
135
+ createSlotNode,
136
+ isTextNode,
137
+ replaceText,
138
+ insertNode,
139
+ removeNode,
140
+ setProperty,
141
+ getParentNode,
142
+ getFirstChild,
143
+ getNextSibling
144
+ }) {
145
+ function insert(parent, accessor, marker, initial) {
146
+ if (marker !== undefined && !initial)
147
+ initial = [];
148
+ if (typeof accessor !== "function")
149
+ return insertExpression(parent, accessor, initial, marker);
150
+ createRenderEffect((current) => insertExpression(parent, accessor(), current, marker), initial);
151
+ }
152
+ function insertExpression(parent, value, current, marker, unwrapArray) {
153
+ while (typeof current === "function")
154
+ current = current();
155
+ if (value === current)
156
+ return current;
157
+ const t = typeof value, multi = marker !== undefined;
158
+ if (t === "string" || t === "number") {
159
+ if (t === "number")
160
+ value = value.toString();
161
+ if (multi) {
162
+ let node = current[0];
163
+ if (node && isTextNode(node)) {
164
+ replaceText(node, value);
165
+ } else
166
+ node = createTextNode(value);
167
+ current = cleanChildren(parent, current, marker, node);
168
+ } else {
169
+ if (current !== "" && typeof current === "string") {
170
+ replaceText(getFirstChild(parent), current = value);
171
+ } else {
172
+ cleanChildren(parent, current, marker, createTextNode(value));
173
+ current = value;
174
+ }
175
+ }
176
+ } else if (value == null || t === "boolean") {
177
+ current = cleanChildren(parent, current, marker);
178
+ } else if (t === "function") {
179
+ createRenderEffect(() => {
180
+ let v = value();
181
+ while (typeof v === "function")
182
+ v = v();
183
+ current = insertExpression(parent, v, current, marker);
184
+ });
185
+ return () => current;
186
+ } else if (Array.isArray(value)) {
187
+ const array = [];
188
+ if (normalizeIncomingArray(array, value, unwrapArray)) {
189
+ createRenderEffect(() => current = insertExpression(parent, array, current, marker, true));
190
+ return () => current;
191
+ }
192
+ if (array.length === 0) {
193
+ const replacement = cleanChildren(parent, current, marker);
194
+ if (multi)
195
+ return current = replacement;
196
+ } else {
197
+ if (Array.isArray(current)) {
198
+ if (current.length === 0) {
199
+ appendNodes(parent, array, marker);
200
+ } else
201
+ reconcileArrays(parent, current, array);
202
+ } else if (current == null || current === "") {
203
+ appendNodes(parent, array);
204
+ } else {
205
+ reconcileArrays(parent, multi && current || [getFirstChild(parent)], array);
206
+ }
207
+ }
208
+ current = array;
209
+ } else {
210
+ if (Array.isArray(current)) {
211
+ if (multi)
212
+ return current = cleanChildren(parent, current, marker, value);
213
+ cleanChildren(parent, current, null, value);
214
+ } else if (current == null || current === "" || !getFirstChild(parent)) {
215
+ insertNode(parent, value);
216
+ } else
217
+ replaceNode(parent, value, getFirstChild(parent));
218
+ current = value;
219
+ }
220
+ return current;
221
+ }
222
+ function normalizeIncomingArray(normalized, array, unwrap) {
223
+ let dynamic = false;
224
+ for (let i = 0, len = array.length;i < len; i++) {
225
+ let item = array[i], t;
226
+ if (item == null || item === true || item === false)
227
+ ;
228
+ else if (Array.isArray(item)) {
229
+ dynamic = normalizeIncomingArray(normalized, item) || dynamic;
230
+ } else if ((t = typeof item) === "string" || t === "number") {
231
+ normalized.push(createTextNode(item));
232
+ } else if (t === "function") {
233
+ if (unwrap) {
234
+ while (typeof item === "function")
235
+ item = item();
236
+ dynamic = normalizeIncomingArray(normalized, Array.isArray(item) ? item : [item]) || dynamic;
237
+ } else {
238
+ normalized.push(item);
239
+ dynamic = true;
240
+ }
241
+ } else
242
+ normalized.push(item);
243
+ }
244
+ return dynamic;
245
+ }
246
+ function reconcileArrays(parentNode, a, b) {
247
+ let bLength = b.length, aEnd = a.length, bEnd = bLength, aStart = 0, bStart = 0, after = getNextSibling(a[aEnd - 1]), map = null;
248
+ while (aStart < aEnd || bStart < bEnd) {
249
+ if (a[aStart] === b[bStart]) {
250
+ aStart++;
251
+ bStart++;
252
+ continue;
253
+ }
254
+ while (a[aEnd - 1] === b[bEnd - 1]) {
255
+ aEnd--;
256
+ bEnd--;
257
+ }
258
+ if (aEnd === aStart) {
259
+ const node = bEnd < bLength ? bStart ? getNextSibling(b[bStart - 1]) : b[bEnd - bStart] : after;
260
+ while (bStart < bEnd)
261
+ insertNode(parentNode, b[bStart++], node);
262
+ } else if (bEnd === bStart) {
263
+ while (aStart < aEnd) {
264
+ if (!map || !map.has(a[aStart]))
265
+ removeNode(parentNode, a[aStart]);
266
+ aStart++;
267
+ }
268
+ } else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
269
+ const node = getNextSibling(a[--aEnd]);
270
+ insertNode(parentNode, b[bStart++], getNextSibling(a[aStart++]));
271
+ insertNode(parentNode, b[--bEnd], node);
272
+ a[aEnd] = b[bEnd];
273
+ } else {
274
+ if (!map) {
275
+ map = new Map;
276
+ let i = bStart;
277
+ while (i < bEnd)
278
+ map.set(b[i], i++);
279
+ }
280
+ const index = map.get(a[aStart]);
281
+ if (index != null) {
282
+ if (bStart < index && index < bEnd) {
283
+ let i = aStart, sequence = 1, t;
284
+ while (++i < aEnd && i < bEnd) {
285
+ if ((t = map.get(a[i])) == null || t !== index + sequence)
286
+ break;
287
+ sequence++;
288
+ }
289
+ if (sequence > index - bStart) {
290
+ const node = a[aStart];
291
+ while (bStart < index)
292
+ insertNode(parentNode, b[bStart++], node);
293
+ } else
294
+ replaceNode(parentNode, b[bStart++], a[aStart++]);
295
+ } else
296
+ aStart++;
297
+ } else
298
+ removeNode(parentNode, a[aStart++]);
299
+ }
300
+ }
301
+ }
302
+ function cleanChildren(parent, current, marker, replacement) {
303
+ if (marker === undefined) {
304
+ let removed;
305
+ while (removed = getFirstChild(parent))
306
+ removeNode(parent, removed);
307
+ replacement && insertNode(parent, replacement);
308
+ return replacement ?? "";
309
+ }
310
+ const node = replacement || createSlotNode();
311
+ if (current.length) {
312
+ let inserted = false;
313
+ for (let i = current.length - 1;i >= 0; i--) {
314
+ const el = current[i];
315
+ if (node !== el) {
316
+ const isParent = getParentNode(el) === parent;
317
+ if (!inserted && !i)
318
+ isParent ? replaceNode(parent, node, el) : insertNode(parent, node, marker);
319
+ else
320
+ isParent && removeNode(parent, el);
321
+ } else
322
+ inserted = true;
323
+ }
324
+ } else
325
+ insertNode(parent, node, marker);
326
+ return [node];
327
+ }
328
+ function appendNodes(parent, array, marker) {
329
+ for (let i = 0, len = array.length;i < len; i++)
330
+ insertNode(parent, array[i], marker);
331
+ }
332
+ function replaceNode(parent, newNode, oldNode) {
333
+ insertNode(parent, newNode, oldNode);
334
+ removeNode(parent, oldNode);
335
+ }
336
+ function spreadExpression(node, props, prevProps = {}, skipChildren) {
337
+ props || (props = {});
338
+ if (!skipChildren) {
339
+ createRenderEffect(() => prevProps.children = insertExpression(node, props.children, prevProps.children));
340
+ }
341
+ createRenderEffect(() => props.ref && props.ref(node));
342
+ createRenderEffect(() => {
343
+ for (const prop in props) {
344
+ if (prop === "children" || prop === "ref")
345
+ continue;
346
+ const value = props[prop];
347
+ if (value === prevProps[prop])
348
+ continue;
349
+ setProperty(node, prop, value, prevProps[prop]);
350
+ prevProps[prop] = value;
351
+ }
352
+ });
353
+ return prevProps;
354
+ }
355
+ return {
356
+ render(code, element) {
357
+ let disposer;
358
+ createRoot((dispose) => {
359
+ disposer = dispose;
360
+ insert(element, code());
361
+ });
362
+ return disposer;
363
+ },
364
+ insert,
365
+ spread(node, accessor, skipChildren) {
366
+ if (typeof accessor === "function") {
367
+ createRenderEffect((current) => spreadExpression(node, accessor(), current, skipChildren));
368
+ } else
369
+ spreadExpression(node, accessor, undefined, skipChildren);
370
+ },
371
+ createElement,
372
+ createTextNode,
373
+ insertNode,
374
+ setProp(node, name, value, prev) {
375
+ setProperty(node, name, value, prev);
376
+ return value;
377
+ },
378
+ mergeProps,
379
+ effect: createRenderEffect,
380
+ memo,
381
+ createComponent,
382
+ use(fn, element, arg) {
383
+ return untrack(() => fn(element, arg));
384
+ }
385
+ };
386
+ }
387
+
388
+ // src/renderer/index.ts
389
+ import { mergeProps as mergeProps2 } from "solid-js";
390
+ function createRenderer2(options) {
391
+ const renderer = createRenderer(options);
392
+ renderer.mergeProps = mergeProps2;
393
+ return renderer;
394
+ }
395
+
396
+ // src/utils/id-counter.ts
397
+ var idCounter = new Map;
398
+ function getNextId(elementType) {
399
+ if (!idCounter.has(elementType)) {
400
+ idCounter.set(elementType, 0);
401
+ }
402
+ const value = idCounter.get(elementType) + 1;
403
+ idCounter.set(elementType, value);
404
+ return `${elementType}-${value}`;
405
+ }
406
+
407
+ // src/utils/log.ts
408
+ var log = (...args) => {
409
+ if (process.env.DEBUG) {
410
+ console.log("[Reconciler]", ...args);
411
+ }
412
+ };
413
+
414
+ // src/reconciler.ts
415
+ class TextNode extends TextNodeRenderable {
416
+ static fromString(text, options = {}) {
417
+ const node = new TextNode(options);
418
+ node.add(text);
419
+ return node;
420
+ }
421
+ }
422
+ var logId = (node) => {
423
+ if (!node)
424
+ return;
425
+ return node.id;
426
+ };
427
+ var getNodeChildren = (node) => {
428
+ let children;
429
+ if (node instanceof TextRenderable) {
430
+ children = node.getTextChildren();
431
+ } else {
432
+ children = node.getChildren();
433
+ }
434
+ return children;
435
+ };
436
+ function _insertNode(parent, node, anchor) {
437
+ log("Inserting node:", logId(node), "into parent:", logId(parent), "with anchor:", logId(anchor), node instanceof TextNode);
438
+ if (node instanceof SlotRenderable) {
439
+ node.parent = parent;
440
+ node = node.getSlotChild(parent);
441
+ }
442
+ if (anchor && anchor instanceof SlotRenderable) {
443
+ anchor = anchor.getSlotChild(parent);
444
+ }
445
+ if (isTextNodeRenderable(node)) {
446
+ if (!(parent instanceof TextRenderable) && !isTextNodeRenderable(parent)) {
447
+ throw new Error(`Orphan text error: "${node.toChunks().map((c) => c.text).join("")}" must have a <text> as a parent: ${parent.id} above ${node.id}`);
448
+ }
449
+ }
450
+ if (!(parent instanceof BaseRenderable)) {
451
+ console.error("[INSERT]", "Tried to mount a non base renderable");
452
+ throw new Error("Tried to mount a non base renderable");
453
+ }
454
+ if (!anchor) {
455
+ parent.add(node);
456
+ return;
457
+ }
458
+ const children = getNodeChildren(parent);
459
+ const anchorIndex = children.findIndex((el) => el.id === anchor.id);
460
+ if (anchorIndex === -1) {
461
+ log("[INSERT]", "Could not find anchor", logId(parent), logId(anchor), "[children]", ...children.map((c) => c.id));
462
+ }
463
+ parent.add(node, anchorIndex);
464
+ }
465
+ function _removeNode(parent, node) {
466
+ log("Removing node:", logId(node), "from parent:", logId(parent));
467
+ if (node instanceof SlotRenderable) {
468
+ node.parent = null;
469
+ node = node.getSlotChild(parent);
470
+ }
471
+ parent.remove(node.id);
472
+ process.nextTick(() => {
473
+ if (node instanceof BaseRenderable && !node.parent) {
474
+ node.destroyRecursively();
475
+ return;
476
+ }
477
+ });
478
+ }
479
+ function _createTextNode(value) {
480
+ log("Creating text node:", value);
481
+ const id = getNextId("text-node");
482
+ if (typeof value === "number") {
483
+ value = value.toString();
484
+ }
485
+ return TextNode.fromString(value, { id });
486
+ }
487
+ function createSlotNode() {
488
+ const id = getNextId("slot-node");
489
+ log("Creating slot node", id);
490
+ return new SlotRenderable(id);
491
+ }
492
+ function _getParentNode(childNode) {
493
+ log("Getting parent of node:", logId(childNode));
494
+ let parent = childNode.parent ?? undefined;
495
+ if (parent instanceof RootTextNodeRenderable) {
496
+ parent = parent.textParent ?? undefined;
497
+ }
498
+ const scrollBoxCandidate = parent?.parent?.parent?.parent;
499
+ if (scrollBoxCandidate instanceof ScrollBoxRenderable && scrollBoxCandidate.content === parent) {
500
+ parent = scrollBoxCandidate;
501
+ }
502
+ return parent;
503
+ }
504
+ var {
505
+ render: _render,
506
+ effect,
507
+ memo: memo2,
508
+ createComponent: createComponent2,
509
+ createElement,
510
+ createTextNode,
511
+ insertNode,
512
+ insert,
513
+ spread,
514
+ setProp,
515
+ mergeProps: mergeProps3,
516
+ use
517
+ } = createRenderer2({
518
+ createElement(tagName) {
519
+ log("Creating element:", tagName);
520
+ const id = getNextId(tagName);
521
+ const solidRenderer = useContext2(RendererContext);
522
+ if (!solidRenderer) {
523
+ throw new Error("No renderer found");
524
+ }
525
+ const elements = getComponentCatalogue();
526
+ if (!elements[tagName]) {
527
+ throw new Error(`[Reconciler] Unknown component type: ${tagName}`);
528
+ }
529
+ const element = new elements[tagName](solidRenderer, { id });
530
+ log("Element created with id:", id);
531
+ return element;
532
+ },
533
+ createTextNode: _createTextNode,
534
+ createSlotNode,
535
+ replaceText(textNode, value) {
536
+ log("Replacing text:", value, "in node:", logId(textNode));
537
+ if (!(textNode instanceof TextNode))
538
+ return;
539
+ textNode.replace(value, 0);
540
+ },
541
+ setProperty(node, name, value, prev) {
542
+ if (name.startsWith("on:")) {
543
+ const eventName = name.slice(3);
544
+ if (value) {
545
+ node.on(eventName, value);
546
+ }
547
+ if (prev) {
548
+ node.off(eventName, prev);
549
+ }
550
+ return;
551
+ }
552
+ if (isTextNodeRenderable(node)) {
553
+ if (name === "href") {
554
+ node.link = { url: value };
555
+ return;
556
+ }
557
+ if (name === "style") {
558
+ node.attributes |= createTextAttributes(value);
559
+ node.fg = value.fg ? parseColor(value.fg) : node.fg;
560
+ node.bg = value.bg ? parseColor(value.bg) : node.bg;
561
+ return;
562
+ }
563
+ return;
564
+ }
565
+ switch (name) {
566
+ case "id":
567
+ log("Id mapped", node.id, "=", value);
568
+ node[name] = value;
569
+ break;
570
+ case "focused":
571
+ if (!(node instanceof Renderable))
572
+ return;
573
+ if (value) {
574
+ node.focus();
575
+ } else {
576
+ node.blur();
577
+ }
578
+ break;
579
+ case "onChange":
580
+ let event = undefined;
581
+ if (node instanceof SelectRenderable) {
582
+ event = SelectRenderableEvents.SELECTION_CHANGED;
583
+ } else if (node instanceof TabSelectRenderable) {
584
+ event = TabSelectRenderableEvents.SELECTION_CHANGED;
585
+ } else if (node instanceof InputRenderable) {
586
+ event = InputRenderableEvents.CHANGE;
587
+ }
588
+ if (!event)
589
+ break;
590
+ if (value) {
591
+ node.on(event, value);
592
+ }
593
+ if (prev) {
594
+ node.off(event, prev);
595
+ }
596
+ break;
597
+ case "onInput":
598
+ if (node instanceof InputRenderable) {
599
+ if (value) {
600
+ node.on(InputRenderableEvents.INPUT, value);
601
+ }
602
+ if (prev) {
603
+ node.off(InputRenderableEvents.INPUT, prev);
604
+ }
605
+ }
606
+ break;
607
+ case "onSubmit":
608
+ if (node instanceof InputRenderable) {
609
+ if (value) {
610
+ node.on(InputRenderableEvents.ENTER, value);
611
+ }
612
+ if (prev) {
613
+ node.off(InputRenderableEvents.ENTER, prev);
614
+ }
615
+ } else {
616
+ node[name] = value;
617
+ }
618
+ break;
619
+ case "onSelect":
620
+ if (node instanceof SelectRenderable) {
621
+ if (value) {
622
+ node.on(SelectRenderableEvents.ITEM_SELECTED, value);
623
+ }
624
+ if (prev) {
625
+ node.off(SelectRenderableEvents.ITEM_SELECTED, prev);
626
+ }
627
+ } else if (node instanceof TabSelectRenderable) {
628
+ if (value) {
629
+ node.on(TabSelectRenderableEvents.ITEM_SELECTED, value);
630
+ }
631
+ if (prev) {
632
+ node.off(TabSelectRenderableEvents.ITEM_SELECTED, prev);
633
+ }
634
+ }
635
+ break;
636
+ case "style":
637
+ for (const prop in value) {
638
+ const propVal = value[prop];
639
+ if (prev !== undefined && propVal === prev[prop])
640
+ continue;
641
+ node[prop] = propVal;
642
+ }
643
+ break;
644
+ case "text":
645
+ case "content":
646
+ node[name] = typeof value === "string" ? value : Array.isArray(value) ? value.join("") : `${value}`;
647
+ break;
648
+ default:
649
+ node[name] = value;
650
+ }
651
+ },
652
+ isTextNode(node) {
653
+ return node instanceof TextNode;
654
+ },
655
+ insertNode: _insertNode,
656
+ removeNode: _removeNode,
657
+ getParentNode: _getParentNode,
658
+ getFirstChild(node) {
659
+ log("Getting first child of node:", logId(node));
660
+ const firstChild = getNodeChildren(node)[0];
661
+ if (!firstChild) {
662
+ log("No first child found for node:", logId(node));
663
+ return;
664
+ }
665
+ log("First child found:", logId(firstChild), "for node:", logId(node));
666
+ return firstChild;
667
+ },
668
+ getNextSibling(node) {
669
+ log("Getting next sibling of node:", logId(node));
670
+ const parent = _getParentNode(node);
671
+ if (!parent) {
672
+ log("No parent found for node:", logId(node));
673
+ return;
674
+ }
675
+ const siblings = getNodeChildren(parent);
676
+ const index = siblings.indexOf(node);
677
+ if (index === -1 || index === siblings.length - 1) {
678
+ log("No next sibling found for node:", logId(node));
679
+ return;
680
+ }
681
+ const nextSibling = siblings[index + 1];
682
+ if (!nextSibling) {
683
+ log("Next sibling is null for node:", logId(node));
684
+ return;
685
+ }
686
+ log("Next sibling found:", logId(nextSibling), "for node:", logId(node));
687
+ return nextSibling;
688
+ }
689
+ });
690
+
691
+ // src/elements/extras.ts
692
+ function Portal(props) {
693
+ const renderer = useRenderer();
694
+ const marker = createSlotNode(), mount = () => props.mount || renderer.root, owner = getOwner();
695
+ let content;
696
+ createEffect(() => {
697
+ content || (content = runWithOwner(owner, () => createMemo2(() => props.children)));
698
+ const el = mount();
699
+ const container = createElement("box"), renderRoot = container;
700
+ Object.defineProperty(container, "_$host", {
701
+ get() {
702
+ return marker.parent;
703
+ },
704
+ configurable: true
705
+ });
706
+ insert(renderRoot, content);
707
+ el.add(container);
708
+ props.ref && props.ref(container);
709
+ onCleanup2(() => el.remove(container.id));
710
+ }, undefined, { render: true });
711
+ return marker;
712
+ }
713
+ function createDynamic(component, props) {
714
+ const cached = createMemo2(component);
715
+ return createMemo2(() => {
716
+ const component2 = cached();
717
+ switch (typeof component2) {
718
+ case "function":
719
+ return untrack2(() => component2(props));
720
+ case "string":
721
+ const el = createElement(component2);
722
+ spread(el, props);
723
+ return el;
724
+ default:
725
+ break;
726
+ }
727
+ });
728
+ }
729
+ function Dynamic(props) {
730
+ const [, others] = splitProps(props, ["component"]);
731
+ return createDynamic(() => props.component, others);
732
+ }
733
+ // src/elements/slot.ts
734
+ import { BaseRenderable as BaseRenderable2, isTextNodeRenderable as isTextNodeRenderable2, TextNodeRenderable as TextNodeRenderable2, TextRenderable as TextRenderable2, Yoga } from "@cascadetui/core";
735
+
736
+ class SlotBaseRenderable extends BaseRenderable2 {
737
+ constructor(id) {
738
+ super({
739
+ id
740
+ });
741
+ }
742
+ add(obj, index) {
743
+ throw new Error("Can't add children on an Slot renderable");
744
+ }
745
+ getChildren() {
746
+ return [];
747
+ }
748
+ remove(id) {}
749
+ insertBefore(obj, anchor) {
750
+ throw new Error("Can't add children on an Slot renderable");
751
+ }
752
+ getRenderable(id) {
753
+ return;
754
+ }
755
+ getChildrenCount() {
756
+ return 0;
757
+ }
758
+ requestRender() {}
759
+ findDescendantById(id) {
760
+ return;
761
+ }
762
+ }
763
+
764
+ class TextSlotRenderable extends TextNodeRenderable2 {
765
+ slotParent;
766
+ destroyed = false;
767
+ constructor(id, parent) {
768
+ super({ id });
769
+ this._visible = false;
770
+ this.slotParent = parent;
771
+ }
772
+ destroy() {
773
+ if (this.destroyed) {
774
+ return;
775
+ }
776
+ this.destroyed = true;
777
+ this.slotParent?.destroy();
778
+ super.destroy();
779
+ }
780
+ }
781
+
782
+ class LayoutSlotRenderable extends SlotBaseRenderable {
783
+ yogaNode;
784
+ slotParent;
785
+ destroyed = false;
786
+ constructor(id, parent) {
787
+ super(id);
788
+ this._visible = false;
789
+ this.slotParent = parent;
790
+ this.yogaNode = Yoga.default.Node.create();
791
+ this.yogaNode.setDisplay(Yoga.Display.None);
792
+ }
793
+ getLayoutNode() {
794
+ return this.yogaNode;
795
+ }
796
+ updateFromLayout() {}
797
+ updateLayout() {}
798
+ onRemove() {}
799
+ destroy() {
800
+ if (this.destroyed) {
801
+ return;
802
+ }
803
+ this.destroyed = true;
804
+ super.destroy();
805
+ this.slotParent?.destroy();
806
+ }
807
+ }
808
+
809
+ class SlotRenderable extends SlotBaseRenderable {
810
+ layoutNode;
811
+ textNode;
812
+ destroyed = false;
813
+ constructor(id) {
814
+ super(id);
815
+ this._visible = false;
816
+ }
817
+ getSlotChild(parent) {
818
+ if (isTextNodeRenderable2(parent) || parent instanceof TextRenderable2) {
819
+ if (!this.textNode) {
820
+ this.textNode = new TextSlotRenderable(`slot-text-${this.id}`, this);
821
+ }
822
+ return this.textNode;
823
+ }
824
+ if (!this.layoutNode) {
825
+ this.layoutNode = new LayoutSlotRenderable(`slot-layout-${this.id}`, this);
826
+ }
827
+ return this.layoutNode;
828
+ }
829
+ destroy() {
830
+ if (this.destroyed) {
831
+ return;
832
+ }
833
+ this.destroyed = true;
834
+ if (this.layoutNode) {
835
+ this.layoutNode.destroy();
836
+ }
837
+ if (this.textNode) {
838
+ this.textNode.destroy();
839
+ }
840
+ }
841
+ }
842
+
843
+ // src/elements/index.ts
844
+ class SpanRenderable extends TextNodeRenderable3 {
845
+ _ctx;
846
+ constructor(_ctx, options) {
847
+ super(options);
848
+ this._ctx = _ctx;
849
+ }
850
+ }
851
+ var textNodeKeys = ["span", "b", "strong", "i", "em", "u", "a"];
852
+
853
+ class TextModifierRenderable extends SpanRenderable {
854
+ constructor(options, modifier) {
855
+ super(null, options);
856
+ if (modifier === "b" || modifier === "strong") {
857
+ this.attributes = (this.attributes || 0) | TextAttributes.BOLD;
858
+ } else if (modifier === "i" || modifier === "em") {
859
+ this.attributes = (this.attributes || 0) | TextAttributes.ITALIC;
860
+ } else if (modifier === "u") {
861
+ this.attributes = (this.attributes || 0) | TextAttributes.UNDERLINE;
862
+ }
863
+ }
864
+ }
865
+
866
+ class BoldSpanRenderable extends TextModifierRenderable {
867
+ constructor(options) {
868
+ super(options, "b");
869
+ }
870
+ }
871
+
872
+ class ItalicSpanRenderable extends TextModifierRenderable {
873
+ constructor(options) {
874
+ super(options, "i");
875
+ }
876
+ }
877
+
878
+ class UnderlineSpanRenderable extends TextModifierRenderable {
879
+ constructor(options) {
880
+ super(options, "u");
881
+ }
882
+ }
883
+
884
+ class LineBreakRenderable extends SpanRenderable {
885
+ constructor(_ctx, options) {
886
+ super(null, options);
887
+ this.add();
888
+ }
889
+ add() {
890
+ return super.add(`
891
+ `);
892
+ }
893
+ }
894
+
895
+ class LinkRenderable extends SpanRenderable {
896
+ constructor(_ctx, options) {
897
+ const linkOptions = {
898
+ ...options,
899
+ link: { url: options.href }
900
+ };
901
+ super(null, linkOptions);
902
+ }
903
+ }
904
+ var baseComponents = {
905
+ box: BoxRenderable,
906
+ text: TextRenderable3,
907
+ input: InputRenderable2,
908
+ select: SelectRenderable2,
909
+ textarea: TextareaRenderable,
910
+ ascii_font: ASCIIFontRenderable,
911
+ tab_select: TabSelectRenderable2,
912
+ scrollbox: ScrollBoxRenderable2,
913
+ code: CodeRenderable,
914
+ diff: DiffRenderable,
915
+ line_number: LineNumberRenderable,
916
+ markdown: MarkdownRenderable,
917
+ span: SpanRenderable,
918
+ strong: BoldSpanRenderable,
919
+ b: BoldSpanRenderable,
920
+ em: ItalicSpanRenderable,
921
+ i: ItalicSpanRenderable,
922
+ u: UnderlineSpanRenderable,
923
+ br: LineBreakRenderable,
924
+ a: LinkRenderable
925
+ };
926
+ var componentCatalogue = { ...baseComponents };
927
+ function extend(objects) {
928
+ Object.assign(componentCatalogue, objects);
929
+ }
930
+ function getComponentCatalogue() {
931
+ return componentCatalogue;
932
+ }
933
+
934
+ // index.ts
935
+ var render = async (node, rendererOrConfig = {}) => {
936
+ let isDisposed = false;
937
+ let dispose;
938
+ const renderer = rendererOrConfig instanceof CliRenderer ? rendererOrConfig : await createCliRenderer({
939
+ ...rendererOrConfig,
940
+ onDestroy: () => {
941
+ if (!isDisposed) {
942
+ isDisposed = true;
943
+ dispose();
944
+ }
945
+ rendererOrConfig.onDestroy?.();
946
+ }
947
+ });
948
+ if (rendererOrConfig instanceof CliRenderer) {
949
+ renderer.on("destroy", () => {
950
+ if (!isDisposed) {
951
+ isDisposed = true;
952
+ dispose();
953
+ }
954
+ });
955
+ }
956
+ engine2.attach(renderer);
957
+ dispose = _render(() => createComponent2(RendererContext.Provider, {
958
+ get value() {
959
+ return renderer;
960
+ },
961
+ get children() {
962
+ return createComponent2(node, {});
963
+ }
964
+ }), renderer.root);
965
+ };
966
+ var testRender = async (node, renderConfig = {}) => {
967
+ let isDisposed = false;
968
+ const testSetup = await createTestRenderer({
969
+ ...renderConfig,
970
+ onDestroy: () => {
971
+ if (!isDisposed) {
972
+ isDisposed = true;
973
+ dispose();
974
+ }
975
+ renderConfig.onDestroy?.();
976
+ }
977
+ });
978
+ engine2.attach(testSetup.renderer);
979
+ const dispose = _render(() => createComponent2(RendererContext.Provider, {
980
+ get value() {
981
+ return testSetup.renderer;
982
+ },
983
+ get children() {
984
+ return createComponent2(node, {});
985
+ }
986
+ }), testSetup.renderer.root);
987
+ return testSetup;
988
+ };
989
+ export {
990
+ useTimeline,
991
+ useTerminalDimensions,
992
+ useSelectionHandler,
993
+ useRenderer,
994
+ usePaste,
995
+ useKeyboard,
996
+ useKeyHandler,
997
+ use,
998
+ textNodeKeys,
999
+ testRender,
1000
+ spread,
1001
+ setProp,
1002
+ render,
1003
+ onResize,
1004
+ mergeProps3 as mergeProps,
1005
+ memo2 as memo,
1006
+ insertNode,
1007
+ insert,
1008
+ getComponentCatalogue,
1009
+ extend,
1010
+ effect,
1011
+ createTextNode,
1012
+ createSlotNode,
1013
+ createElement,
1014
+ createDynamic,
1015
+ createComponent2 as createComponent,
1016
+ componentCatalogue,
1017
+ baseComponents,
1018
+ _render,
1019
+ UnderlineSpanRenderable,
1020
+ TextSlotRenderable,
1021
+ SlotRenderable,
1022
+ RendererContext,
1023
+ Portal,
1024
+ LinkRenderable,
1025
+ LineBreakRenderable,
1026
+ LayoutSlotRenderable,
1027
+ ItalicSpanRenderable,
1028
+ Dynamic,
1029
+ BoldSpanRenderable
1030
+ };