@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,93 @@
|
|
|
1
|
+
const BLOCK_TYPES = new Set([
|
|
2
|
+
'paragraph',
|
|
3
|
+
'heading',
|
|
4
|
+
'quote',
|
|
5
|
+
'code',
|
|
6
|
+
'list',
|
|
7
|
+
'listitem',
|
|
8
|
+
'table',
|
|
9
|
+
'tablerow',
|
|
10
|
+
'tablecell',
|
|
11
|
+
'layout-container',
|
|
12
|
+
'layout-item',
|
|
13
|
+
'admonition',
|
|
14
|
+
'horizontalrule',
|
|
15
|
+
'youtube',
|
|
16
|
+
'vimeo'
|
|
17
|
+
]);
|
|
18
|
+
function isBlockType(type) {
|
|
19
|
+
return BLOCK_TYPES.has(type);
|
|
20
|
+
}
|
|
21
|
+
const INLINE_TYPES = new Set([
|
|
22
|
+
'text',
|
|
23
|
+
'linebreak',
|
|
24
|
+
'tab',
|
|
25
|
+
'link',
|
|
26
|
+
'autolink',
|
|
27
|
+
'mark',
|
|
28
|
+
'overflow',
|
|
29
|
+
'code-highlight',
|
|
30
|
+
'inline-image'
|
|
31
|
+
]);
|
|
32
|
+
function isInlineType(type) {
|
|
33
|
+
return INLINE_TYPES.has(type);
|
|
34
|
+
}
|
|
35
|
+
const urlText = (node)=>{
|
|
36
|
+
const attributes = node.attributes;
|
|
37
|
+
const url = 'string' == typeof node.url ? node.url : attributes?.url;
|
|
38
|
+
return 'string' == typeof url && url.length > 0 ? url : void 0;
|
|
39
|
+
};
|
|
40
|
+
const DECLARED_CONVERSIONS = {
|
|
41
|
+
heading: {
|
|
42
|
+
kind: 'to-paragraph'
|
|
43
|
+
},
|
|
44
|
+
quote: {
|
|
45
|
+
kind: 'to-paragraph'
|
|
46
|
+
},
|
|
47
|
+
code: {
|
|
48
|
+
kind: 'to-paragraph'
|
|
49
|
+
},
|
|
50
|
+
listitem: {
|
|
51
|
+
kind: 'to-paragraph'
|
|
52
|
+
},
|
|
53
|
+
table: {
|
|
54
|
+
kind: 'lift-blocks'
|
|
55
|
+
},
|
|
56
|
+
tablerow: {
|
|
57
|
+
kind: 'lift-blocks'
|
|
58
|
+
},
|
|
59
|
+
tablecell: {
|
|
60
|
+
kind: 'lift-blocks'
|
|
61
|
+
},
|
|
62
|
+
list: {
|
|
63
|
+
kind: 'lift-blocks'
|
|
64
|
+
},
|
|
65
|
+
'layout-container': {
|
|
66
|
+
kind: 'lift-blocks'
|
|
67
|
+
},
|
|
68
|
+
'layout-item': {
|
|
69
|
+
kind: 'lift-blocks'
|
|
70
|
+
},
|
|
71
|
+
admonition: {
|
|
72
|
+
kind: 'lift-blocks',
|
|
73
|
+
preserveText: (node)=>'string' == typeof node.title && node.title.length > 0 ? node.title : void 0
|
|
74
|
+
},
|
|
75
|
+
'code-highlight': {
|
|
76
|
+
kind: 'to-text'
|
|
77
|
+
},
|
|
78
|
+
link: {
|
|
79
|
+
kind: 'unwrap-inline',
|
|
80
|
+
preserveText: urlText
|
|
81
|
+
},
|
|
82
|
+
autolink: {
|
|
83
|
+
kind: 'unwrap-inline',
|
|
84
|
+
preserveText: urlText
|
|
85
|
+
},
|
|
86
|
+
horizontalrule: {
|
|
87
|
+
kind: 'drop'
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
function conversionFor(type) {
|
|
91
|
+
return DECLARED_CONVERSIONS[type];
|
|
92
|
+
}
|
|
93
|
+
export { BLOCK_TYPES, DECLARED_CONVERSIONS, INLINE_TYPES, conversionFor, isBlockType, isInlineType };
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
import type * as React from 'react';
|
|
9
|
+
export type NormalizationStatus = {
|
|
10
|
+
kind: 'ok';
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'adapted';
|
|
13
|
+
convertedTypes: string[];
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'refused';
|
|
16
|
+
unsupportedTypes: string[];
|
|
17
|
+
};
|
|
18
|
+
interface ContextValue {
|
|
19
|
+
status: NormalizationStatus;
|
|
20
|
+
setStatus: (status: NormalizationStatus) => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Carries how the stored value fared against this field's capabilities.
|
|
24
|
+
*
|
|
25
|
+
* Provided ABOVE the composer, like the other shared contexts, so the
|
|
26
|
+
* surface that renders the notice sits outside the editor while the
|
|
27
|
+
* plugin that discovers the status sits inside it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function NormalizationStatusProvider({ children, }: {
|
|
30
|
+
children: React.ReactNode;
|
|
31
|
+
}): React.JSX.Element;
|
|
32
|
+
export declare function useNormalizationStatus(): ContextValue;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useMemo, useState } from "react";
|
|
4
|
+
const Context = /*#__PURE__*/ createContext({
|
|
5
|
+
status: {
|
|
6
|
+
kind: 'ok'
|
|
7
|
+
},
|
|
8
|
+
setStatus: ()=>{}
|
|
9
|
+
});
|
|
10
|
+
function NormalizationStatusProvider({ children }) {
|
|
11
|
+
const [status, setStatus] = useState({
|
|
12
|
+
kind: 'ok'
|
|
13
|
+
});
|
|
14
|
+
const value = useMemo(()=>({
|
|
15
|
+
status,
|
|
16
|
+
setStatus
|
|
17
|
+
}), [
|
|
18
|
+
status
|
|
19
|
+
]);
|
|
20
|
+
return /*#__PURE__*/ jsx(Context.Provider, {
|
|
21
|
+
value: value,
|
|
22
|
+
children: children
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function useNormalizationStatus() {
|
|
26
|
+
return useContext(Context);
|
|
27
|
+
}
|
|
28
|
+
export { NormalizationStatusProvider, useNormalizationStatus };
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
import type { SerializedEditorState } from 'lexical';
|
|
9
|
+
export type NormalizeResult = {
|
|
10
|
+
status: 'unchanged';
|
|
11
|
+
} | {
|
|
12
|
+
status: 'adapted';
|
|
13
|
+
value: SerializedEditorState;
|
|
14
|
+
convertedTypes: string[];
|
|
15
|
+
} | {
|
|
16
|
+
status: 'refused';
|
|
17
|
+
unsupportedTypes: string[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Adapt a stored value to what an editor can actually accept.
|
|
21
|
+
*
|
|
22
|
+
* Lexical throws `parseEditorState: type "X" + not found` on an
|
|
23
|
+
* unregistered type and the text is unrecoverable, so a field that no
|
|
24
|
+
* longer supports a structure would otherwise open blank and erroring.
|
|
25
|
+
*
|
|
26
|
+
* Only the unsupported nodes are converted. A supported node is copied
|
|
27
|
+
* with its own properties intact — it was already in a valid position in
|
|
28
|
+
* the saved document, so its position is never changed — while its
|
|
29
|
+
* children are still inspected, because a supported parent may hold an
|
|
30
|
+
* unsupported descendant. Re-encoding supported content to fix an
|
|
31
|
+
* unrelated structure is exactly what this must not do: an inline image
|
|
32
|
+
* sitting beside a heading would lose its media relation and its
|
|
33
|
+
* nested-editor caption as collateral.
|
|
34
|
+
*
|
|
35
|
+
* The input is never mutated. Refusal wins over any conversion, so the
|
|
36
|
+
* whole tree is walked before a decision is returned.
|
|
37
|
+
*/
|
|
38
|
+
export declare function normalizeValue(value: SerializedEditorState, supportedTypes: ReadonlySet<string>): NormalizeResult;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { conversionFor, isBlockType, isInlineType } from "./declared-conversions.js";
|
|
2
|
+
const textNode = (text)=>({
|
|
3
|
+
detail: 0,
|
|
4
|
+
format: 0,
|
|
5
|
+
mode: 'normal',
|
|
6
|
+
style: '',
|
|
7
|
+
text,
|
|
8
|
+
type: 'text',
|
|
9
|
+
version: 1
|
|
10
|
+
});
|
|
11
|
+
const textFromNode = (node)=>({
|
|
12
|
+
detail: 'number' == typeof node.detail ? node.detail : 0,
|
|
13
|
+
format: 'number' == typeof node.format ? node.format : 0,
|
|
14
|
+
mode: 'string' == typeof node.mode ? node.mode : 'normal',
|
|
15
|
+
style: 'string' == typeof node.style ? node.style : '',
|
|
16
|
+
text: 'string' == typeof node.text ? node.text : '',
|
|
17
|
+
type: 'text',
|
|
18
|
+
version: 1
|
|
19
|
+
});
|
|
20
|
+
const paragraphNode = (children)=>({
|
|
21
|
+
children,
|
|
22
|
+
direction: null,
|
|
23
|
+
format: '',
|
|
24
|
+
indent: 0,
|
|
25
|
+
type: 'paragraph',
|
|
26
|
+
version: 1
|
|
27
|
+
});
|
|
28
|
+
function normalizeValue(value, supportedTypes) {
|
|
29
|
+
const converted = new Set();
|
|
30
|
+
const refused = new Set();
|
|
31
|
+
function groupIntoBlocks(nodes) {
|
|
32
|
+
const out = [];
|
|
33
|
+
let run = [];
|
|
34
|
+
const flush = ()=>{
|
|
35
|
+
if (run.length > 0) {
|
|
36
|
+
out.push(paragraphNode(run));
|
|
37
|
+
run = [];
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
for (const node of nodes){
|
|
41
|
+
if (isInlineType(node.type)) {
|
|
42
|
+
run.push(node);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (!isBlockType(node.type)) refused.add(node.type);
|
|
46
|
+
flush();
|
|
47
|
+
out.push(node);
|
|
48
|
+
}
|
|
49
|
+
flush();
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
function visit(node) {
|
|
53
|
+
const children = Array.isArray(node.children) ? node.children : void 0;
|
|
54
|
+
if ('root' === node.type || supportedTypes.has(node.type)) return null == children ? [
|
|
55
|
+
node
|
|
56
|
+
] : [
|
|
57
|
+
{
|
|
58
|
+
...node,
|
|
59
|
+
children: children.flatMap(visit)
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
const conversion = conversionFor(node.type);
|
|
63
|
+
if (null == conversion) {
|
|
64
|
+
refused.add(node.type);
|
|
65
|
+
return [
|
|
66
|
+
node
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
converted.add(node.type);
|
|
70
|
+
const preserved = conversion.preserveText?.(node);
|
|
71
|
+
const inner = (children ?? []).flatMap(visit);
|
|
72
|
+
switch(conversion.kind){
|
|
73
|
+
case 'drop':
|
|
74
|
+
return [];
|
|
75
|
+
case 'to-paragraph':
|
|
76
|
+
{
|
|
77
|
+
const children = null != preserved ? [
|
|
78
|
+
...inner,
|
|
79
|
+
textNode(` ${preserved}`)
|
|
80
|
+
] : inner;
|
|
81
|
+
const grouped = groupIntoBlocks(children);
|
|
82
|
+
return grouped.length > 0 ? grouped : [
|
|
83
|
+
paragraphNode([])
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
case 'to-text':
|
|
87
|
+
return [
|
|
88
|
+
textFromNode(node)
|
|
89
|
+
];
|
|
90
|
+
case 'lift-blocks':
|
|
91
|
+
return null != preserved ? [
|
|
92
|
+
paragraphNode([
|
|
93
|
+
textNode(preserved)
|
|
94
|
+
]),
|
|
95
|
+
...inner
|
|
96
|
+
] : inner;
|
|
97
|
+
case 'unwrap-inline':
|
|
98
|
+
return null != preserved ? [
|
|
99
|
+
...inner,
|
|
100
|
+
textNode(` ${preserved}`)
|
|
101
|
+
] : inner;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const visited = visit(value.root)[0];
|
|
105
|
+
if (refused.size > 0) return {
|
|
106
|
+
status: 'refused',
|
|
107
|
+
unsupportedTypes: [
|
|
108
|
+
...refused
|
|
109
|
+
]
|
|
110
|
+
};
|
|
111
|
+
if (0 === converted.size) return {
|
|
112
|
+
status: 'unchanged'
|
|
113
|
+
};
|
|
114
|
+
const children = Array.isArray(visited.children) ? visited.children : [];
|
|
115
|
+
const nextRoot = {
|
|
116
|
+
...visited,
|
|
117
|
+
children: children.length > 0 ? children : [
|
|
118
|
+
paragraphNode([])
|
|
119
|
+
]
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
status: 'adapted',
|
|
123
|
+
value: {
|
|
124
|
+
...value,
|
|
125
|
+
root: nextRoot
|
|
126
|
+
},
|
|
127
|
+
convertedTypes: [
|
|
128
|
+
...converted
|
|
129
|
+
]
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export { normalizeValue };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface NoticeText {
|
|
2
|
+
t: (key: string, values?: Record<string, string>) => string;
|
|
3
|
+
locale: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Translate a notice, tolerating the absence of an I18nProvider.
|
|
7
|
+
*
|
|
8
|
+
* Reads `I18nContext` directly rather than calling `useTranslation`,
|
|
9
|
+
* which throws without a provider.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useNoticeText(): NoticeText;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useContext, useMemo } from "react";
|
|
3
|
+
import { I18nContext } from "@byline/i18n/react";
|
|
4
|
+
const FALLBACKS = {
|
|
5
|
+
'richtext.adapted.notice': 'This content contains formatting this editor no longer supports. Saving edits will use the supported formatting.',
|
|
6
|
+
'richtext.unsupported.notice': 'This content contains {items}, which this field no longer supports. The field is read-only so the content is not lost.',
|
|
7
|
+
'richtext.unsupported.action': 'Ask an administrator to restore support for it, or to migrate the content.',
|
|
8
|
+
'richtext.content.image': 'an image',
|
|
9
|
+
'richtext.content.youtube': 'a YouTube embed',
|
|
10
|
+
'richtext.content.vimeo': 'a Vimeo embed'
|
|
11
|
+
};
|
|
12
|
+
function useNoticeText() {
|
|
13
|
+
const context = useContext(I18nContext);
|
|
14
|
+
return useMemo(()=>{
|
|
15
|
+
if (null == context) return {
|
|
16
|
+
locale: 'en',
|
|
17
|
+
t: (key, values)=>interpolate(FALLBACKS[key] ?? key, values)
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
locale: context.activeLocale,
|
|
21
|
+
t: (key, values)=>{
|
|
22
|
+
const translated = context.formatter.t('byline-admin', key, values);
|
|
23
|
+
return translated === key ? interpolate(FALLBACKS[key] ?? key, values) : translated;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}, [
|
|
27
|
+
context
|
|
28
|
+
]);
|
|
29
|
+
}
|
|
30
|
+
function interpolate(template, values) {
|
|
31
|
+
if (null == values) return template;
|
|
32
|
+
return template.replace(/\{(\w+)\}/g, (match, name)=>values[name] ?? match);
|
|
33
|
+
}
|
|
34
|
+
export { useNoticeText };
|
|
@@ -13,4 +13,27 @@
|
|
|
13
13
|
*
|
|
14
14
|
*/
|
|
15
15
|
import type * as React from 'react';
|
|
16
|
+
import type { LexicalEditor } from 'lexical';
|
|
17
|
+
export type BlockFormat = 'paragraph' | 'h1' | 'h2' | 'h3' | 'h4' | 'bullet' | 'number' | 'check' | 'quote' | 'code';
|
|
18
|
+
/**
|
|
19
|
+
* Block formats this editor can actually produce. Paragraph is always
|
|
20
|
+
* available.
|
|
21
|
+
*
|
|
22
|
+
* Structural availability comes from REGISTERED NODES, not from whether
|
|
23
|
+
* an extension appears in the configuration list: table and list nodes
|
|
24
|
+
* arrive through `@lexical/table` and `@lexical/list` dependencies, so a
|
|
25
|
+
* membership test would be wrong for exactly those cases.
|
|
26
|
+
*
|
|
27
|
+
* Registered nodes are necessary but not always sufficient.
|
|
28
|
+
* `hasCheckListBehaviour` is passed in because check lists need
|
|
29
|
+
* `CheckListExtension` registered as well as the list nodes — removing
|
|
30
|
+
* that extension alone leaves `ListNode` and `ListItemNode` in place, so
|
|
31
|
+
* a node-only rule would keep offering a control that no longer works.
|
|
32
|
+
*
|
|
33
|
+
* This is a correctness concern rather than a cosmetic one: creating an
|
|
34
|
+
* unregistered node throws "Attempted to create node X that was not
|
|
35
|
+
* configured to be used on the editor", so an offered-but-unsupported
|
|
36
|
+
* format is a crash.
|
|
37
|
+
*/
|
|
38
|
+
export declare function availableBlockFormats(editor: LexicalEditor, hasCheckListBehaviour: boolean): BlockFormat[];
|
|
16
39
|
export declare function ToolbarPlugin(): React.JSX.Element;
|