@byline/richtext-lexical 5.2.0 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +1 -1
- package/dist/field/apply-value-plugin.js +31 -6
- package/dist/field/capabilities/filter-transformers.d.ts +29 -0
- package/dist/field/capabilities/filter-transformers.js +8 -0
- package/dist/field/capabilities/registered-node-types.d.ts +29 -0
- package/dist/field/capabilities/registered-node-types.js +7 -0
- package/dist/field/config/built-in-extension-names.d.ts +42 -0
- package/dist/field/config/built-in-extension-names.js +12 -2
- package/dist/field/config/default-extensions.js +4 -0
- package/dist/field/config/default.js +8 -8
- package/dist/field/config/editor-config-context.d.ts +2 -2
- package/dist/field/config/editor-config-context.js +10 -13
- package/dist/field/config/resolve-editor-config.js +3 -3
- package/dist/field/config/root-dependencies.d.ts +26 -0
- package/dist/field/config/root-dependencies.js +8 -0
- package/dist/field/config/types.d.ts +61 -8
- package/dist/field/editor-context.js +44 -27
- package/dist/field/editor.js +15 -8
- package/dist/field/extensions/core-nodes/core-nodes-extension.d.ts +24 -0
- package/dist/field/extensions/core-nodes/core-nodes-extension.js +11 -0
- package/dist/field/extensions/heading/heading-extension.d.ts +20 -0
- package/dist/field/extensions/heading/heading-extension.js +9 -0
- package/dist/field/extensions/quote/quote-extension.d.ts +16 -0
- package/dist/field/extensions/quote/quote-extension.js +9 -0
- package/dist/field/hooks/use-markdown-toggle.d.ts +15 -0
- package/dist/field/hooks/use-markdown-toggle.js +12 -4
- package/dist/field/hooks/use-platform-modifier.d.ts +16 -0
- package/dist/field/hooks/use-platform-modifier.js +8 -0
- package/dist/field/markdown/transformers.d.ts +1 -0
- package/dist/field/markdown/transformers.js +5 -4
- package/dist/field/nodes/index.d.ts +11 -1
- package/dist/field/nodes/index.js +2 -2
- package/dist/field/normalize/adapted-notice.css +34 -0
- package/dist/field/normalize/adapted-notice.d.ts +29 -0
- package/dist/field/normalize/adapted-notice.js +35 -0
- package/dist/field/normalize/content-labels.d.ts +15 -0
- package/dist/field/normalize/content-labels.js +19 -0
- package/dist/field/normalize/declared-conversions.d.ts +131 -0
- package/dist/field/normalize/declared-conversions.js +93 -0
- package/dist/field/normalize/normalization-status.d.ts +33 -0
- package/dist/field/normalize/normalization-status.js +28 -0
- package/dist/field/normalize/normalize-value.d.ts +38 -0
- package/dist/field/normalize/normalize-value.js +132 -0
- package/dist/field/normalize/use-notice-text.d.ts +11 -0
- package/dist/field/normalize/use-notice-text.js +34 -0
- package/dist/field/plugins/toolbar-plugin/index.d.ts +23 -0
- package/dist/field/plugins/toolbar-plugin/index.js +104 -78
- package/dist/field/test-support/build-test-editor.js +49 -0
- package/dist/field/test-support/capture-editor.js +7 -0
- package/dist/field/test-support/frame-control.js +40 -0
- package/dist/field/test-support/jsdom-setup.js +21 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +6 -1
- package/dist/scan/capability-manifest.d.ts +30 -0
- package/dist/scan/capability-manifest.js +43 -0
- package/dist/scan/scan-documents.d.ts +29 -0
- package/dist/scan/scan-documents.js +39 -0
- package/dist/scan/types.d.ts +63 -0
- package/dist/scan/types.js +1 -0
- package/dist/scan.d.ts +25 -0
- package/dist/scan.js +1 -0
- package/package.json +14 -5
- package/src/config.ts +1 -1
- package/src/field/apply-value-plugin.tsx +71 -5
- package/src/field/capabilities/filter-transformers.test.tsx +71 -0
- package/src/field/capabilities/filter-transformers.ts +42 -0
- package/src/field/capabilities/markdown-behaviour.test.tsx +188 -0
- package/src/field/capabilities/no-blanket-registration.test.tsx +86 -0
- package/src/field/capabilities/registered-node-types.test.tsx +29 -0
- package/src/field/capabilities/registered-node-types.ts +36 -0
- package/src/field/config/built-in-extension-names.test.node.ts +38 -14
- package/src/field/config/built-in-extension-names.ts +29 -1
- package/src/field/config/default-extensions.ts +6 -0
- package/src/field/config/default.ts +8 -8
- package/src/field/config/editor-config-context.tsx +14 -9
- package/src/field/config/list-removal.test.tsx +44 -0
- package/src/field/config/resolve-editor-config.test.node.ts +27 -6
- package/src/field/config/resolve-editor-config.ts +3 -3
- package/src/field/config/root-dependencies.ts +32 -0
- package/src/field/config/types.ts +61 -17
- package/src/field/editor-component.test.tsx +18 -3
- package/src/field/editor-context.regression.test.tsx +124 -0
- package/src/field/editor-context.tsx +90 -22
- package/src/field/editor.tsx +22 -12
- package/src/field/extensions/core-nodes/core-nodes-extension.test.tsx +13 -0
- package/src/field/extensions/core-nodes/core-nodes-extension.ts +32 -0
- package/src/field/extensions/heading/heading-extension.test.tsx +32 -0
- package/src/field/extensions/heading/heading-extension.ts +27 -0
- package/src/field/extensions/quote/quote-extension.ts +23 -0
- package/src/field/hooks/markdown-source-mode.test.tsx +221 -0
- package/src/field/hooks/use-markdown-toggle.ts +39 -4
- package/src/field/hooks/use-platform-modifier.test.tsx +81 -0
- package/src/field/hooks/use-platform-modifier.ts +41 -0
- package/src/field/markdown/transformers.ts +18 -4
- package/src/field/nodes/index.ts +11 -1
- package/src/field/normalize/adapted-notice.css +52 -0
- package/src/field/normalize/adapted-notice.tsx +63 -0
- package/src/field/normalize/clipboard-equivalence.test.tsx +330 -0
- package/src/field/normalize/content-labels.ts +44 -0
- package/src/field/normalize/declared-conversions.test.node.ts +67 -0
- package/src/field/normalize/declared-conversions.ts +160 -0
- package/src/field/normalize/emission-gate.test.tsx +302 -0
- package/src/field/normalize/normalization-status.tsx +48 -0
- package/src/field/normalize/normalize-load.test.tsx +371 -0
- package/src/field/normalize/normalize-value.test.node.ts +530 -0
- package/src/field/normalize/normalize-value.ts +180 -0
- package/src/field/normalize/notice-i18n.test.tsx +128 -0
- package/src/field/normalize/use-notice-text.ts +82 -0
- package/src/field/normalize/wiring.test.tsx +348 -0
- package/src/field/plugins/toolbar-plugin/block-format-capabilities.test.tsx +57 -0
- package/src/field/plugins/toolbar-plugin/index.tsx +131 -68
- package/src/field/test-support/build-test-editor.test.tsx +17 -0
- package/src/field/test-support/build-test-editor.ts +99 -0
- package/src/field/test-support/capture-editor.tsx +20 -0
- package/src/field/test-support/frame-control.ts +91 -0
- package/src/field/test-support/jsdom-setup.ts +41 -0
- package/src/index.ts +12 -1
- package/src/scan/capability-manifest.test.tsx +82 -0
- package/src/scan/capability-manifest.ts +81 -0
- package/src/scan/scan-documents.test.node.ts +125 -0
- package/src/scan/scan-documents.ts +78 -0
- package/src/scan/types.ts +66 -0
- package/src/scan.ts +27 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { $getRoot } from 'lexical'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { registeredNodeTypes } from '../capabilities/registered-node-types'
|
|
5
|
+
import { builtInExtensions } from '../config/built-in-extension-names'
|
|
6
|
+
import { buildRestrictedEditor } from '../test-support/build-test-editor'
|
|
7
|
+
import { normalizeValue } from './normalize-value'
|
|
8
|
+
|
|
9
|
+
const text = (value: string, format = 0) => ({
|
|
10
|
+
detail: 0,
|
|
11
|
+
format,
|
|
12
|
+
mode: 'normal',
|
|
13
|
+
style: '',
|
|
14
|
+
text: value,
|
|
15
|
+
type: 'text',
|
|
16
|
+
version: 1,
|
|
17
|
+
})
|
|
18
|
+
const para = (...children: unknown[]) => ({
|
|
19
|
+
children,
|
|
20
|
+
direction: null,
|
|
21
|
+
format: '',
|
|
22
|
+
indent: 0,
|
|
23
|
+
type: 'paragraph',
|
|
24
|
+
version: 1,
|
|
25
|
+
})
|
|
26
|
+
const heading = (tag: string, ...children: unknown[]) => ({
|
|
27
|
+
children,
|
|
28
|
+
direction: null,
|
|
29
|
+
format: '',
|
|
30
|
+
indent: 0,
|
|
31
|
+
type: 'heading',
|
|
32
|
+
version: 1,
|
|
33
|
+
tag,
|
|
34
|
+
})
|
|
35
|
+
// biome-ignore lint/suspicious/noExplicitAny: serialized fixtures are structural
|
|
36
|
+
const doc = (...children: unknown[]): any => ({
|
|
37
|
+
root: { children, direction: null, format: '', indent: 0, type: 'root', version: 1 },
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Normalize for this editor and actually load the result.
|
|
42
|
+
*
|
|
43
|
+
* Structural assertions on the JSON are not enough: only Lexical can say
|
|
44
|
+
* whether the tree it produced is one it will accept, and an invalid
|
|
45
|
+
* parent/child arrangement throws here rather than in a unit assertion.
|
|
46
|
+
*/
|
|
47
|
+
function normalizeAndLoad(
|
|
48
|
+
/** Undefined means the default fully-stripped editor. */
|
|
49
|
+
removals: string[] | undefined,
|
|
50
|
+
// biome-ignore lint/suspicious/noExplicitAny: serialized fixtures are structural
|
|
51
|
+
value: any
|
|
52
|
+
): { types: string[]; text: string; formats: number[] } {
|
|
53
|
+
const editor = buildRestrictedEditor(removals)
|
|
54
|
+
const result = normalizeValue(value, registeredNodeTypes(editor))
|
|
55
|
+
if (result.status !== 'adapted') throw new Error(`expected adapted, got ${result.status}`)
|
|
56
|
+
|
|
57
|
+
// Actually COMMIT the state. Parsing alone does not exercise
|
|
58
|
+
// setEditorState's own validation — an empty root parses happily and
|
|
59
|
+
// then throws "setEditorState: the editor state is empty" on commit.
|
|
60
|
+
const state = editor.parseEditorState(JSON.stringify(result.value))
|
|
61
|
+
editor.setEditorState(state)
|
|
62
|
+
|
|
63
|
+
let types: string[] = []
|
|
64
|
+
let content = ''
|
|
65
|
+
let formats: number[] = []
|
|
66
|
+
editor.getEditorState().read(() => {
|
|
67
|
+
types = $getRoot()
|
|
68
|
+
.getChildren()
|
|
69
|
+
.map((node) => node.getType())
|
|
70
|
+
content = $getRoot().getTextContent()
|
|
71
|
+
formats = $getRoot()
|
|
72
|
+
.getAllTextNodes()
|
|
73
|
+
.map((node) => node.getFormat())
|
|
74
|
+
})
|
|
75
|
+
editor.dispose()
|
|
76
|
+
return { types, text: content, formats }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
describe('normalized output loads into a real editor', () => {
|
|
80
|
+
it('commits a document whose only node was dropped', () => {
|
|
81
|
+
const result = normalizeAndLoad(undefined, doc({ type: 'horizontalrule', version: 1 }))
|
|
82
|
+
expect(result.types).toEqual(['paragraph'])
|
|
83
|
+
expect(result.text).toBe('')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('commits highlighted code as plain text with formats intact', () => {
|
|
87
|
+
const code = {
|
|
88
|
+
children: [
|
|
89
|
+
{
|
|
90
|
+
detail: 0,
|
|
91
|
+
format: 1,
|
|
92
|
+
mode: 'normal',
|
|
93
|
+
style: '',
|
|
94
|
+
text: 'const',
|
|
95
|
+
type: 'code-highlight',
|
|
96
|
+
version: 1,
|
|
97
|
+
highlightType: 'keyword',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
detail: 0,
|
|
101
|
+
format: 0,
|
|
102
|
+
mode: 'normal',
|
|
103
|
+
style: '',
|
|
104
|
+
text: ' x = 1',
|
|
105
|
+
type: 'code-highlight',
|
|
106
|
+
version: 1,
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
direction: null,
|
|
110
|
+
format: '',
|
|
111
|
+
indent: 0,
|
|
112
|
+
type: 'code',
|
|
113
|
+
version: 1,
|
|
114
|
+
language: 'js',
|
|
115
|
+
}
|
|
116
|
+
const result = normalizeAndLoad([builtInExtensions.CodeHighlight], doc(code))
|
|
117
|
+
expect(result.types).toEqual(['paragraph'])
|
|
118
|
+
expect(result.text).toBe('const x = 1')
|
|
119
|
+
expect(result.formats).toContain(1)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('commits a nested list flattened to paragraphs', () => {
|
|
123
|
+
const inner = {
|
|
124
|
+
children: [
|
|
125
|
+
{
|
|
126
|
+
children: [text('inner')],
|
|
127
|
+
direction: null,
|
|
128
|
+
format: '',
|
|
129
|
+
indent: 1,
|
|
130
|
+
type: 'listitem',
|
|
131
|
+
version: 1,
|
|
132
|
+
value: 1,
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
direction: null,
|
|
136
|
+
format: '',
|
|
137
|
+
indent: 0,
|
|
138
|
+
type: 'list',
|
|
139
|
+
version: 1,
|
|
140
|
+
listType: 'bullet',
|
|
141
|
+
start: 1,
|
|
142
|
+
tag: 'ul',
|
|
143
|
+
}
|
|
144
|
+
const outer = {
|
|
145
|
+
children: [
|
|
146
|
+
{
|
|
147
|
+
children: [text('outer')],
|
|
148
|
+
direction: null,
|
|
149
|
+
format: '',
|
|
150
|
+
indent: 0,
|
|
151
|
+
type: 'listitem',
|
|
152
|
+
version: 1,
|
|
153
|
+
value: 1,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
children: [inner],
|
|
157
|
+
direction: null,
|
|
158
|
+
format: '',
|
|
159
|
+
indent: 0,
|
|
160
|
+
type: 'listitem',
|
|
161
|
+
version: 1,
|
|
162
|
+
value: 2,
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
direction: null,
|
|
166
|
+
format: '',
|
|
167
|
+
indent: 0,
|
|
168
|
+
type: 'list',
|
|
169
|
+
version: 1,
|
|
170
|
+
listType: 'bullet',
|
|
171
|
+
start: 1,
|
|
172
|
+
tag: 'ul',
|
|
173
|
+
}
|
|
174
|
+
const result = normalizeAndLoad(undefined, doc(outer))
|
|
175
|
+
expect(new Set(result.types)).toEqual(new Set(['paragraph']))
|
|
176
|
+
expect(result.text).toContain('outer')
|
|
177
|
+
expect(result.text).toContain('inner')
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('loads mixed content — adjacent headings, an empty one, a table and a list', () => {
|
|
181
|
+
const cell = {
|
|
182
|
+
children: [para(text('cell text'))],
|
|
183
|
+
direction: null,
|
|
184
|
+
format: '',
|
|
185
|
+
indent: 0,
|
|
186
|
+
type: 'tablecell',
|
|
187
|
+
version: 1,
|
|
188
|
+
colSpan: 1,
|
|
189
|
+
rowSpan: 1,
|
|
190
|
+
headerState: 0,
|
|
191
|
+
}
|
|
192
|
+
const table = {
|
|
193
|
+
children: [
|
|
194
|
+
{
|
|
195
|
+
children: [cell],
|
|
196
|
+
direction: null,
|
|
197
|
+
format: '',
|
|
198
|
+
indent: 0,
|
|
199
|
+
type: 'tablerow',
|
|
200
|
+
version: 1,
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
direction: null,
|
|
204
|
+
format: '',
|
|
205
|
+
indent: 0,
|
|
206
|
+
type: 'table',
|
|
207
|
+
version: 1,
|
|
208
|
+
}
|
|
209
|
+
const list = {
|
|
210
|
+
children: [
|
|
211
|
+
{
|
|
212
|
+
children: [text('item one')],
|
|
213
|
+
direction: null,
|
|
214
|
+
format: '',
|
|
215
|
+
indent: 0,
|
|
216
|
+
type: 'listitem',
|
|
217
|
+
version: 1,
|
|
218
|
+
value: 1,
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
direction: null,
|
|
222
|
+
format: '',
|
|
223
|
+
indent: 0,
|
|
224
|
+
type: 'list',
|
|
225
|
+
version: 1,
|
|
226
|
+
listType: 'bullet',
|
|
227
|
+
start: 1,
|
|
228
|
+
tag: 'ul',
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const result = normalizeAndLoad(
|
|
232
|
+
undefined,
|
|
233
|
+
doc(
|
|
234
|
+
heading('h1', text('First')),
|
|
235
|
+
heading('h2'),
|
|
236
|
+
heading('h2', text('Second')),
|
|
237
|
+
table,
|
|
238
|
+
list,
|
|
239
|
+
para(text('tail'))
|
|
240
|
+
)
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
// Every block came back as a paragraph and Lexical accepted the tree.
|
|
244
|
+
expect(new Set(result.types)).toEqual(new Set(['paragraph']))
|
|
245
|
+
for (const fragment of ['First', 'Second', 'cell text', 'item one', 'tail']) {
|
|
246
|
+
expect(result.text, fragment).toContain(fragment)
|
|
247
|
+
}
|
|
248
|
+
// Adjacent headings did not merge into one paragraph.
|
|
249
|
+
expect(result.text).not.toContain('FirstSecond')
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it('preserves bold through the load, not just through the rewrite', () => {
|
|
253
|
+
const result = normalizeAndLoad(undefined, doc(heading('h1', text('Bold title', 1))))
|
|
254
|
+
expect(result.types).toEqual(['paragraph'])
|
|
255
|
+
expect(result.text).toBe('Bold title')
|
|
256
|
+
expect(result.formats).toContain(1)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('loads a preserved link URL as readable text', () => {
|
|
260
|
+
const link = {
|
|
261
|
+
children: [text('link text')],
|
|
262
|
+
direction: null,
|
|
263
|
+
format: '',
|
|
264
|
+
indent: 0,
|
|
265
|
+
type: 'link',
|
|
266
|
+
version: 2,
|
|
267
|
+
attributes: { url: 'https://x.test/a' },
|
|
268
|
+
}
|
|
269
|
+
const result = normalizeAndLoad([builtInExtensions.Link], doc(para(link)))
|
|
270
|
+
expect(result.types).toEqual(['paragraph'])
|
|
271
|
+
expect(result.text).toContain('link text')
|
|
272
|
+
expect(result.text).toContain('https://x.test/a')
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('loads a preserved admonition title as the first line', () => {
|
|
276
|
+
const admonition = {
|
|
277
|
+
children: [para(text('body copy'))],
|
|
278
|
+
direction: null,
|
|
279
|
+
format: '',
|
|
280
|
+
indent: 0,
|
|
281
|
+
type: 'admonition',
|
|
282
|
+
version: 1,
|
|
283
|
+
title: 'Note title',
|
|
284
|
+
}
|
|
285
|
+
const result = normalizeAndLoad([builtInExtensions.Admonition], doc(admonition))
|
|
286
|
+
expect(result.types).toEqual(['paragraph', 'paragraph'])
|
|
287
|
+
expect(result.text.indexOf('Note title')).toBeLessThan(result.text.indexOf('body copy'))
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
it('loads a layout that still contains its supported image', () => {
|
|
291
|
+
// Shaped as InlineImageNode.exportJSON writes it: the relation is
|
|
292
|
+
// spread at the top level, and `caption` is a whole nested editor
|
|
293
|
+
// state — which is exactly why an inline image has no safe
|
|
294
|
+
// structural conversion and must take the refusal path instead.
|
|
295
|
+
const image = {
|
|
296
|
+
type: 'inline-image',
|
|
297
|
+
version: 1,
|
|
298
|
+
targetDocumentId: 'doc-1',
|
|
299
|
+
targetCollectionPath: 'media',
|
|
300
|
+
src: '/cat.png',
|
|
301
|
+
position: 'full',
|
|
302
|
+
altText: 'a cat',
|
|
303
|
+
width: 10,
|
|
304
|
+
height: 10,
|
|
305
|
+
showCaption: false,
|
|
306
|
+
caption: {
|
|
307
|
+
editorState: {
|
|
308
|
+
root: {
|
|
309
|
+
children: [para(text('caption words'))],
|
|
310
|
+
direction: null,
|
|
311
|
+
format: '',
|
|
312
|
+
indent: 0,
|
|
313
|
+
type: 'root',
|
|
314
|
+
version: 1,
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
}
|
|
319
|
+
const item = {
|
|
320
|
+
children: [para(image)],
|
|
321
|
+
direction: null,
|
|
322
|
+
format: '',
|
|
323
|
+
indent: 0,
|
|
324
|
+
type: 'layout-item',
|
|
325
|
+
version: 1,
|
|
326
|
+
}
|
|
327
|
+
const container = {
|
|
328
|
+
children: [item],
|
|
329
|
+
direction: null,
|
|
330
|
+
format: '',
|
|
331
|
+
indent: 0,
|
|
332
|
+
type: 'layout-container',
|
|
333
|
+
version: 1,
|
|
334
|
+
templateColumns: '1fr',
|
|
335
|
+
}
|
|
336
|
+
// Layout removed, inline image KEPT: the image must survive intact.
|
|
337
|
+
const editor = buildRestrictedEditor([builtInExtensions.Layout])
|
|
338
|
+
const result = normalizeValue(doc(container), registeredNodeTypes(editor))
|
|
339
|
+
if (result.status !== 'adapted') throw new Error('expected adapted')
|
|
340
|
+
const state = editor.parseEditorState(JSON.stringify(result.value))
|
|
341
|
+
const types: string[] = []
|
|
342
|
+
let sources = ''
|
|
343
|
+
state.read(() => {
|
|
344
|
+
const walk = (
|
|
345
|
+
nodes: ReturnType<typeof $getRoot>['getChildren'] extends () => infer R ? R : never
|
|
346
|
+
) => {
|
|
347
|
+
for (const node of nodes as Array<{
|
|
348
|
+
getType: () => string
|
|
349
|
+
getChildren?: () => unknown[]
|
|
350
|
+
}>) {
|
|
351
|
+
types.push(node.getType())
|
|
352
|
+
if (typeof node.getChildren === 'function') {
|
|
353
|
+
// biome-ignore lint/suspicious/noExplicitAny: structural walk
|
|
354
|
+
walk(node.getChildren() as any)
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// biome-ignore lint/suspicious/noExplicitAny: structural walk
|
|
359
|
+
walk($getRoot().getChildren() as any)
|
|
360
|
+
sources = JSON.stringify(result.value)
|
|
361
|
+
})
|
|
362
|
+
// The layout wrapper is gone, the image it held is still there.
|
|
363
|
+
expect(types).not.toContain('layout-container')
|
|
364
|
+
expect(types).toContain('inline-image')
|
|
365
|
+
expect(sources).toContain('/cat.png')
|
|
366
|
+
expect(sources).toContain('doc-1')
|
|
367
|
+
// The caption's nested editor state survived untouched.
|
|
368
|
+
expect(sources).toContain('caption words')
|
|
369
|
+
editor.dispose()
|
|
370
|
+
})
|
|
371
|
+
})
|