@byline/richtext-lexical 3.20.1 → 3.20.2
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.
|
@@ -16,9 +16,11 @@ function EditorContext(props) {
|
|
|
16
16
|
const editable = true !== readOnly;
|
|
17
17
|
const rootExtension = useMemo(()=>{
|
|
18
18
|
const extensionsList = editorConfig.extensions ?? defaultExtensionsList();
|
|
19
|
-
const
|
|
19
|
+
const configured = extensionsList.clone();
|
|
20
|
+
if (configured.has(InlineImageExtension)) configured.configure(InlineImageExtension, {
|
|
20
21
|
collection: editorConfig.settings.inlineImageUploadCollection
|
|
21
|
-
})
|
|
22
|
+
});
|
|
23
|
+
const dependencies = configured.toArray();
|
|
22
24
|
return defineExtension({
|
|
23
25
|
name: '[root]',
|
|
24
26
|
namespace: editorConfig.lexical.namespace,
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": false,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
|
-
"version": "3.20.
|
|
6
|
+
"version": "3.20.2",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=20.9.0"
|
|
9
9
|
},
|
|
@@ -73,10 +73,10 @@
|
|
|
73
73
|
"lexical": "0.46.0",
|
|
74
74
|
"npm-run-all": "^4.1.5",
|
|
75
75
|
"react-error-boundary": "^6.1.2",
|
|
76
|
-
"@byline/
|
|
77
|
-
"@byline/
|
|
78
|
-
"@byline/
|
|
79
|
-
"@byline/
|
|
76
|
+
"@byline/core": "3.20.2",
|
|
77
|
+
"@byline/admin": "3.20.2",
|
|
78
|
+
"@byline/client": "3.20.2",
|
|
79
|
+
"@byline/ui": "3.20.2"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
82
|
"react": "^19.0.0",
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { AnyLexicalExtensionArgument } from '@lexical/extension'
|
|
10
|
+
import { describe, expect, it } from 'vitest'
|
|
11
|
+
|
|
12
|
+
import { ExtensionsList } from './extensions-list'
|
|
13
|
+
|
|
14
|
+
// Structural stand-ins — ExtensionsList compares by `.name`, so plain
|
|
15
|
+
// objects are sufficient and keep the heavy extension classes (React,
|
|
16
|
+
// Lexical nodes) out of this node-mode test.
|
|
17
|
+
const extA = { name: 'test/A' } as unknown as AnyLexicalExtensionArgument
|
|
18
|
+
const extB = { name: 'test/B' } as unknown as AnyLexicalExtensionArgument
|
|
19
|
+
|
|
20
|
+
describe('ExtensionsList', () => {
|
|
21
|
+
it('remove() by name string drops the entry; has() reflects it', () => {
|
|
22
|
+
const list = new ExtensionsList([extA, extB])
|
|
23
|
+
expect(list.has('test/A')).toBe(true)
|
|
24
|
+
list.remove('test/A')
|
|
25
|
+
expect(list.has('test/A')).toBe(false)
|
|
26
|
+
expect(list.has('test/B')).toBe(true)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('configure() upserts — documented behaviour: absent extension is ADDED', () => {
|
|
30
|
+
const list = new ExtensionsList([extB])
|
|
31
|
+
// biome-ignore lint/suspicious/noExplicitAny: structural stand-in
|
|
32
|
+
list.configure(extA as any, {})
|
|
33
|
+
expect(list.has('test/A')).toBe(true)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('REGRESSION: callers forwarding settings must gate configure() on has() — the clone survives a prior remove', () => {
|
|
37
|
+
// Mirrors editor-context.tsx: settings forwarding used to call
|
|
38
|
+
// `.configure(InlineImageExtension, …)` unconditionally, and the
|
|
39
|
+
// upsert resurrected an extension the registration had deliberately
|
|
40
|
+
// removed. The gated pattern must leave the removal intact.
|
|
41
|
+
const list = new ExtensionsList([extA, extB])
|
|
42
|
+
list.remove('test/A')
|
|
43
|
+
|
|
44
|
+
const configured = list.clone()
|
|
45
|
+
if (configured.has('test/A')) {
|
|
46
|
+
// biome-ignore lint/suspicious/noExplicitAny: structural stand-in
|
|
47
|
+
configured.configure(extA as any, {})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
expect(configured.has('test/A')).toBe(false)
|
|
51
|
+
expect(configured.toArray().length).toBe(1)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('clone() is independent — mutations do not leak back', () => {
|
|
55
|
+
const list = new ExtensionsList([extA, extB])
|
|
56
|
+
const copy = list.clone()
|
|
57
|
+
copy.remove('test/B')
|
|
58
|
+
expect(list.has('test/B')).toBe(true)
|
|
59
|
+
expect(copy.has('test/B')).toBe(false)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -80,14 +80,19 @@ export function EditorContext(props: {
|
|
|
80
80
|
const extensionsList = editorConfig.extensions ?? defaultExtensionsList()
|
|
81
81
|
|
|
82
82
|
// Forward the inline-image upload collection from the settings facade
|
|
83
|
-
// onto the InlineImageExtension's typed config
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
// onto the InlineImageExtension's typed config — but ONLY when the
|
|
84
|
+
// extension is actually present. `configure()` has upsert semantics
|
|
85
|
+
// (absent → added), so an ungated call here silently resurrected
|
|
86
|
+
// InlineImageExtension on every editor build for registrations that
|
|
87
|
+
// had deliberately removed it via
|
|
88
|
+
// `lexicalEditor((c) => c.extensions.remove(builtInExtensions.InlineImage))`.
|
|
89
|
+
const configured = extensionsList.clone()
|
|
90
|
+
if (configured.has(InlineImageExtension)) {
|
|
91
|
+
configured.configure(InlineImageExtension, {
|
|
88
92
|
collection: editorConfig.settings.inlineImageUploadCollection,
|
|
89
93
|
})
|
|
90
|
-
|
|
94
|
+
}
|
|
95
|
+
const dependencies = configured.toArray()
|
|
91
96
|
|
|
92
97
|
return defineExtension({
|
|
93
98
|
name: '[root]',
|