@yurikilian/lex4 1.4.1 → 1.5.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.
- package/README.md +6 -4
- package/dist/ast/inline-mapper.d.ts.map +1 -1
- package/dist/ast/types.d.ts +1 -1
- package/dist/ast/types.d.ts.map +1 -1
- package/dist/components/BlockTypePicker.d.ts +11 -0
- package/dist/components/BlockTypePicker.d.ts.map +1 -0
- package/dist/components/CanvasControls.d.ts.map +1 -1
- package/dist/components/HeaderFooterToggle.d.ts +1 -0
- package/dist/components/HeaderFooterToggle.d.ts.map +1 -1
- package/dist/components/Lex4Editor.d.ts.map +1 -1
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/context/document-context.d.ts +1 -0
- package/dist/context/document-context.d.ts.map +1 -1
- package/dist/context/document-provider.d.ts.map +1 -1
- package/dist/context/toolbar-config.d.ts +18 -0
- package/dist/context/toolbar-config.d.ts.map +1 -0
- package/dist/extensions/variables-extension.d.ts.map +1 -1
- package/dist/i18n/defaults.d.ts.map +1 -1
- package/dist/i18n/pt-BR.d.ts.map +1 -1
- package/dist/i18n/types.d.ts +12 -0
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lex4-editor.cjs +845 -163
- package/dist/lex4-editor.cjs.map +1 -1
- package/dist/lex4-editor.js +829 -147
- package/dist/lex4-editor.js.map +1 -1
- package/dist/lexical/commands/block-commands.d.ts +5 -0
- package/dist/lexical/commands/block-commands.d.ts.map +1 -0
- package/dist/lexical/theme.d.ts.map +1 -1
- package/dist/lexical/utils/import-document-content.d.ts +4 -0
- package/dist/lexical/utils/import-document-content.d.ts.map +1 -0
- package/dist/style.css +156 -25
- package/dist/types/editor-handle.d.ts +2 -0
- package/dist/types/editor-handle.d.ts.map +1 -1
- package/dist/types/editor-props.d.ts +16 -0
- package/dist/types/editor-props.d.ts.map +1 -1
- package/dist/utils/text-style.d.ts +7 -0
- package/dist/utils/text-style.d.ts.map +1 -0
- package/dist/variables/variable-formatting.d.ts +11 -0
- package/dist/variables/variable-formatting.d.ts.map +1 -0
- package/dist/variables/variable-node.d.ts +10 -2
- package/dist/variables/variable-node.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/lex4-editor.js
CHANGED
|
@@ -3,16 +3,18 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
5
5
|
import React, { createContext, useContext, useMemo, useReducer, useState, useRef, useCallback, useEffect, forwardRef, createElement, useImperativeHandle } from "react";
|
|
6
|
-
import { $getRoot, $createRangeSelectionFromDom, $getSelection, $isRangeSelection, $isTextNode, FORMAT_ELEMENT_COMMAND, FORMAT_TEXT_COMMAND, OUTDENT_CONTENT_COMMAND, INDENT_CONTENT_COMMAND, $
|
|
6
|
+
import { $getRoot, $createRangeSelectionFromDom, $getSelection, $isRangeSelection, $isTextNode, FORMAT_ELEMENT_COMMAND, FORMAT_TEXT_COMMAND, OUTDENT_CONTENT_COMMAND, INDENT_CONTENT_COMMAND, $createParagraphNode, $applyNodeReplacement, DecoratorNode, KEY_BACKSPACE_COMMAND, COMMAND_PRIORITY_LOW, KEY_DELETE_COMMAND, $isNodeSelection, $getNodeByKey, $selectAll, SELECTION_CHANGE_COMMAND, KEY_TAB_COMMAND, $isElementNode, $isParagraphNode, $setSelection, FOCUS_COMMAND, $splitNode, $getNearestNodeFromDOMNode, CONTROLLED_TEXT_INSERTION_COMMAND, KEY_DOWN_COMMAND, PASTE_COMMAND, KEY_ENTER_COMMAND, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_CRITICAL, $insertNodes, $createLineBreakNode, $createTextNode, createCommand, COMMAND_PRIORITY_EDITOR } from "lexical";
|
|
7
7
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
8
|
-
import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, ListNode, ListItemNode, $isListNode } from "@lexical/list";
|
|
8
|
+
import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, ListNode, ListItemNode, $isListNode, $createListItemNode, $createListNode } from "@lexical/list";
|
|
9
|
+
import { $setBlocksType } from "@lexical/selection";
|
|
10
|
+
import { $createHeadingNode, $isHeadingNode, HeadingNode, QuoteNode, $createQuoteNode } from "@lexical/rich-text";
|
|
11
|
+
import { useLexicalNodeSelection } from "@lexical/react/useLexicalNodeSelection";
|
|
9
12
|
import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
10
13
|
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
11
14
|
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
12
15
|
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
|
|
13
16
|
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
14
17
|
import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
|
|
15
|
-
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
|
|
16
18
|
function createEmptyPage(id) {
|
|
17
19
|
return {
|
|
18
20
|
id: id ?? crypto.randomUUID(),
|
|
@@ -471,6 +473,15 @@ const DEFAULT_TRANSLATIONS = {
|
|
|
471
473
|
bulletList: "Bullet List",
|
|
472
474
|
indent: "Indent",
|
|
473
475
|
outdent: "Outdent",
|
|
476
|
+
history: "History",
|
|
477
|
+
blockType: "Block type",
|
|
478
|
+
paragraph: "Paragraph",
|
|
479
|
+
heading1: "Heading 1",
|
|
480
|
+
heading2: "Heading 2",
|
|
481
|
+
heading3: "Heading 3",
|
|
482
|
+
heading4: "Heading 4",
|
|
483
|
+
heading5: "Heading 5",
|
|
484
|
+
heading6: "Heading 6",
|
|
474
485
|
openHistory: "Open History",
|
|
475
486
|
closeHistory: "Close History"
|
|
476
487
|
},
|
|
@@ -502,7 +513,9 @@ const DEFAULT_TRANSLATIONS = {
|
|
|
502
513
|
indentedContent: "Indented content",
|
|
503
514
|
outdentedContent: "Outdented content",
|
|
504
515
|
fontChanged: "Font changed to {{value}}",
|
|
505
|
-
fontSizeChanged: "Font size changed to {{value}}pt"
|
|
516
|
+
fontSizeChanged: "Font size changed to {{value}}pt",
|
|
517
|
+
blockTypeChanged: "Block type changed to {{value}}",
|
|
518
|
+
insertedDocumentContent: "Inserted document content"
|
|
506
519
|
}
|
|
507
520
|
},
|
|
508
521
|
variables: {
|
|
@@ -602,6 +615,15 @@ const PT_BR_TRANSLATIONS = {
|
|
|
602
615
|
bulletList: "Lista com Marcadores",
|
|
603
616
|
indent: "Aumentar Recuo",
|
|
604
617
|
outdent: "Diminuir Recuo",
|
|
618
|
+
history: "Histórico",
|
|
619
|
+
blockType: "Tipo de bloco",
|
|
620
|
+
paragraph: "Parágrafo",
|
|
621
|
+
heading1: "Título 1",
|
|
622
|
+
heading2: "Título 2",
|
|
623
|
+
heading3: "Título 3",
|
|
624
|
+
heading4: "Título 4",
|
|
625
|
+
heading5: "Título 5",
|
|
626
|
+
heading6: "Título 6",
|
|
605
627
|
openHistory: "Abrir Histórico",
|
|
606
628
|
closeHistory: "Fechar Histórico"
|
|
607
629
|
},
|
|
@@ -633,7 +655,9 @@ const PT_BR_TRANSLATIONS = {
|
|
|
633
655
|
indentedContent: "Conteúdo recuado",
|
|
634
656
|
outdentedContent: "Recuo reduzido",
|
|
635
657
|
fontChanged: "Fonte alterada para {{value}}",
|
|
636
|
-
fontSizeChanged: "Tamanho da fonte alterado para {{value}}pt"
|
|
658
|
+
fontSizeChanged: "Tamanho da fonte alterado para {{value}}pt",
|
|
659
|
+
blockTypeChanged: "Tipo de bloco alterado para {{value}}",
|
|
660
|
+
insertedDocumentContent: "Conteúdo do documento inserido"
|
|
637
661
|
}
|
|
638
662
|
},
|
|
639
663
|
variables: {
|
|
@@ -1284,6 +1308,7 @@ const DocumentProvider = ({
|
|
|
1284
1308
|
activePageId,
|
|
1285
1309
|
setActivePageId,
|
|
1286
1310
|
activeEditor: activeEditorRef.current,
|
|
1311
|
+
activeCaretPosition: activeCaretPositionRef.current,
|
|
1287
1312
|
consumePendingCaretPosition,
|
|
1288
1313
|
consumePendingFocusAtEnd,
|
|
1289
1314
|
requestFocusAtEnd,
|
|
@@ -1433,33 +1458,33 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
1433
1458
|
* This source code is licensed under the ISC license.
|
|
1434
1459
|
* See the LICENSE file in the root directory of this source tree.
|
|
1435
1460
|
*/
|
|
1436
|
-
const __iconNode$
|
|
1461
|
+
const __iconNode$q = [
|
|
1437
1462
|
["path", { d: "m15 16 2.536-7.328a1.02 1.02 1 0 1 1.928 0L22 16", key: "xik6mr" }],
|
|
1438
1463
|
["path", { d: "M15.697 14h5.606", key: "1stdlc" }],
|
|
1439
1464
|
["path", { d: "m2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16", key: "d5nyq2" }],
|
|
1440
1465
|
["path", { d: "M3.304 13h6.392", key: "1q3zxz" }]
|
|
1441
1466
|
];
|
|
1442
|
-
const ALargeSmall = createLucideIcon("a-large-small", __iconNode$
|
|
1467
|
+
const ALargeSmall = createLucideIcon("a-large-small", __iconNode$q);
|
|
1443
1468
|
/**
|
|
1444
1469
|
* @license lucide-react v1.8.0 - ISC
|
|
1445
1470
|
*
|
|
1446
1471
|
* This source code is licensed under the ISC license.
|
|
1447
1472
|
* See the LICENSE file in the root directory of this source tree.
|
|
1448
1473
|
*/
|
|
1449
|
-
const __iconNode$
|
|
1474
|
+
const __iconNode$p = [
|
|
1450
1475
|
[
|
|
1451
1476
|
"path",
|
|
1452
1477
|
{ d: "M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8", key: "mg9rjx" }
|
|
1453
1478
|
]
|
|
1454
1479
|
];
|
|
1455
|
-
const Bold = createLucideIcon("bold", __iconNode$
|
|
1480
|
+
const Bold = createLucideIcon("bold", __iconNode$p);
|
|
1456
1481
|
/**
|
|
1457
1482
|
* @license lucide-react v1.8.0 - ISC
|
|
1458
1483
|
*
|
|
1459
1484
|
* This source code is licensed under the ISC license.
|
|
1460
1485
|
* See the LICENSE file in the root directory of this source tree.
|
|
1461
1486
|
*/
|
|
1462
|
-
const __iconNode$
|
|
1487
|
+
const __iconNode$o = [
|
|
1463
1488
|
[
|
|
1464
1489
|
"path",
|
|
1465
1490
|
{ d: "M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1", key: "ezmyqa" }
|
|
@@ -1472,7 +1497,15 @@ const __iconNode$n = [
|
|
|
1472
1497
|
}
|
|
1473
1498
|
]
|
|
1474
1499
|
];
|
|
1475
|
-
const Braces = createLucideIcon("braces", __iconNode$
|
|
1500
|
+
const Braces = createLucideIcon("braces", __iconNode$o);
|
|
1501
|
+
/**
|
|
1502
|
+
* @license lucide-react v1.8.0 - ISC
|
|
1503
|
+
*
|
|
1504
|
+
* This source code is licensed under the ISC license.
|
|
1505
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1506
|
+
*/
|
|
1507
|
+
const __iconNode$n = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
1508
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$n);
|
|
1476
1509
|
/**
|
|
1477
1510
|
* @license lucide-react v1.8.0 - ISC
|
|
1478
1511
|
*
|
|
@@ -1890,6 +1923,36 @@ const HistorySidebar = () => {
|
|
|
1890
1923
|
}
|
|
1891
1924
|
);
|
|
1892
1925
|
};
|
|
1926
|
+
const DEFAULT_TOOLBAR_CONTROL_CONFIG = {
|
|
1927
|
+
visible: true,
|
|
1928
|
+
showLabel: true
|
|
1929
|
+
};
|
|
1930
|
+
const DEFAULT_TOOLBAR_CONFIG = {
|
|
1931
|
+
history: DEFAULT_TOOLBAR_CONTROL_CONFIG,
|
|
1932
|
+
variables: DEFAULT_TOOLBAR_CONTROL_CONFIG,
|
|
1933
|
+
headerFooter: DEFAULT_TOOLBAR_CONTROL_CONFIG
|
|
1934
|
+
};
|
|
1935
|
+
const ToolbarConfigContext = createContext(DEFAULT_TOOLBAR_CONFIG);
|
|
1936
|
+
function resolveControlConfig(config) {
|
|
1937
|
+
return {
|
|
1938
|
+
visible: (config == null ? void 0 : config.visible) ?? true,
|
|
1939
|
+
showLabel: (config == null ? void 0 : config.showLabel) ?? true
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
function normalizeToolbarConfig(config) {
|
|
1943
|
+
return {
|
|
1944
|
+
history: resolveControlConfig(config == null ? void 0 : config.history),
|
|
1945
|
+
variables: resolveControlConfig(config == null ? void 0 : config.variables),
|
|
1946
|
+
headerFooter: resolveControlConfig(config == null ? void 0 : config.headerFooter)
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
const ToolbarConfigProvider = ({ toolbar, children }) => {
|
|
1950
|
+
const resolvedConfig = useMemo(() => normalizeToolbarConfig(toolbar), [toolbar]);
|
|
1951
|
+
return /* @__PURE__ */ jsx(ToolbarConfigContext.Provider, { value: resolvedConfig, children });
|
|
1952
|
+
};
|
|
1953
|
+
function useToolbarConfig() {
|
|
1954
|
+
return useContext(ToolbarConfigContext);
|
|
1955
|
+
}
|
|
1893
1956
|
function resolveExtensions(extensions) {
|
|
1894
1957
|
const resolved = {
|
|
1895
1958
|
nodes: [],
|
|
@@ -2022,6 +2085,7 @@ const SUPPORTED_FONT_SIZES = [
|
|
|
2022
2085
|
48,
|
|
2023
2086
|
72
|
|
2024
2087
|
];
|
|
2088
|
+
const DEFAULT_FONT_SIZE = 12;
|
|
2025
2089
|
function applyFontSize(editor, size) {
|
|
2026
2090
|
editor.update(() => {
|
|
2027
2091
|
const selection = $getSelection();
|
|
@@ -2072,9 +2136,495 @@ function indentContent(editor) {
|
|
|
2072
2136
|
function outdentContent(editor) {
|
|
2073
2137
|
editor.dispatchCommand(OUTDENT_CONTENT_COMMAND, void 0);
|
|
2074
2138
|
}
|
|
2139
|
+
function setBlockType(editor, blockType) {
|
|
2140
|
+
editor.update(() => {
|
|
2141
|
+
const selection = $getSelection();
|
|
2142
|
+
if (!$isRangeSelection(selection)) {
|
|
2143
|
+
return;
|
|
2144
|
+
}
|
|
2145
|
+
if (blockType === "paragraph") {
|
|
2146
|
+
$setBlocksType(selection, () => $createParagraphNode());
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
$setBlocksType(selection, () => $createHeadingNode(blockType));
|
|
2150
|
+
});
|
|
2151
|
+
}
|
|
2152
|
+
function getActiveBlockType(editor) {
|
|
2153
|
+
let blockType = "paragraph";
|
|
2154
|
+
editor.getEditorState().read(() => {
|
|
2155
|
+
const selection = $getSelection();
|
|
2156
|
+
if (!$isRangeSelection(selection)) {
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
const anchorNode = selection.anchor.getNode();
|
|
2160
|
+
const topLevelElement = anchorNode.getTopLevelElementOrThrow();
|
|
2161
|
+
if ($isHeadingNode(topLevelElement)) {
|
|
2162
|
+
blockType = topLevelElement.getTag();
|
|
2163
|
+
}
|
|
2164
|
+
});
|
|
2165
|
+
return blockType;
|
|
2166
|
+
}
|
|
2167
|
+
function extractStyleValue(style, property) {
|
|
2168
|
+
const escapedProperty = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2169
|
+
const match = style.match(new RegExp(`${escapedProperty}:\\s*([^;]+)`));
|
|
2170
|
+
return match ? match[1].trim().replace(/['"]/g, "") : void 0;
|
|
2171
|
+
}
|
|
2172
|
+
function mergeStyleDeclaration(existingStyle, property, value) {
|
|
2173
|
+
const escapedProperty = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2174
|
+
const stripped = existingStyle.replace(
|
|
2175
|
+
new RegExp(`${escapedProperty}:\\s*[^;]+;?\\s*`, "g"),
|
|
2176
|
+
""
|
|
2177
|
+
).trim();
|
|
2178
|
+
const declaration = `${property}: ${value}`;
|
|
2179
|
+
return stripped ? `${stripped}; ${declaration}` : declaration;
|
|
2180
|
+
}
|
|
2181
|
+
function extractFontFamilyFromStyle(style) {
|
|
2182
|
+
return extractStyleValue(style, "font-family");
|
|
2183
|
+
}
|
|
2184
|
+
function extractFontSizePtFromStyle(style) {
|
|
2185
|
+
const value = extractStyleValue(style, "font-size");
|
|
2186
|
+
if (!value) {
|
|
2187
|
+
return void 0;
|
|
2188
|
+
}
|
|
2189
|
+
const match = value.match(/^(\d+(?:\.\d+)?)\s*pt$/);
|
|
2190
|
+
return match ? parseFloat(match[1]) : void 0;
|
|
2191
|
+
}
|
|
2192
|
+
function mergeFontFamilyStyle(existingStyle, fontFamily) {
|
|
2193
|
+
return mergeStyleDeclaration(existingStyle, "font-family", fontFamily);
|
|
2194
|
+
}
|
|
2195
|
+
function mergeFontSizeStyle(existingStyle, size) {
|
|
2196
|
+
return mergeStyleDeclaration(existingStyle, "font-size", `${size}pt`);
|
|
2197
|
+
}
|
|
2198
|
+
const EMPTY_CONTEXT = {
|
|
2199
|
+
definitions: [],
|
|
2200
|
+
refreshDefinitions: () => {
|
|
2201
|
+
},
|
|
2202
|
+
getDefinition: () => void 0
|
|
2203
|
+
};
|
|
2204
|
+
const VariableContext = createContext(EMPTY_CONTEXT);
|
|
2205
|
+
const VariableProvider = ({
|
|
2206
|
+
initialDefinitions = [],
|
|
2207
|
+
children
|
|
2208
|
+
}) => {
|
|
2209
|
+
const [definitions, setDefinitions] = useState(initialDefinitions);
|
|
2210
|
+
const refresh = useCallback((newDefinitions) => {
|
|
2211
|
+
setDefinitions(newDefinitions);
|
|
2212
|
+
}, []);
|
|
2213
|
+
const getDefinition = useCallback(
|
|
2214
|
+
(key) => {
|
|
2215
|
+
return definitions.find((d) => d.key === key);
|
|
2216
|
+
},
|
|
2217
|
+
[definitions]
|
|
2218
|
+
);
|
|
2219
|
+
const value = useMemo(
|
|
2220
|
+
() => ({ definitions, refreshDefinitions: refresh, getDefinition }),
|
|
2221
|
+
[definitions, refresh, getDefinition]
|
|
2222
|
+
);
|
|
2223
|
+
return /* @__PURE__ */ jsx(VariableContext.Provider, { value, children });
|
|
2224
|
+
};
|
|
2225
|
+
function useVariables() {
|
|
2226
|
+
return useContext(VariableContext);
|
|
2227
|
+
}
|
|
2228
|
+
class VariableNode extends DecoratorNode {
|
|
2229
|
+
constructor(variableKey, format = 0, style = "", key) {
|
|
2230
|
+
super(key);
|
|
2231
|
+
__publicField(this, "__variableKey");
|
|
2232
|
+
__publicField(this, "__format");
|
|
2233
|
+
__publicField(this, "__style");
|
|
2234
|
+
this.__variableKey = variableKey;
|
|
2235
|
+
this.__format = format;
|
|
2236
|
+
this.__style = style;
|
|
2237
|
+
}
|
|
2238
|
+
static getType() {
|
|
2239
|
+
return "variable-node";
|
|
2240
|
+
}
|
|
2241
|
+
static clone(node) {
|
|
2242
|
+
return new VariableNode(node.__variableKey, node.__format, node.__style, node.__key);
|
|
2243
|
+
}
|
|
2244
|
+
getVariableKey() {
|
|
2245
|
+
return this.getLatest().__variableKey;
|
|
2246
|
+
}
|
|
2247
|
+
getFormat() {
|
|
2248
|
+
return this.getLatest().__format;
|
|
2249
|
+
}
|
|
2250
|
+
setFormat(format) {
|
|
2251
|
+
const writable = this.getWritable();
|
|
2252
|
+
writable.__format = format;
|
|
2253
|
+
return writable;
|
|
2254
|
+
}
|
|
2255
|
+
getStyle() {
|
|
2256
|
+
return this.getLatest().__style;
|
|
2257
|
+
}
|
|
2258
|
+
setStyle(style) {
|
|
2259
|
+
const writable = this.getWritable();
|
|
2260
|
+
writable.__style = style;
|
|
2261
|
+
return writable;
|
|
2262
|
+
}
|
|
2263
|
+
// -- Serialization --
|
|
2264
|
+
static importJSON(serializedNode) {
|
|
2265
|
+
return $createVariableNode(
|
|
2266
|
+
serializedNode.variableKey,
|
|
2267
|
+
serializedNode.format ?? 0,
|
|
2268
|
+
serializedNode.style ?? ""
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
exportJSON() {
|
|
2272
|
+
return {
|
|
2273
|
+
type: "variable-node",
|
|
2274
|
+
version: 1,
|
|
2275
|
+
variableKey: this.__variableKey,
|
|
2276
|
+
format: this.__format,
|
|
2277
|
+
style: this.__style
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
// -- DOM --
|
|
2281
|
+
createDOM() {
|
|
2282
|
+
const span = document.createElement("span");
|
|
2283
|
+
span.className = "lex4-variable";
|
|
2284
|
+
span.setAttribute("data-variable-key", this.__variableKey);
|
|
2285
|
+
span.setAttribute("data-testid", `variable-${this.__variableKey}`);
|
|
2286
|
+
span.contentEditable = "false";
|
|
2287
|
+
return span;
|
|
2288
|
+
}
|
|
2289
|
+
updateDOM() {
|
|
2290
|
+
return false;
|
|
2291
|
+
}
|
|
2292
|
+
exportDOM() {
|
|
2293
|
+
const span = document.createElement("span");
|
|
2294
|
+
span.setAttribute("data-variable-key", this.__variableKey);
|
|
2295
|
+
span.textContent = `{{${this.__variableKey}}}`;
|
|
2296
|
+
return { element: span };
|
|
2297
|
+
}
|
|
2298
|
+
static importDOM() {
|
|
2299
|
+
return null;
|
|
2300
|
+
}
|
|
2301
|
+
// -- Behavior --
|
|
2302
|
+
isInline() {
|
|
2303
|
+
return true;
|
|
2304
|
+
}
|
|
2305
|
+
isKeyboardSelectable() {
|
|
2306
|
+
return true;
|
|
2307
|
+
}
|
|
2308
|
+
getTextContent() {
|
|
2309
|
+
return `{{${this.__variableKey}}}`;
|
|
2310
|
+
}
|
|
2311
|
+
// -- Rendering --
|
|
2312
|
+
decorate() {
|
|
2313
|
+
return /* @__PURE__ */ jsx(
|
|
2314
|
+
VariableChip,
|
|
2315
|
+
{
|
|
2316
|
+
nodeKey: this.__key,
|
|
2317
|
+
variableKey: this.__variableKey,
|
|
2318
|
+
format: this.__format,
|
|
2319
|
+
styleValue: this.__style
|
|
2320
|
+
}
|
|
2321
|
+
);
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
function VariableChip({
|
|
2325
|
+
nodeKey,
|
|
2326
|
+
variableKey,
|
|
2327
|
+
format,
|
|
2328
|
+
styleValue
|
|
2329
|
+
}) {
|
|
2330
|
+
const { getDefinition } = useVariables();
|
|
2331
|
+
const [editor] = useLexicalComposerContext();
|
|
2332
|
+
const [isSelected, setSelected, clearOtherSelections] = useLexicalNodeSelection(nodeKey);
|
|
2333
|
+
const def = getDefinition(variableKey);
|
|
2334
|
+
const label = (def == null ? void 0 : def.label) ?? variableKey;
|
|
2335
|
+
const group = def == null ? void 0 : def.group;
|
|
2336
|
+
const style = useMemo(() => {
|
|
2337
|
+
const fontFamily = extractFontFamilyFromStyle(styleValue);
|
|
2338
|
+
const fontSize = extractFontSizePtFromStyle(styleValue);
|
|
2339
|
+
return {
|
|
2340
|
+
...fontFamily ? { fontFamily } : {},
|
|
2341
|
+
...fontSize ? { fontSize: `${fontSize}pt` } : {}
|
|
2342
|
+
};
|
|
2343
|
+
}, [styleValue]);
|
|
2344
|
+
const className = [
|
|
2345
|
+
"lex4-variable-chip",
|
|
2346
|
+
isSelected && "lex4-variable-chip-selected",
|
|
2347
|
+
format & 1 ? "lex4-text-bold" : "",
|
|
2348
|
+
format & 2 ? "lex4-text-italic" : "",
|
|
2349
|
+
format & 8 ? "lex4-text-underline" : "",
|
|
2350
|
+
format & 4 ? "lex4-text-strikethrough" : ""
|
|
2351
|
+
].filter(Boolean).join(" ");
|
|
2352
|
+
const handleClick = useCallback((event) => {
|
|
2353
|
+
event.preventDefault();
|
|
2354
|
+
if (!event.shiftKey) {
|
|
2355
|
+
clearOtherSelections();
|
|
2356
|
+
}
|
|
2357
|
+
setSelected(!isSelected);
|
|
2358
|
+
}, [clearOtherSelections, isSelected, setSelected]);
|
|
2359
|
+
useEffect(() => {
|
|
2360
|
+
const removeSelectedNodes = () => {
|
|
2361
|
+
editor.update(() => {
|
|
2362
|
+
const selection = $getSelection();
|
|
2363
|
+
if (!$isNodeSelection(selection)) {
|
|
2364
|
+
const node = $getNodeByKey(nodeKey);
|
|
2365
|
+
if ($isVariableNode(node)) {
|
|
2366
|
+
node.remove();
|
|
2367
|
+
}
|
|
2368
|
+
return;
|
|
2369
|
+
}
|
|
2370
|
+
for (const node of selection.getNodes()) {
|
|
2371
|
+
if ($isVariableNode(node)) {
|
|
2372
|
+
node.remove();
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
});
|
|
2376
|
+
};
|
|
2377
|
+
const unregisterBackspace = editor.registerCommand(
|
|
2378
|
+
KEY_BACKSPACE_COMMAND,
|
|
2379
|
+
() => {
|
|
2380
|
+
if (!isSelected) {
|
|
2381
|
+
return false;
|
|
2382
|
+
}
|
|
2383
|
+
removeSelectedNodes();
|
|
2384
|
+
return true;
|
|
2385
|
+
},
|
|
2386
|
+
COMMAND_PRIORITY_LOW
|
|
2387
|
+
);
|
|
2388
|
+
const unregisterDelete = editor.registerCommand(
|
|
2389
|
+
KEY_DELETE_COMMAND,
|
|
2390
|
+
() => {
|
|
2391
|
+
if (!isSelected) {
|
|
2392
|
+
return false;
|
|
2393
|
+
}
|
|
2394
|
+
removeSelectedNodes();
|
|
2395
|
+
return true;
|
|
2396
|
+
},
|
|
2397
|
+
COMMAND_PRIORITY_LOW
|
|
2398
|
+
);
|
|
2399
|
+
return () => {
|
|
2400
|
+
unregisterBackspace();
|
|
2401
|
+
unregisterDelete();
|
|
2402
|
+
};
|
|
2403
|
+
}, [editor, isSelected, nodeKey]);
|
|
2404
|
+
return /* @__PURE__ */ jsx(
|
|
2405
|
+
"span",
|
|
2406
|
+
{
|
|
2407
|
+
className,
|
|
2408
|
+
"data-testid": `variable-chip-${variableKey}`,
|
|
2409
|
+
"data-variable-group": group,
|
|
2410
|
+
title: variableKey,
|
|
2411
|
+
style,
|
|
2412
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
2413
|
+
onClick: handleClick,
|
|
2414
|
+
children: label
|
|
2415
|
+
}
|
|
2416
|
+
);
|
|
2417
|
+
}
|
|
2418
|
+
function $createVariableNode(variableKey, format = 0, style = "") {
|
|
2419
|
+
return $applyNodeReplacement(new VariableNode(variableKey, format, style));
|
|
2420
|
+
}
|
|
2421
|
+
function $isVariableNode(node) {
|
|
2422
|
+
return node instanceof VariableNode;
|
|
2423
|
+
}
|
|
2424
|
+
const FORMAT_MASKS = {
|
|
2425
|
+
bold: 1,
|
|
2426
|
+
italic: 2,
|
|
2427
|
+
strikethrough: 4,
|
|
2428
|
+
underline: 8
|
|
2429
|
+
};
|
|
2430
|
+
function withSelectedVariableNodes(editor, updater) {
|
|
2431
|
+
let updated = false;
|
|
2432
|
+
editor.update(() => {
|
|
2433
|
+
const selection = $getSelection();
|
|
2434
|
+
if (!$isNodeSelection(selection)) {
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
const nodes = selection.getNodes().filter($isVariableNode);
|
|
2438
|
+
if (nodes.length === 0) {
|
|
2439
|
+
return;
|
|
2440
|
+
}
|
|
2441
|
+
updater(nodes);
|
|
2442
|
+
updated = true;
|
|
2443
|
+
});
|
|
2444
|
+
return updated;
|
|
2445
|
+
}
|
|
2446
|
+
function getSelectedVariableNodes(editor) {
|
|
2447
|
+
let nodes = [];
|
|
2448
|
+
editor.getEditorState().read(() => {
|
|
2449
|
+
const selection = $getSelection();
|
|
2450
|
+
if (!$isNodeSelection(selection)) {
|
|
2451
|
+
return;
|
|
2452
|
+
}
|
|
2453
|
+
nodes = selection.getNodes().filter($isVariableNode);
|
|
2454
|
+
});
|
|
2455
|
+
return nodes;
|
|
2456
|
+
}
|
|
2457
|
+
function toggleSelectedVariableFormat(editor, format) {
|
|
2458
|
+
const mask = FORMAT_MASKS[format];
|
|
2459
|
+
if (!mask) {
|
|
2460
|
+
return false;
|
|
2461
|
+
}
|
|
2462
|
+
return withSelectedVariableNodes(editor, (nodes) => {
|
|
2463
|
+
const shouldEnable = nodes.some((node) => (node.getFormat() & mask) === 0);
|
|
2464
|
+
for (const node of nodes) {
|
|
2465
|
+
const nextFormat = shouldEnable ? node.getFormat() | mask : node.getFormat() & ~mask;
|
|
2466
|
+
node.setFormat(nextFormat);
|
|
2467
|
+
}
|
|
2468
|
+
});
|
|
2469
|
+
}
|
|
2470
|
+
function applyFontFamilyToSelectedVariables(editor, fontFamily) {
|
|
2471
|
+
return withSelectedVariableNodes(editor, (nodes) => {
|
|
2472
|
+
for (const node of nodes) {
|
|
2473
|
+
node.setStyle(mergeFontFamilyStyle(node.getStyle(), fontFamily));
|
|
2474
|
+
}
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
function applyFontSizeToSelectedVariables(editor, size) {
|
|
2478
|
+
return withSelectedVariableNodes(editor, (nodes) => {
|
|
2479
|
+
for (const node of nodes) {
|
|
2480
|
+
node.setStyle(mergeFontSizeStyle(node.getStyle(), size));
|
|
2481
|
+
}
|
|
2482
|
+
});
|
|
2483
|
+
}
|
|
2484
|
+
function readSelectedVariableFormatting(editor) {
|
|
2485
|
+
const firstNode = getSelectedVariableNodes(editor)[0];
|
|
2486
|
+
if (!firstNode) {
|
|
2487
|
+
return {};
|
|
2488
|
+
}
|
|
2489
|
+
const style = firstNode.getStyle();
|
|
2490
|
+
return {
|
|
2491
|
+
fontFamily: extractFontFamilyFromStyle(style),
|
|
2492
|
+
fontSize: extractFontSizePtFromStyle(style)
|
|
2493
|
+
};
|
|
2494
|
+
}
|
|
2495
|
+
const BLOCK_TYPE_OPTIONS = [
|
|
2496
|
+
{ value: "paragraph", shortLabel: "P" },
|
|
2497
|
+
{ value: "h1", shortLabel: "H1" },
|
|
2498
|
+
{ value: "h2", shortLabel: "H2" },
|
|
2499
|
+
{ value: "h3", shortLabel: "H3" },
|
|
2500
|
+
{ value: "h4", shortLabel: "H4" },
|
|
2501
|
+
{ value: "h5", shortLabel: "H5" },
|
|
2502
|
+
{ value: "h6", shortLabel: "H6" }
|
|
2503
|
+
];
|
|
2504
|
+
function getBlockTypeLabel(t, blockType) {
|
|
2505
|
+
switch (blockType) {
|
|
2506
|
+
case "h1":
|
|
2507
|
+
return t.toolbar.heading1;
|
|
2508
|
+
case "h2":
|
|
2509
|
+
return t.toolbar.heading2;
|
|
2510
|
+
case "h3":
|
|
2511
|
+
return t.toolbar.heading3;
|
|
2512
|
+
case "h4":
|
|
2513
|
+
return t.toolbar.heading4;
|
|
2514
|
+
case "h5":
|
|
2515
|
+
return t.toolbar.heading5;
|
|
2516
|
+
case "h6":
|
|
2517
|
+
return t.toolbar.heading6;
|
|
2518
|
+
default:
|
|
2519
|
+
return t.toolbar.paragraph;
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
function getBlockTypeShortLabel(blockType) {
|
|
2523
|
+
var _a;
|
|
2524
|
+
return ((_a = BLOCK_TYPE_OPTIONS.find((option) => option.value === blockType)) == null ? void 0 : _a.shortLabel) ?? "P";
|
|
2525
|
+
}
|
|
2526
|
+
const BlockTypePicker = ({ value, onChange }) => {
|
|
2527
|
+
const t = useTranslations();
|
|
2528
|
+
const [open, setOpen] = useState(false);
|
|
2529
|
+
const containerRef = useRef(null);
|
|
2530
|
+
useEffect(() => {
|
|
2531
|
+
if (!open) {
|
|
2532
|
+
return;
|
|
2533
|
+
}
|
|
2534
|
+
const handleClickOutside = (event) => {
|
|
2535
|
+
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
2536
|
+
setOpen(false);
|
|
2537
|
+
}
|
|
2538
|
+
};
|
|
2539
|
+
const handleEscape = (event) => {
|
|
2540
|
+
if (event.key === "Escape") {
|
|
2541
|
+
setOpen(false);
|
|
2542
|
+
}
|
|
2543
|
+
};
|
|
2544
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2545
|
+
document.addEventListener("keydown", handleEscape);
|
|
2546
|
+
return () => {
|
|
2547
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
2548
|
+
document.removeEventListener("keydown", handleEscape);
|
|
2549
|
+
};
|
|
2550
|
+
}, [open]);
|
|
2551
|
+
return /* @__PURE__ */ jsxs(
|
|
2552
|
+
"div",
|
|
2553
|
+
{
|
|
2554
|
+
ref: containerRef,
|
|
2555
|
+
className: "lex4-block-type-picker",
|
|
2556
|
+
"data-testid": "block-type-picker",
|
|
2557
|
+
children: [
|
|
2558
|
+
/* @__PURE__ */ jsxs(
|
|
2559
|
+
"button",
|
|
2560
|
+
{
|
|
2561
|
+
type: "button",
|
|
2562
|
+
className: `lex4-block-type-trigger${open ? " open" : ""}`,
|
|
2563
|
+
"data-testid": "block-type-selector",
|
|
2564
|
+
"aria-label": t.toolbar.blockType,
|
|
2565
|
+
"aria-expanded": open,
|
|
2566
|
+
"aria-haspopup": "menu",
|
|
2567
|
+
title: getBlockTypeLabel(t, value),
|
|
2568
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
2569
|
+
onClick: () => setOpen((current) => !current),
|
|
2570
|
+
children: [
|
|
2571
|
+
/* @__PURE__ */ jsx(
|
|
2572
|
+
"span",
|
|
2573
|
+
{
|
|
2574
|
+
className: `lex4-block-type-trigger-code${value === "paragraph" ? "" : " heading"}`,
|
|
2575
|
+
children: getBlockTypeShortLabel(value)
|
|
2576
|
+
}
|
|
2577
|
+
),
|
|
2578
|
+
/* @__PURE__ */ jsx(ChevronDown, { size: 14, className: `lex4-block-type-trigger-chevron${open ? " open" : ""}` })
|
|
2579
|
+
]
|
|
2580
|
+
}
|
|
2581
|
+
),
|
|
2582
|
+
open && /* @__PURE__ */ jsx(
|
|
2583
|
+
"div",
|
|
2584
|
+
{
|
|
2585
|
+
className: "lex4-block-type-menu",
|
|
2586
|
+
role: "menu",
|
|
2587
|
+
"data-testid": "block-type-menu",
|
|
2588
|
+
children: BLOCK_TYPE_OPTIONS.map((option) => {
|
|
2589
|
+
const label = getBlockTypeLabel(t, option.value);
|
|
2590
|
+
const active = option.value === value;
|
|
2591
|
+
return /* @__PURE__ */ jsxs(
|
|
2592
|
+
"button",
|
|
2593
|
+
{
|
|
2594
|
+
type: "button",
|
|
2595
|
+
role: "menuitemradio",
|
|
2596
|
+
"aria-checked": active,
|
|
2597
|
+
className: `lex4-block-type-item${active ? " active" : ""}`,
|
|
2598
|
+
"data-testid": `block-type-option-${option.value}`,
|
|
2599
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
2600
|
+
onClick: () => {
|
|
2601
|
+
onChange(option.value);
|
|
2602
|
+
setOpen(false);
|
|
2603
|
+
},
|
|
2604
|
+
children: [
|
|
2605
|
+
/* @__PURE__ */ jsx(
|
|
2606
|
+
"span",
|
|
2607
|
+
{
|
|
2608
|
+
className: `lex4-block-type-item-code${option.value === "paragraph" ? "" : " heading"}${active ? " active" : ""}`,
|
|
2609
|
+
children: option.shortLabel
|
|
2610
|
+
}
|
|
2611
|
+
),
|
|
2612
|
+
/* @__PURE__ */ jsx("span", { className: "lex4-block-type-item-label", children: label })
|
|
2613
|
+
]
|
|
2614
|
+
},
|
|
2615
|
+
option.value
|
|
2616
|
+
);
|
|
2617
|
+
})
|
|
2618
|
+
}
|
|
2619
|
+
)
|
|
2620
|
+
]
|
|
2621
|
+
}
|
|
2622
|
+
);
|
|
2623
|
+
};
|
|
2075
2624
|
const HeaderFooterToggle = ({
|
|
2076
2625
|
enabled,
|
|
2077
|
-
onToggle
|
|
2626
|
+
onToggle,
|
|
2627
|
+
showLabel = true
|
|
2078
2628
|
}) => {
|
|
2079
2629
|
const t = useTranslations();
|
|
2080
2630
|
return /* @__PURE__ */ jsxs(
|
|
@@ -2084,18 +2634,20 @@ const HeaderFooterToggle = ({
|
|
|
2084
2634
|
"data-testid": "header-footer-toggle",
|
|
2085
2635
|
children: [
|
|
2086
2636
|
/* @__PURE__ */ jsx(FileText, { size: 14, className: "lex4-hf-toggle-icon" }),
|
|
2087
|
-
/* @__PURE__ */ jsx("span", { className: "lex4-hf-toggle-label", children: t.headerFooter.label }),
|
|
2637
|
+
showLabel && /* @__PURE__ */ jsx("span", { className: "lex4-hf-toggle-label", children: t.headerFooter.label }),
|
|
2088
2638
|
/* @__PURE__ */ jsx(
|
|
2089
2639
|
"button",
|
|
2090
2640
|
{
|
|
2091
2641
|
type: "button",
|
|
2092
2642
|
role: "switch",
|
|
2093
2643
|
"aria-checked": enabled,
|
|
2644
|
+
"aria-label": t.headerFooter.label,
|
|
2094
2645
|
onMouseDown: (e) => e.preventDefault(),
|
|
2095
2646
|
onClick: () => onToggle(!enabled),
|
|
2096
2647
|
className: "lex4-hf-switch",
|
|
2097
2648
|
style: { backgroundColor: enabled ? "var(--color-primary)" : "var(--color-muted)" },
|
|
2098
2649
|
"data-testid": "header-footer-switch",
|
|
2650
|
+
title: t.headerFooter.label,
|
|
2099
2651
|
children: /* @__PURE__ */ jsx("span", { className: "lex4-hf-switch-knob" })
|
|
2100
2652
|
}
|
|
2101
2653
|
)
|
|
@@ -2259,6 +2811,7 @@ const MenuItem = ({ icon, label, onClick, disabled, testId }) => /* @__PURE__ */
|
|
|
2259
2811
|
const MenuDivider = () => /* @__PURE__ */ jsx("div", { className: "lex4-settings-divider" });
|
|
2260
2812
|
const CanvasControls = () => {
|
|
2261
2813
|
const { document: document2, dispatch, activePageId, runHistoryAction } = useDocument();
|
|
2814
|
+
const toolbarConfig = useToolbarConfig();
|
|
2262
2815
|
const t = useTranslations();
|
|
2263
2816
|
const runCanvasAction = useCallback((label, callback) => {
|
|
2264
2817
|
runHistoryAction(
|
|
@@ -2325,12 +2878,16 @@ const CanvasControls = () => {
|
|
|
2325
2878
|
dispatch({ type: "SET_PAGE_COUNTER_MODE", mode });
|
|
2326
2879
|
});
|
|
2327
2880
|
}, [dispatch, runCanvasAction, t.history.actions.pageCounterSet]);
|
|
2881
|
+
if (!toolbarConfig.headerFooter.visible) {
|
|
2882
|
+
return null;
|
|
2883
|
+
}
|
|
2328
2884
|
return /* @__PURE__ */ jsxs("div", { className: "lex4-toolbar-group lex4-toolbar-group-gap", "data-testid": "header-footer-controls", children: [
|
|
2329
2885
|
/* @__PURE__ */ jsx(
|
|
2330
2886
|
HeaderFooterToggle,
|
|
2331
2887
|
{
|
|
2332
2888
|
enabled: document2.headerFooterEnabled,
|
|
2333
|
-
onToggle: handleToggle
|
|
2889
|
+
onToggle: handleToggle,
|
|
2890
|
+
showLabel: toolbarConfig.headerFooter.showLabel
|
|
2334
2891
|
}
|
|
2335
2892
|
),
|
|
2336
2893
|
document2.headerFooterEnabled && /* @__PURE__ */ jsx(
|
|
@@ -2363,7 +2920,17 @@ const Toolbar = () => {
|
|
|
2363
2920
|
undo
|
|
2364
2921
|
} = useDocument();
|
|
2365
2922
|
const { toolbarItems, toolbarEndItems } = useExtensions();
|
|
2923
|
+
const toolbarConfig = useToolbarConfig();
|
|
2366
2924
|
const t = useTranslations();
|
|
2925
|
+
const [activeBlockType, setActiveBlockType] = useState("paragraph");
|
|
2926
|
+
const [activeFontFamily, setActiveFontFamily] = useState("Calibri");
|
|
2927
|
+
const [activeFontSize, setActiveFontSize] = useState(DEFAULT_FONT_SIZE);
|
|
2928
|
+
const normalizeFontFamily = useCallback((fontFamily) => {
|
|
2929
|
+
if (fontFamily && SUPPORTED_FONTS.includes(fontFamily)) {
|
|
2930
|
+
return fontFamily;
|
|
2931
|
+
}
|
|
2932
|
+
return "Calibri";
|
|
2933
|
+
}, []);
|
|
2367
2934
|
const withBodySelection = useCallback(
|
|
2368
2935
|
(editor, action) => {
|
|
2369
2936
|
editor.update(() => {
|
|
@@ -2399,27 +2966,91 @@ const Toolbar = () => {
|
|
|
2399
2966
|
},
|
|
2400
2967
|
[runHistoryAction]
|
|
2401
2968
|
);
|
|
2969
|
+
useEffect(() => {
|
|
2970
|
+
if (!activeEditor) {
|
|
2971
|
+
setActiveBlockType("paragraph");
|
|
2972
|
+
setActiveFontFamily("Calibri");
|
|
2973
|
+
setActiveFontSize(DEFAULT_FONT_SIZE);
|
|
2974
|
+
return;
|
|
2975
|
+
}
|
|
2976
|
+
const updateSelectionState = () => {
|
|
2977
|
+
const selectedVariables = getSelectedVariableNodes(activeEditor);
|
|
2978
|
+
if (selectedVariables.length > 0) {
|
|
2979
|
+
const formatting = readSelectedVariableFormatting(activeEditor);
|
|
2980
|
+
setActiveBlockType("paragraph");
|
|
2981
|
+
setActiveFontFamily(normalizeFontFamily(formatting.fontFamily));
|
|
2982
|
+
setActiveFontSize(formatting.fontSize ?? DEFAULT_FONT_SIZE);
|
|
2983
|
+
return;
|
|
2984
|
+
}
|
|
2985
|
+
setActiveBlockType(getActiveBlockType(activeEditor));
|
|
2986
|
+
let nextFontFamily = "Calibri";
|
|
2987
|
+
let nextFontSize = DEFAULT_FONT_SIZE;
|
|
2988
|
+
activeEditor.getEditorState().read(() => {
|
|
2989
|
+
const selection = $getSelection();
|
|
2990
|
+
if (!$isRangeSelection(selection)) {
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2993
|
+
const textNode = selection.getNodes().find($isTextNode);
|
|
2994
|
+
if (!textNode) {
|
|
2995
|
+
return;
|
|
2996
|
+
}
|
|
2997
|
+
const style = textNode.getStyle();
|
|
2998
|
+
nextFontFamily = normalizeFontFamily(extractFontFamilyFromStyle(style));
|
|
2999
|
+
nextFontSize = extractFontSizePtFromStyle(style) ?? DEFAULT_FONT_SIZE;
|
|
3000
|
+
});
|
|
3001
|
+
setActiveFontFamily(nextFontFamily);
|
|
3002
|
+
setActiveFontSize(nextFontSize);
|
|
3003
|
+
};
|
|
3004
|
+
updateSelectionState();
|
|
3005
|
+
const unregisterSelectionChange = activeEditor.registerCommand(
|
|
3006
|
+
SELECTION_CHANGE_COMMAND,
|
|
3007
|
+
() => {
|
|
3008
|
+
updateSelectionState();
|
|
3009
|
+
return false;
|
|
3010
|
+
},
|
|
3011
|
+
COMMAND_PRIORITY_LOW
|
|
3012
|
+
);
|
|
3013
|
+
const unregisterUpdateListener = activeEditor.registerUpdateListener(() => {
|
|
3014
|
+
updateSelectionState();
|
|
3015
|
+
});
|
|
3016
|
+
return () => {
|
|
3017
|
+
unregisterSelectionChange();
|
|
3018
|
+
unregisterUpdateListener();
|
|
3019
|
+
};
|
|
3020
|
+
}, [activeEditor, normalizeFontFamily]);
|
|
2402
3021
|
const handleBold = useCallback(() => {
|
|
2403
3022
|
debug("toolbar", `bold (globalSelection=${globalSelectionActive}, editors=${editorRegistry.all().length}, hasEditor=${!!activeEditor})`);
|
|
2404
3023
|
runToolbarAction(t.history.actions.boldApplied, () => {
|
|
3024
|
+
if (activeEditor && toggleSelectedVariableFormat(activeEditor, "bold")) {
|
|
3025
|
+
return;
|
|
3026
|
+
}
|
|
2405
3027
|
applyToBodyEditors(toggleBold);
|
|
2406
3028
|
});
|
|
2407
3029
|
}, [activeEditor, applyToBodyEditors, editorRegistry, globalSelectionActive, runToolbarAction, t.history.actions.boldApplied]);
|
|
2408
3030
|
const handleItalic = useCallback(() => {
|
|
2409
3031
|
debug("toolbar", `italic (globalSelection=${globalSelectionActive}, hasEditor=${!!activeEditor})`);
|
|
2410
3032
|
runToolbarAction(t.history.actions.italicApplied, () => {
|
|
3033
|
+
if (activeEditor && toggleSelectedVariableFormat(activeEditor, "italic")) {
|
|
3034
|
+
return;
|
|
3035
|
+
}
|
|
2411
3036
|
applyToBodyEditors(toggleItalic);
|
|
2412
3037
|
});
|
|
2413
3038
|
}, [activeEditor, applyToBodyEditors, globalSelectionActive, runToolbarAction, t.history.actions.italicApplied]);
|
|
2414
3039
|
const handleUnderline = useCallback(() => {
|
|
2415
3040
|
debug("toolbar", `underline (globalSelection=${globalSelectionActive}, hasEditor=${!!activeEditor})`);
|
|
2416
3041
|
runToolbarAction(t.history.actions.underlineApplied, () => {
|
|
3042
|
+
if (activeEditor && toggleSelectedVariableFormat(activeEditor, "underline")) {
|
|
3043
|
+
return;
|
|
3044
|
+
}
|
|
2417
3045
|
applyToBodyEditors(toggleUnderline);
|
|
2418
3046
|
});
|
|
2419
3047
|
}, [activeEditor, applyToBodyEditors, globalSelectionActive, runToolbarAction, t.history.actions.underlineApplied]);
|
|
2420
3048
|
const handleStrikethrough = useCallback(() => {
|
|
2421
3049
|
debug("toolbar", `strikethrough (globalSelection=${globalSelectionActive}, hasEditor=${!!activeEditor})`);
|
|
2422
3050
|
runToolbarAction(t.history.actions.strikethroughApplied, () => {
|
|
3051
|
+
if (activeEditor && toggleSelectedVariableFormat(activeEditor, "strikethrough")) {
|
|
3052
|
+
return;
|
|
3053
|
+
}
|
|
2423
3054
|
applyToBodyEditors(toggleStrikethrough);
|
|
2424
3055
|
});
|
|
2425
3056
|
}, [activeEditor, applyToBodyEditors, globalSelectionActive, runToolbarAction, t.history.actions.strikethroughApplied]);
|
|
@@ -2465,20 +3096,43 @@ const Toolbar = () => {
|
|
|
2465
3096
|
}, [applyToBodyEditors, runToolbarAction, t.history.actions.outdentedContent]);
|
|
2466
3097
|
const handleFontChange = useCallback(
|
|
2467
3098
|
(e) => {
|
|
2468
|
-
|
|
2469
|
-
|
|
3099
|
+
const fontFamily = e.target.value;
|
|
3100
|
+
runToolbarAction(interpolate(t.history.actions.fontChanged, { value: fontFamily }), () => {
|
|
3101
|
+
if (activeEditor && applyFontFamilyToSelectedVariables(activeEditor, fontFamily)) {
|
|
3102
|
+
return;
|
|
3103
|
+
}
|
|
3104
|
+
applyToBodyEditors((editor) => applyFontFamily(editor, fontFamily));
|
|
2470
3105
|
});
|
|
2471
3106
|
},
|
|
2472
|
-
[applyToBodyEditors, runToolbarAction, t.history.actions.fontChanged]
|
|
3107
|
+
[activeEditor, applyToBodyEditors, runToolbarAction, t.history.actions.fontChanged]
|
|
2473
3108
|
);
|
|
2474
3109
|
const handleFontSizeChange = useCallback(
|
|
2475
3110
|
(e) => {
|
|
2476
3111
|
const size = parseInt(e.target.value, 10);
|
|
2477
3112
|
runToolbarAction(interpolate(t.history.actions.fontSizeChanged, { value: String(size) }), () => {
|
|
3113
|
+
if (activeEditor && applyFontSizeToSelectedVariables(activeEditor, size)) {
|
|
3114
|
+
return;
|
|
3115
|
+
}
|
|
2478
3116
|
applyToBodyEditors((editor) => applyFontSize(editor, size));
|
|
2479
3117
|
});
|
|
2480
3118
|
},
|
|
2481
|
-
[applyToBodyEditors, runToolbarAction, t.history.actions.fontSizeChanged]
|
|
3119
|
+
[activeEditor, applyToBodyEditors, runToolbarAction, t.history.actions.fontSizeChanged]
|
|
3120
|
+
);
|
|
3121
|
+
const handleBlockTypeChange = useCallback(
|
|
3122
|
+
(blockType) => {
|
|
3123
|
+
runToolbarAction(
|
|
3124
|
+
interpolate(t.history.actions.blockTypeChanged, { value: getBlockTypeLabel(t, blockType) }),
|
|
3125
|
+
() => {
|
|
3126
|
+
applyToBodyEditors((editor) => setBlockType(editor, blockType));
|
|
3127
|
+
}
|
|
3128
|
+
);
|
|
3129
|
+
},
|
|
3130
|
+
[
|
|
3131
|
+
applyToBodyEditors,
|
|
3132
|
+
runToolbarAction,
|
|
3133
|
+
t.history.actions.blockTypeChanged,
|
|
3134
|
+
t
|
|
3135
|
+
]
|
|
2482
3136
|
);
|
|
2483
3137
|
const handleToggleHistory = useCallback(() => {
|
|
2484
3138
|
setHistorySidebarOpen(!historySidebarOpen);
|
|
@@ -2512,6 +3166,14 @@ const Toolbar = () => {
|
|
|
2512
3166
|
)
|
|
2513
3167
|
] }),
|
|
2514
3168
|
/* @__PURE__ */ jsx(Divider, {}),
|
|
3169
|
+
/* @__PURE__ */ jsx("div", { className: "lex4-toolbar-group", children: /* @__PURE__ */ jsx(
|
|
3170
|
+
BlockTypePicker,
|
|
3171
|
+
{
|
|
3172
|
+
value: activeBlockType,
|
|
3173
|
+
onChange: handleBlockTypeChange
|
|
3174
|
+
}
|
|
3175
|
+
) }),
|
|
3176
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
2515
3177
|
/* @__PURE__ */ jsxs("div", { className: "lex4-toolbar-group-gap", children: [
|
|
2516
3178
|
/* @__PURE__ */ jsx(Type, { size: 14, className: "lex4-toolbar-icon" }),
|
|
2517
3179
|
/* @__PURE__ */ jsx(
|
|
@@ -2519,7 +3181,7 @@ const Toolbar = () => {
|
|
|
2519
3181
|
{
|
|
2520
3182
|
className: "lex4-toolbar-select",
|
|
2521
3183
|
"data-testid": "font-selector",
|
|
2522
|
-
|
|
3184
|
+
value: activeFontFamily,
|
|
2523
3185
|
onChange: handleFontChange,
|
|
2524
3186
|
children: SUPPORTED_FONTS.map((font) => /* @__PURE__ */ jsx("option", { value: font, style: { fontFamily: font }, children: font }, font))
|
|
2525
3187
|
}
|
|
@@ -2532,7 +3194,7 @@ const Toolbar = () => {
|
|
|
2532
3194
|
{
|
|
2533
3195
|
className: "lex4-toolbar-select lex4-toolbar-select-narrow",
|
|
2534
3196
|
"data-testid": "font-size-selector",
|
|
2535
|
-
|
|
3197
|
+
value: String(activeFontSize),
|
|
2536
3198
|
onChange: handleFontSizeChange,
|
|
2537
3199
|
children: SUPPORTED_FONT_SIZES.map((size) => /* @__PURE__ */ jsx("option", { value: size, children: size }, size))
|
|
2538
3200
|
}
|
|
@@ -2567,7 +3229,7 @@ const Toolbar = () => {
|
|
|
2567
3229
|
/* @__PURE__ */ jsx(CanvasControls, {}),
|
|
2568
3230
|
/* @__PURE__ */ jsxs("div", { className: "lex4-toolbar-end", children: [
|
|
2569
3231
|
toolbarEndItems.map((EndItem, idx) => /* @__PURE__ */ jsx(EndItem, {}, idx)),
|
|
2570
|
-
/* @__PURE__ */ jsxs(
|
|
3232
|
+
toolbarConfig.history.visible && /* @__PURE__ */ jsxs(
|
|
2571
3233
|
"button",
|
|
2572
3234
|
{
|
|
2573
3235
|
type: "button",
|
|
@@ -2579,7 +3241,7 @@ const Toolbar = () => {
|
|
|
2579
3241
|
"aria-label": historySidebarOpen ? t.toolbar.closeHistory : t.toolbar.openHistory,
|
|
2580
3242
|
children: [
|
|
2581
3243
|
/* @__PURE__ */ jsx(History, { size: 14 }),
|
|
2582
|
-
|
|
3244
|
+
toolbarConfig.history.showLabel && t.toolbar.history
|
|
2583
3245
|
]
|
|
2584
3246
|
}
|
|
2585
3247
|
)
|
|
@@ -2923,7 +3585,8 @@ const lexicalTheme = {
|
|
|
2923
3585
|
h2: "lex4-heading lex4-heading-h2",
|
|
2924
3586
|
h3: "lex4-heading lex4-heading-h3",
|
|
2925
3587
|
h4: "lex4-heading lex4-heading-h4",
|
|
2926
|
-
h5: "lex4-heading lex4-heading-h5"
|
|
3588
|
+
h5: "lex4-heading lex4-heading-h5",
|
|
3589
|
+
h6: "lex4-heading lex4-heading-h6"
|
|
2927
3590
|
},
|
|
2928
3591
|
text: {
|
|
2929
3592
|
bold: "lex4-text-bold",
|
|
@@ -4460,12 +5123,10 @@ function decodeFormatBitmask(format) {
|
|
|
4460
5123
|
return marks;
|
|
4461
5124
|
}
|
|
4462
5125
|
function extractFontFamily(style) {
|
|
4463
|
-
|
|
4464
|
-
return match ? match[1].trim().replace(/['"]/g, "") : void 0;
|
|
5126
|
+
return extractFontFamilyFromStyle(style);
|
|
4465
5127
|
}
|
|
4466
5128
|
function extractFontSizePt(style) {
|
|
4467
|
-
|
|
4468
|
-
return match ? parseFloat(match[1]) : void 0;
|
|
5129
|
+
return extractFontSizePtFromStyle(style);
|
|
4469
5130
|
}
|
|
4470
5131
|
function buildTextMarks(format, style) {
|
|
4471
5132
|
const formatMarks = decodeFormatBitmask(format);
|
|
@@ -4499,9 +5160,11 @@ function mapTextNode(node) {
|
|
|
4499
5160
|
};
|
|
4500
5161
|
}
|
|
4501
5162
|
function mapVariableNode(node) {
|
|
5163
|
+
const marks = buildTextMarks(node.format ?? 0, node.style);
|
|
4502
5164
|
return {
|
|
4503
5165
|
type: "variable",
|
|
4504
|
-
key: node.variableKey
|
|
5166
|
+
key: node.variableKey,
|
|
5167
|
+
...marks ? { marks } : {}
|
|
4505
5168
|
};
|
|
4506
5169
|
}
|
|
4507
5170
|
function mapLineBreak() {
|
|
@@ -4565,7 +5228,7 @@ function mapParagraph(node) {
|
|
|
4565
5228
|
function mapHeading(node) {
|
|
4566
5229
|
var _a;
|
|
4567
5230
|
const alignment = decodeAlignment(node.format);
|
|
4568
|
-
const tagMatch = (_a = node.tag) == null ? void 0 : _a.match(/^h(
|
|
5231
|
+
const tagMatch = (_a = node.tag) == null ? void 0 : _a.match(/^h([1-6])$/);
|
|
4569
5232
|
const level = tagMatch ? parseInt(tagMatch[1], 10) : 1;
|
|
4570
5233
|
return {
|
|
4571
5234
|
type: "heading",
|
|
@@ -4690,6 +5353,105 @@ function buildSavePayload(ast, options) {
|
|
|
4690
5353
|
function serializeDocumentJson(ast) {
|
|
4691
5354
|
return JSON.stringify(ast, null, 2);
|
|
4692
5355
|
}
|
|
5356
|
+
function appendChildren(parent, children = []) {
|
|
5357
|
+
const nodes = children.map(buildLexicalNode).filter((node) => node !== null);
|
|
5358
|
+
if (nodes.length > 0) {
|
|
5359
|
+
parent.append(...nodes);
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
5362
|
+
function applyElementFormatting(node, serializedNode) {
|
|
5363
|
+
if (typeof serializedNode.format === "string" && ["left", "center", "right", "justify"].includes(serializedNode.format) && node.setFormat) {
|
|
5364
|
+
node.setFormat(serializedNode.format);
|
|
5365
|
+
}
|
|
5366
|
+
if (typeof serializedNode.indent === "number" && serializedNode.indent > 0 && node.setIndent) {
|
|
5367
|
+
node.setIndent(serializedNode.indent);
|
|
5368
|
+
}
|
|
5369
|
+
}
|
|
5370
|
+
function buildLexicalNode(serializedNode) {
|
|
5371
|
+
switch (serializedNode.type) {
|
|
5372
|
+
case "paragraph": {
|
|
5373
|
+
const node = $createParagraphNode();
|
|
5374
|
+
applyElementFormatting(node, serializedNode);
|
|
5375
|
+
appendChildren(node, serializedNode.children);
|
|
5376
|
+
return node;
|
|
5377
|
+
}
|
|
5378
|
+
case "heading": {
|
|
5379
|
+
const tag = typeof serializedNode.tag === "string" && /^h[1-6]$/.test(serializedNode.tag) ? serializedNode.tag : "h1";
|
|
5380
|
+
const node = $createHeadingNode(tag);
|
|
5381
|
+
applyElementFormatting(node, serializedNode);
|
|
5382
|
+
appendChildren(node, serializedNode.children);
|
|
5383
|
+
return node;
|
|
5384
|
+
}
|
|
5385
|
+
case "quote": {
|
|
5386
|
+
const node = $createQuoteNode();
|
|
5387
|
+
applyElementFormatting(node, serializedNode);
|
|
5388
|
+
appendChildren(node, serializedNode.children);
|
|
5389
|
+
return node;
|
|
5390
|
+
}
|
|
5391
|
+
case "list": {
|
|
5392
|
+
const listType = serializedNode.listType === "number" ? "number" : "bullet";
|
|
5393
|
+
const node = $createListNode(listType, typeof serializedNode.start === "number" ? serializedNode.start : 1);
|
|
5394
|
+
appendChildren(node, serializedNode.children);
|
|
5395
|
+
return node;
|
|
5396
|
+
}
|
|
5397
|
+
case "listitem": {
|
|
5398
|
+
const node = $createListItemNode();
|
|
5399
|
+
appendChildren(node, serializedNode.children);
|
|
5400
|
+
return node;
|
|
5401
|
+
}
|
|
5402
|
+
case "text": {
|
|
5403
|
+
const node = $createTextNode(serializedNode.text ?? "");
|
|
5404
|
+
if (typeof serializedNode.format === "number" && serializedNode.format > 0) {
|
|
5405
|
+
node.setFormat(serializedNode.format);
|
|
5406
|
+
}
|
|
5407
|
+
if (typeof serializedNode.style === "string" && serializedNode.style.trim() !== "") {
|
|
5408
|
+
node.setStyle(serializedNode.style);
|
|
5409
|
+
}
|
|
5410
|
+
return node;
|
|
5411
|
+
}
|
|
5412
|
+
case "linebreak":
|
|
5413
|
+
return $createLineBreakNode();
|
|
5414
|
+
case "variable-node":
|
|
5415
|
+
return $createVariableNode(
|
|
5416
|
+
serializedNode.variableKey ?? "",
|
|
5417
|
+
typeof serializedNode.format === "number" ? serializedNode.format : 0,
|
|
5418
|
+
typeof serializedNode.style === "string" ? serializedNode.style : ""
|
|
5419
|
+
);
|
|
5420
|
+
default:
|
|
5421
|
+
return null;
|
|
5422
|
+
}
|
|
5423
|
+
}
|
|
5424
|
+
function getBodyChildren(pageState) {
|
|
5425
|
+
const root = pageState == null ? void 0 : pageState.root;
|
|
5426
|
+
return (root == null ? void 0 : root.children) ?? [];
|
|
5427
|
+
}
|
|
5428
|
+
function insertDocumentContent(editor, document2) {
|
|
5429
|
+
let inserted = false;
|
|
5430
|
+
editor.update(() => {
|
|
5431
|
+
const nodes = document2.pages.flatMap((page) => getBodyChildren(page.bodyState)).map(buildLexicalNode).filter((node) => node !== null);
|
|
5432
|
+
if (nodes.length === 0) {
|
|
5433
|
+
return;
|
|
5434
|
+
}
|
|
5435
|
+
const selection = $getSelection();
|
|
5436
|
+
if ($isRangeSelection(selection)) {
|
|
5437
|
+
if (selection.isCollapsed()) {
|
|
5438
|
+
selection.insertParagraph();
|
|
5439
|
+
}
|
|
5440
|
+
const nextSelection = $getSelection();
|
|
5441
|
+
if ($isRangeSelection(nextSelection) || $isNodeSelection(nextSelection)) {
|
|
5442
|
+
nextSelection.insertNodes(nodes);
|
|
5443
|
+
} else {
|
|
5444
|
+
$insertNodes(nodes);
|
|
5445
|
+
}
|
|
5446
|
+
} else if ($isNodeSelection(selection)) {
|
|
5447
|
+
selection.insertNodes(nodes);
|
|
5448
|
+
} else {
|
|
5449
|
+
$insertNodes(nodes);
|
|
5450
|
+
}
|
|
5451
|
+
inserted = true;
|
|
5452
|
+
});
|
|
5453
|
+
return inserted;
|
|
5454
|
+
}
|
|
4693
5455
|
function selectEntireDocument(rootElement, selectionBuffer) {
|
|
4694
5456
|
if (!rootElement || !selectionBuffer) {
|
|
4695
5457
|
return;
|
|
@@ -4896,10 +5658,13 @@ const EditorWithHandle = forwardRef(({ captureHistoryShortcutsOnWindow, onSave,
|
|
|
4896
5658
|
const {
|
|
4897
5659
|
document: doc,
|
|
4898
5660
|
activeEditor,
|
|
5661
|
+
activeCaretPosition,
|
|
4899
5662
|
historySidebarOpen,
|
|
5663
|
+
runHistoryAction,
|
|
4900
5664
|
setHistorySidebarOpen
|
|
4901
5665
|
} = useDocument();
|
|
4902
5666
|
const { handleFactories } = useExtensions();
|
|
5667
|
+
const t = useTranslations();
|
|
4903
5668
|
const getDocument = useCallback(() => doc, [doc]);
|
|
4904
5669
|
const getActiveEditor = useCallback(() => activeEditor, [activeEditor]);
|
|
4905
5670
|
const extensionCtx = useExtensionContext(getDocument, getActiveEditor);
|
|
@@ -4910,6 +5675,23 @@ const EditorWithHandle = forwardRef(({ captureHistoryShortcutsOnWindow, onSave,
|
|
|
4910
5675
|
},
|
|
4911
5676
|
toggleHistorySidebar: () => {
|
|
4912
5677
|
setHistorySidebarOpen(!historySidebarOpen);
|
|
5678
|
+
},
|
|
5679
|
+
insertDocumentContent: (documentToInsert) => {
|
|
5680
|
+
if (!activeEditor || (activeCaretPosition == null ? void 0 : activeCaretPosition.region) !== "body") {
|
|
5681
|
+
return false;
|
|
5682
|
+
}
|
|
5683
|
+
let inserted = false;
|
|
5684
|
+
runHistoryAction(
|
|
5685
|
+
{
|
|
5686
|
+
label: t.history.actions.insertedDocumentContent,
|
|
5687
|
+
source: "toolbar",
|
|
5688
|
+
region: "document"
|
|
5689
|
+
},
|
|
5690
|
+
() => {
|
|
5691
|
+
inserted = insertDocumentContent(activeEditor, documentToInsert);
|
|
5692
|
+
}
|
|
5693
|
+
);
|
|
5694
|
+
return inserted;
|
|
4913
5695
|
}
|
|
4914
5696
|
};
|
|
4915
5697
|
for (const factory of handleFactories) {
|
|
@@ -4917,7 +5699,16 @@ const EditorWithHandle = forwardRef(({ captureHistoryShortcutsOnWindow, onSave,
|
|
|
4917
5699
|
Object.assign(handle, methods);
|
|
4918
5700
|
}
|
|
4919
5701
|
return handle;
|
|
4920
|
-
}, [
|
|
5702
|
+
}, [
|
|
5703
|
+
activeCaretPosition == null ? void 0 : activeCaretPosition.region,
|
|
5704
|
+
activeEditor,
|
|
5705
|
+
extensionCtx,
|
|
5706
|
+
handleFactories,
|
|
5707
|
+
historySidebarOpen,
|
|
5708
|
+
runHistoryAction,
|
|
5709
|
+
setHistorySidebarOpen,
|
|
5710
|
+
t.history.actions.insertedDocumentContent
|
|
5711
|
+
]);
|
|
4921
5712
|
return /* @__PURE__ */ jsx(
|
|
4922
5713
|
EditorChrome,
|
|
4923
5714
|
{
|
|
@@ -4935,9 +5726,10 @@ const Lex4Editor = forwardRef(({
|
|
|
4935
5726
|
onSave,
|
|
4936
5727
|
extensions,
|
|
4937
5728
|
translations,
|
|
5729
|
+
toolbar,
|
|
4938
5730
|
className
|
|
4939
5731
|
}, ref) => {
|
|
4940
|
-
return /* @__PURE__ */ jsx(TranslationsProvider, { translations, children: /* @__PURE__ */ jsx(ExtensionStateProvider, { children: /* @__PURE__ */ jsx(ExtensionProvider, { extensions, children: /* @__PURE__ */ jsx(
|
|
5732
|
+
return /* @__PURE__ */ jsx(TranslationsProvider, { translations, children: /* @__PURE__ */ jsx(ToolbarConfigProvider, { toolbar, children: /* @__PURE__ */ jsx(ExtensionStateProvider, { children: /* @__PURE__ */ jsx(ExtensionProvider, { extensions, children: /* @__PURE__ */ jsx(
|
|
4941
5733
|
DocumentProvider,
|
|
4942
5734
|
{
|
|
4943
5735
|
initialDocument,
|
|
@@ -4952,7 +5744,7 @@ const Lex4Editor = forwardRef(({
|
|
|
4952
5744
|
}
|
|
4953
5745
|
)
|
|
4954
5746
|
}
|
|
4955
|
-
) }) }) });
|
|
5747
|
+
) }) }) }) });
|
|
4956
5748
|
});
|
|
4957
5749
|
Lex4Editor.displayName = "Lex4Editor";
|
|
4958
5750
|
function useOverflowDetection(bodyHeight, onOverflow, debounceMs = 100) {
|
|
@@ -5046,120 +5838,6 @@ function astExtension() {
|
|
|
5046
5838
|
}
|
|
5047
5839
|
};
|
|
5048
5840
|
}
|
|
5049
|
-
const EMPTY_CONTEXT = {
|
|
5050
|
-
definitions: [],
|
|
5051
|
-
refreshDefinitions: () => {
|
|
5052
|
-
},
|
|
5053
|
-
getDefinition: () => void 0
|
|
5054
|
-
};
|
|
5055
|
-
const VariableContext = createContext(EMPTY_CONTEXT);
|
|
5056
|
-
const VariableProvider = ({
|
|
5057
|
-
initialDefinitions = [],
|
|
5058
|
-
children
|
|
5059
|
-
}) => {
|
|
5060
|
-
const [definitions, setDefinitions] = useState(initialDefinitions);
|
|
5061
|
-
const refresh = useCallback((newDefinitions) => {
|
|
5062
|
-
setDefinitions(newDefinitions);
|
|
5063
|
-
}, []);
|
|
5064
|
-
const getDefinition = useCallback(
|
|
5065
|
-
(key) => {
|
|
5066
|
-
return definitions.find((d) => d.key === key);
|
|
5067
|
-
},
|
|
5068
|
-
[definitions]
|
|
5069
|
-
);
|
|
5070
|
-
const value = useMemo(
|
|
5071
|
-
() => ({ definitions, refreshDefinitions: refresh, getDefinition }),
|
|
5072
|
-
[definitions, refresh, getDefinition]
|
|
5073
|
-
);
|
|
5074
|
-
return /* @__PURE__ */ jsx(VariableContext.Provider, { value, children });
|
|
5075
|
-
};
|
|
5076
|
-
function useVariables() {
|
|
5077
|
-
return useContext(VariableContext);
|
|
5078
|
-
}
|
|
5079
|
-
class VariableNode extends DecoratorNode {
|
|
5080
|
-
constructor(variableKey, key) {
|
|
5081
|
-
super(key);
|
|
5082
|
-
__publicField(this, "__variableKey");
|
|
5083
|
-
this.__variableKey = variableKey;
|
|
5084
|
-
}
|
|
5085
|
-
static getType() {
|
|
5086
|
-
return "variable-node";
|
|
5087
|
-
}
|
|
5088
|
-
static clone(node) {
|
|
5089
|
-
return new VariableNode(node.__variableKey, node.__key);
|
|
5090
|
-
}
|
|
5091
|
-
getVariableKey() {
|
|
5092
|
-
return this.__variableKey;
|
|
5093
|
-
}
|
|
5094
|
-
// -- Serialization --
|
|
5095
|
-
static importJSON(serializedNode) {
|
|
5096
|
-
return $createVariableNode(serializedNode.variableKey);
|
|
5097
|
-
}
|
|
5098
|
-
exportJSON() {
|
|
5099
|
-
return {
|
|
5100
|
-
type: "variable-node",
|
|
5101
|
-
version: 1,
|
|
5102
|
-
variableKey: this.__variableKey
|
|
5103
|
-
};
|
|
5104
|
-
}
|
|
5105
|
-
// -- DOM --
|
|
5106
|
-
createDOM() {
|
|
5107
|
-
const span = document.createElement("span");
|
|
5108
|
-
span.className = "lex4-variable";
|
|
5109
|
-
span.setAttribute("data-variable-key", this.__variableKey);
|
|
5110
|
-
span.setAttribute("data-testid", `variable-${this.__variableKey}`);
|
|
5111
|
-
span.contentEditable = "false";
|
|
5112
|
-
return span;
|
|
5113
|
-
}
|
|
5114
|
-
updateDOM() {
|
|
5115
|
-
return false;
|
|
5116
|
-
}
|
|
5117
|
-
exportDOM() {
|
|
5118
|
-
const span = document.createElement("span");
|
|
5119
|
-
span.setAttribute("data-variable-key", this.__variableKey);
|
|
5120
|
-
span.textContent = `{{${this.__variableKey}}}`;
|
|
5121
|
-
return { element: span };
|
|
5122
|
-
}
|
|
5123
|
-
static importDOM() {
|
|
5124
|
-
return null;
|
|
5125
|
-
}
|
|
5126
|
-
// -- Behavior --
|
|
5127
|
-
isInline() {
|
|
5128
|
-
return true;
|
|
5129
|
-
}
|
|
5130
|
-
isKeyboardSelectable() {
|
|
5131
|
-
return true;
|
|
5132
|
-
}
|
|
5133
|
-
getTextContent() {
|
|
5134
|
-
return `{{${this.__variableKey}}}`;
|
|
5135
|
-
}
|
|
5136
|
-
// -- Rendering --
|
|
5137
|
-
decorate() {
|
|
5138
|
-
return /* @__PURE__ */ jsx(VariableChip, { variableKey: this.__variableKey });
|
|
5139
|
-
}
|
|
5140
|
-
}
|
|
5141
|
-
function VariableChip({ variableKey }) {
|
|
5142
|
-
const { getDefinition } = useVariables();
|
|
5143
|
-
const def = getDefinition(variableKey);
|
|
5144
|
-
const label = (def == null ? void 0 : def.label) ?? variableKey;
|
|
5145
|
-
const group = def == null ? void 0 : def.group;
|
|
5146
|
-
return /* @__PURE__ */ jsx(
|
|
5147
|
-
"span",
|
|
5148
|
-
{
|
|
5149
|
-
className: "lex4-variable-chip",
|
|
5150
|
-
"data-testid": `variable-chip-${variableKey}`,
|
|
5151
|
-
"data-variable-group": group,
|
|
5152
|
-
title: variableKey,
|
|
5153
|
-
children: label
|
|
5154
|
-
}
|
|
5155
|
-
);
|
|
5156
|
-
}
|
|
5157
|
-
function $createVariableNode(variableKey) {
|
|
5158
|
-
return $applyNodeReplacement(new VariableNode(variableKey));
|
|
5159
|
-
}
|
|
5160
|
-
function $isVariableNode(node) {
|
|
5161
|
-
return node instanceof VariableNode;
|
|
5162
|
-
}
|
|
5163
5841
|
const INSERT_VARIABLE_COMMAND = createCommand("INSERT_VARIABLE");
|
|
5164
5842
|
const VariablePlugin = () => {
|
|
5165
5843
|
const [editor] = useLexicalComposerContext();
|
|
@@ -5420,7 +6098,11 @@ const VariablePanelStateProvider = ({ children }) => {
|
|
|
5420
6098
|
};
|
|
5421
6099
|
const VariableToolbarToggle = () => {
|
|
5422
6100
|
const { panelOpen, setPanelOpen } = useVariablePanelState();
|
|
6101
|
+
const toolbarConfig = useToolbarConfig();
|
|
5423
6102
|
const t = useTranslations();
|
|
6103
|
+
if (!toolbarConfig.variables.visible) {
|
|
6104
|
+
return null;
|
|
6105
|
+
}
|
|
5424
6106
|
return /* @__PURE__ */ jsxs(
|
|
5425
6107
|
"button",
|
|
5426
6108
|
{
|
|
@@ -5433,7 +6115,7 @@ const VariableToolbarToggle = () => {
|
|
|
5433
6115
|
"aria-label": panelOpen ? t.variables.closePanel : t.variables.openPanel,
|
|
5434
6116
|
children: [
|
|
5435
6117
|
/* @__PURE__ */ jsx(Braces, { size: 14 }),
|
|
5436
|
-
t.variables.title
|
|
6118
|
+
toolbarConfig.variables.showLabel && t.variables.title
|
|
5437
6119
|
]
|
|
5438
6120
|
}
|
|
5439
6121
|
);
|