@opentui/solid 0.1.13 → 0.1.15

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.d.ts CHANGED
@@ -3,4 +3,5 @@ import type { JSX } from "./jsx-runtime";
3
3
  export declare const render: (node: () => JSX.Element, renderConfig?: CliRendererConfig) => Promise<void>;
4
4
  export * from "./src/reconciler";
5
5
  export * from "./src/elements";
6
+ export * from "./src/types/elements";
6
7
  export { type JSX };
package/index.js CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  ASCIIFontRenderable,
8
8
  BoxRenderable,
9
9
  InputRenderable,
10
+ ScrollBoxRenderable,
10
11
  SelectRenderable,
11
12
  TabSelectRenderable,
12
13
  TextRenderable
@@ -37,14 +38,14 @@ var onResize = (callback) => {
37
38
  };
38
39
  var useTerminalDimensions = () => {
39
40
  const renderer = useRenderer();
40
- const [terminalDimensions, setTerminalDimensions] = createSignal({ width: renderer.terminalWidth, height: renderer.terminalHeight });
41
+ const [terminalDimensions, setTerminalDimensions] = createSignal({ width: renderer.width, height: renderer.height });
41
42
  const callback = (width, height) => {
42
43
  setTerminalDimensions({ width, height });
43
44
  };
44
45
  onResize(callback);
45
46
  return terminalDimensions;
46
47
  };
47
- var useKeyHandler = (callback) => {
48
+ var useKeyboard = (callback) => {
48
49
  const keyHandler = getKeyHandler();
49
50
  onMount(() => {
50
51
  keyHandler.on("keypress", callback);
@@ -53,6 +54,7 @@ var useKeyHandler = (callback) => {
53
54
  keyHandler.off("keypress", callback);
54
55
  });
55
56
  };
57
+ var useKeyHandler = useKeyboard;
56
58
  var useSelectionHandler = (callback) => {
57
59
  const renderer = useRenderer();
58
60
  onMount(() => {
@@ -93,14 +95,22 @@ var useTimeline = (timeline, initialValue, targetValue, options, startTime = 0)
93
95
  };
94
96
 
95
97
  // src/elements/index.ts
96
- var elements = {
97
- ascii_font: ASCIIFontRenderable,
98
+ var baseComponents = {
98
99
  box: BoxRenderable,
100
+ text: TextRenderable,
99
101
  input: InputRenderable,
100
102
  select: SelectRenderable,
103
+ ascii_font: ASCIIFontRenderable,
101
104
  tab_select: TabSelectRenderable,
102
- text: TextRenderable
105
+ scrollbox: ScrollBoxRenderable
103
106
  };
107
+ var componentCatalogue = { ...baseComponents };
108
+ function extend(objects) {
109
+ Object.assign(componentCatalogue, objects);
110
+ }
111
+ function getComponentCatalogue() {
112
+ return componentCatalogue;
113
+ }
104
114
 
105
115
  // src/reconciler.ts
106
116
  import {
@@ -114,6 +124,7 @@ import {
114
124
  TabSelectRenderableEvents,
115
125
  TextRenderable as TextRenderable3
116
126
  } from "@opentui/core";
127
+ import { useContext as useContext2 } from "solid-js";
117
128
  import { createRenderer } from "solid-js/universal";
118
129
 
119
130
  // src/elements/text-node.ts
@@ -140,6 +151,9 @@ var log = (...args) => {
140
151
  // src/elements/text-node.ts
141
152
  var GHOST_NODE_TAG = "text-ghost";
142
153
  var ChunkToTextNodeMap = new WeakMap;
154
+ var isTextChunk = (node) => {
155
+ return typeof node === "object" && "__isChunk" in node;
156
+ };
143
157
 
144
158
  class TextNode {
145
159
  id;
@@ -193,6 +207,7 @@ class TextNode {
193
207
  }
194
208
  }
195
209
  textParent.content = styledText;
210
+ textParent.visible = styledText.toString() !== "";
196
211
  this.parent = parent;
197
212
  }
198
213
  remove(parent) {
@@ -251,9 +266,27 @@ class GhostTextRenderable extends TextRenderable2 {
251
266
  }
252
267
 
253
268
  // src/reconciler.ts
254
- import { useContext as useContext2 } from "solid-js";
269
+ var logId = (node) => {
270
+ if (!node)
271
+ return;
272
+ if (isTextChunk(node)) {
273
+ return node.plainText;
274
+ }
275
+ return node.id;
276
+ };
255
277
  function _insertNode(parent, node, anchor) {
256
- log("Inserting node:", node.id, "into parent:", parent.id, "with anchor:", anchor?.id);
278
+ log("Inserting node:", logId(node), "into parent:", logId(parent), "with anchor:", logId(anchor), node instanceof TextNode);
279
+ if (node instanceof StyledText) {
280
+ log("Inserting styled text:", node.toString());
281
+ for (const chunk of node.chunks) {
282
+ _insertNode(parent, _createTextNode(chunk), anchor);
283
+ return;
284
+ }
285
+ }
286
+ if (isTextChunk(node)) {
287
+ _insertNode(parent, _createTextNode(node), anchor);
288
+ return;
289
+ }
257
290
  if (node instanceof TextNode) {
258
291
  return node.insert(parent, anchor);
259
292
  }
@@ -261,6 +294,10 @@ function _insertNode(parent, node, anchor) {
261
294
  return;
262
295
  }
263
296
  if (anchor) {
297
+ if (isTextChunk(anchor)) {
298
+ console.warn("Cannot add non text node with text chunk anchor");
299
+ return;
300
+ }
264
301
  const anchorIndex = parent.getChildren().findIndex((el) => {
265
302
  if (anchor instanceof TextNode) {
266
303
  return el.id === anchor.textParent?.id;
@@ -273,7 +310,20 @@ function _insertNode(parent, node, anchor) {
273
310
  }
274
311
  }
275
312
  function _removeNode(parent, node) {
276
- log("Removing node:", node.id, "from parent:", parent.id);
313
+ log("Removing node:", logId(node), "from parent:", logId(parent));
314
+ if (isTextChunk(node)) {
315
+ const textNode = TextNode.getTextNodeFromChunk(node);
316
+ if (textNode) {
317
+ _removeNode(parent, textNode);
318
+ }
319
+ } else if (node instanceof StyledText) {
320
+ for (const chunk of node.chunks) {
321
+ const textNode = TextNode.getTextNodeFromChunk(chunk);
322
+ if (!textNode)
323
+ continue;
324
+ _removeNode(parent, textNode);
325
+ }
326
+ }
277
327
  if (node instanceof TextNode) {
278
328
  return node.remove(parent);
279
329
  }
@@ -282,6 +332,16 @@ function _removeNode(parent, node) {
282
332
  node.destroyRecursively();
283
333
  }
284
334
  }
335
+ function _createTextNode(value) {
336
+ log("Creating text node:", value);
337
+ const chunk = value && isTextChunk(value) ? value : {
338
+ __isChunk: true,
339
+ text: new TextEncoder().encode(`${value}`),
340
+ plainText: `${value}`
341
+ };
342
+ const textNode = new TextNode(chunk);
343
+ return textNode;
344
+ }
285
345
  var {
286
346
  render: _render,
287
347
  effect,
@@ -290,7 +350,7 @@ var {
290
350
  createElement,
291
351
  createTextNode,
292
352
  insertNode,
293
- insert: solidUniversalInsert,
353
+ insert,
294
354
  spread,
295
355
  setProp,
296
356
  mergeProps,
@@ -303,24 +363,23 @@ var {
303
363
  if (!solidRenderer) {
304
364
  throw new Error("No renderer found");
305
365
  }
366
+ const elements = getComponentCatalogue();
367
+ if (!elements[tagName]) {
368
+ throw new Error(`[Reconciler] Unknown component type: ${tagName}`);
369
+ }
306
370
  const element = new elements[tagName](solidRenderer, { id });
307
371
  log("Element created with id:", id);
308
372
  return element;
309
373
  },
310
- createTextNode(value) {
311
- log("Creating text node:", value);
312
- const chunk = typeof value === "object" && "__isChunk" in value ? value : {
313
- __isChunk: true,
314
- text: new TextEncoder().encode(`${value}`),
315
- plainText: `${value}`
316
- };
317
- const textNode = new TextNode(chunk);
318
- return textNode;
319
- },
374
+ createTextNode: _createTextNode,
320
375
  replaceText(textNode, value) {
321
- log("Replacing text:", value, "in node:", textNode.id);
376
+ log("Replacing text:", value, "in node:", logId(textNode));
322
377
  if (textNode instanceof Renderable2)
323
378
  return;
379
+ if (isTextChunk(textNode)) {
380
+ console.warn("Cannot replace text on text chunk", logId(textNode));
381
+ return;
382
+ }
324
383
  const newChunk = {
325
384
  __isChunk: true,
326
385
  text: new TextEncoder().encode(value),
@@ -329,8 +388,8 @@ var {
329
388
  textNode.replaceText(newChunk);
330
389
  },
331
390
  setProperty(node, name, value, prev) {
332
- if (node instanceof TextNode) {
333
- console.warn("Cannot set property on text node:", node.id);
391
+ if (node instanceof TextNode || isTextChunk(node)) {
392
+ console.warn("Cannot set property on text node:", logId(node));
334
393
  return;
335
394
  }
336
395
  if (name.startsWith("on:")) {
@@ -427,18 +486,25 @@ var {
427
486
  },
428
487
  insertNode: _insertNode,
429
488
  removeNode: _removeNode,
430
- getParentNode(node) {
431
- log("Getting parent of node:", node.id);
489
+ getParentNode(childNode) {
490
+ log("Getting parent of node:", logId(childNode));
491
+ let node = childNode;
492
+ if (isTextChunk(childNode)) {
493
+ const parentTextNode = TextNode.getTextNodeFromChunk(childNode);
494
+ if (!parentTextNode)
495
+ return;
496
+ node = parentTextNode;
497
+ }
432
498
  const parent = node.parent;
433
499
  if (!parent) {
434
- log("No parent found for node:", node.id);
500
+ log("No parent found for node:", logId(node));
435
501
  return;
436
502
  }
437
- log("Parent found:", parent.id, "for node:", node.id);
503
+ log("Parent found:", logId(parent), "for node:", logId(node));
438
504
  return parent;
439
505
  },
440
506
  getFirstChild(node) {
441
- log("Getting first child of node:", node.id);
507
+ log("Getting first child of node:", logId(node));
442
508
  if (node instanceof TextRenderable3) {
443
509
  const chunk = node.content.chunks[0];
444
510
  if (chunk) {
@@ -447,22 +513,26 @@ var {
447
513
  return;
448
514
  }
449
515
  }
450
- if (node instanceof TextNode) {
516
+ if (node instanceof TextNode || isTextChunk(node)) {
451
517
  return;
452
518
  }
453
519
  const firstChild = node.getChildren()[0];
454
520
  if (!firstChild) {
455
- log("No first child found for node:", node.id);
521
+ log("No first child found for node:", logId(node));
456
522
  return;
457
523
  }
458
- log("First child found:", firstChild.id, "for node:", node.id);
524
+ log("First child found:", logId(firstChild), "for node:", logId(node));
459
525
  return firstChild;
460
526
  },
461
527
  getNextSibling(node) {
462
- log("Getting next sibling of node:", node.id);
528
+ log("Getting next sibling of node:", logId(node));
529
+ if (isTextChunk(node)) {
530
+ console.warn("Cannot get next sibling of text chunk");
531
+ return;
532
+ }
463
533
  const parent = node.parent;
464
534
  if (!parent) {
465
- log("No parent found for node:", node.id);
535
+ log("No parent found for node:", logId(node));
466
536
  return;
467
537
  }
468
538
  if (node instanceof TextNode) {
@@ -470,73 +540,34 @@ var {
470
540
  const siblings2 = parent.content.chunks;
471
541
  const index2 = siblings2.indexOf(node.chunk);
472
542
  if (index2 === -1 || index2 === siblings2.length - 1) {
473
- log("No next sibling found for node:", node.id);
543
+ log("No next sibling found for node:", logId(node));
474
544
  return;
475
545
  }
476
546
  const nextSibling2 = siblings2[index2 + 1];
477
547
  if (!nextSibling2) {
478
- log("Next sibling is null for node:", node.id);
548
+ log("Next sibling is null for node:", logId(node));
479
549
  return;
480
550
  }
481
551
  return TextNode.getTextNodeFromChunk(nextSibling2);
482
552
  }
483
- console.warn("Text parent is not a text node:", node.id);
553
+ console.warn("Text parent is not a text node:", logId(node));
484
554
  return;
485
555
  }
486
556
  const siblings = parent.getChildren();
487
557
  const index = siblings.indexOf(node);
488
558
  if (index === -1 || index === siblings.length - 1) {
489
- log("No next sibling found for node:", node.id);
559
+ log("No next sibling found for node:", logId(node));
490
560
  return;
491
561
  }
492
562
  const nextSibling = siblings[index + 1];
493
563
  if (!nextSibling) {
494
- log("Next sibling is null for node:", node.id);
564
+ log("Next sibling is null for node:", logId(node));
495
565
  return;
496
566
  }
497
- log("Next sibling found:", nextSibling.id, "for node:", node.id);
567
+ log("Next sibling found:", logId(nextSibling), "for node:", logId(node));
498
568
  return nextSibling;
499
569
  }
500
570
  });
501
- var insertStyledText = (parent, value, current, marker) => {
502
- while (typeof current === "function")
503
- current = current();
504
- if (value === current)
505
- return current;
506
- if (current) {
507
- if (typeof current === "object" && "__isChunk" in current) {
508
- const node = TextNode.getTextNodeFromChunk(current);
509
- if (node) {
510
- _removeNode(parent, node);
511
- }
512
- } else if (current instanceof StyledText) {
513
- for (const chunk of current.chunks) {
514
- const chunkNode = TextNode.getTextNodeFromChunk(chunk);
515
- if (!chunkNode)
516
- continue;
517
- _removeNode(parent, chunkNode);
518
- }
519
- }
520
- }
521
- if (value instanceof StyledText) {
522
- log("Inserting styled text:", value.toString());
523
- for (const chunk of value.chunks) {
524
- insertNode(parent, createTextNode(chunk), marker);
525
- }
526
- return value;
527
- } else if (value && typeof value === "object" && "__isChunk" in value) {
528
- insertNode(parent, createTextNode(value), marker);
529
- return value;
530
- }
531
- return solidUniversalInsert(parent, value, marker, current);
532
- };
533
- var insert = (parent, accessor, marker, initial) => {
534
- if (marker !== undefined && !initial)
535
- initial = [];
536
- if (typeof accessor !== "function")
537
- return insertStyledText(parent, accessor, initial, marker);
538
- effect((current) => insertStyledText(parent, accessor(), current, marker), initial);
539
- };
540
571
 
541
572
  // index.ts
542
573
  var render = async (node, renderConfig = {}) => {
@@ -555,10 +586,10 @@ export {
555
586
  useTerminalDimensions,
556
587
  useSelectionHandler,
557
588
  useRenderer,
589
+ useKeyboard,
558
590
  useKeyHandler,
559
591
  use,
560
592
  spread,
561
- solidUniversalInsert,
562
593
  setProp,
563
594
  render,
564
595
  onResize,
@@ -566,12 +597,15 @@ export {
566
597
  memo,
567
598
  insertNode,
568
599
  insert,
569
- elements,
600
+ getComponentCatalogue,
601
+ extend,
570
602
  effect,
571
603
  createTextNode,
572
604
  createElement,
573
605
  createComponentTimeline,
574
606
  createComponent,
607
+ componentCatalogue,
608
+ baseComponents,
575
609
  _render,
576
610
  RendererContext
577
611
  };
package/jsx-runtime.d.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  import { Renderable } from "@opentui/core"
2
- import {
3
- ASCIIFontElementProps,
4
- BoxElementProps,
5
- InputElementProps,
6
- SelectElementProps,
7
- TabSelectElementProps,
8
- TextElementProps,
9
- } from "./src/elements/index"
2
+ import type {
3
+ AsciiFontProps,
4
+ BoxProps,
5
+ ExtendedIntrinsicElements,
6
+ InputProps,
7
+ OpenTUIComponents,
8
+ SelectProps,
9
+ TabSelectProps,
10
+ TextProps,
11
+ } from "./src/types/elements"
10
12
 
11
13
  declare namespace JSX {
12
14
  // Replace Node with Renderable
@@ -14,13 +16,13 @@ declare namespace JSX {
14
16
 
15
17
  interface ArrayElement extends Array<Element> {}
16
18
 
17
- interface IntrinsicElements {
18
- ascii_font: ASCIIFontElementProps
19
- box: BoxElementProps
20
- input: InputElementProps
21
- select: SelectElementProps
22
- tab_select: TabSelectElementProps
23
- text: TextElementProps
19
+ interface IntrinsicElements extends ExtendedIntrinsicElements<OpenTUIComponents> {
20
+ box: BoxProps
21
+ text: TextProps
22
+ input: InputProps
23
+ select: SelectProps
24
+ ascii_font: AsciiFontProps
25
+ tab_select: TabSelectProps
24
26
  }
25
27
 
26
28
  interface ElementChildrenAttribute {
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "type": "module",
7
- "version": "0.1.13",
7
+ "version": "0.1.15",
8
8
  "description": "SolidJS renderer for OpenTUI",
9
9
  "license": "MIT",
10
10
  "repository": {
@@ -25,7 +25,7 @@
25
25
  "./jsx-dev-runtime": "./jsx-runtime.d.ts"
26
26
  },
27
27
  "dependencies": {
28
- "@opentui/core": "0.1.13",
28
+ "@opentui/core": "0.1.15",
29
29
  "babel-plugin-module-resolver": "5.0.2",
30
30
  "@babel/core": "7.28.0",
31
31
  "@babel/preset-typescript": "7.27.1",
@@ -6,6 +6,10 @@ export declare const useTerminalDimensions: () => import("solid-js").Accessor<{
6
6
  width: number;
7
7
  height: number;
8
8
  }>;
9
+ export declare const useKeyboard: (callback: (key: ParsedKey) => void) => void;
10
+ /**
11
+ * @deprecated renamed to useKeyboard
12
+ */
9
13
  export declare const useKeyHandler: (callback: (key: ParsedKey) => void) => void;
10
14
  export declare const useSelectionHandler: (callback: (selection: Selection) => void) => void;
11
15
  export declare const createComponentTimeline: (options?: TimelineOptions) => Timeline;
@@ -1,52 +1,29 @@
1
- import type { ASCIIFontOptions, BoxOptions, InputRenderableOptions, Renderable, RenderableOptions, SelectOption, SelectRenderableOptions, StyledText, TabSelectOption, TabSelectRenderableOptions, TextChunk, TextOptions } from "@opentui/core";
2
- import { ASCIIFontRenderable, BoxRenderable, InputRenderable, SelectRenderable, TabSelectRenderable, TextRenderable } from "@opentui/core";
3
- import type { JSX, Ref } from "solid-js";
1
+ import { ASCIIFontRenderable, BoxRenderable, InputRenderable, ScrollBoxRenderable, SelectRenderable, TabSelectRenderable, TextRenderable } from "@opentui/core";
2
+ import type { RenderableConstructor } from "../types/elements";
4
3
  export * from "./hooks";
5
- export declare const elements: {
6
- ascii_font: typeof ASCIIFontRenderable;
4
+ export declare const baseComponents: {
7
5
  box: typeof BoxRenderable;
6
+ text: typeof TextRenderable;
8
7
  input: typeof InputRenderable;
9
8
  select: typeof SelectRenderable;
9
+ ascii_font: typeof ASCIIFontRenderable;
10
10
  tab_select: typeof TabSelectRenderable;
11
- text: typeof TextRenderable;
12
- };
13
- export type Element = keyof typeof elements;
14
- type RenderableNonStyleKeys = "buffered";
15
- type ElementProps<T extends RenderableOptions<K>, K extends Renderable = Renderable, NonStyleKeys extends keyof T = RenderableNonStyleKeys> = {
16
- style?: Omit<T, NonStyleKeys | RenderableNonStyleKeys>;
17
- ref?: Ref<K>;
18
- } & T;
19
- type ContainerProps = {
20
- children?: JSX.Element;
21
- };
22
- export type BoxElementProps = ElementProps<BoxOptions, BoxRenderable, "title"> & ContainerProps;
23
- export type BoxStyle = BoxElementProps["style"];
24
- export type InputElementProps = ElementProps<InputRenderableOptions, InputRenderable, "value" | "maxLength" | "placeholder"> & {
25
- onInput?: (value: string) => void;
26
- onSubmit?: (value: string) => void;
27
- onChange?: (value: string) => void;
28
- focused?: boolean;
29
- };
30
- export type InputStyle = InputElementProps["style"];
31
- type TabSelectEventCallback = (index: number, option: TabSelectOption) => void;
32
- export type TabSelectElementProps = ElementProps<TabSelectRenderableOptions, TabSelectRenderable, "options" | "showScrollArrows" | "showDescription" | "wrapSelection"> & {
33
- onSelect?: TabSelectEventCallback;
34
- onChange?: TabSelectEventCallback;
35
- focused?: boolean;
36
- };
37
- export type TabSelectStyle = TabSelectElementProps["style"];
38
- type SelectEventCallback = (index: number, option: SelectOption) => void;
39
- export type SelectElementProps = ElementProps<SelectRenderableOptions, SelectRenderable, "options" | "showScrollIndicator" | "wrapSelection" | "fastScrollStep"> & {
40
- onSelect?: SelectEventCallback;
41
- onChange?: SelectEventCallback;
42
- focused?: boolean;
43
- };
44
- export type SelectStyle = SelectElementProps["style"];
45
- type TextChildTypes = (string & {}) | number | boolean | null | undefined;
46
- type TextProps = {
47
- children: TextChildTypes | StyledText | TextChunk | Array<TextChildTypes | TextChunk>;
11
+ scrollbox: typeof ScrollBoxRenderable;
48
12
  };
49
- export type ASCIIFontElementProps = ElementProps<ASCIIFontOptions, ASCIIFontRenderable, "text" | "selectable"> & {};
50
- export type ASCIIFontStyle = ASCIIFontElementProps["style"];
51
- export type TextElementProps = ElementProps<TextOptions, TextRenderable, "content" | "selectable"> & TextProps;
52
- export type TextStyle = TextElementProps["style"];
13
+ type ComponentCatalogue = Record<string, RenderableConstructor>;
14
+ export declare const componentCatalogue: ComponentCatalogue;
15
+ /**
16
+ * Extend the component catalogue with new renderable components
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * // Extend with an object of components
21
+ * extend({
22
+ * consoleButton: ConsoleButtonRenderable,
23
+ * customBox: CustomBoxRenderable
24
+ * })
25
+ * ```
26
+ */
27
+ export declare function extend<T extends ComponentCatalogue>(objects: T): void;
28
+ export declare function getComponentCatalogue(): ComponentCatalogue;
29
+ export type { ExtendedComponentProps, ExtendedIntrinsicElements, RenderableConstructor } from "../types/elements";
@@ -1,5 +1,6 @@
1
1
  import { Renderable, TextRenderable, type RenderContext, type TextChunk, type TextOptions } from "@opentui/core";
2
2
  import { type DomNode } from "../reconciler";
3
+ export declare const isTextChunk: (node: any) => node is TextChunk;
3
4
  /**
4
5
  * Represents a text node in the SolidJS reconciler.
5
6
  */
@@ -1,5 +1,4 @@
1
- import { Renderable } from "@opentui/core";
1
+ import { Renderable, type TextChunk } from "@opentui/core";
2
2
  import { TextNode } from "./elements/text-node";
3
- export type DomNode = Renderable | TextNode;
4
- export declare const _render: (code: () => DomNode, node: DomNode) => () => void, effect: <T>(fn: (prev?: T) => T, init?: T) => void, memo: <T>(fn: () => T, equal: boolean) => () => T, createComponent: <T>(Comp: (props: T) => DomNode, props: T) => DomNode, createElement: (tag: string) => DomNode, createTextNode: (value: string) => DomNode, insertNode: (parent: DomNode, node: DomNode, anchor?: DomNode | undefined) => void, solidUniversalInsert: <T>(parent: any, accessor: T | (() => T), marker?: any | null, initial?: any) => DomNode, spread: <T>(node: any, accessor: (() => T) | T, skipChildren?: boolean) => void, setProp: <T>(node: DomNode, name: string, value: T, prev?: T | undefined) => T, mergeProps: (...sources: unknown[]) => unknown, use: <A, T>(fn: (element: DomNode, arg: A) => T, element: DomNode, arg: A) => T;
5
- export declare const insert: typeof solidUniversalInsert;
3
+ export type DomNode = Renderable | TextNode | TextChunk;
4
+ export declare const _render: (code: () => DomNode, node: DomNode) => () => void, effect: <T>(fn: (prev?: T) => T, init?: T) => void, memo: <T>(fn: () => T, equal: boolean) => () => T, createComponent: <T>(Comp: (props: T) => DomNode, props: T) => DomNode, createElement: (tag: string) => DomNode, createTextNode: (value: string) => DomNode, insertNode: (parent: DomNode, node: DomNode, anchor?: DomNode | undefined) => void, insert: <T>(parent: any, accessor: T | (() => T), marker?: any | null, initial?: any) => DomNode, spread: <T>(node: any, accessor: (() => T) | T, skipChildren?: boolean) => void, setProp: <T>(node: DomNode, name: string, value: T, prev?: T | undefined) => T, mergeProps: (...sources: unknown[]) => unknown, use: <A, T>(fn: (element: DomNode, arg: A) => T, element: DomNode, arg: A) => T;
@@ -0,0 +1,67 @@
1
+ import type { ASCIIFontOptions, ASCIIFontRenderable, BoxOptions, BoxRenderable, InputRenderable, InputRenderableOptions, Renderable, RenderableOptions, RenderContext, ScrollBoxOptions, ScrollBoxRenderable, SelectOption, SelectRenderable, SelectRenderableOptions, StyledText, TabSelectOption, TabSelectRenderable, TabSelectRenderableOptions, TextChunk, TextOptions, TextRenderable } from "@opentui/core";
2
+ import type { JSX, Ref } from "solid-js";
3
+ /** Properties that should not be included in the style prop */
4
+ export type NonStyledProps = "id" | "buffered" | "live" | "enableLayout" | "selectable" | "renderAfter" | "renderBefore" | `on${string}`;
5
+ /** Solid-specific props for all components */
6
+ export type ElementProps<TRenderable = unknown> = {
7
+ ref?: Ref<TRenderable>;
8
+ };
9
+ /** Base type for any renderable constructor */
10
+ export type RenderableConstructor<TRenderable extends Renderable = Renderable> = new (ctx: RenderContext, options: any) => TRenderable;
11
+ /** Extract the options type from a renderable constructor */
12
+ type ExtractRenderableOptions<TConstructor> = TConstructor extends new (ctx: RenderContext, options: infer TOptions) => any ? TOptions : never;
13
+ /** Extract the renderable type from a constructor */
14
+ type ExtractRenderable<TConstructor> = TConstructor extends new (ctx: RenderContext, options: any) => infer TRenderable ? TRenderable : never;
15
+ /** Determine which properties should be excluded from styling for different renderable types */
16
+ export type GetNonStyledProperties<TConstructor> = TConstructor extends RenderableConstructor<TextRenderable> ? NonStyledProps | "content" : TConstructor extends RenderableConstructor<BoxRenderable> ? NonStyledProps | "title" : TConstructor extends RenderableConstructor<ASCIIFontRenderable> ? NonStyledProps | "text" | "selectable" : TConstructor extends RenderableConstructor<InputRenderable> ? NonStyledProps | "placeholder" | "value" : NonStyledProps;
17
+ /** Base props for container components that accept children */
18
+ type ContainerProps<TOptions> = TOptions & {
19
+ children?: JSX.Element;
20
+ };
21
+ /** Smart component props that automatically determine excluded properties */
22
+ type ComponentProps<TOptions extends RenderableOptions<TRenderable>, TRenderable extends Renderable> = TOptions & {
23
+ style?: Partial<Omit<TOptions, GetNonStyledProperties<RenderableConstructor<TRenderable>>>>;
24
+ } & ElementProps<TRenderable>;
25
+ /** Valid text content types for Text component children */
26
+ type TextChildren = (string & {}) | number | boolean | null | undefined;
27
+ export type TextProps = ComponentProps<TextOptions, TextRenderable> & {
28
+ children?: TextChildren | StyledText | TextChunk | Array<TextChildren | StyledText | TextChunk>;
29
+ };
30
+ export type BoxProps = ComponentProps<ContainerProps<BoxOptions>, BoxRenderable>;
31
+ export type InputProps = ComponentProps<InputRenderableOptions, InputRenderable> & {
32
+ focused?: boolean;
33
+ onInput?: (value: string) => void;
34
+ onChange?: (value: string) => void;
35
+ onSubmit?: (value: string) => void;
36
+ };
37
+ export type SelectProps = ComponentProps<SelectRenderableOptions, SelectRenderable> & {
38
+ focused?: boolean;
39
+ onChange?: (index: number, option: SelectOption | null) => void;
40
+ onSelect?: (index: number, option: SelectOption | null) => void;
41
+ };
42
+ export type AsciiFontProps = ComponentProps<ASCIIFontOptions, ASCIIFontRenderable>;
43
+ export type TabSelectProps = ComponentProps<TabSelectRenderableOptions, TabSelectRenderable> & {
44
+ focused?: boolean;
45
+ onChange?: (index: number, option: TabSelectOption | null) => void;
46
+ onSelect?: (index: number, option: TabSelectOption | null) => void;
47
+ };
48
+ export type ScrollBoxProps = ComponentProps<ContainerProps<ScrollBoxOptions>, ScrollBoxRenderable> & {
49
+ focused?: boolean;
50
+ };
51
+ /** Convert renderable constructor to component props with proper style exclusions */
52
+ export type ExtendedComponentProps<TConstructor extends RenderableConstructor, TOptions = ExtractRenderableOptions<TConstructor>> = TOptions & {
53
+ children?: JSX.Element;
54
+ style?: Partial<Omit<TOptions, GetNonStyledProperties<TConstructor>>>;
55
+ } & ElementProps<ExtractRenderable<TConstructor>>;
56
+ /** Helper type to create JSX element properties from a component catalogue */
57
+ export type ExtendedIntrinsicElements<TComponentCatalogue extends Record<string, RenderableConstructor>> = {
58
+ [TComponentName in keyof TComponentCatalogue]: ExtendedComponentProps<TComponentCatalogue[TComponentName]>;
59
+ };
60
+ /**
61
+ * Global augmentation interface for extended components
62
+ * This will be augmented by user code using module augmentation
63
+ */
64
+ export interface OpenTUIComponents {
65
+ [componentName: string]: RenderableConstructor;
66
+ }
67
+ export {};