@opentui/solid 0.1.12 → 0.1.14
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 +3 -1
- package/index.js +121 -41
- package/jsx-runtime.d.ts +17 -17
- package/package.json +2 -7
- package/scripts/solid-plugin.ts +1 -1
- package/src/elements/index.d.ts +22 -49
- package/src/elements/text-node.d.ts +1 -0
- package/src/reconciler.d.ts +3 -4
- package/src/types/elements.d.ts +64 -0
- package/src/reconciler.js +0 -481
package/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type CliRendererConfig } from "@opentui/core";
|
|
2
2
|
import type { JSX } from "./jsx-runtime";
|
|
3
|
-
export * from "./src/elements";
|
|
4
3
|
export declare const render: (node: () => JSX.Element, renderConfig?: CliRendererConfig) => Promise<void>;
|
|
4
|
+
export * from "./src/reconciler";
|
|
5
|
+
export * from "./src/elements";
|
|
6
|
+
export * from "./src/types/elements";
|
|
5
7
|
export { type JSX };
|
package/index.js
CHANGED
|
@@ -6,7 +6,6 @@ import { createCliRenderer } from "@opentui/core";
|
|
|
6
6
|
import {
|
|
7
7
|
ASCIIFontRenderable,
|
|
8
8
|
BoxRenderable,
|
|
9
|
-
GroupRenderable,
|
|
10
9
|
InputRenderable,
|
|
11
10
|
SelectRenderable,
|
|
12
11
|
TabSelectRenderable,
|
|
@@ -38,7 +37,7 @@ var onResize = (callback) => {
|
|
|
38
37
|
};
|
|
39
38
|
var useTerminalDimensions = () => {
|
|
40
39
|
const renderer = useRenderer();
|
|
41
|
-
const [terminalDimensions, setTerminalDimensions] = createSignal({ width: renderer.
|
|
40
|
+
const [terminalDimensions, setTerminalDimensions] = createSignal({ width: renderer.width, height: renderer.height });
|
|
42
41
|
const callback = (width, height) => {
|
|
43
42
|
setTerminalDimensions({ width, height });
|
|
44
43
|
};
|
|
@@ -94,15 +93,21 @@ var useTimeline = (timeline, initialValue, targetValue, options, startTime = 0)
|
|
|
94
93
|
};
|
|
95
94
|
|
|
96
95
|
// src/elements/index.ts
|
|
97
|
-
var
|
|
98
|
-
ascii_font: ASCIIFontRenderable,
|
|
96
|
+
var baseComponents = {
|
|
99
97
|
box: BoxRenderable,
|
|
100
|
-
|
|
98
|
+
text: TextRenderable,
|
|
101
99
|
input: InputRenderable,
|
|
102
100
|
select: SelectRenderable,
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
ascii_font: ASCIIFontRenderable,
|
|
102
|
+
tab_select: TabSelectRenderable
|
|
105
103
|
};
|
|
104
|
+
var componentCatalogue = { ...baseComponents };
|
|
105
|
+
function extend(objects) {
|
|
106
|
+
Object.assign(componentCatalogue, objects);
|
|
107
|
+
}
|
|
108
|
+
function getComponentCatalogue() {
|
|
109
|
+
return componentCatalogue;
|
|
110
|
+
}
|
|
106
111
|
|
|
107
112
|
// src/reconciler.ts
|
|
108
113
|
import {
|
|
@@ -116,6 +121,7 @@ import {
|
|
|
116
121
|
TabSelectRenderableEvents,
|
|
117
122
|
TextRenderable as TextRenderable3
|
|
118
123
|
} from "@opentui/core";
|
|
124
|
+
import { useContext as useContext2 } from "solid-js";
|
|
119
125
|
import { createRenderer } from "solid-js/universal";
|
|
120
126
|
|
|
121
127
|
// src/elements/text-node.ts
|
|
@@ -142,6 +148,9 @@ var log = (...args) => {
|
|
|
142
148
|
// src/elements/text-node.ts
|
|
143
149
|
var GHOST_NODE_TAG = "text-ghost";
|
|
144
150
|
var ChunkToTextNodeMap = new WeakMap;
|
|
151
|
+
var isTextChunk = (node) => {
|
|
152
|
+
return typeof node === "object" && "__isChunk" in node;
|
|
153
|
+
};
|
|
145
154
|
|
|
146
155
|
class TextNode {
|
|
147
156
|
id;
|
|
@@ -195,6 +204,7 @@ class TextNode {
|
|
|
195
204
|
}
|
|
196
205
|
}
|
|
197
206
|
textParent.content = styledText;
|
|
207
|
+
textParent.visible = styledText.toString() !== "";
|
|
198
208
|
this.parent = parent;
|
|
199
209
|
}
|
|
200
210
|
remove(parent) {
|
|
@@ -253,9 +263,27 @@ class GhostTextRenderable extends TextRenderable2 {
|
|
|
253
263
|
}
|
|
254
264
|
|
|
255
265
|
// src/reconciler.ts
|
|
256
|
-
|
|
266
|
+
var logId = (node) => {
|
|
267
|
+
if (!node)
|
|
268
|
+
return;
|
|
269
|
+
if (isTextChunk(node)) {
|
|
270
|
+
return node.plainText;
|
|
271
|
+
}
|
|
272
|
+
return node.id;
|
|
273
|
+
};
|
|
257
274
|
function _insertNode(parent, node, anchor) {
|
|
258
|
-
log("Inserting node:", node
|
|
275
|
+
log("Inserting node:", logId(node), "into parent:", logId(parent), "with anchor:", logId(anchor), node instanceof TextNode);
|
|
276
|
+
if (node instanceof StyledText) {
|
|
277
|
+
log("Inserting styled text:", node.toString());
|
|
278
|
+
for (const chunk of node.chunks) {
|
|
279
|
+
_insertNode(parent, _createTextNode(chunk), anchor);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (isTextChunk(node)) {
|
|
284
|
+
_insertNode(parent, _createTextNode(node), anchor);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
259
287
|
if (node instanceof TextNode) {
|
|
260
288
|
return node.insert(parent, anchor);
|
|
261
289
|
}
|
|
@@ -263,6 +291,10 @@ function _insertNode(parent, node, anchor) {
|
|
|
263
291
|
return;
|
|
264
292
|
}
|
|
265
293
|
if (anchor) {
|
|
294
|
+
if (isTextChunk(anchor)) {
|
|
295
|
+
console.warn("Cannot add non text node with text chunk anchor");
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
266
298
|
const anchorIndex = parent.getChildren().findIndex((el) => {
|
|
267
299
|
if (anchor instanceof TextNode) {
|
|
268
300
|
return el.id === anchor.textParent?.id;
|
|
@@ -275,7 +307,20 @@ function _insertNode(parent, node, anchor) {
|
|
|
275
307
|
}
|
|
276
308
|
}
|
|
277
309
|
function _removeNode(parent, node) {
|
|
278
|
-
log("Removing node:", node
|
|
310
|
+
log("Removing node:", logId(node), "from parent:", logId(parent));
|
|
311
|
+
if (isTextChunk(node)) {
|
|
312
|
+
const textNode = TextNode.getTextNodeFromChunk(node);
|
|
313
|
+
if (textNode) {
|
|
314
|
+
_removeNode(parent, textNode);
|
|
315
|
+
}
|
|
316
|
+
} else if (node instanceof StyledText) {
|
|
317
|
+
for (const chunk of node.chunks) {
|
|
318
|
+
const textNode = TextNode.getTextNodeFromChunk(chunk);
|
|
319
|
+
if (!textNode)
|
|
320
|
+
continue;
|
|
321
|
+
_removeNode(parent, textNode);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
279
324
|
if (node instanceof TextNode) {
|
|
280
325
|
return node.remove(parent);
|
|
281
326
|
}
|
|
@@ -284,6 +329,16 @@ function _removeNode(parent, node) {
|
|
|
284
329
|
node.destroyRecursively();
|
|
285
330
|
}
|
|
286
331
|
}
|
|
332
|
+
function _createTextNode(value) {
|
|
333
|
+
log("Creating text node:", value);
|
|
334
|
+
const chunk = value && isTextChunk(value) ? value : {
|
|
335
|
+
__isChunk: true,
|
|
336
|
+
text: new TextEncoder().encode(`${value}`),
|
|
337
|
+
plainText: `${value}`
|
|
338
|
+
};
|
|
339
|
+
const textNode = new TextNode(chunk);
|
|
340
|
+
return textNode;
|
|
341
|
+
}
|
|
287
342
|
var {
|
|
288
343
|
render: _render,
|
|
289
344
|
effect,
|
|
@@ -292,7 +347,7 @@ var {
|
|
|
292
347
|
createElement,
|
|
293
348
|
createTextNode,
|
|
294
349
|
insertNode,
|
|
295
|
-
insert
|
|
350
|
+
insert,
|
|
296
351
|
spread,
|
|
297
352
|
setProp,
|
|
298
353
|
mergeProps,
|
|
@@ -305,24 +360,23 @@ var {
|
|
|
305
360
|
if (!solidRenderer) {
|
|
306
361
|
throw new Error("No renderer found");
|
|
307
362
|
}
|
|
363
|
+
const elements = getComponentCatalogue();
|
|
364
|
+
if (!elements[tagName]) {
|
|
365
|
+
throw new Error(`[Reconciler] Unknown component type: ${tagName}`);
|
|
366
|
+
}
|
|
308
367
|
const element = new elements[tagName](solidRenderer, { id });
|
|
309
368
|
log("Element created with id:", id);
|
|
310
369
|
return element;
|
|
311
370
|
},
|
|
312
|
-
createTextNode
|
|
313
|
-
log("Creating text node:", value);
|
|
314
|
-
const chunk = typeof value === "object" && "__isChunk" in value ? value : {
|
|
315
|
-
__isChunk: true,
|
|
316
|
-
text: new TextEncoder().encode(`${value}`),
|
|
317
|
-
plainText: `${value}`
|
|
318
|
-
};
|
|
319
|
-
const textNode = new TextNode(chunk);
|
|
320
|
-
return textNode;
|
|
321
|
-
},
|
|
371
|
+
createTextNode: _createTextNode,
|
|
322
372
|
replaceText(textNode, value) {
|
|
323
|
-
log("Replacing text:", value, "in node:", textNode
|
|
373
|
+
log("Replacing text:", value, "in node:", logId(textNode));
|
|
324
374
|
if (textNode instanceof Renderable2)
|
|
325
375
|
return;
|
|
376
|
+
if (isTextChunk(textNode)) {
|
|
377
|
+
console.warn("Cannot replace text on text chunk", logId(textNode));
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
326
380
|
const newChunk = {
|
|
327
381
|
__isChunk: true,
|
|
328
382
|
text: new TextEncoder().encode(value),
|
|
@@ -331,8 +385,8 @@ var {
|
|
|
331
385
|
textNode.replaceText(newChunk);
|
|
332
386
|
},
|
|
333
387
|
setProperty(node, name, value, prev) {
|
|
334
|
-
if (node instanceof TextNode) {
|
|
335
|
-
console.warn("Cannot set property on text node:", node
|
|
388
|
+
if (node instanceof TextNode || isTextChunk(node)) {
|
|
389
|
+
console.warn("Cannot set property on text node:", logId(node));
|
|
336
390
|
return;
|
|
337
391
|
}
|
|
338
392
|
if (name.startsWith("on:")) {
|
|
@@ -429,18 +483,25 @@ var {
|
|
|
429
483
|
},
|
|
430
484
|
insertNode: _insertNode,
|
|
431
485
|
removeNode: _removeNode,
|
|
432
|
-
getParentNode(
|
|
433
|
-
log("Getting parent of node:",
|
|
486
|
+
getParentNode(childNode) {
|
|
487
|
+
log("Getting parent of node:", logId(childNode));
|
|
488
|
+
let node = childNode;
|
|
489
|
+
if (isTextChunk(childNode)) {
|
|
490
|
+
const parentTextNode = TextNode.getTextNodeFromChunk(childNode);
|
|
491
|
+
if (!parentTextNode)
|
|
492
|
+
return;
|
|
493
|
+
node = parentTextNode;
|
|
494
|
+
}
|
|
434
495
|
const parent = node.parent;
|
|
435
496
|
if (!parent) {
|
|
436
|
-
log("No parent found for node:", node
|
|
497
|
+
log("No parent found for node:", logId(node));
|
|
437
498
|
return;
|
|
438
499
|
}
|
|
439
|
-
log("Parent found:", parent
|
|
500
|
+
log("Parent found:", logId(parent), "for node:", logId(node));
|
|
440
501
|
return parent;
|
|
441
502
|
},
|
|
442
503
|
getFirstChild(node) {
|
|
443
|
-
log("Getting first child of node:", node
|
|
504
|
+
log("Getting first child of node:", logId(node));
|
|
444
505
|
if (node instanceof TextRenderable3) {
|
|
445
506
|
const chunk = node.content.chunks[0];
|
|
446
507
|
if (chunk) {
|
|
@@ -449,22 +510,26 @@ var {
|
|
|
449
510
|
return;
|
|
450
511
|
}
|
|
451
512
|
}
|
|
452
|
-
if (node instanceof TextNode) {
|
|
513
|
+
if (node instanceof TextNode || isTextChunk(node)) {
|
|
453
514
|
return;
|
|
454
515
|
}
|
|
455
516
|
const firstChild = node.getChildren()[0];
|
|
456
517
|
if (!firstChild) {
|
|
457
|
-
log("No first child found for node:", node
|
|
518
|
+
log("No first child found for node:", logId(node));
|
|
458
519
|
return;
|
|
459
520
|
}
|
|
460
|
-
log("First child found:", firstChild
|
|
521
|
+
log("First child found:", logId(firstChild), "for node:", logId(node));
|
|
461
522
|
return firstChild;
|
|
462
523
|
},
|
|
463
524
|
getNextSibling(node) {
|
|
464
|
-
log("Getting next sibling of node:", node
|
|
525
|
+
log("Getting next sibling of node:", logId(node));
|
|
526
|
+
if (isTextChunk(node)) {
|
|
527
|
+
console.warn("Cannot get next sibling of text chunk");
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
465
530
|
const parent = node.parent;
|
|
466
531
|
if (!parent) {
|
|
467
|
-
log("No parent found for node:", node
|
|
532
|
+
log("No parent found for node:", logId(node));
|
|
468
533
|
return;
|
|
469
534
|
}
|
|
470
535
|
if (node instanceof TextNode) {
|
|
@@ -472,31 +537,31 @@ var {
|
|
|
472
537
|
const siblings2 = parent.content.chunks;
|
|
473
538
|
const index2 = siblings2.indexOf(node.chunk);
|
|
474
539
|
if (index2 === -1 || index2 === siblings2.length - 1) {
|
|
475
|
-
log("No next sibling found for node:", node
|
|
540
|
+
log("No next sibling found for node:", logId(node));
|
|
476
541
|
return;
|
|
477
542
|
}
|
|
478
543
|
const nextSibling2 = siblings2[index2 + 1];
|
|
479
544
|
if (!nextSibling2) {
|
|
480
|
-
log("Next sibling is null for node:", node
|
|
545
|
+
log("Next sibling is null for node:", logId(node));
|
|
481
546
|
return;
|
|
482
547
|
}
|
|
483
548
|
return TextNode.getTextNodeFromChunk(nextSibling2);
|
|
484
549
|
}
|
|
485
|
-
console.warn("Text parent is not a text node:", node
|
|
550
|
+
console.warn("Text parent is not a text node:", logId(node));
|
|
486
551
|
return;
|
|
487
552
|
}
|
|
488
553
|
const siblings = parent.getChildren();
|
|
489
554
|
const index = siblings.indexOf(node);
|
|
490
555
|
if (index === -1 || index === siblings.length - 1) {
|
|
491
|
-
log("No next sibling found for node:", node
|
|
556
|
+
log("No next sibling found for node:", logId(node));
|
|
492
557
|
return;
|
|
493
558
|
}
|
|
494
559
|
const nextSibling = siblings[index + 1];
|
|
495
560
|
if (!nextSibling) {
|
|
496
|
-
log("Next sibling is null for node:", node
|
|
561
|
+
log("Next sibling is null for node:", logId(node));
|
|
497
562
|
return;
|
|
498
563
|
}
|
|
499
|
-
log("Next sibling found:", nextSibling
|
|
564
|
+
log("Next sibling found:", logId(nextSibling), "for node:", logId(node));
|
|
500
565
|
return nextSibling;
|
|
501
566
|
}
|
|
502
567
|
});
|
|
@@ -519,9 +584,24 @@ export {
|
|
|
519
584
|
useSelectionHandler,
|
|
520
585
|
useRenderer,
|
|
521
586
|
useKeyHandler,
|
|
587
|
+
use,
|
|
588
|
+
spread,
|
|
589
|
+
setProp,
|
|
522
590
|
render,
|
|
523
591
|
onResize,
|
|
524
|
-
|
|
592
|
+
mergeProps,
|
|
593
|
+
memo,
|
|
594
|
+
insertNode,
|
|
595
|
+
insert,
|
|
596
|
+
getComponentCatalogue,
|
|
597
|
+
extend,
|
|
598
|
+
effect,
|
|
599
|
+
createTextNode,
|
|
600
|
+
createElement,
|
|
525
601
|
createComponentTimeline,
|
|
602
|
+
createComponent,
|
|
603
|
+
componentCatalogue,
|
|
604
|
+
baseComponents,
|
|
605
|
+
_render,
|
|
526
606
|
RendererContext
|
|
527
607
|
};
|
package/jsx-runtime.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Renderable } from "@opentui/core"
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
import type {
|
|
3
|
+
AsciiFontProps,
|
|
4
|
+
BoxProps,
|
|
5
|
+
ExtendedIntrinsicElements,
|
|
6
|
+
InputProps,
|
|
7
|
+
OpenTUIComponents,
|
|
8
|
+
SelectProps,
|
|
9
|
+
TabSelectProps,
|
|
10
|
+
TextProps,
|
|
11
|
+
} from "./src/types/elements"
|
|
11
12
|
|
|
12
13
|
declare namespace JSX {
|
|
13
14
|
// Replace Node with Renderable
|
|
@@ -15,14 +16,13 @@ declare namespace JSX {
|
|
|
15
16
|
|
|
16
17
|
interface ArrayElement extends Array<Element> {}
|
|
17
18
|
|
|
18
|
-
interface IntrinsicElements {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
tab_select:
|
|
25
|
-
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
|
|
26
26
|
}
|
|
27
27
|
|
|
28
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.
|
|
7
|
+
"version": "0.1.14",
|
|
8
8
|
"description": "SolidJS renderer for OpenTUI",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"repository": {
|
|
@@ -18,11 +18,6 @@
|
|
|
18
18
|
"import": "./index.js",
|
|
19
19
|
"require": "./index.js"
|
|
20
20
|
},
|
|
21
|
-
"./reconciler": {
|
|
22
|
-
"types": "./src/reconciler.d.ts",
|
|
23
|
-
"import": "./src/reconciler.js",
|
|
24
|
-
"require": "./src/reconciler.js"
|
|
25
|
-
},
|
|
26
21
|
"./preload": {
|
|
27
22
|
"import": "./scripts/preload.ts"
|
|
28
23
|
},
|
|
@@ -30,7 +25,7 @@
|
|
|
30
25
|
"./jsx-dev-runtime": "./jsx-runtime.d.ts"
|
|
31
26
|
},
|
|
32
27
|
"dependencies": {
|
|
33
|
-
"@opentui/core": "0.1.
|
|
28
|
+
"@opentui/core": "0.1.14",
|
|
34
29
|
"babel-plugin-module-resolver": "5.0.2",
|
|
35
30
|
"@babel/core": "7.28.0",
|
|
36
31
|
"@babel/preset-typescript": "7.27.1",
|
package/scripts/solid-plugin.ts
CHANGED
package/src/elements/index.d.ts
CHANGED
|
@@ -1,55 +1,28 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import type { JSX, Ref } from "solid-js";
|
|
1
|
+
import { ASCIIFontRenderable, BoxRenderable, InputRenderable, SelectRenderable, TabSelectRenderable, TextRenderable } from "@opentui/core";
|
|
2
|
+
import type { RenderableConstructor } from "../types/elements";
|
|
4
3
|
export * from "./hooks";
|
|
5
|
-
export declare const
|
|
6
|
-
ascii_font: typeof ASCIIFontRenderable;
|
|
4
|
+
export declare const baseComponents: {
|
|
7
5
|
box: typeof BoxRenderable;
|
|
8
|
-
|
|
6
|
+
text: typeof TextRenderable;
|
|
9
7
|
input: typeof InputRenderable;
|
|
10
8
|
select: typeof SelectRenderable;
|
|
9
|
+
ascii_font: typeof ASCIIFontRenderable;
|
|
11
10
|
tab_select: typeof TabSelectRenderable;
|
|
12
|
-
text: typeof TextRenderable;
|
|
13
|
-
};
|
|
14
|
-
export type Element = keyof typeof elements;
|
|
15
|
-
type RenderableNonStyleKeys = "buffered";
|
|
16
|
-
type ElementProps<T extends RenderableOptions<K>, K extends Renderable = Renderable, NonStyleKeys extends keyof T = RenderableNonStyleKeys> = {
|
|
17
|
-
style?: Omit<T, NonStyleKeys | RenderableNonStyleKeys>;
|
|
18
|
-
ref?: Ref<K>;
|
|
19
|
-
} & T;
|
|
20
|
-
type ContainerProps = {
|
|
21
|
-
children?: JSX.Element;
|
|
22
|
-
};
|
|
23
|
-
export type BoxElementProps = ElementProps<BoxOptions, BoxRenderable, "title"> & ContainerProps;
|
|
24
|
-
export type BoxStyle = BoxElementProps["style"];
|
|
25
|
-
export type GroupElementProps = ElementProps<RenderableOptions, GroupRenderable> & ContainerProps;
|
|
26
|
-
export type GroupStyle = GroupElementProps["style"];
|
|
27
|
-
export type InputElementProps = ElementProps<InputRenderableOptions, InputRenderable, "value" | "maxLength" | "placeholder"> & {
|
|
28
|
-
onInput?: (value: string) => void;
|
|
29
|
-
onSubmit?: (value: string) => void;
|
|
30
|
-
onChange?: (value: string) => void;
|
|
31
|
-
focused?: boolean;
|
|
32
|
-
};
|
|
33
|
-
export type InputStyle = InputElementProps["style"];
|
|
34
|
-
type TabSelectEventCallback = (index: number, option: TabSelectOption) => void;
|
|
35
|
-
export type TabSelectElementProps = ElementProps<TabSelectRenderableOptions, TabSelectRenderable, "options" | "showScrollArrows" | "showDescription" | "wrapSelection"> & {
|
|
36
|
-
onSelect?: TabSelectEventCallback;
|
|
37
|
-
onChange?: TabSelectEventCallback;
|
|
38
|
-
focused?: boolean;
|
|
39
|
-
};
|
|
40
|
-
export type TabSelectStyle = TabSelectElementProps["style"];
|
|
41
|
-
type SelectEventCallback = (index: number, option: SelectOption) => void;
|
|
42
|
-
export type SelectElementProps = ElementProps<SelectRenderableOptions, SelectRenderable, "options" | "showScrollIndicator" | "wrapSelection" | "fastScrollStep"> & {
|
|
43
|
-
onSelect?: SelectEventCallback;
|
|
44
|
-
onChange?: SelectEventCallback;
|
|
45
|
-
focused?: boolean;
|
|
46
|
-
};
|
|
47
|
-
export type SelectStyle = SelectElementProps["style"];
|
|
48
|
-
type TextChildTypes = (string & {}) | number | boolean | null | undefined;
|
|
49
|
-
type TextProps = {
|
|
50
|
-
children: TextChildTypes | StyledText | TextChunk | Array<TextChildTypes | TextChunk>;
|
|
51
11
|
};
|
|
52
|
-
|
|
53
|
-
export
|
|
54
|
-
|
|
55
|
-
|
|
12
|
+
type ComponentCatalogue = Record<string, RenderableConstructor>;
|
|
13
|
+
export declare const componentCatalogue: ComponentCatalogue;
|
|
14
|
+
/**
|
|
15
|
+
* Extend the component catalogue with new renderable components
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* // Extend with an object of components
|
|
20
|
+
* extend({
|
|
21
|
+
* consoleButton: ConsoleButtonRenderable,
|
|
22
|
+
* customBox: CustomBoxRenderable
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function extend<T extends ComponentCatalogue>(objects: T): void;
|
|
27
|
+
export declare function getComponentCatalogue(): ComponentCatalogue;
|
|
28
|
+
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
|
*/
|
package/src/reconciler.d.ts
CHANGED
|
@@ -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,
|
|
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,64 @@
|
|
|
1
|
+
import type { ASCIIFontOptions, ASCIIFontRenderable, BoxOptions, BoxRenderable, InputRenderable, InputRenderableOptions, Renderable, RenderableOptions, RenderContext, 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
|
+
/** Convert renderable constructor to component props with proper style exclusions */
|
|
49
|
+
export type ExtendedComponentProps<TConstructor extends RenderableConstructor, TOptions = ExtractRenderableOptions<TConstructor>> = TOptions & {
|
|
50
|
+
children?: JSX.Element;
|
|
51
|
+
style?: Partial<Omit<TOptions, GetNonStyledProperties<TConstructor>>>;
|
|
52
|
+
} & ElementProps<ExtractRenderable<TConstructor>>;
|
|
53
|
+
/** Helper type to create JSX element properties from a component catalogue */
|
|
54
|
+
export type ExtendedIntrinsicElements<TComponentCatalogue extends Record<string, RenderableConstructor>> = {
|
|
55
|
+
[TComponentName in keyof TComponentCatalogue]: ExtendedComponentProps<TComponentCatalogue[TComponentName]>;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Global augmentation interface for extended components
|
|
59
|
+
* This will be augmented by user code using module augmentation
|
|
60
|
+
*/
|
|
61
|
+
export interface OpenTUIComponents {
|
|
62
|
+
[componentName: string]: RenderableConstructor;
|
|
63
|
+
}
|
|
64
|
+
export {};
|
package/src/reconciler.js
DELETED
|
@@ -1,481 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// src/reconciler.ts
|
|
3
|
-
import {
|
|
4
|
-
InputRenderable as InputRenderable2,
|
|
5
|
-
InputRenderableEvents,
|
|
6
|
-
Renderable as Renderable2,
|
|
7
|
-
SelectRenderable as SelectRenderable2,
|
|
8
|
-
SelectRenderableEvents,
|
|
9
|
-
StyledText,
|
|
10
|
-
TabSelectRenderable as TabSelectRenderable2,
|
|
11
|
-
TabSelectRenderableEvents,
|
|
12
|
-
TextRenderable as TextRenderable3
|
|
13
|
-
} from "@opentui/core";
|
|
14
|
-
import { createRenderer } from "solid-js/universal";
|
|
15
|
-
|
|
16
|
-
// src/elements/index.ts
|
|
17
|
-
import {
|
|
18
|
-
ASCIIFontRenderable,
|
|
19
|
-
BoxRenderable,
|
|
20
|
-
GroupRenderable,
|
|
21
|
-
InputRenderable,
|
|
22
|
-
SelectRenderable,
|
|
23
|
-
TabSelectRenderable,
|
|
24
|
-
TextRenderable
|
|
25
|
-
} from "@opentui/core";
|
|
26
|
-
|
|
27
|
-
// src/elements/hooks.ts
|
|
28
|
-
import {
|
|
29
|
-
getKeyHandler,
|
|
30
|
-
Timeline
|
|
31
|
-
} from "@opentui/core";
|
|
32
|
-
import { createContext, createSignal, onCleanup, onMount, useContext } from "solid-js";
|
|
33
|
-
var RendererContext = createContext();
|
|
34
|
-
|
|
35
|
-
// src/elements/index.ts
|
|
36
|
-
var elements = {
|
|
37
|
-
ascii_font: ASCIIFontRenderable,
|
|
38
|
-
box: BoxRenderable,
|
|
39
|
-
group: GroupRenderable,
|
|
40
|
-
input: InputRenderable,
|
|
41
|
-
select: SelectRenderable,
|
|
42
|
-
tab_select: TabSelectRenderable,
|
|
43
|
-
text: TextRenderable
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// src/elements/text-node.ts
|
|
47
|
-
import { Renderable, TextRenderable as TextRenderable2 } from "@opentui/core";
|
|
48
|
-
|
|
49
|
-
// src/utils/id-counter.ts
|
|
50
|
-
var idCounter = new Map;
|
|
51
|
-
function getNextId(elementType) {
|
|
52
|
-
if (!idCounter.has(elementType)) {
|
|
53
|
-
idCounter.set(elementType, 0);
|
|
54
|
-
}
|
|
55
|
-
const value = idCounter.get(elementType) + 1;
|
|
56
|
-
idCounter.set(elementType, value);
|
|
57
|
-
return `${elementType}-${value}`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// src/utils/log.ts
|
|
61
|
-
var log = (...args) => {
|
|
62
|
-
if (process.env.DEBUG) {
|
|
63
|
-
console.log("[Reconciler]", ...args);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// src/elements/text-node.ts
|
|
68
|
-
var GHOST_NODE_TAG = "text-ghost";
|
|
69
|
-
var ChunkToTextNodeMap = new WeakMap;
|
|
70
|
-
|
|
71
|
-
class TextNode {
|
|
72
|
-
id;
|
|
73
|
-
chunk;
|
|
74
|
-
parent;
|
|
75
|
-
textParent;
|
|
76
|
-
constructor(chunk) {
|
|
77
|
-
this.id = getNextId("text-node");
|
|
78
|
-
this.chunk = chunk;
|
|
79
|
-
ChunkToTextNodeMap.set(chunk, this);
|
|
80
|
-
}
|
|
81
|
-
replaceText(newChunk) {
|
|
82
|
-
const textParent = this.textParent;
|
|
83
|
-
if (!textParent) {
|
|
84
|
-
log("No parent found for text node:", this.id);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
textParent.content = textParent.content.replace(newChunk, this.chunk);
|
|
88
|
-
this.chunk = newChunk;
|
|
89
|
-
ChunkToTextNodeMap.set(newChunk, this);
|
|
90
|
-
}
|
|
91
|
-
static getTextNodeFromChunk(chunk) {
|
|
92
|
-
return ChunkToTextNodeMap.get(chunk);
|
|
93
|
-
}
|
|
94
|
-
insert(parent, anchor) {
|
|
95
|
-
if (!(parent instanceof Renderable)) {
|
|
96
|
-
log("Attaching text node to parent text node, impossible");
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
let textParent;
|
|
100
|
-
if (!(parent instanceof TextRenderable2)) {
|
|
101
|
-
textParent = this.getOrCreateTextGhostNode(parent, anchor);
|
|
102
|
-
} else {
|
|
103
|
-
textParent = parent;
|
|
104
|
-
}
|
|
105
|
-
this.textParent = textParent;
|
|
106
|
-
let styledText = textParent.content;
|
|
107
|
-
if (anchor && anchor instanceof TextNode) {
|
|
108
|
-
const anchorIndex = styledText.chunks.indexOf(anchor.chunk);
|
|
109
|
-
if (anchorIndex === -1) {
|
|
110
|
-
log("anchor not found");
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
styledText = styledText.insert(this.chunk, anchorIndex);
|
|
114
|
-
} else {
|
|
115
|
-
const firstChunk = textParent.content.chunks[0];
|
|
116
|
-
if (firstChunk && !ChunkToTextNodeMap.has(firstChunk)) {
|
|
117
|
-
styledText = styledText.replace(this.chunk, firstChunk);
|
|
118
|
-
} else {
|
|
119
|
-
styledText = styledText.insert(this.chunk);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
textParent.content = styledText;
|
|
123
|
-
this.parent = parent;
|
|
124
|
-
}
|
|
125
|
-
remove(parent) {
|
|
126
|
-
if (!(parent instanceof Renderable)) {
|
|
127
|
-
ChunkToTextNodeMap.delete(this.chunk);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
if (parent === this.textParent && parent instanceof TextRenderable2) {
|
|
131
|
-
ChunkToTextNodeMap.delete(this.chunk);
|
|
132
|
-
parent.content = parent.content.remove(this.chunk);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
if (this.textParent) {
|
|
136
|
-
ChunkToTextNodeMap.delete(this.chunk);
|
|
137
|
-
let styledText = this.textParent.content;
|
|
138
|
-
styledText = styledText.remove(this.chunk);
|
|
139
|
-
if (styledText.chunks.length > 0) {
|
|
140
|
-
this.textParent.content = styledText;
|
|
141
|
-
} else {
|
|
142
|
-
this.parent?.remove(this.textParent.id);
|
|
143
|
-
this.textParent.destroyRecursively();
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
getOrCreateTextGhostNode(parent, anchor) {
|
|
148
|
-
if (anchor instanceof TextNode && anchor.textParent) {
|
|
149
|
-
return anchor.textParent;
|
|
150
|
-
}
|
|
151
|
-
const children = parent.getChildren();
|
|
152
|
-
if (anchor instanceof Renderable) {
|
|
153
|
-
const anchorIndex = children.findIndex((el) => el.id === anchor.id);
|
|
154
|
-
const beforeAnchor = children[anchorIndex - 1];
|
|
155
|
-
if (beforeAnchor instanceof GhostTextRenderable) {
|
|
156
|
-
return beforeAnchor;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
const lastChild = children.at(-1);
|
|
160
|
-
if (lastChild instanceof GhostTextRenderable) {
|
|
161
|
-
return lastChild;
|
|
162
|
-
}
|
|
163
|
-
const ghostNode = new GhostTextRenderable(parent.ctx, {
|
|
164
|
-
id: getNextId(GHOST_NODE_TAG)
|
|
165
|
-
});
|
|
166
|
-
insertNode(parent, ghostNode, anchor);
|
|
167
|
-
return ghostNode;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
class GhostTextRenderable extends TextRenderable2 {
|
|
172
|
-
constructor(ctx, options) {
|
|
173
|
-
super(ctx, options);
|
|
174
|
-
}
|
|
175
|
-
static isGhostNode(node) {
|
|
176
|
-
return node instanceof GhostTextRenderable;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// src/reconciler.ts
|
|
181
|
-
import { useContext as useContext2 } from "solid-js";
|
|
182
|
-
function _insertNode(parent, node, anchor) {
|
|
183
|
-
log("Inserting node:", node.id, "into parent:", parent.id, "with anchor:", anchor?.id);
|
|
184
|
-
if (node instanceof TextNode) {
|
|
185
|
-
return node.insert(parent, anchor);
|
|
186
|
-
}
|
|
187
|
-
if (!(parent instanceof Renderable2)) {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
if (anchor) {
|
|
191
|
-
const anchorIndex = parent.getChildren().findIndex((el) => {
|
|
192
|
-
if (anchor instanceof TextNode) {
|
|
193
|
-
return el.id === anchor.textParent?.id;
|
|
194
|
-
}
|
|
195
|
-
return el.id === anchor.id;
|
|
196
|
-
});
|
|
197
|
-
parent.add(node, anchorIndex);
|
|
198
|
-
} else {
|
|
199
|
-
parent.add(node);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
function _removeNode(parent, node) {
|
|
203
|
-
log("Removing node:", node.id, "from parent:", parent.id);
|
|
204
|
-
if (node instanceof TextNode) {
|
|
205
|
-
return node.remove(parent);
|
|
206
|
-
}
|
|
207
|
-
if (parent instanceof Renderable2 && node instanceof Renderable2) {
|
|
208
|
-
parent.remove(node.id);
|
|
209
|
-
node.destroyRecursively();
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
var {
|
|
213
|
-
render: _render,
|
|
214
|
-
effect,
|
|
215
|
-
memo,
|
|
216
|
-
createComponent,
|
|
217
|
-
createElement,
|
|
218
|
-
createTextNode,
|
|
219
|
-
insertNode,
|
|
220
|
-
insert: solidUniversalInsert,
|
|
221
|
-
spread,
|
|
222
|
-
setProp,
|
|
223
|
-
mergeProps,
|
|
224
|
-
use
|
|
225
|
-
} = createRenderer({
|
|
226
|
-
createElement(tagName) {
|
|
227
|
-
log("Creating element:", tagName);
|
|
228
|
-
const id = getNextId(tagName);
|
|
229
|
-
const solidRenderer = useContext2(RendererContext);
|
|
230
|
-
if (!solidRenderer) {
|
|
231
|
-
throw new Error("No renderer found");
|
|
232
|
-
}
|
|
233
|
-
const element = new elements[tagName](solidRenderer, { id });
|
|
234
|
-
log("Element created with id:", id);
|
|
235
|
-
return element;
|
|
236
|
-
},
|
|
237
|
-
createTextNode(value) {
|
|
238
|
-
log("Creating text node:", value);
|
|
239
|
-
const chunk = typeof value === "object" && "__isChunk" in value ? value : {
|
|
240
|
-
__isChunk: true,
|
|
241
|
-
text: new TextEncoder().encode(`${value}`),
|
|
242
|
-
plainText: `${value}`
|
|
243
|
-
};
|
|
244
|
-
const textNode = new TextNode(chunk);
|
|
245
|
-
return textNode;
|
|
246
|
-
},
|
|
247
|
-
replaceText(textNode, value) {
|
|
248
|
-
log("Replacing text:", value, "in node:", textNode.id);
|
|
249
|
-
if (textNode instanceof Renderable2)
|
|
250
|
-
return;
|
|
251
|
-
const newChunk = {
|
|
252
|
-
__isChunk: true,
|
|
253
|
-
text: new TextEncoder().encode(value),
|
|
254
|
-
plainText: value
|
|
255
|
-
};
|
|
256
|
-
textNode.replaceText(newChunk);
|
|
257
|
-
},
|
|
258
|
-
setProperty(node, name, value, prev) {
|
|
259
|
-
if (node instanceof TextNode) {
|
|
260
|
-
console.warn("Cannot set property on text node:", node.id);
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
if (name.startsWith("on:")) {
|
|
264
|
-
const eventName = name.slice(3);
|
|
265
|
-
if (value) {
|
|
266
|
-
node.on(eventName, value);
|
|
267
|
-
}
|
|
268
|
-
if (prev) {
|
|
269
|
-
node.off(eventName, prev);
|
|
270
|
-
}
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
switch (name) {
|
|
274
|
-
case "focused":
|
|
275
|
-
if (value) {
|
|
276
|
-
node.focus();
|
|
277
|
-
} else {
|
|
278
|
-
node.blur();
|
|
279
|
-
}
|
|
280
|
-
break;
|
|
281
|
-
case "onChange":
|
|
282
|
-
let event = undefined;
|
|
283
|
-
if (node instanceof SelectRenderable2) {
|
|
284
|
-
event = SelectRenderableEvents.SELECTION_CHANGED;
|
|
285
|
-
} else if (node instanceof TabSelectRenderable2) {
|
|
286
|
-
event = TabSelectRenderableEvents.SELECTION_CHANGED;
|
|
287
|
-
} else if (node instanceof InputRenderable2) {
|
|
288
|
-
event = InputRenderableEvents.CHANGE;
|
|
289
|
-
}
|
|
290
|
-
if (!event)
|
|
291
|
-
break;
|
|
292
|
-
if (value) {
|
|
293
|
-
node.on(event, value);
|
|
294
|
-
}
|
|
295
|
-
if (prev) {
|
|
296
|
-
node.off(event, prev);
|
|
297
|
-
}
|
|
298
|
-
break;
|
|
299
|
-
case "onInput":
|
|
300
|
-
if (node instanceof InputRenderable2) {
|
|
301
|
-
if (value) {
|
|
302
|
-
node.on(InputRenderableEvents.INPUT, value);
|
|
303
|
-
}
|
|
304
|
-
if (prev) {
|
|
305
|
-
node.off(InputRenderableEvents.INPUT, prev);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
break;
|
|
309
|
-
case "onSubmit":
|
|
310
|
-
if (node instanceof InputRenderable2) {
|
|
311
|
-
if (value) {
|
|
312
|
-
node.on(InputRenderableEvents.ENTER, value);
|
|
313
|
-
}
|
|
314
|
-
if (prev) {
|
|
315
|
-
node.off(InputRenderableEvents.ENTER, prev);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
break;
|
|
319
|
-
case "onSelect":
|
|
320
|
-
if (node instanceof SelectRenderable2) {
|
|
321
|
-
if (value) {
|
|
322
|
-
node.on(SelectRenderableEvents.ITEM_SELECTED, value);
|
|
323
|
-
}
|
|
324
|
-
if (prev) {
|
|
325
|
-
node.off(SelectRenderableEvents.ITEM_SELECTED, prev);
|
|
326
|
-
}
|
|
327
|
-
} else if (node instanceof TabSelectRenderable2) {
|
|
328
|
-
if (value) {
|
|
329
|
-
node.on(TabSelectRenderableEvents.ITEM_SELECTED, value);
|
|
330
|
-
}
|
|
331
|
-
if (prev) {
|
|
332
|
-
node.off(TabSelectRenderableEvents.ITEM_SELECTED, prev);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
break;
|
|
336
|
-
case "style":
|
|
337
|
-
for (const prop in value) {
|
|
338
|
-
const propVal = value[prop];
|
|
339
|
-
if (prev !== undefined && propVal === prev[prop])
|
|
340
|
-
continue;
|
|
341
|
-
node[prop] = propVal;
|
|
342
|
-
}
|
|
343
|
-
break;
|
|
344
|
-
case "text":
|
|
345
|
-
case "content":
|
|
346
|
-
node[name] = typeof value === "string" ? value : Array.isArray(value) ? value.join("") : `${value}`;
|
|
347
|
-
break;
|
|
348
|
-
default:
|
|
349
|
-
node[name] = value;
|
|
350
|
-
}
|
|
351
|
-
},
|
|
352
|
-
isTextNode(node) {
|
|
353
|
-
return node instanceof TextNode;
|
|
354
|
-
},
|
|
355
|
-
insertNode: _insertNode,
|
|
356
|
-
removeNode: _removeNode,
|
|
357
|
-
getParentNode(node) {
|
|
358
|
-
log("Getting parent of node:", node.id);
|
|
359
|
-
const parent = node.parent;
|
|
360
|
-
if (!parent) {
|
|
361
|
-
log("No parent found for node:", node.id);
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
log("Parent found:", parent.id, "for node:", node.id);
|
|
365
|
-
return parent;
|
|
366
|
-
},
|
|
367
|
-
getFirstChild(node) {
|
|
368
|
-
log("Getting first child of node:", node.id);
|
|
369
|
-
if (node instanceof TextRenderable3) {
|
|
370
|
-
const chunk = node.content.chunks[0];
|
|
371
|
-
if (chunk) {
|
|
372
|
-
return TextNode.getTextNodeFromChunk(chunk);
|
|
373
|
-
} else {
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
if (node instanceof TextNode) {
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
const firstChild = node.getChildren()[0];
|
|
381
|
-
if (!firstChild) {
|
|
382
|
-
log("No first child found for node:", node.id);
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
log("First child found:", firstChild.id, "for node:", node.id);
|
|
386
|
-
return firstChild;
|
|
387
|
-
},
|
|
388
|
-
getNextSibling(node) {
|
|
389
|
-
log("Getting next sibling of node:", node.id);
|
|
390
|
-
const parent = node.parent;
|
|
391
|
-
if (!parent) {
|
|
392
|
-
log("No parent found for node:", node.id);
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
if (node instanceof TextNode) {
|
|
396
|
-
if (parent instanceof TextRenderable3) {
|
|
397
|
-
const siblings2 = parent.content.chunks;
|
|
398
|
-
const index2 = siblings2.indexOf(node.chunk);
|
|
399
|
-
if (index2 === -1 || index2 === siblings2.length - 1) {
|
|
400
|
-
log("No next sibling found for node:", node.id);
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
const nextSibling2 = siblings2[index2 + 1];
|
|
404
|
-
if (!nextSibling2) {
|
|
405
|
-
log("Next sibling is null for node:", node.id);
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
return TextNode.getTextNodeFromChunk(nextSibling2);
|
|
409
|
-
}
|
|
410
|
-
console.warn("Text parent is not a text node:", node.id);
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
const siblings = parent.getChildren();
|
|
414
|
-
const index = siblings.indexOf(node);
|
|
415
|
-
if (index === -1 || index === siblings.length - 1) {
|
|
416
|
-
log("No next sibling found for node:", node.id);
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
const nextSibling = siblings[index + 1];
|
|
420
|
-
if (!nextSibling) {
|
|
421
|
-
log("Next sibling is null for node:", node.id);
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
log("Next sibling found:", nextSibling.id, "for node:", node.id);
|
|
425
|
-
return nextSibling;
|
|
426
|
-
}
|
|
427
|
-
});
|
|
428
|
-
var insertStyledText = (parent, value, current, marker) => {
|
|
429
|
-
while (typeof current === "function")
|
|
430
|
-
current = current();
|
|
431
|
-
if (value === current)
|
|
432
|
-
return current;
|
|
433
|
-
if (current) {
|
|
434
|
-
if (typeof current === "object" && "__isChunk" in current) {
|
|
435
|
-
const node = TextNode.getTextNodeFromChunk(current);
|
|
436
|
-
if (node) {
|
|
437
|
-
_removeNode(parent, node);
|
|
438
|
-
}
|
|
439
|
-
} else if (current instanceof StyledText) {
|
|
440
|
-
for (const chunk of current.chunks) {
|
|
441
|
-
const chunkNode = TextNode.getTextNodeFromChunk(chunk);
|
|
442
|
-
if (!chunkNode)
|
|
443
|
-
continue;
|
|
444
|
-
_removeNode(parent, chunkNode);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
if (value instanceof StyledText) {
|
|
449
|
-
log("Inserting styled text:", value.toString());
|
|
450
|
-
for (const chunk of value.chunks) {
|
|
451
|
-
insertNode(parent, createTextNode(chunk), marker);
|
|
452
|
-
}
|
|
453
|
-
return value;
|
|
454
|
-
} else if (value && typeof value === "object" && "__isChunk" in value) {
|
|
455
|
-
insertNode(parent, createTextNode(value), marker);
|
|
456
|
-
return value;
|
|
457
|
-
}
|
|
458
|
-
return solidUniversalInsert(parent, value, marker, current);
|
|
459
|
-
};
|
|
460
|
-
var insert = (parent, accessor, marker, initial) => {
|
|
461
|
-
if (marker !== undefined && !initial)
|
|
462
|
-
initial = [];
|
|
463
|
-
if (typeof accessor !== "function")
|
|
464
|
-
return insertStyledText(parent, accessor, initial, marker);
|
|
465
|
-
effect((current) => insertStyledText(parent, accessor(), current, marker), initial);
|
|
466
|
-
};
|
|
467
|
-
export {
|
|
468
|
-
use,
|
|
469
|
-
spread,
|
|
470
|
-
solidUniversalInsert,
|
|
471
|
-
setProp,
|
|
472
|
-
mergeProps,
|
|
473
|
-
memo,
|
|
474
|
-
insertNode,
|
|
475
|
-
insert,
|
|
476
|
-
effect,
|
|
477
|
-
createTextNode,
|
|
478
|
-
createElement,
|
|
479
|
-
createComponent,
|
|
480
|
-
_render
|
|
481
|
-
};
|