@opentui/solid 0.1.6 → 0.1.8
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/README.md +5 -3
- package/index.js +91 -40
- package/jsx-runtime.d.ts +11 -11
- package/package.json +8 -8
- package/scripts/preload.ts +3 -3
- package/scripts/solid-plugin.ts +11 -11
- package/src/reconciler.d.ts +2 -1
- package/src/reconciler.js +91 -40
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ bun install solid-js @opentui/solid
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
1. Add jsx config to tsconfig.json:
|
|
14
|
+
|
|
14
15
|
```json
|
|
15
16
|
{
|
|
16
17
|
"compilerOptions": {
|
|
@@ -21,16 +22,17 @@ bun install solid-js @opentui/solid
|
|
|
21
22
|
```
|
|
22
23
|
|
|
23
24
|
2. Add preload script to bunfig.toml:
|
|
25
|
+
|
|
24
26
|
```toml
|
|
25
27
|
preload = ["@opentui/solid/preload"]
|
|
26
28
|
```
|
|
27
29
|
|
|
28
30
|
3. Add render function to index.tsx:
|
|
31
|
+
|
|
29
32
|
```tsx
|
|
30
|
-
import { render } from "@opentui/solid"
|
|
33
|
+
import { render } from "@opentui/solid"
|
|
31
34
|
|
|
32
|
-
render(() => <text>Hello, World!</text>)
|
|
35
|
+
render(() => <text>Hello, World!</text>)
|
|
33
36
|
```
|
|
34
37
|
|
|
35
|
-
|
|
36
38
|
4. Run with `bun --conditions=browser index.tsx`.
|
package/index.js
CHANGED
|
@@ -106,7 +106,6 @@ var elements = {
|
|
|
106
106
|
|
|
107
107
|
// src/reconciler.ts
|
|
108
108
|
import {
|
|
109
|
-
GroupRenderable as GroupRenderable2,
|
|
110
109
|
InputRenderable as InputRenderable2,
|
|
111
110
|
InputRenderableEvents,
|
|
112
111
|
Renderable,
|
|
@@ -131,10 +130,13 @@ function getNextId(elementType) {
|
|
|
131
130
|
}
|
|
132
131
|
|
|
133
132
|
// src/reconciler.ts
|
|
133
|
+
var GHOST_NODE_TAG = "text-ghost";
|
|
134
|
+
|
|
134
135
|
class TextNode {
|
|
135
136
|
id;
|
|
136
137
|
chunk;
|
|
137
138
|
parent;
|
|
139
|
+
textParent;
|
|
138
140
|
constructor(chunk) {
|
|
139
141
|
this.id = getNextId("text-node");
|
|
140
142
|
this.chunk = chunk;
|
|
@@ -144,43 +146,94 @@ var ChunkToTextNodeMap = new WeakMap;
|
|
|
144
146
|
var log = (...args) => {
|
|
145
147
|
console.log("[Reconciler]", ...args);
|
|
146
148
|
};
|
|
147
|
-
function
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
149
|
+
function getOrCreateTextGhostNode(parent, anchor) {
|
|
150
|
+
if (anchor instanceof TextNode && anchor.textParent) {
|
|
151
|
+
return anchor.textParent;
|
|
152
|
+
}
|
|
153
|
+
const children = parent.getChildren();
|
|
154
|
+
if (anchor instanceof Renderable) {
|
|
155
|
+
const anchorIndex = children.findIndex((el) => el.id === anchor.id);
|
|
156
|
+
const beforeAnchor = children[anchorIndex - 1];
|
|
157
|
+
if (beforeAnchor instanceof TextRenderable2 && beforeAnchor.id.startsWith(GHOST_NODE_TAG)) {
|
|
158
|
+
return beforeAnchor;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const lastChild = children.at(-1);
|
|
162
|
+
if (lastChild instanceof TextRenderable2 && lastChild.id.startsWith(GHOST_NODE_TAG)) {
|
|
163
|
+
return lastChild;
|
|
164
|
+
}
|
|
165
|
+
const ghostNode = new TextRenderable2(getNextId(GHOST_NODE_TAG), {});
|
|
166
|
+
_insertNode(parent, ghostNode, anchor);
|
|
167
|
+
return ghostNode;
|
|
168
|
+
}
|
|
169
|
+
function insertTextNode(parent, node, anchor) {
|
|
170
|
+
if (!(parent instanceof Renderable)) {
|
|
171
|
+
console.warn("Attaching text node to parent text node, impossible");
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
log("Inserting text node:", node.id, "into parent:", parent.id, "with anchor:", anchor?.id);
|
|
175
|
+
let textParent;
|
|
176
|
+
if (!(parent instanceof TextRenderable2)) {
|
|
177
|
+
textParent = getOrCreateTextGhostNode(parent, anchor);
|
|
178
|
+
} else {
|
|
179
|
+
textParent = parent;
|
|
180
|
+
}
|
|
181
|
+
node.textParent = textParent;
|
|
182
|
+
let styledText = textParent.content;
|
|
183
|
+
if (anchor && anchor instanceof TextNode) {
|
|
184
|
+
const anchorIndex = styledText.chunks.indexOf(anchor.chunk);
|
|
185
|
+
if (anchorIndex == -1) {
|
|
186
|
+
console.log("anchor not found");
|
|
157
187
|
return;
|
|
158
188
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
styledText.insert(node.chunk, anchorIndex);
|
|
189
|
+
styledText = styledText.insert(node.chunk, anchorIndex);
|
|
190
|
+
} else {
|
|
191
|
+
const firstChunk = textParent.content.chunks[0];
|
|
192
|
+
if (firstChunk && !ChunkToTextNodeMap.has(firstChunk)) {
|
|
193
|
+
styledText = styledText.replace(node.chunk, firstChunk);
|
|
167
194
|
} else {
|
|
168
|
-
|
|
169
|
-
if (firstChunk && !ChunkToTextNodeMap.has(firstChunk)) {
|
|
170
|
-
styledText.replace(node.chunk, firstChunk);
|
|
171
|
-
} else {
|
|
172
|
-
styledText.insert(node.chunk);
|
|
173
|
-
}
|
|
195
|
+
styledText = styledText.insert(node.chunk);
|
|
174
196
|
}
|
|
175
|
-
|
|
176
|
-
|
|
197
|
+
}
|
|
198
|
+
textParent.content = styledText;
|
|
199
|
+
node.parent = parent;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
function removeTextNode(parent, node) {
|
|
203
|
+
if (!(parent instanceof Renderable)) {
|
|
204
|
+
ChunkToTextNodeMap.delete(node.chunk);
|
|
177
205
|
return;
|
|
178
206
|
}
|
|
207
|
+
if (parent === node.textParent && parent instanceof TextRenderable2) {
|
|
208
|
+
ChunkToTextNodeMap.delete(node.chunk);
|
|
209
|
+
parent.content = parent.content.remove(node.chunk);
|
|
210
|
+
} else if (node.textParent) {
|
|
211
|
+
ChunkToTextNodeMap.delete(node.chunk);
|
|
212
|
+
let styledText = node.textParent.content;
|
|
213
|
+
styledText = styledText.remove(node.chunk);
|
|
214
|
+
if (styledText.chunks.length > 0) {
|
|
215
|
+
node.textParent.content = styledText;
|
|
216
|
+
} else {
|
|
217
|
+
node.parent?.remove(node.textParent.id);
|
|
218
|
+
node.textParent.destroyRecursively();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function _insertNode(parent, node, anchor) {
|
|
223
|
+
log("Inserting node:", node.id, "into parent:", parent.id, "with anchor:", anchor?.id);
|
|
224
|
+
if (node instanceof TextNode) {
|
|
225
|
+
return insertTextNode(parent, node, anchor);
|
|
226
|
+
}
|
|
179
227
|
if (!(parent instanceof Renderable)) {
|
|
180
228
|
return;
|
|
181
229
|
}
|
|
182
230
|
if (anchor) {
|
|
183
|
-
const anchorIndex = parent.getChildren().findIndex((el) =>
|
|
231
|
+
const anchorIndex = parent.getChildren().findIndex((el) => {
|
|
232
|
+
if (anchor instanceof TextNode) {
|
|
233
|
+
return el.id === anchor.textParent?.id;
|
|
234
|
+
}
|
|
235
|
+
return el.id === anchor.id;
|
|
236
|
+
});
|
|
184
237
|
parent.add(node, anchorIndex);
|
|
185
238
|
} else {
|
|
186
239
|
parent.add(node);
|
|
@@ -188,14 +241,12 @@ function _insertNode(parent, node, anchor) {
|
|
|
188
241
|
}
|
|
189
242
|
function _removeNode(parent, node) {
|
|
190
243
|
log("Removing node:", node.id, "from parent:", parent.id);
|
|
191
|
-
if (
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
parent.content = styledText;
|
|
196
|
-
} else if (parent instanceof Renderable && node instanceof Renderable) {
|
|
197
|
-
node.destroyRecursively();
|
|
244
|
+
if (node instanceof TextNode) {
|
|
245
|
+
return removeTextNode(parent, node);
|
|
246
|
+
}
|
|
247
|
+
if (parent instanceof Renderable && node instanceof Renderable) {
|
|
198
248
|
parent.remove(node.id);
|
|
249
|
+
node.destroyRecursively();
|
|
199
250
|
}
|
|
200
251
|
}
|
|
201
252
|
var {
|
|
@@ -239,15 +290,15 @@ var {
|
|
|
239
290
|
text: new TextEncoder().encode(value),
|
|
240
291
|
plainText: value
|
|
241
292
|
};
|
|
242
|
-
const
|
|
243
|
-
if (!
|
|
293
|
+
const textParent = textNode.textParent;
|
|
294
|
+
if (!textParent) {
|
|
244
295
|
log("No parent found for text node:", textNode.id);
|
|
245
296
|
return;
|
|
246
297
|
}
|
|
247
|
-
if (
|
|
248
|
-
const styledText =
|
|
298
|
+
if (textParent instanceof TextRenderable2) {
|
|
299
|
+
const styledText = textParent.content;
|
|
249
300
|
styledText.replace(newChunk, textNode.chunk);
|
|
250
|
-
|
|
301
|
+
textParent.content = styledText;
|
|
251
302
|
textNode.chunk = newChunk;
|
|
252
303
|
ChunkToTextNodeMap.set(newChunk, textNode);
|
|
253
304
|
}
|
package/jsx-runtime.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Renderable } from "@opentui/core"
|
|
1
|
+
import { Renderable } from "@opentui/core"
|
|
2
2
|
import {
|
|
3
3
|
ASCIIFontElementProps,
|
|
4
4
|
BoxElementProps,
|
|
@@ -7,25 +7,25 @@ import {
|
|
|
7
7
|
SelectElementProps,
|
|
8
8
|
TabSelectElementProps,
|
|
9
9
|
TextElementProps,
|
|
10
|
-
} from "./src/elements/index"
|
|
10
|
+
} from "./src/elements/index"
|
|
11
11
|
|
|
12
12
|
declare namespace JSX {
|
|
13
13
|
// Replace Node with Renderable
|
|
14
|
-
type Element = Renderable | ArrayElement | (string & {}) | number | boolean | null | undefined
|
|
14
|
+
type Element = Renderable | ArrayElement | (string & {}) | number | boolean | null | undefined
|
|
15
15
|
|
|
16
16
|
interface ArrayElement extends Array<Element> {}
|
|
17
17
|
|
|
18
18
|
interface IntrinsicElements {
|
|
19
|
-
ascii_font: ASCIIFontElementProps
|
|
20
|
-
box: BoxElementProps
|
|
21
|
-
group: GroupElementProps
|
|
22
|
-
input: InputElementProps
|
|
23
|
-
select: SelectElementProps
|
|
24
|
-
tab_select: TabSelectElementProps
|
|
25
|
-
text: TextElementProps
|
|
19
|
+
ascii_font: ASCIIFontElementProps
|
|
20
|
+
box: BoxElementProps
|
|
21
|
+
group: GroupElementProps
|
|
22
|
+
input: InputElementProps
|
|
23
|
+
select: SelectElementProps
|
|
24
|
+
tab_select: TabSelectElementProps
|
|
25
|
+
text: TextElementProps
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
interface ElementChildrenAttribute {
|
|
29
|
-
children: {}
|
|
29
|
+
children: {}
|
|
30
30
|
}
|
|
31
31
|
}
|
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.8",
|
|
8
8
|
"description": "SolidJS renderer for OpenTUI",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"repository": {
|
|
@@ -30,18 +30,18 @@
|
|
|
30
30
|
"./jsx-dev-runtime": "./jsx-runtime.d.ts"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@opentui/core": "0.1.
|
|
33
|
+
"@opentui/core": "0.1.8"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@types/babel__core": "
|
|
37
|
-
"babel-plugin-module-resolver": "
|
|
38
|
-
"@babel/core": "
|
|
39
|
-
"@babel/preset-typescript": "
|
|
40
|
-
"babel-preset-solid": "
|
|
36
|
+
"@types/babel__core": "7.20.5",
|
|
37
|
+
"babel-plugin-module-resolver": "5.0.2",
|
|
38
|
+
"@babel/core": "7.28.0",
|
|
39
|
+
"@babel/preset-typescript": "7.27.1",
|
|
40
|
+
"babel-preset-solid": "1.9.9",
|
|
41
41
|
"@types/bun": "latest"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
|
-
"solid-js": "
|
|
44
|
+
"solid-js": "1.9.9",
|
|
45
45
|
"typescript": "^5"
|
|
46
46
|
}
|
|
47
47
|
}
|
package/scripts/preload.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import solidTransformPlugin from "./solid-plugin"
|
|
2
|
-
import { plugin, type BunPlugin } from "bun"
|
|
1
|
+
import solidTransformPlugin from "./solid-plugin"
|
|
2
|
+
import { plugin, type BunPlugin } from "bun"
|
|
3
3
|
|
|
4
|
-
plugin(solidTransformPlugin)
|
|
4
|
+
plugin(solidTransformPlugin)
|
package/scripts/solid-plugin.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { transformAsync } from "@babel/core"
|
|
1
|
+
import { transformAsync } from "@babel/core"
|
|
2
2
|
// @ts-expect-error - Types not important.
|
|
3
|
-
import ts from "@babel/preset-typescript"
|
|
3
|
+
import ts from "@babel/preset-typescript"
|
|
4
4
|
// @ts-expect-error - Types not important.
|
|
5
|
-
import solid from "babel-preset-solid"
|
|
6
|
-
import { type BunPlugin } from "bun"
|
|
5
|
+
import solid from "babel-preset-solid"
|
|
6
|
+
import { type BunPlugin } from "bun"
|
|
7
7
|
|
|
8
8
|
const solidTransformPlugin: BunPlugin = {
|
|
9
9
|
name: "bun-plugin-solid",
|
|
@@ -26,8 +26,8 @@ const solidTransformPlugin: BunPlugin = {
|
|
|
26
26
|
// };
|
|
27
27
|
// });
|
|
28
28
|
build.onLoad({ filter: /\.(js|ts)x$/ }, async (args) => {
|
|
29
|
-
const { readFile } = await import("node:fs/promises")
|
|
30
|
-
const code = await readFile(args.path, "utf8")
|
|
29
|
+
const { readFile } = await import("node:fs/promises")
|
|
30
|
+
const code = await readFile(args.path, "utf8")
|
|
31
31
|
const transforms = await transformAsync(code, {
|
|
32
32
|
filename: args.path,
|
|
33
33
|
// env: {
|
|
@@ -46,13 +46,13 @@ const solidTransformPlugin: BunPlugin = {
|
|
|
46
46
|
],
|
|
47
47
|
[ts],
|
|
48
48
|
],
|
|
49
|
-
})
|
|
49
|
+
})
|
|
50
50
|
return {
|
|
51
51
|
contents: transforms?.code ?? "",
|
|
52
52
|
loader: "js",
|
|
53
|
-
}
|
|
54
|
-
})
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
55
|
},
|
|
56
|
-
}
|
|
56
|
+
}
|
|
57
57
|
|
|
58
|
-
export default solidTransformPlugin
|
|
58
|
+
export default solidTransformPlugin
|
package/src/reconciler.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Renderable, type TextChunk } from "@opentui/core";
|
|
1
|
+
import { Renderable, TextRenderable, type TextChunk } from "@opentui/core";
|
|
2
2
|
declare class TextNode {
|
|
3
3
|
id: string;
|
|
4
4
|
chunk: TextChunk;
|
|
5
5
|
parent?: Renderable;
|
|
6
|
+
textParent?: TextRenderable;
|
|
6
7
|
constructor(chunk: TextChunk);
|
|
7
8
|
}
|
|
8
9
|
type DomNode = Renderable | TextNode;
|
package/src/reconciler.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/reconciler.ts
|
|
3
3
|
import {
|
|
4
|
-
GroupRenderable as GroupRenderable2,
|
|
5
4
|
InputRenderable as InputRenderable2,
|
|
6
5
|
InputRenderableEvents,
|
|
7
6
|
Renderable,
|
|
@@ -56,10 +55,13 @@ function getNextId(elementType) {
|
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
// src/reconciler.ts
|
|
58
|
+
var GHOST_NODE_TAG = "text-ghost";
|
|
59
|
+
|
|
59
60
|
class TextNode {
|
|
60
61
|
id;
|
|
61
62
|
chunk;
|
|
62
63
|
parent;
|
|
64
|
+
textParent;
|
|
63
65
|
constructor(chunk) {
|
|
64
66
|
this.id = getNextId("text-node");
|
|
65
67
|
this.chunk = chunk;
|
|
@@ -69,43 +71,94 @@ var ChunkToTextNodeMap = new WeakMap;
|
|
|
69
71
|
var log = (...args) => {
|
|
70
72
|
console.log("[Reconciler]", ...args);
|
|
71
73
|
};
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
function getOrCreateTextGhostNode(parent, anchor) {
|
|
75
|
+
if (anchor instanceof TextNode && anchor.textParent) {
|
|
76
|
+
return anchor.textParent;
|
|
77
|
+
}
|
|
78
|
+
const children = parent.getChildren();
|
|
79
|
+
if (anchor instanceof Renderable) {
|
|
80
|
+
const anchorIndex = children.findIndex((el) => el.id === anchor.id);
|
|
81
|
+
const beforeAnchor = children[anchorIndex - 1];
|
|
82
|
+
if (beforeAnchor instanceof TextRenderable2 && beforeAnchor.id.startsWith(GHOST_NODE_TAG)) {
|
|
83
|
+
return beforeAnchor;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const lastChild = children.at(-1);
|
|
87
|
+
if (lastChild instanceof TextRenderable2 && lastChild.id.startsWith(GHOST_NODE_TAG)) {
|
|
88
|
+
return lastChild;
|
|
89
|
+
}
|
|
90
|
+
const ghostNode = new TextRenderable2(getNextId(GHOST_NODE_TAG), {});
|
|
91
|
+
_insertNode(parent, ghostNode, anchor);
|
|
92
|
+
return ghostNode;
|
|
93
|
+
}
|
|
94
|
+
function insertTextNode(parent, node, anchor) {
|
|
95
|
+
if (!(parent instanceof Renderable)) {
|
|
96
|
+
console.warn("Attaching text node to parent text node, impossible");
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
log("Inserting text node:", node.id, "into parent:", parent.id, "with anchor:", anchor?.id);
|
|
100
|
+
let textParent;
|
|
101
|
+
if (!(parent instanceof TextRenderable2)) {
|
|
102
|
+
textParent = getOrCreateTextGhostNode(parent, anchor);
|
|
103
|
+
} else {
|
|
104
|
+
textParent = parent;
|
|
105
|
+
}
|
|
106
|
+
node.textParent = textParent;
|
|
107
|
+
let styledText = textParent.content;
|
|
108
|
+
if (anchor && anchor instanceof TextNode) {
|
|
109
|
+
const anchorIndex = styledText.chunks.indexOf(anchor.chunk);
|
|
110
|
+
if (anchorIndex == -1) {
|
|
111
|
+
console.log("anchor not found");
|
|
82
112
|
return;
|
|
83
113
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
styledText.insert(node.chunk, anchorIndex);
|
|
114
|
+
styledText = styledText.insert(node.chunk, anchorIndex);
|
|
115
|
+
} else {
|
|
116
|
+
const firstChunk = textParent.content.chunks[0];
|
|
117
|
+
if (firstChunk && !ChunkToTextNodeMap.has(firstChunk)) {
|
|
118
|
+
styledText = styledText.replace(node.chunk, firstChunk);
|
|
92
119
|
} else {
|
|
93
|
-
|
|
94
|
-
if (firstChunk && !ChunkToTextNodeMap.has(firstChunk)) {
|
|
95
|
-
styledText.replace(node.chunk, firstChunk);
|
|
96
|
-
} else {
|
|
97
|
-
styledText.insert(node.chunk);
|
|
98
|
-
}
|
|
120
|
+
styledText = styledText.insert(node.chunk);
|
|
99
121
|
}
|
|
100
|
-
|
|
101
|
-
|
|
122
|
+
}
|
|
123
|
+
textParent.content = styledText;
|
|
124
|
+
node.parent = parent;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
function removeTextNode(parent, node) {
|
|
128
|
+
if (!(parent instanceof Renderable)) {
|
|
129
|
+
ChunkToTextNodeMap.delete(node.chunk);
|
|
102
130
|
return;
|
|
103
131
|
}
|
|
132
|
+
if (parent === node.textParent && parent instanceof TextRenderable2) {
|
|
133
|
+
ChunkToTextNodeMap.delete(node.chunk);
|
|
134
|
+
parent.content = parent.content.remove(node.chunk);
|
|
135
|
+
} else if (node.textParent) {
|
|
136
|
+
ChunkToTextNodeMap.delete(node.chunk);
|
|
137
|
+
let styledText = node.textParent.content;
|
|
138
|
+
styledText = styledText.remove(node.chunk);
|
|
139
|
+
if (styledText.chunks.length > 0) {
|
|
140
|
+
node.textParent.content = styledText;
|
|
141
|
+
} else {
|
|
142
|
+
node.parent?.remove(node.textParent.id);
|
|
143
|
+
node.textParent.destroyRecursively();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function _insertNode(parent, node, anchor) {
|
|
148
|
+
log("Inserting node:", node.id, "into parent:", parent.id, "with anchor:", anchor?.id);
|
|
149
|
+
if (node instanceof TextNode) {
|
|
150
|
+
return insertTextNode(parent, node, anchor);
|
|
151
|
+
}
|
|
104
152
|
if (!(parent instanceof Renderable)) {
|
|
105
153
|
return;
|
|
106
154
|
}
|
|
107
155
|
if (anchor) {
|
|
108
|
-
const anchorIndex = parent.getChildren().findIndex((el) =>
|
|
156
|
+
const anchorIndex = parent.getChildren().findIndex((el) => {
|
|
157
|
+
if (anchor instanceof TextNode) {
|
|
158
|
+
return el.id === anchor.textParent?.id;
|
|
159
|
+
}
|
|
160
|
+
return el.id === anchor.id;
|
|
161
|
+
});
|
|
109
162
|
parent.add(node, anchorIndex);
|
|
110
163
|
} else {
|
|
111
164
|
parent.add(node);
|
|
@@ -113,14 +166,12 @@ function _insertNode(parent, node, anchor) {
|
|
|
113
166
|
}
|
|
114
167
|
function _removeNode(parent, node) {
|
|
115
168
|
log("Removing node:", node.id, "from parent:", parent.id);
|
|
116
|
-
if (
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
parent.content = styledText;
|
|
121
|
-
} else if (parent instanceof Renderable && node instanceof Renderable) {
|
|
122
|
-
node.destroyRecursively();
|
|
169
|
+
if (node instanceof TextNode) {
|
|
170
|
+
return removeTextNode(parent, node);
|
|
171
|
+
}
|
|
172
|
+
if (parent instanceof Renderable && node instanceof Renderable) {
|
|
123
173
|
parent.remove(node.id);
|
|
174
|
+
node.destroyRecursively();
|
|
124
175
|
}
|
|
125
176
|
}
|
|
126
177
|
var {
|
|
@@ -164,15 +215,15 @@ var {
|
|
|
164
215
|
text: new TextEncoder().encode(value),
|
|
165
216
|
plainText: value
|
|
166
217
|
};
|
|
167
|
-
const
|
|
168
|
-
if (!
|
|
218
|
+
const textParent = textNode.textParent;
|
|
219
|
+
if (!textParent) {
|
|
169
220
|
log("No parent found for text node:", textNode.id);
|
|
170
221
|
return;
|
|
171
222
|
}
|
|
172
|
-
if (
|
|
173
|
-
const styledText =
|
|
223
|
+
if (textParent instanceof TextRenderable2) {
|
|
224
|
+
const styledText = textParent.content;
|
|
174
225
|
styledText.replace(newChunk, textNode.chunk);
|
|
175
|
-
|
|
226
|
+
textParent.content = styledText;
|
|
176
227
|
textNode.chunk = newChunk;
|
|
177
228
|
ChunkToTextNodeMap.set(newChunk, textNode);
|
|
178
229
|
}
|