@opentui/solid 0.0.0-20250908-4906ddad → 0.0.0-20250915-f5db043a

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.
@@ -0,0 +1,88 @@
1
+ export function useTimeline(timeline: any, initialValue: any, targetValue: any, options: any, startTime?: number): import("solid-js").Accessor<any>;
2
+ export function useTerminalDimensions(): import("solid-js").Accessor<{
3
+ width: any;
4
+ height: any;
5
+ }>;
6
+ export function useSelectionHandler(callback: any): void;
7
+ export function useRenderer(): any;
8
+ export function useKeyboard(callback: any): void;
9
+ export function useKeyHandler(callback: any): void;
10
+ export var use: <A, T>(fn: (element: any, arg: A) => T, element: any, arg: A) => T;
11
+ export var textNodeKeys: string[];
12
+ export var spread: <T>(node: any, accessor: (() => T) | T, skipChildren?: boolean) => void;
13
+ export var setProp: <T>(node: any, name: string, value: T, prev?: T | undefined) => T;
14
+ export function render(node: any, renderConfig?: {}): Promise<void>;
15
+ export function onResize(callback: any): void;
16
+ export var mergeProps: (...sources: unknown[]) => unknown;
17
+ export var memo: <T>(fn: () => T, equal: boolean) => () => T;
18
+ export var insertNode: (parent: any, node: any, anchor?: any) => void;
19
+ export var insert: <T>(parent: any, accessor: T | (() => T), marker?: any | null, initial?: any) => any;
20
+ export function getComponentCatalogue(): {
21
+ box: typeof BoxRenderable;
22
+ text: typeof TextRenderable;
23
+ input: typeof InputRenderable;
24
+ select: typeof SelectRenderable;
25
+ ascii_font: typeof ASCIIFontRenderable;
26
+ tab_select: typeof TabSelectRenderable;
27
+ scrollbox: typeof ScrollBoxRenderable;
28
+ span: typeof SpanRenderable;
29
+ strong: typeof BoldSpanRenderable;
30
+ b: typeof BoldSpanRenderable;
31
+ em: typeof ItalicSpanRenderable;
32
+ i: typeof ItalicSpanRenderable;
33
+ u: typeof UnderlineSpanRenderable;
34
+ br: typeof LineBreakRenderable;
35
+ };
36
+ export function extend(objects: any): void;
37
+ export var effect: <T>(fn: (prev?: T) => T, init?: T) => void;
38
+ export var createTextNode: (value: string) => any;
39
+ export var createElement: (tag: string) => any;
40
+ export function createComponentTimeline(options?: {}): Timeline;
41
+ export var createComponent: <T>(Comp: (props: T) => any, props: T) => any;
42
+ export namespace componentCatalogue {
43
+ export { BoxRenderable as box };
44
+ export { TextRenderable as text };
45
+ export { InputRenderable as input };
46
+ export { SelectRenderable as select };
47
+ export { ASCIIFontRenderable as ascii_font };
48
+ export { TabSelectRenderable as tab_select };
49
+ export { ScrollBoxRenderable as scrollbox };
50
+ export { SpanRenderable as span };
51
+ export { BoldSpanRenderable as strong };
52
+ export { BoldSpanRenderable as b };
53
+ export { ItalicSpanRenderable as em };
54
+ export { ItalicSpanRenderable as i };
55
+ export { UnderlineSpanRenderable as u };
56
+ export { LineBreakRenderable as br };
57
+ }
58
+ export namespace baseComponents { }
59
+ export var _render: (code: () => any, node: any) => () => void;
60
+ export class UnderlineSpanRenderable extends TextModifierRenderable {
61
+ constructor(options: any);
62
+ }
63
+ export var RendererContext: import("solid-js").Context<any>;
64
+ export class LineBreakRenderable extends SpanRenderable {
65
+ add(): number;
66
+ }
67
+ export class ItalicSpanRenderable extends TextModifierRenderable {
68
+ constructor(options: any);
69
+ }
70
+ export class BoldSpanRenderable extends TextModifierRenderable {
71
+ constructor(options: any);
72
+ }
73
+ import { BoxRenderable } from "@opentui/core";
74
+ import { TextRenderable } from "@opentui/core";
75
+ import { InputRenderable } from "@opentui/core";
76
+ import { SelectRenderable } from "@opentui/core";
77
+ import { ASCIIFontRenderable } from "@opentui/core";
78
+ import { TabSelectRenderable } from "@opentui/core";
79
+ import { ScrollBoxRenderable } from "@opentui/core";
80
+ declare class SpanRenderable extends TextNodeRenderable {
81
+ constructor(_ctx: any, options: any);
82
+ _ctx: any;
83
+ }
84
+ import { Timeline } from "@opentui/core";
85
+ declare class TextModifierRenderable extends SpanRenderable {
86
+ }
87
+ import { TextNodeRenderable } from "@opentui/core";
88
+ export {};
package/index.js CHANGED
@@ -10,6 +10,8 @@ import {
10
10
  ScrollBoxRenderable,
11
11
  SelectRenderable,
12
12
  TabSelectRenderable,
13
+ TextAttributes,
14
+ TextNodeRenderable,
13
15
  TextRenderable
14
16
  } from "@opentui/core";
15
17
 
@@ -95,6 +97,56 @@ var useTimeline = (timeline, initialValue, targetValue, options, startTime = 0)
95
97
  };
96
98
 
97
99
  // src/elements/index.ts
100
+ class SpanRenderable extends TextNodeRenderable {
101
+ _ctx;
102
+ constructor(_ctx, options) {
103
+ super(options);
104
+ this._ctx = _ctx;
105
+ }
106
+ }
107
+ var textNodeKeys = ["span", "b", "strong", "i", "em", "u"];
108
+
109
+ class TextModifierRenderable extends SpanRenderable {
110
+ constructor(options, modifier) {
111
+ super(null, options);
112
+ if (modifier === "b" || modifier === "strong") {
113
+ this.attributes = (this.attributes || 0) | TextAttributes.BOLD;
114
+ } else if (modifier === "i" || modifier === "em") {
115
+ this.attributes = (this.attributes || 0) | TextAttributes.ITALIC;
116
+ } else if (modifier === "u") {
117
+ this.attributes = (this.attributes || 0) | TextAttributes.UNDERLINE;
118
+ }
119
+ }
120
+ }
121
+
122
+ class BoldSpanRenderable extends TextModifierRenderable {
123
+ constructor(options) {
124
+ super(options, "b");
125
+ }
126
+ }
127
+
128
+ class ItalicSpanRenderable extends TextModifierRenderable {
129
+ constructor(options) {
130
+ super(options, "i");
131
+ }
132
+ }
133
+
134
+ class UnderlineSpanRenderable extends TextModifierRenderable {
135
+ constructor(options) {
136
+ super(options, "u");
137
+ }
138
+ }
139
+
140
+ class LineBreakRenderable extends SpanRenderable {
141
+ constructor(_ctx, options) {
142
+ super(null, options);
143
+ this.add();
144
+ }
145
+ add() {
146
+ return super.add(`
147
+ `);
148
+ }
149
+ }
98
150
  var baseComponents = {
99
151
  box: BoxRenderable,
100
152
  text: TextRenderable,
@@ -102,7 +154,14 @@ var baseComponents = {
102
154
  select: SelectRenderable,
103
155
  ascii_font: ASCIIFontRenderable,
104
156
  tab_select: TabSelectRenderable,
105
- scrollbox: ScrollBoxRenderable
157
+ scrollbox: ScrollBoxRenderable,
158
+ span: SpanRenderable,
159
+ strong: BoldSpanRenderable,
160
+ b: BoldSpanRenderable,
161
+ em: ItalicSpanRenderable,
162
+ i: ItalicSpanRenderable,
163
+ u: UnderlineSpanRenderable,
164
+ br: LineBreakRenderable
106
165
  };
107
166
  var componentCatalogue = { ...baseComponents };
108
167
  function extend(objects) {
@@ -114,22 +173,24 @@ function getComponentCatalogue() {
114
173
 
115
174
  // src/reconciler.ts
116
175
  import {
176
+ BaseRenderable,
177
+ createTextAttributes,
117
178
  InputRenderable as InputRenderable2,
118
179
  InputRenderableEvents,
119
- Renderable as Renderable2,
180
+ isTextNodeRenderable,
181
+ parseColor,
182
+ Renderable,
183
+ RootTextNodeRenderable,
120
184
  SelectRenderable as SelectRenderable2,
121
185
  SelectRenderableEvents,
122
- StyledText,
123
186
  TabSelectRenderable as TabSelectRenderable2,
124
187
  TabSelectRenderableEvents,
125
- TextRenderable as TextRenderable3
188
+ TextNodeRenderable as TextNodeRenderable2,
189
+ TextRenderable as TextRenderable2
126
190
  } from "@opentui/core";
127
191
  import { useContext as useContext2 } from "solid-js";
128
192
  import { createRenderer } from "solid-js/universal";
129
193
 
130
- // src/elements/text-node.ts
131
- import { Renderable, TextRenderable as TextRenderable2 } from "@opentui/core";
132
-
133
194
  // src/utils/id-counter.ts
134
195
  var idCounter = new Map;
135
196
  function getNextId(elementType) {
@@ -148,216 +209,76 @@ var log = (...args) => {
148
209
  }
149
210
  };
150
211
 
151
- // src/elements/text-node.ts
152
- var GHOST_NODE_TAG = "text-ghost";
153
- var ChunkToTextNodeMap = new WeakMap;
154
- var isTextChunk = (node) => {
155
- return typeof node === "object" && "__isChunk" in node;
156
- };
157
-
158
- class TextNode {
159
- id;
160
- chunk;
161
- parent;
162
- textParent;
163
- constructor(chunk) {
164
- this.id = getNextId("text-node");
165
- this.chunk = chunk;
166
- ChunkToTextNodeMap.set(chunk, this);
167
- }
168
- replaceText(newChunk) {
169
- const textParent = this.textParent;
170
- if (!textParent) {
171
- log("No parent found for text node:", this.id);
172
- return;
173
- }
174
- textParent.content = textParent.content.replace(newChunk, this.chunk);
175
- this.chunk = newChunk;
176
- ChunkToTextNodeMap.set(newChunk, this);
177
- }
178
- static getTextNodeFromChunk(chunk) {
179
- return ChunkToTextNodeMap.get(chunk);
180
- }
181
- insert(parent, anchor) {
182
- if (!(parent instanceof Renderable)) {
183
- log("Attaching text node to parent text node, impossible");
184
- return;
185
- }
186
- let textParent;
187
- if (!(parent instanceof TextRenderable2)) {
188
- textParent = this.getOrCreateTextGhostNode(parent, anchor);
189
- } else {
190
- textParent = parent;
191
- }
192
- this.textParent = textParent;
193
- let styledText = textParent.content;
194
- if (anchor) {
195
- if (anchor instanceof Renderable) {
196
- console.warn("text node can't be anchored to Renderable");
197
- return;
198
- } else if (isTextChunk(anchor)) {
199
- anchor = ChunkToTextNodeMap.get(anchor);
200
- }
201
- const anchorIndex = anchor ? styledText.chunks.indexOf(anchor.chunk) : -1;
202
- if (anchorIndex === -1) {
203
- log("anchor not found");
204
- styledText = styledText.insert(this.chunk);
205
- } else {
206
- styledText = styledText.insert(this.chunk, anchorIndex);
207
- }
208
- } else {
209
- const firstChunk = textParent.content.chunks[0];
210
- if (firstChunk && !ChunkToTextNodeMap.has(firstChunk)) {
211
- styledText = styledText.replace(this.chunk, firstChunk);
212
- } else {
213
- styledText = styledText.insert(this.chunk);
214
- }
215
- }
216
- textParent.content = styledText;
217
- textParent.visible = textParent.textLength !== 0;
218
- this.parent = parent;
219
- }
220
- remove(parent) {
221
- if (!(parent instanceof Renderable)) {
222
- ChunkToTextNodeMap.delete(this.chunk);
223
- return;
224
- }
225
- if (parent === this.textParent && parent instanceof TextRenderable2) {
226
- ChunkToTextNodeMap.delete(this.chunk);
227
- parent.content = parent.content.remove(this.chunk);
228
- return;
229
- }
230
- if (this.textParent) {
231
- ChunkToTextNodeMap.delete(this.chunk);
232
- let styledText = this.textParent.content;
233
- styledText = styledText.remove(this.chunk);
234
- if (styledText.chunks.length > 0) {
235
- this.textParent.content = styledText;
236
- } else {
237
- this.parent?.remove(this.textParent.id);
238
- process.nextTick(() => {
239
- if (!this.textParent)
240
- return;
241
- if (!this.textParent.parent) {
242
- this.textParent.destroyRecursively();
243
- }
244
- });
245
- }
246
- }
247
- }
248
- getOrCreateTextGhostNode(parent, anchor) {
249
- if (anchor instanceof TextNode && anchor.textParent) {
250
- return anchor.textParent;
251
- }
252
- const children = parent.getChildren();
253
- if (anchor instanceof Renderable) {
254
- const anchorIndex = children.findIndex((el) => el.id === anchor.id);
255
- const beforeAnchor = children[anchorIndex - 1];
256
- if (beforeAnchor instanceof GhostTextRenderable) {
257
- return beforeAnchor;
258
- }
259
- }
260
- const lastChild = children.at(-1);
261
- if (lastChild instanceof GhostTextRenderable) {
262
- return lastChild;
263
- }
264
- const ghostNode = new GhostTextRenderable(parent.ctx, {
265
- id: getNextId(GHOST_NODE_TAG)
266
- });
267
- insertNode(parent, ghostNode, anchor);
268
- return ghostNode;
269
- }
270
- }
271
-
272
- class GhostTextRenderable extends TextRenderable2 {
273
- constructor(ctx, options) {
274
- super(ctx, options);
275
- }
276
- static isGhostNode(node) {
277
- return node instanceof GhostTextRenderable;
212
+ // src/reconciler.ts
213
+ class TextNode extends TextNodeRenderable2 {
214
+ static fromString(text, options = {}) {
215
+ const node = new TextNode(options);
216
+ node.add(text);
217
+ return node;
278
218
  }
279
219
  }
280
-
281
- // src/reconciler.ts
282
220
  var logId = (node) => {
283
221
  if (!node)
284
222
  return;
285
- if (isTextChunk(node)) {
286
- return node.plainText;
287
- }
288
223
  return node.id;
289
224
  };
225
+ var getNodeChildren = (node) => {
226
+ let children;
227
+ if (node instanceof TextRenderable2) {
228
+ children = node.getTextChildren();
229
+ } else {
230
+ children = node.getChildren();
231
+ }
232
+ return children;
233
+ };
290
234
  function _insertNode(parent, node, anchor) {
291
235
  log("Inserting node:", logId(node), "into parent:", logId(parent), "with anchor:", logId(anchor), node instanceof TextNode);
292
- if (node instanceof StyledText) {
293
- log("Inserting styled text:", node.toString());
294
- for (const chunk of node.chunks) {
295
- _insertNode(parent, _createTextNode(chunk), anchor);
236
+ if (isTextNodeRenderable(node)) {
237
+ if (!(parent instanceof TextRenderable2) && !isTextNodeRenderable(parent)) {
238
+ log(`Text must have a <text> as a parent: ${parent.id} above ${node.id}`);
296
239
  return;
297
240
  }
298
241
  }
299
- if (isTextChunk(node)) {
300
- _insertNode(parent, _createTextNode(node), anchor);
242
+ if (!(parent instanceof BaseRenderable)) {
243
+ log("[INSERT]", "Tried to mount a non base renderable");
301
244
  return;
302
245
  }
303
- if (node instanceof TextNode) {
304
- return node.insert(parent, anchor);
305
- }
306
- if (!(parent instanceof Renderable2)) {
246
+ if (!anchor) {
247
+ parent.add(node);
307
248
  return;
308
249
  }
309
- if (anchor) {
310
- if (isTextChunk(anchor)) {
311
- console.warn("Cannot add non text node with text chunk anchor");
312
- return;
313
- }
314
- const anchorIndex = parent.getChildren().findIndex((el) => {
315
- if (anchor instanceof TextNode) {
316
- return el.id === anchor.textParent?.id;
317
- }
318
- return el.id === anchor.id;
319
- });
320
- parent.add(node, anchorIndex);
321
- } else {
322
- parent.add(node);
250
+ const children = getNodeChildren(parent);
251
+ const anchorIndex = children.findIndex((el) => el.id === anchor.id);
252
+ if (anchorIndex === -1) {
253
+ log("[INSERT]", "Could not find anchor", logId(parent), logId(anchor), "[children]", ...children.map((c) => c.id));
323
254
  }
255
+ parent.add(node, anchorIndex);
324
256
  }
325
257
  function _removeNode(parent, node) {
326
258
  log("Removing node:", logId(node), "from parent:", logId(parent));
327
- if (isTextChunk(node)) {
328
- const textNode = TextNode.getTextNodeFromChunk(node);
329
- if (textNode) {
330
- _removeNode(parent, textNode);
331
- }
332
- } else if (node instanceof StyledText) {
333
- for (const chunk of node.chunks) {
334
- const textNode = TextNode.getTextNodeFromChunk(chunk);
335
- if (!textNode)
336
- continue;
337
- _removeNode(parent, textNode);
259
+ parent.remove(node.id);
260
+ process.nextTick(() => {
261
+ if (node instanceof Renderable && !node.parent) {
262
+ node.destroyRecursively();
263
+ return;
338
264
  }
339
- }
340
- if (node instanceof TextNode) {
341
- return node.remove(parent);
342
- }
343
- if (parent instanceof Renderable2 && node instanceof Renderable2) {
344
- parent.remove(node.id);
345
- process.nextTick(() => {
346
- if (!node.parent) {
347
- node.destroyRecursively();
348
- }
349
- });
350
- }
265
+ });
351
266
  }
352
267
  function _createTextNode(value) {
353
268
  log("Creating text node:", value);
354
- const chunk = value && isTextChunk(value) ? value : {
355
- __isChunk: true,
356
- text: new TextEncoder().encode(`${value}`),
357
- plainText: `${value}`
358
- };
359
- const textNode = new TextNode(chunk);
360
- return textNode;
269
+ const id = getNextId("text-node");
270
+ if (typeof value === "number") {
271
+ value = value.toString();
272
+ }
273
+ return TextNode.fromString(value, { id });
274
+ }
275
+ function _getParentNode(childNode) {
276
+ log("Getting parent of node:", logId(childNode));
277
+ let parent = childNode.parent ?? undefined;
278
+ if (parent instanceof RootTextNodeRenderable) {
279
+ parent = parent.textParent ?? undefined;
280
+ }
281
+ return parent;
361
282
  }
362
283
  var {
363
284
  render: _render,
@@ -391,24 +312,11 @@ var {
391
312
  createTextNode: _createTextNode,
392
313
  replaceText(textNode, value) {
393
314
  log("Replacing text:", value, "in node:", logId(textNode));
394
- if (textNode instanceof Renderable2)
395
- return;
396
- if (isTextChunk(textNode)) {
397
- console.warn("Cannot replace text on text chunk", logId(textNode));
315
+ if (!(textNode instanceof TextNode))
398
316
  return;
399
- }
400
- const newChunk = {
401
- __isChunk: true,
402
- text: new TextEncoder().encode(value),
403
- plainText: value
404
- };
405
- textNode.replaceText(newChunk);
317
+ textNode.replace(value, 0);
406
318
  },
407
319
  setProperty(node, name, value, prev) {
408
- if (node instanceof TextNode || isTextChunk(node)) {
409
- console.warn("Cannot set property on text node:", logId(node));
410
- return;
411
- }
412
320
  if (name.startsWith("on:")) {
413
321
  const eventName = name.slice(3);
414
322
  if (value) {
@@ -419,8 +327,19 @@ var {
419
327
  }
420
328
  return;
421
329
  }
330
+ if (isTextNodeRenderable(node)) {
331
+ if (name !== "style") {
332
+ return;
333
+ }
334
+ node.attributes |= createTextAttributes(value);
335
+ node.fg = value.fg ? parseColor(value.fg) : node.fg;
336
+ node.bg = value.bg ? parseColor(value.bg) : node.bg;
337
+ return;
338
+ }
422
339
  switch (name) {
423
340
  case "focused":
341
+ if (!(node instanceof Renderable))
342
+ return;
424
343
  if (value) {
425
344
  node.focus();
426
345
  } else {
@@ -503,37 +422,10 @@ var {
503
422
  },
504
423
  insertNode: _insertNode,
505
424
  removeNode: _removeNode,
506
- getParentNode(childNode) {
507
- log("Getting parent of node:", logId(childNode));
508
- let node = childNode;
509
- if (isTextChunk(childNode)) {
510
- const parentTextNode = TextNode.getTextNodeFromChunk(childNode);
511
- if (!parentTextNode)
512
- return;
513
- node = parentTextNode;
514
- }
515
- const parent = node.parent;
516
- if (!parent) {
517
- log("No parent found for node:", logId(node));
518
- return;
519
- }
520
- log("Parent found:", logId(parent), "for node:", logId(node));
521
- return parent;
522
- },
425
+ getParentNode: _getParentNode,
523
426
  getFirstChild(node) {
524
427
  log("Getting first child of node:", logId(node));
525
- if (node instanceof TextRenderable3) {
526
- const chunk = node.content.chunks[0];
527
- if (chunk) {
528
- return TextNode.getTextNodeFromChunk(chunk);
529
- } else {
530
- return;
531
- }
532
- }
533
- if (node instanceof TextNode || isTextChunk(node)) {
534
- return;
535
- }
536
- const firstChild = node.getChildren()[0];
428
+ const firstChild = getNodeChildren(node)[0];
537
429
  if (!firstChild) {
538
430
  log("No first child found for node:", logId(node));
539
431
  return;
@@ -543,34 +435,12 @@ var {
543
435
  },
544
436
  getNextSibling(node) {
545
437
  log("Getting next sibling of node:", logId(node));
546
- if (isTextChunk(node)) {
547
- console.warn("Cannot get next sibling of text chunk");
548
- return;
549
- }
550
- const parent = node.parent;
438
+ const parent = _getParentNode(node);
551
439
  if (!parent) {
552
440
  log("No parent found for node:", logId(node));
553
441
  return;
554
442
  }
555
- if (node instanceof TextNode) {
556
- if (parent instanceof TextRenderable3) {
557
- const siblings2 = parent.content.chunks;
558
- const index2 = siblings2.indexOf(node.chunk);
559
- if (index2 === -1 || index2 === siblings2.length - 1) {
560
- log("No next sibling found for node:", logId(node));
561
- return;
562
- }
563
- const nextSibling2 = siblings2[index2 + 1];
564
- if (!nextSibling2) {
565
- log("Next sibling is null for node:", logId(node));
566
- return;
567
- }
568
- return TextNode.getTextNodeFromChunk(nextSibling2);
569
- }
570
- console.warn("Text parent is not a text node:", logId(node));
571
- return;
572
- }
573
- const siblings = parent.getChildren();
443
+ const siblings = getNodeChildren(node);
574
444
  const index = siblings.indexOf(node);
575
445
  if (index === -1 || index === siblings.length - 1) {
576
446
  log("No next sibling found for node:", logId(node));
@@ -606,6 +476,7 @@ export {
606
476
  useKeyboard,
607
477
  useKeyHandler,
608
478
  use,
479
+ textNodeKeys,
609
480
  spread,
610
481
  setProp,
611
482
  render,
@@ -624,5 +495,9 @@ export {
624
495
  componentCatalogue,
625
496
  baseComponents,
626
497
  _render,
627
- RendererContext
498
+ UnderlineSpanRenderable,
499
+ RendererContext,
500
+ LineBreakRenderable,
501
+ ItalicSpanRenderable,
502
+ BoldSpanRenderable
628
503
  };
package/jsx-runtime.d.ts CHANGED
@@ -5,24 +5,36 @@ import type {
5
5
  ExtendedIntrinsicElements,
6
6
  InputProps,
7
7
  OpenTUIComponents,
8
+ ScrollBoxProps,
8
9
  SelectProps,
10
+ SpanProps,
9
11
  TabSelectProps,
10
12
  TextProps,
11
13
  } from "./src/types/elements"
14
+ import type { DomNode } from "./dist"
12
15
 
13
16
  declare namespace JSX {
14
17
  // Replace Node with Renderable
15
- type Element = Renderable | ArrayElement | (string & {}) | number | boolean | null | undefined
18
+ type Element = DomNode | ArrayElement | string | number | boolean | null | undefined
16
19
 
17
- interface ArrayElement extends Array<Element> {}
20
+ type ArrayElement = Array<Element>
18
21
 
19
22
  interface IntrinsicElements extends ExtendedIntrinsicElements<OpenTUIComponents> {
20
23
  box: BoxProps
21
24
  text: TextProps
25
+ span: SpanProps
22
26
  input: InputProps
23
27
  select: SelectProps
24
28
  ascii_font: AsciiFontProps
25
29
  tab_select: TabSelectProps
30
+ scrollbox: ScrollBoxProps
31
+
32
+ b: SpanProps
33
+ strong: SpanProps
34
+ i: SpanProps
35
+ em: SpanProps
36
+ u: SpanProps
37
+ br: {}
26
38
  }
27
39
 
28
40
  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.0.0-20250908-4906ddad",
7
+ "version": "0.0.0-20250915-f5db043a",
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.0.0-20250908-4906ddad",
28
+ "@opentui/core": "0.0.0-20250915-f5db043a",
29
29
  "babel-plugin-module-resolver": "5.0.2",
30
30
  "@babel/core": "7.28.0",
31
31
  "@babel/preset-typescript": "7.27.1",
@@ -14,6 +14,12 @@ const solidTransformPlugin: BunPlugin = {
14
14
  const code = await file.text()
15
15
  return { contents: code, loader: "js" }
16
16
  })
17
+ build.onLoad({ filter: /\/node_modules\/solid-js\/store\/dist\/server\.js$/ }, async (args) => {
18
+ const path = args.path.replace("server.js", "store.js")
19
+ const file = Bun.file(path)
20
+ const code = await file.text()
21
+ return { contents: code, loader: "js" }
22
+ })
17
23
  build.onLoad({ filter: /\.(js|ts)x$/ }, async (args) => {
18
24
  const file = Bun.file(args.path)
19
25
  const code = await file.text()
@@ -1,6 +1,28 @@
1
- import { ASCIIFontRenderable, BoxRenderable, InputRenderable, ScrollBoxRenderable, SelectRenderable, TabSelectRenderable, TextRenderable } from "@opentui/core";
1
+ import { ASCIIFontRenderable, BoxRenderable, InputRenderable, ScrollBoxRenderable, SelectRenderable, TabSelectRenderable, TextNodeRenderable, TextRenderable, type RenderContext, type TextNodeOptions } from "@opentui/core";
2
2
  import type { RenderableConstructor } from "../types/elements";
3
3
  export * from "./hooks";
4
+ declare class SpanRenderable extends TextNodeRenderable {
5
+ private readonly _ctx;
6
+ constructor(_ctx: RenderContext | null, options: TextNodeOptions);
7
+ }
8
+ export declare const textNodeKeys: readonly ["span", "b", "strong", "i", "em", "u"];
9
+ export type TextNodeKey = (typeof textNodeKeys)[number];
10
+ declare class TextModifierRenderable extends SpanRenderable {
11
+ constructor(options: any, modifier?: TextNodeKey);
12
+ }
13
+ export declare class BoldSpanRenderable extends TextModifierRenderable {
14
+ constructor(options: any);
15
+ }
16
+ export declare class ItalicSpanRenderable extends TextModifierRenderable {
17
+ constructor(options: any);
18
+ }
19
+ export declare class UnderlineSpanRenderable extends TextModifierRenderable {
20
+ constructor(options: any);
21
+ }
22
+ export declare class LineBreakRenderable extends SpanRenderable {
23
+ constructor(_ctx: RenderContext | null, options: TextNodeOptions);
24
+ add(): number;
25
+ }
4
26
  export declare const baseComponents: {
5
27
  box: typeof BoxRenderable;
6
28
  text: typeof TextRenderable;
@@ -9,6 +31,13 @@ export declare const baseComponents: {
9
31
  ascii_font: typeof ASCIIFontRenderable;
10
32
  tab_select: typeof TabSelectRenderable;
11
33
  scrollbox: typeof ScrollBoxRenderable;
34
+ span: typeof SpanRenderable;
35
+ strong: typeof BoldSpanRenderable;
36
+ b: typeof BoldSpanRenderable;
37
+ em: typeof ItalicSpanRenderable;
38
+ i: typeof ItalicSpanRenderable;
39
+ u: typeof UnderlineSpanRenderable;
40
+ br: typeof LineBreakRenderable;
12
41
  };
13
42
  type ComponentCatalogue = Record<string, RenderableConstructor>;
14
43
  export declare const componentCatalogue: ComponentCatalogue;
@@ -1,4 +1,3 @@
1
- import { Renderable, type TextChunk } from "@opentui/core";
2
- import { TextNode } from "./elements/text-node";
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;
1
+ import { BaseRenderable } from "@opentui/core";
2
+ export type DomNode = BaseRenderable;
3
+ export declare const _render: (code: () => BaseRenderable, node: BaseRenderable) => () => void, effect: <T>(fn: (prev?: T) => T, init?: T) => void, memo: <T>(fn: () => T, equal: boolean) => () => T, createComponent: <T>(Comp: (props: T) => BaseRenderable, props: T) => BaseRenderable, createElement: (tag: string) => BaseRenderable, createTextNode: (value: string) => BaseRenderable, insertNode: (parent: BaseRenderable, node: BaseRenderable, anchor?: BaseRenderable | undefined) => void, insert: <T>(parent: any, accessor: T | (() => T), marker?: any | null, initial?: any) => BaseRenderable, spread: <T>(node: any, accessor: (() => T) | T, skipChildren?: boolean) => void, setProp: <T>(node: BaseRenderable, name: string, value: T, prev?: T | undefined) => T, mergeProps: (...sources: unknown[]) => unknown, use: <A, T>(fn: (element: BaseRenderable, arg: A) => T, element: BaseRenderable, arg: A) => T;
@@ -1,5 +1,6 @@
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";
1
+ import type { ASCIIFontOptions, ASCIIFontRenderable, BaseRenderable, BoxOptions, BoxRenderable, InputRenderable, InputRenderableOptions, RenderableOptions, RenderContext, ScrollBoxOptions, ScrollBoxRenderable, SelectOption, SelectRenderable, SelectRenderableOptions, TabSelectOption, TabSelectRenderable, TabSelectRenderableOptions, TextNodeRenderable, TextOptions, TextRenderable } from "@opentui/core";
2
+ import type { Ref } from "solid-js";
3
+ import type { JSX } from "../../jsx-runtime";
3
4
  /** Properties that should not be included in the style prop */
4
5
  export type NonStyledProps = "id" | "buffered" | "live" | "enableLayout" | "selectable" | "renderAfter" | "renderBefore" | `on${string}`;
5
6
  /** Solid-specific props for all components */
@@ -7,7 +8,7 @@ export type ElementProps<TRenderable = unknown> = {
7
8
  ref?: Ref<TRenderable>;
8
9
  };
9
10
  /** Base type for any renderable constructor */
10
- export type RenderableConstructor<TRenderable extends Renderable = Renderable> = new (ctx: RenderContext, options: any) => TRenderable;
11
+ export type RenderableConstructor<TRenderable extends BaseRenderable = BaseRenderable> = new (ctx: RenderContext, options: any) => TRenderable;
11
12
  /** Extract the options type from a renderable constructor */
12
13
  type ExtractRenderableOptions<TConstructor> = TConstructor extends new (ctx: RenderContext, options: infer TOptions) => any ? TOptions : never;
13
14
  /** Extract the renderable type from a constructor */
@@ -19,13 +20,16 @@ type ContainerProps<TOptions> = TOptions & {
19
20
  children?: JSX.Element;
20
21
  };
21
22
  /** Smart component props that automatically determine excluded properties */
22
- type ComponentProps<TOptions extends RenderableOptions<TRenderable>, TRenderable extends Renderable> = TOptions & {
23
+ type ComponentProps<TOptions extends RenderableOptions<TRenderable>, TRenderable extends BaseRenderable> = TOptions & {
23
24
  style?: Partial<Omit<TOptions, GetNonStyledProperties<RenderableConstructor<TRenderable>>>>;
24
25
  } & ElementProps<TRenderable>;
25
26
  /** Valid text content types for Text component children */
26
- type TextChildren = (string & {}) | number | boolean | null | undefined;
27
+ type TextChildren = string | number | boolean | null | undefined | JSX.Element;
27
28
  export type TextProps = ComponentProps<TextOptions, TextRenderable> & {
28
- children?: TextChildren | StyledText | TextChunk | Array<TextChildren | StyledText | TextChunk>;
29
+ children?: TextChildren | Array<TextChildren>;
30
+ };
31
+ export type SpanProps = ComponentProps<{}, TextNodeRenderable> & {
32
+ children?: TextChildren | Array<TextChildren>;
29
33
  };
30
34
  export type BoxProps = ComponentProps<ContainerProps<BoxOptions>, BoxRenderable>;
31
35
  export type InputProps = ComponentProps<InputRenderableOptions, InputRenderable> & {
@@ -47,6 +51,8 @@ export type TabSelectProps = ComponentProps<TabSelectRenderableOptions, TabSelec
47
51
  };
48
52
  export type ScrollBoxProps = ComponentProps<ContainerProps<ScrollBoxOptions>, ScrollBoxRenderable> & {
49
53
  focused?: boolean;
54
+ stickyScroll?: boolean;
55
+ stickyStart?: "bottom" | "top" | "left" | "right";
50
56
  };
51
57
  /** Convert renderable constructor to component props with proper style exclusions */
52
58
  export type ExtendedComponentProps<TConstructor extends RenderableConstructor, TOptions = ExtractRenderableOptions<TConstructor>> = TOptions & {
@@ -1,48 +0,0 @@
1
- import { Renderable, TextRenderable, type RenderContext, type TextChunk, type TextOptions } from "@opentui/core";
2
- import { type DomNode } from "../reconciler";
3
- export declare const isTextChunk: (node: any) => node is TextChunk;
4
- /**
5
- * Represents a text node in the SolidJS reconciler.
6
- */
7
- export declare class TextNode {
8
- id: string;
9
- chunk: TextChunk;
10
- parent?: Renderable;
11
- textParent?: TextRenderable | GhostTextRenderable;
12
- constructor(chunk: TextChunk);
13
- /**
14
- * Replaces the current text chunk with a new one.
15
- * @param newChunk The new text chunk to replace with.
16
- */
17
- replaceText(newChunk: TextChunk): void;
18
- /**
19
- * Retrieves the TextNode associated with a given TextChunk.
20
- * @param chunk The text chunk to look up.
21
- * @returns The associated TextNode or undefined if not found.
22
- */
23
- static getTextNodeFromChunk(chunk: TextChunk): TextNode | undefined;
24
- /**
25
- * Inserts this text node into the DOM structure.
26
- * @param parent The parent DOM node.
27
- * @param anchor The anchor node for positioning.
28
- */
29
- insert(parent: DomNode, anchor?: DomNode): void;
30
- /**
31
- * Removes this text node from the DOM structure.
32
- * @param parent The parent DOM node.
33
- */
34
- remove(parent: DomNode): void;
35
- /**
36
- * Gets or creates a ghost text node for rendering text content.
37
- * @param parent The parent renderable.
38
- * @param anchor The anchor node for positioning.
39
- * @returns The text renderable ghost node.
40
- * @private
41
- */
42
- private getOrCreateTextGhostNode;
43
- }
44
- declare class GhostTextRenderable extends TextRenderable {
45
- constructor(ctx: RenderContext, options: TextOptions);
46
- static isGhostNode(node: DomNode): node is GhostTextRenderable;
47
- }
48
- export {};