@yurikilian/lex4 1.4.0 → 1.5.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/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/CanvasControls.d.ts.map +1 -1
- package/dist/components/HeaderFooterActions.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 +25 -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 +773 -178
- package/dist/lex4-editor.cjs.map +1 -1
- package/dist/lex4-editor.js +757 -162
- 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 +51 -23
- 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: {
|
|
@@ -548,7 +561,20 @@ const DEFAULT_TRANSLATIONS = {
|
|
|
548
561
|
page: "Page {{page}}"
|
|
549
562
|
},
|
|
550
563
|
headerFooter: {
|
|
551
|
-
label: "Headers & Footers"
|
|
564
|
+
label: "Headers & Footers",
|
|
565
|
+
settingsLabel: "Header and footer settings",
|
|
566
|
+
pageCounter: "Page counter",
|
|
567
|
+
pageCounterModes: {
|
|
568
|
+
none: "None",
|
|
569
|
+
header: "Header",
|
|
570
|
+
footer: "Footer",
|
|
571
|
+
both: "Both"
|
|
572
|
+
},
|
|
573
|
+
headerSection: "Header",
|
|
574
|
+
footerSection: "Footer",
|
|
575
|
+
copyToAllPages: "Copy to all pages",
|
|
576
|
+
clearThisPage: "Clear this page",
|
|
577
|
+
clearAll: "Clear all"
|
|
552
578
|
},
|
|
553
579
|
sidebar: {
|
|
554
580
|
close: "Close sidebar"
|
|
@@ -589,6 +615,15 @@ const PT_BR_TRANSLATIONS = {
|
|
|
589
615
|
bulletList: "Lista com Marcadores",
|
|
590
616
|
indent: "Aumentar Recuo",
|
|
591
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",
|
|
592
627
|
openHistory: "Abrir Histórico",
|
|
593
628
|
closeHistory: "Fechar Histórico"
|
|
594
629
|
},
|
|
@@ -620,7 +655,9 @@ const PT_BR_TRANSLATIONS = {
|
|
|
620
655
|
indentedContent: "Conteúdo recuado",
|
|
621
656
|
outdentedContent: "Recuo reduzido",
|
|
622
657
|
fontChanged: "Fonte alterada para {{value}}",
|
|
623
|
-
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"
|
|
624
661
|
}
|
|
625
662
|
},
|
|
626
663
|
variables: {
|
|
@@ -666,7 +703,20 @@ const PT_BR_TRANSLATIONS = {
|
|
|
666
703
|
page: "Página {{page}}"
|
|
667
704
|
},
|
|
668
705
|
headerFooter: {
|
|
669
|
-
label: "Cabeçalhos e Rodapés"
|
|
706
|
+
label: "Cabeçalhos e Rodapés",
|
|
707
|
+
settingsLabel: "Configurações de cabeçalho e rodapé",
|
|
708
|
+
pageCounter: "Contador de páginas",
|
|
709
|
+
pageCounterModes: {
|
|
710
|
+
none: "Nenhum",
|
|
711
|
+
header: "Cabeçalho",
|
|
712
|
+
footer: "Rodapé",
|
|
713
|
+
both: "Ambos"
|
|
714
|
+
},
|
|
715
|
+
headerSection: "Cabeçalho",
|
|
716
|
+
footerSection: "Rodapé",
|
|
717
|
+
copyToAllPages: "Copiar para todas as páginas",
|
|
718
|
+
clearThisPage: "Limpar esta página",
|
|
719
|
+
clearAll: "Limpar tudo"
|
|
670
720
|
},
|
|
671
721
|
sidebar: {
|
|
672
722
|
close: "Fechar barra lateral"
|
|
@@ -1258,6 +1308,7 @@ const DocumentProvider = ({
|
|
|
1258
1308
|
activePageId,
|
|
1259
1309
|
setActivePageId,
|
|
1260
1310
|
activeEditor: activeEditorRef.current,
|
|
1311
|
+
activeCaretPosition: activeCaretPositionRef.current,
|
|
1261
1312
|
consumePendingCaretPosition,
|
|
1262
1313
|
consumePendingFocusAtEnd,
|
|
1263
1314
|
requestFocusAtEnd,
|
|
@@ -1864,6 +1915,36 @@ const HistorySidebar = () => {
|
|
|
1864
1915
|
}
|
|
1865
1916
|
);
|
|
1866
1917
|
};
|
|
1918
|
+
const DEFAULT_TOOLBAR_CONTROL_CONFIG = {
|
|
1919
|
+
visible: true,
|
|
1920
|
+
showLabel: true
|
|
1921
|
+
};
|
|
1922
|
+
const DEFAULT_TOOLBAR_CONFIG = {
|
|
1923
|
+
history: DEFAULT_TOOLBAR_CONTROL_CONFIG,
|
|
1924
|
+
variables: DEFAULT_TOOLBAR_CONTROL_CONFIG,
|
|
1925
|
+
headerFooter: DEFAULT_TOOLBAR_CONTROL_CONFIG
|
|
1926
|
+
};
|
|
1927
|
+
const ToolbarConfigContext = createContext(DEFAULT_TOOLBAR_CONFIG);
|
|
1928
|
+
function resolveControlConfig(config) {
|
|
1929
|
+
return {
|
|
1930
|
+
visible: (config == null ? void 0 : config.visible) ?? true,
|
|
1931
|
+
showLabel: (config == null ? void 0 : config.showLabel) ?? true
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
function normalizeToolbarConfig(config) {
|
|
1935
|
+
return {
|
|
1936
|
+
history: resolveControlConfig(config == null ? void 0 : config.history),
|
|
1937
|
+
variables: resolveControlConfig(config == null ? void 0 : config.variables),
|
|
1938
|
+
headerFooter: resolveControlConfig(config == null ? void 0 : config.headerFooter)
|
|
1939
|
+
};
|
|
1940
|
+
}
|
|
1941
|
+
const ToolbarConfigProvider = ({ toolbar, children }) => {
|
|
1942
|
+
const resolvedConfig = useMemo(() => normalizeToolbarConfig(toolbar), [toolbar]);
|
|
1943
|
+
return /* @__PURE__ */ jsx(ToolbarConfigContext.Provider, { value: resolvedConfig, children });
|
|
1944
|
+
};
|
|
1945
|
+
function useToolbarConfig() {
|
|
1946
|
+
return useContext(ToolbarConfigContext);
|
|
1947
|
+
}
|
|
1867
1948
|
function resolveExtensions(extensions) {
|
|
1868
1949
|
const resolved = {
|
|
1869
1950
|
nodes: [],
|
|
@@ -1996,6 +2077,7 @@ const SUPPORTED_FONT_SIZES = [
|
|
|
1996
2077
|
48,
|
|
1997
2078
|
72
|
|
1998
2079
|
];
|
|
2080
|
+
const DEFAULT_FONT_SIZE = 12;
|
|
1999
2081
|
function applyFontSize(editor, size) {
|
|
2000
2082
|
editor.update(() => {
|
|
2001
2083
|
const selection = $getSelection();
|
|
@@ -2046,9 +2128,366 @@ function indentContent(editor) {
|
|
|
2046
2128
|
function outdentContent(editor) {
|
|
2047
2129
|
editor.dispatchCommand(OUTDENT_CONTENT_COMMAND, void 0);
|
|
2048
2130
|
}
|
|
2131
|
+
function setBlockType(editor, blockType) {
|
|
2132
|
+
editor.update(() => {
|
|
2133
|
+
const selection = $getSelection();
|
|
2134
|
+
if (!$isRangeSelection(selection)) {
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
if (blockType === "paragraph") {
|
|
2138
|
+
$setBlocksType(selection, () => $createParagraphNode());
|
|
2139
|
+
return;
|
|
2140
|
+
}
|
|
2141
|
+
$setBlocksType(selection, () => $createHeadingNode(blockType));
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
function getActiveBlockType(editor) {
|
|
2145
|
+
let blockType = "paragraph";
|
|
2146
|
+
editor.getEditorState().read(() => {
|
|
2147
|
+
const selection = $getSelection();
|
|
2148
|
+
if (!$isRangeSelection(selection)) {
|
|
2149
|
+
return;
|
|
2150
|
+
}
|
|
2151
|
+
const anchorNode = selection.anchor.getNode();
|
|
2152
|
+
const topLevelElement = anchorNode.getTopLevelElementOrThrow();
|
|
2153
|
+
if ($isHeadingNode(topLevelElement)) {
|
|
2154
|
+
blockType = topLevelElement.getTag();
|
|
2155
|
+
}
|
|
2156
|
+
});
|
|
2157
|
+
return blockType;
|
|
2158
|
+
}
|
|
2159
|
+
function extractStyleValue(style, property) {
|
|
2160
|
+
const escapedProperty = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2161
|
+
const match = style.match(new RegExp(`${escapedProperty}:\\s*([^;]+)`));
|
|
2162
|
+
return match ? match[1].trim().replace(/['"]/g, "") : void 0;
|
|
2163
|
+
}
|
|
2164
|
+
function mergeStyleDeclaration(existingStyle, property, value) {
|
|
2165
|
+
const escapedProperty = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2166
|
+
const stripped = existingStyle.replace(
|
|
2167
|
+
new RegExp(`${escapedProperty}:\\s*[^;]+;?\\s*`, "g"),
|
|
2168
|
+
""
|
|
2169
|
+
).trim();
|
|
2170
|
+
const declaration = `${property}: ${value}`;
|
|
2171
|
+
return stripped ? `${stripped}; ${declaration}` : declaration;
|
|
2172
|
+
}
|
|
2173
|
+
function extractFontFamilyFromStyle(style) {
|
|
2174
|
+
return extractStyleValue(style, "font-family");
|
|
2175
|
+
}
|
|
2176
|
+
function extractFontSizePtFromStyle(style) {
|
|
2177
|
+
const value = extractStyleValue(style, "font-size");
|
|
2178
|
+
if (!value) {
|
|
2179
|
+
return void 0;
|
|
2180
|
+
}
|
|
2181
|
+
const match = value.match(/^(\d+(?:\.\d+)?)\s*pt$/);
|
|
2182
|
+
return match ? parseFloat(match[1]) : void 0;
|
|
2183
|
+
}
|
|
2184
|
+
function mergeFontFamilyStyle(existingStyle, fontFamily) {
|
|
2185
|
+
return mergeStyleDeclaration(existingStyle, "font-family", fontFamily);
|
|
2186
|
+
}
|
|
2187
|
+
function mergeFontSizeStyle(existingStyle, size) {
|
|
2188
|
+
return mergeStyleDeclaration(existingStyle, "font-size", `${size}pt`);
|
|
2189
|
+
}
|
|
2190
|
+
const EMPTY_CONTEXT = {
|
|
2191
|
+
definitions: [],
|
|
2192
|
+
refreshDefinitions: () => {
|
|
2193
|
+
},
|
|
2194
|
+
getDefinition: () => void 0
|
|
2195
|
+
};
|
|
2196
|
+
const VariableContext = createContext(EMPTY_CONTEXT);
|
|
2197
|
+
const VariableProvider = ({
|
|
2198
|
+
initialDefinitions = [],
|
|
2199
|
+
children
|
|
2200
|
+
}) => {
|
|
2201
|
+
const [definitions, setDefinitions] = useState(initialDefinitions);
|
|
2202
|
+
const refresh = useCallback((newDefinitions) => {
|
|
2203
|
+
setDefinitions(newDefinitions);
|
|
2204
|
+
}, []);
|
|
2205
|
+
const getDefinition = useCallback(
|
|
2206
|
+
(key) => {
|
|
2207
|
+
return definitions.find((d) => d.key === key);
|
|
2208
|
+
},
|
|
2209
|
+
[definitions]
|
|
2210
|
+
);
|
|
2211
|
+
const value = useMemo(
|
|
2212
|
+
() => ({ definitions, refreshDefinitions: refresh, getDefinition }),
|
|
2213
|
+
[definitions, refresh, getDefinition]
|
|
2214
|
+
);
|
|
2215
|
+
return /* @__PURE__ */ jsx(VariableContext.Provider, { value, children });
|
|
2216
|
+
};
|
|
2217
|
+
function useVariables() {
|
|
2218
|
+
return useContext(VariableContext);
|
|
2219
|
+
}
|
|
2220
|
+
class VariableNode extends DecoratorNode {
|
|
2221
|
+
constructor(variableKey, format = 0, style = "", key) {
|
|
2222
|
+
super(key);
|
|
2223
|
+
__publicField(this, "__variableKey");
|
|
2224
|
+
__publicField(this, "__format");
|
|
2225
|
+
__publicField(this, "__style");
|
|
2226
|
+
this.__variableKey = variableKey;
|
|
2227
|
+
this.__format = format;
|
|
2228
|
+
this.__style = style;
|
|
2229
|
+
}
|
|
2230
|
+
static getType() {
|
|
2231
|
+
return "variable-node";
|
|
2232
|
+
}
|
|
2233
|
+
static clone(node) {
|
|
2234
|
+
return new VariableNode(node.__variableKey, node.__format, node.__style, node.__key);
|
|
2235
|
+
}
|
|
2236
|
+
getVariableKey() {
|
|
2237
|
+
return this.getLatest().__variableKey;
|
|
2238
|
+
}
|
|
2239
|
+
getFormat() {
|
|
2240
|
+
return this.getLatest().__format;
|
|
2241
|
+
}
|
|
2242
|
+
setFormat(format) {
|
|
2243
|
+
const writable = this.getWritable();
|
|
2244
|
+
writable.__format = format;
|
|
2245
|
+
return writable;
|
|
2246
|
+
}
|
|
2247
|
+
getStyle() {
|
|
2248
|
+
return this.getLatest().__style;
|
|
2249
|
+
}
|
|
2250
|
+
setStyle(style) {
|
|
2251
|
+
const writable = this.getWritable();
|
|
2252
|
+
writable.__style = style;
|
|
2253
|
+
return writable;
|
|
2254
|
+
}
|
|
2255
|
+
// -- Serialization --
|
|
2256
|
+
static importJSON(serializedNode) {
|
|
2257
|
+
return $createVariableNode(
|
|
2258
|
+
serializedNode.variableKey,
|
|
2259
|
+
serializedNode.format ?? 0,
|
|
2260
|
+
serializedNode.style ?? ""
|
|
2261
|
+
);
|
|
2262
|
+
}
|
|
2263
|
+
exportJSON() {
|
|
2264
|
+
return {
|
|
2265
|
+
type: "variable-node",
|
|
2266
|
+
version: 1,
|
|
2267
|
+
variableKey: this.__variableKey,
|
|
2268
|
+
format: this.__format,
|
|
2269
|
+
style: this.__style
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
// -- DOM --
|
|
2273
|
+
createDOM() {
|
|
2274
|
+
const span = document.createElement("span");
|
|
2275
|
+
span.className = "lex4-variable";
|
|
2276
|
+
span.setAttribute("data-variable-key", this.__variableKey);
|
|
2277
|
+
span.setAttribute("data-testid", `variable-${this.__variableKey}`);
|
|
2278
|
+
span.contentEditable = "false";
|
|
2279
|
+
return span;
|
|
2280
|
+
}
|
|
2281
|
+
updateDOM() {
|
|
2282
|
+
return false;
|
|
2283
|
+
}
|
|
2284
|
+
exportDOM() {
|
|
2285
|
+
const span = document.createElement("span");
|
|
2286
|
+
span.setAttribute("data-variable-key", this.__variableKey);
|
|
2287
|
+
span.textContent = `{{${this.__variableKey}}}`;
|
|
2288
|
+
return { element: span };
|
|
2289
|
+
}
|
|
2290
|
+
static importDOM() {
|
|
2291
|
+
return null;
|
|
2292
|
+
}
|
|
2293
|
+
// -- Behavior --
|
|
2294
|
+
isInline() {
|
|
2295
|
+
return true;
|
|
2296
|
+
}
|
|
2297
|
+
isKeyboardSelectable() {
|
|
2298
|
+
return true;
|
|
2299
|
+
}
|
|
2300
|
+
getTextContent() {
|
|
2301
|
+
return `{{${this.__variableKey}}}`;
|
|
2302
|
+
}
|
|
2303
|
+
// -- Rendering --
|
|
2304
|
+
decorate() {
|
|
2305
|
+
return /* @__PURE__ */ jsx(
|
|
2306
|
+
VariableChip,
|
|
2307
|
+
{
|
|
2308
|
+
nodeKey: this.__key,
|
|
2309
|
+
variableKey: this.__variableKey,
|
|
2310
|
+
format: this.__format,
|
|
2311
|
+
styleValue: this.__style
|
|
2312
|
+
}
|
|
2313
|
+
);
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
function VariableChip({
|
|
2317
|
+
nodeKey,
|
|
2318
|
+
variableKey,
|
|
2319
|
+
format,
|
|
2320
|
+
styleValue
|
|
2321
|
+
}) {
|
|
2322
|
+
const { getDefinition } = useVariables();
|
|
2323
|
+
const [editor] = useLexicalComposerContext();
|
|
2324
|
+
const [isSelected, setSelected, clearOtherSelections] = useLexicalNodeSelection(nodeKey);
|
|
2325
|
+
const def = getDefinition(variableKey);
|
|
2326
|
+
const label = (def == null ? void 0 : def.label) ?? variableKey;
|
|
2327
|
+
const group = def == null ? void 0 : def.group;
|
|
2328
|
+
const style = useMemo(() => {
|
|
2329
|
+
const fontFamily = extractFontFamilyFromStyle(styleValue);
|
|
2330
|
+
const fontSize = extractFontSizePtFromStyle(styleValue);
|
|
2331
|
+
return {
|
|
2332
|
+
...fontFamily ? { fontFamily } : {},
|
|
2333
|
+
...fontSize ? { fontSize: `${fontSize}pt` } : {}
|
|
2334
|
+
};
|
|
2335
|
+
}, [styleValue]);
|
|
2336
|
+
const className = [
|
|
2337
|
+
"lex4-variable-chip",
|
|
2338
|
+
isSelected && "lex4-variable-chip-selected",
|
|
2339
|
+
format & 1 ? "lex4-text-bold" : "",
|
|
2340
|
+
format & 2 ? "lex4-text-italic" : "",
|
|
2341
|
+
format & 8 ? "lex4-text-underline" : "",
|
|
2342
|
+
format & 4 ? "lex4-text-strikethrough" : ""
|
|
2343
|
+
].filter(Boolean).join(" ");
|
|
2344
|
+
const handleClick = useCallback((event) => {
|
|
2345
|
+
event.preventDefault();
|
|
2346
|
+
if (!event.shiftKey) {
|
|
2347
|
+
clearOtherSelections();
|
|
2348
|
+
}
|
|
2349
|
+
setSelected(!isSelected);
|
|
2350
|
+
}, [clearOtherSelections, isSelected, setSelected]);
|
|
2351
|
+
useEffect(() => {
|
|
2352
|
+
const removeSelectedNodes = () => {
|
|
2353
|
+
editor.update(() => {
|
|
2354
|
+
const selection = $getSelection();
|
|
2355
|
+
if (!$isNodeSelection(selection)) {
|
|
2356
|
+
const node = $getNodeByKey(nodeKey);
|
|
2357
|
+
if ($isVariableNode(node)) {
|
|
2358
|
+
node.remove();
|
|
2359
|
+
}
|
|
2360
|
+
return;
|
|
2361
|
+
}
|
|
2362
|
+
for (const node of selection.getNodes()) {
|
|
2363
|
+
if ($isVariableNode(node)) {
|
|
2364
|
+
node.remove();
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
});
|
|
2368
|
+
};
|
|
2369
|
+
const unregisterBackspace = editor.registerCommand(
|
|
2370
|
+
KEY_BACKSPACE_COMMAND,
|
|
2371
|
+
() => {
|
|
2372
|
+
if (!isSelected) {
|
|
2373
|
+
return false;
|
|
2374
|
+
}
|
|
2375
|
+
removeSelectedNodes();
|
|
2376
|
+
return true;
|
|
2377
|
+
},
|
|
2378
|
+
COMMAND_PRIORITY_LOW
|
|
2379
|
+
);
|
|
2380
|
+
const unregisterDelete = editor.registerCommand(
|
|
2381
|
+
KEY_DELETE_COMMAND,
|
|
2382
|
+
() => {
|
|
2383
|
+
if (!isSelected) {
|
|
2384
|
+
return false;
|
|
2385
|
+
}
|
|
2386
|
+
removeSelectedNodes();
|
|
2387
|
+
return true;
|
|
2388
|
+
},
|
|
2389
|
+
COMMAND_PRIORITY_LOW
|
|
2390
|
+
);
|
|
2391
|
+
return () => {
|
|
2392
|
+
unregisterBackspace();
|
|
2393
|
+
unregisterDelete();
|
|
2394
|
+
};
|
|
2395
|
+
}, [editor, isSelected, nodeKey]);
|
|
2396
|
+
return /* @__PURE__ */ jsx(
|
|
2397
|
+
"span",
|
|
2398
|
+
{
|
|
2399
|
+
className,
|
|
2400
|
+
"data-testid": `variable-chip-${variableKey}`,
|
|
2401
|
+
"data-variable-group": group,
|
|
2402
|
+
title: variableKey,
|
|
2403
|
+
style,
|
|
2404
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
2405
|
+
onClick: handleClick,
|
|
2406
|
+
children: label
|
|
2407
|
+
}
|
|
2408
|
+
);
|
|
2409
|
+
}
|
|
2410
|
+
function $createVariableNode(variableKey, format = 0, style = "") {
|
|
2411
|
+
return $applyNodeReplacement(new VariableNode(variableKey, format, style));
|
|
2412
|
+
}
|
|
2413
|
+
function $isVariableNode(node) {
|
|
2414
|
+
return node instanceof VariableNode;
|
|
2415
|
+
}
|
|
2416
|
+
const FORMAT_MASKS = {
|
|
2417
|
+
bold: 1,
|
|
2418
|
+
italic: 2,
|
|
2419
|
+
strikethrough: 4,
|
|
2420
|
+
underline: 8
|
|
2421
|
+
};
|
|
2422
|
+
function withSelectedVariableNodes(editor, updater) {
|
|
2423
|
+
let updated = false;
|
|
2424
|
+
editor.update(() => {
|
|
2425
|
+
const selection = $getSelection();
|
|
2426
|
+
if (!$isNodeSelection(selection)) {
|
|
2427
|
+
return;
|
|
2428
|
+
}
|
|
2429
|
+
const nodes = selection.getNodes().filter($isVariableNode);
|
|
2430
|
+
if (nodes.length === 0) {
|
|
2431
|
+
return;
|
|
2432
|
+
}
|
|
2433
|
+
updater(nodes);
|
|
2434
|
+
updated = true;
|
|
2435
|
+
});
|
|
2436
|
+
return updated;
|
|
2437
|
+
}
|
|
2438
|
+
function getSelectedVariableNodes(editor) {
|
|
2439
|
+
let nodes = [];
|
|
2440
|
+
editor.getEditorState().read(() => {
|
|
2441
|
+
const selection = $getSelection();
|
|
2442
|
+
if (!$isNodeSelection(selection)) {
|
|
2443
|
+
return;
|
|
2444
|
+
}
|
|
2445
|
+
nodes = selection.getNodes().filter($isVariableNode);
|
|
2446
|
+
});
|
|
2447
|
+
return nodes;
|
|
2448
|
+
}
|
|
2449
|
+
function toggleSelectedVariableFormat(editor, format) {
|
|
2450
|
+
const mask = FORMAT_MASKS[format];
|
|
2451
|
+
if (!mask) {
|
|
2452
|
+
return false;
|
|
2453
|
+
}
|
|
2454
|
+
return withSelectedVariableNodes(editor, (nodes) => {
|
|
2455
|
+
const shouldEnable = nodes.some((node) => (node.getFormat() & mask) === 0);
|
|
2456
|
+
for (const node of nodes) {
|
|
2457
|
+
const nextFormat = shouldEnable ? node.getFormat() | mask : node.getFormat() & ~mask;
|
|
2458
|
+
node.setFormat(nextFormat);
|
|
2459
|
+
}
|
|
2460
|
+
});
|
|
2461
|
+
}
|
|
2462
|
+
function applyFontFamilyToSelectedVariables(editor, fontFamily) {
|
|
2463
|
+
return withSelectedVariableNodes(editor, (nodes) => {
|
|
2464
|
+
for (const node of nodes) {
|
|
2465
|
+
node.setStyle(mergeFontFamilyStyle(node.getStyle(), fontFamily));
|
|
2466
|
+
}
|
|
2467
|
+
});
|
|
2468
|
+
}
|
|
2469
|
+
function applyFontSizeToSelectedVariables(editor, size) {
|
|
2470
|
+
return withSelectedVariableNodes(editor, (nodes) => {
|
|
2471
|
+
for (const node of nodes) {
|
|
2472
|
+
node.setStyle(mergeFontSizeStyle(node.getStyle(), size));
|
|
2473
|
+
}
|
|
2474
|
+
});
|
|
2475
|
+
}
|
|
2476
|
+
function readSelectedVariableFormatting(editor) {
|
|
2477
|
+
const firstNode = getSelectedVariableNodes(editor)[0];
|
|
2478
|
+
if (!firstNode) {
|
|
2479
|
+
return {};
|
|
2480
|
+
}
|
|
2481
|
+
const style = firstNode.getStyle();
|
|
2482
|
+
return {
|
|
2483
|
+
fontFamily: extractFontFamilyFromStyle(style),
|
|
2484
|
+
fontSize: extractFontSizePtFromStyle(style)
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2049
2487
|
const HeaderFooterToggle = ({
|
|
2050
2488
|
enabled,
|
|
2051
|
-
onToggle
|
|
2489
|
+
onToggle,
|
|
2490
|
+
showLabel = true
|
|
2052
2491
|
}) => {
|
|
2053
2492
|
const t = useTranslations();
|
|
2054
2493
|
return /* @__PURE__ */ jsxs(
|
|
@@ -2058,18 +2497,20 @@ const HeaderFooterToggle = ({
|
|
|
2058
2497
|
"data-testid": "header-footer-toggle",
|
|
2059
2498
|
children: [
|
|
2060
2499
|
/* @__PURE__ */ jsx(FileText, { size: 14, className: "lex4-hf-toggle-icon" }),
|
|
2061
|
-
/* @__PURE__ */ jsx("span", { className: "lex4-hf-toggle-label", children: t.headerFooter.label }),
|
|
2500
|
+
showLabel && /* @__PURE__ */ jsx("span", { className: "lex4-hf-toggle-label", children: t.headerFooter.label }),
|
|
2062
2501
|
/* @__PURE__ */ jsx(
|
|
2063
2502
|
"button",
|
|
2064
2503
|
{
|
|
2065
2504
|
type: "button",
|
|
2066
2505
|
role: "switch",
|
|
2067
2506
|
"aria-checked": enabled,
|
|
2507
|
+
"aria-label": t.headerFooter.label,
|
|
2068
2508
|
onMouseDown: (e) => e.preventDefault(),
|
|
2069
2509
|
onClick: () => onToggle(!enabled),
|
|
2070
2510
|
className: "lex4-hf-switch",
|
|
2071
2511
|
style: { backgroundColor: enabled ? "var(--color-primary)" : "var(--color-muted)" },
|
|
2072
2512
|
"data-testid": "header-footer-switch",
|
|
2513
|
+
title: t.headerFooter.label,
|
|
2073
2514
|
children: /* @__PURE__ */ jsx("span", { className: "lex4-hf-switch-knob" })
|
|
2074
2515
|
}
|
|
2075
2516
|
)
|
|
@@ -2077,12 +2518,7 @@ const HeaderFooterToggle = ({
|
|
|
2077
2518
|
}
|
|
2078
2519
|
);
|
|
2079
2520
|
};
|
|
2080
|
-
const PAGE_COUNTER_OPTIONS = [
|
|
2081
|
-
{ value: "none", label: "None" },
|
|
2082
|
-
{ value: "header", label: "Header" },
|
|
2083
|
-
{ value: "footer", label: "Footer" },
|
|
2084
|
-
{ value: "both", label: "Both" }
|
|
2085
|
-
];
|
|
2521
|
+
const PAGE_COUNTER_OPTIONS = ["none", "header", "footer", "both"];
|
|
2086
2522
|
const HeaderFooterActions = ({
|
|
2087
2523
|
activePageId,
|
|
2088
2524
|
pageCounterMode,
|
|
@@ -2097,6 +2533,7 @@ const HeaderFooterActions = ({
|
|
|
2097
2533
|
const [open, setOpen] = useState(false);
|
|
2098
2534
|
const containerRef = useRef(null);
|
|
2099
2535
|
const hasActivePage = activePageId !== null;
|
|
2536
|
+
const t = useTranslations();
|
|
2100
2537
|
const close = useCallback(() => setOpen(false), []);
|
|
2101
2538
|
useEffect(() => {
|
|
2102
2539
|
if (!open) return;
|
|
@@ -2123,8 +2560,8 @@ const HeaderFooterActions = ({
|
|
|
2123
2560
|
"data-testid": "header-footer-menu-trigger",
|
|
2124
2561
|
"aria-expanded": open,
|
|
2125
2562
|
"aria-haspopup": "true",
|
|
2126
|
-
"aria-label":
|
|
2127
|
-
title:
|
|
2563
|
+
"aria-label": t.headerFooter.settingsLabel,
|
|
2564
|
+
title: t.headerFooter.settingsLabel,
|
|
2128
2565
|
children: /* @__PURE__ */ jsx(Settings2, { size: 14 })
|
|
2129
2566
|
}
|
|
2130
2567
|
),
|
|
@@ -2135,8 +2572,8 @@ const HeaderFooterActions = ({
|
|
|
2135
2572
|
role: "menu",
|
|
2136
2573
|
"data-testid": "header-footer-menu",
|
|
2137
2574
|
children: [
|
|
2138
|
-
/* @__PURE__ */ jsx(SectionLabel, { children:
|
|
2139
|
-
/* @__PURE__ */ jsx("div", { className: "lex4-settings-counter-grid", "data-testid": "page-counter-mode", children: PAGE_COUNTER_OPTIONS.map((
|
|
2575
|
+
/* @__PURE__ */ jsx(SectionLabel, { children: t.headerFooter.pageCounter }),
|
|
2576
|
+
/* @__PURE__ */ jsx("div", { className: "lex4-settings-counter-grid", "data-testid": "page-counter-mode", children: PAGE_COUNTER_OPTIONS.map((value) => /* @__PURE__ */ jsx(
|
|
2140
2577
|
"button",
|
|
2141
2578
|
{
|
|
2142
2579
|
type: "button",
|
|
@@ -2146,17 +2583,17 @@ const HeaderFooterActions = ({
|
|
|
2146
2583
|
onClick: () => onPageCounterModeChange(value),
|
|
2147
2584
|
className: "lex4-settings-counter-btn",
|
|
2148
2585
|
"data-testid": `page-counter-${value}`,
|
|
2149
|
-
children:
|
|
2586
|
+
children: t.headerFooter.pageCounterModes[value]
|
|
2150
2587
|
},
|
|
2151
2588
|
value
|
|
2152
2589
|
)) }),
|
|
2153
2590
|
/* @__PURE__ */ jsx(MenuDivider, {}),
|
|
2154
|
-
/* @__PURE__ */ jsx(SectionLabel, { children:
|
|
2591
|
+
/* @__PURE__ */ jsx(SectionLabel, { children: t.headerFooter.headerSection }),
|
|
2155
2592
|
/* @__PURE__ */ jsx(
|
|
2156
2593
|
MenuItem,
|
|
2157
2594
|
{
|
|
2158
2595
|
icon: /* @__PURE__ */ jsx(CopyPlus, { size: 14 }),
|
|
2159
|
-
label:
|
|
2596
|
+
label: t.headerFooter.copyToAllPages,
|
|
2160
2597
|
onClick: () => handleAction(onCopyHeaderToAll),
|
|
2161
2598
|
disabled: !hasActivePage,
|
|
2162
2599
|
testId: "copy-header-all"
|
|
@@ -2166,7 +2603,7 @@ const HeaderFooterActions = ({
|
|
|
2166
2603
|
MenuItem,
|
|
2167
2604
|
{
|
|
2168
2605
|
icon: /* @__PURE__ */ jsx(Eraser, { size: 14 }),
|
|
2169
|
-
label:
|
|
2606
|
+
label: t.headerFooter.clearThisPage,
|
|
2170
2607
|
onClick: () => handleAction(onClearHeader),
|
|
2171
2608
|
disabled: !hasActivePage,
|
|
2172
2609
|
testId: "clear-header"
|
|
@@ -2176,18 +2613,18 @@ const HeaderFooterActions = ({
|
|
|
2176
2613
|
MenuItem,
|
|
2177
2614
|
{
|
|
2178
2615
|
icon: /* @__PURE__ */ jsx(Trash2, { size: 14 }),
|
|
2179
|
-
label:
|
|
2616
|
+
label: t.headerFooter.clearAll,
|
|
2180
2617
|
onClick: () => handleAction(onClearAllHeaders),
|
|
2181
2618
|
testId: "clear-all-headers"
|
|
2182
2619
|
}
|
|
2183
2620
|
),
|
|
2184
2621
|
/* @__PURE__ */ jsx(MenuDivider, {}),
|
|
2185
|
-
/* @__PURE__ */ jsx(SectionLabel, { children:
|
|
2622
|
+
/* @__PURE__ */ jsx(SectionLabel, { children: t.headerFooter.footerSection }),
|
|
2186
2623
|
/* @__PURE__ */ jsx(
|
|
2187
2624
|
MenuItem,
|
|
2188
2625
|
{
|
|
2189
2626
|
icon: /* @__PURE__ */ jsx(CopyPlus, { size: 14 }),
|
|
2190
|
-
label:
|
|
2627
|
+
label: t.headerFooter.copyToAllPages,
|
|
2191
2628
|
onClick: () => handleAction(onCopyFooterToAll),
|
|
2192
2629
|
disabled: !hasActivePage,
|
|
2193
2630
|
testId: "copy-footer-all"
|
|
@@ -2197,7 +2634,7 @@ const HeaderFooterActions = ({
|
|
|
2197
2634
|
MenuItem,
|
|
2198
2635
|
{
|
|
2199
2636
|
icon: /* @__PURE__ */ jsx(Eraser, { size: 14 }),
|
|
2200
|
-
label:
|
|
2637
|
+
label: t.headerFooter.clearThisPage,
|
|
2201
2638
|
onClick: () => handleAction(onClearFooter),
|
|
2202
2639
|
disabled: !hasActivePage,
|
|
2203
2640
|
testId: "clear-footer"
|
|
@@ -2207,7 +2644,7 @@ const HeaderFooterActions = ({
|
|
|
2207
2644
|
MenuItem,
|
|
2208
2645
|
{
|
|
2209
2646
|
icon: /* @__PURE__ */ jsx(Trash2, { size: 14 }),
|
|
2210
|
-
label:
|
|
2647
|
+
label: t.headerFooter.clearAll,
|
|
2211
2648
|
onClick: () => handleAction(onClearAllFooters),
|
|
2212
2649
|
testId: "clear-all-footers"
|
|
2213
2650
|
}
|
|
@@ -2237,6 +2674,7 @@ const MenuItem = ({ icon, label, onClick, disabled, testId }) => /* @__PURE__ */
|
|
|
2237
2674
|
const MenuDivider = () => /* @__PURE__ */ jsx("div", { className: "lex4-settings-divider" });
|
|
2238
2675
|
const CanvasControls = () => {
|
|
2239
2676
|
const { document: document2, dispatch, activePageId, runHistoryAction } = useDocument();
|
|
2677
|
+
const toolbarConfig = useToolbarConfig();
|
|
2240
2678
|
const t = useTranslations();
|
|
2241
2679
|
const runCanvasAction = useCallback((label, callback) => {
|
|
2242
2680
|
runHistoryAction(
|
|
@@ -2303,12 +2741,16 @@ const CanvasControls = () => {
|
|
|
2303
2741
|
dispatch({ type: "SET_PAGE_COUNTER_MODE", mode });
|
|
2304
2742
|
});
|
|
2305
2743
|
}, [dispatch, runCanvasAction, t.history.actions.pageCounterSet]);
|
|
2744
|
+
if (!toolbarConfig.headerFooter.visible) {
|
|
2745
|
+
return null;
|
|
2746
|
+
}
|
|
2306
2747
|
return /* @__PURE__ */ jsxs("div", { className: "lex4-toolbar-group lex4-toolbar-group-gap", "data-testid": "header-footer-controls", children: [
|
|
2307
2748
|
/* @__PURE__ */ jsx(
|
|
2308
2749
|
HeaderFooterToggle,
|
|
2309
2750
|
{
|
|
2310
2751
|
enabled: document2.headerFooterEnabled,
|
|
2311
|
-
onToggle: handleToggle
|
|
2752
|
+
onToggle: handleToggle,
|
|
2753
|
+
showLabel: toolbarConfig.headerFooter.showLabel
|
|
2312
2754
|
}
|
|
2313
2755
|
),
|
|
2314
2756
|
document2.headerFooterEnabled && /* @__PURE__ */ jsx(
|
|
@@ -2341,7 +2783,17 @@ const Toolbar = () => {
|
|
|
2341
2783
|
undo
|
|
2342
2784
|
} = useDocument();
|
|
2343
2785
|
const { toolbarItems, toolbarEndItems } = useExtensions();
|
|
2786
|
+
const toolbarConfig = useToolbarConfig();
|
|
2344
2787
|
const t = useTranslations();
|
|
2788
|
+
const [activeBlockType, setActiveBlockType] = useState("paragraph");
|
|
2789
|
+
const [activeFontFamily, setActiveFontFamily] = useState("Calibri");
|
|
2790
|
+
const [activeFontSize, setActiveFontSize] = useState(DEFAULT_FONT_SIZE);
|
|
2791
|
+
const normalizeFontFamily = useCallback((fontFamily) => {
|
|
2792
|
+
if (fontFamily && SUPPORTED_FONTS.includes(fontFamily)) {
|
|
2793
|
+
return fontFamily;
|
|
2794
|
+
}
|
|
2795
|
+
return "Calibri";
|
|
2796
|
+
}, []);
|
|
2345
2797
|
const withBodySelection = useCallback(
|
|
2346
2798
|
(editor, action) => {
|
|
2347
2799
|
editor.update(() => {
|
|
@@ -2377,27 +2829,91 @@ const Toolbar = () => {
|
|
|
2377
2829
|
},
|
|
2378
2830
|
[runHistoryAction]
|
|
2379
2831
|
);
|
|
2832
|
+
useEffect(() => {
|
|
2833
|
+
if (!activeEditor) {
|
|
2834
|
+
setActiveBlockType("paragraph");
|
|
2835
|
+
setActiveFontFamily("Calibri");
|
|
2836
|
+
setActiveFontSize(DEFAULT_FONT_SIZE);
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
const updateSelectionState = () => {
|
|
2840
|
+
const selectedVariables = getSelectedVariableNodes(activeEditor);
|
|
2841
|
+
if (selectedVariables.length > 0) {
|
|
2842
|
+
const formatting = readSelectedVariableFormatting(activeEditor);
|
|
2843
|
+
setActiveBlockType("paragraph");
|
|
2844
|
+
setActiveFontFamily(normalizeFontFamily(formatting.fontFamily));
|
|
2845
|
+
setActiveFontSize(formatting.fontSize ?? DEFAULT_FONT_SIZE);
|
|
2846
|
+
return;
|
|
2847
|
+
}
|
|
2848
|
+
setActiveBlockType(getActiveBlockType(activeEditor));
|
|
2849
|
+
let nextFontFamily = "Calibri";
|
|
2850
|
+
let nextFontSize = DEFAULT_FONT_SIZE;
|
|
2851
|
+
activeEditor.getEditorState().read(() => {
|
|
2852
|
+
const selection = $getSelection();
|
|
2853
|
+
if (!$isRangeSelection(selection)) {
|
|
2854
|
+
return;
|
|
2855
|
+
}
|
|
2856
|
+
const textNode = selection.getNodes().find($isTextNode);
|
|
2857
|
+
if (!textNode) {
|
|
2858
|
+
return;
|
|
2859
|
+
}
|
|
2860
|
+
const style = textNode.getStyle();
|
|
2861
|
+
nextFontFamily = normalizeFontFamily(extractFontFamilyFromStyle(style));
|
|
2862
|
+
nextFontSize = extractFontSizePtFromStyle(style) ?? DEFAULT_FONT_SIZE;
|
|
2863
|
+
});
|
|
2864
|
+
setActiveFontFamily(nextFontFamily);
|
|
2865
|
+
setActiveFontSize(nextFontSize);
|
|
2866
|
+
};
|
|
2867
|
+
updateSelectionState();
|
|
2868
|
+
const unregisterSelectionChange = activeEditor.registerCommand(
|
|
2869
|
+
SELECTION_CHANGE_COMMAND,
|
|
2870
|
+
() => {
|
|
2871
|
+
updateSelectionState();
|
|
2872
|
+
return false;
|
|
2873
|
+
},
|
|
2874
|
+
COMMAND_PRIORITY_LOW
|
|
2875
|
+
);
|
|
2876
|
+
const unregisterUpdateListener = activeEditor.registerUpdateListener(() => {
|
|
2877
|
+
updateSelectionState();
|
|
2878
|
+
});
|
|
2879
|
+
return () => {
|
|
2880
|
+
unregisterSelectionChange();
|
|
2881
|
+
unregisterUpdateListener();
|
|
2882
|
+
};
|
|
2883
|
+
}, [activeEditor, normalizeFontFamily]);
|
|
2380
2884
|
const handleBold = useCallback(() => {
|
|
2381
2885
|
debug("toolbar", `bold (globalSelection=${globalSelectionActive}, editors=${editorRegistry.all().length}, hasEditor=${!!activeEditor})`);
|
|
2382
2886
|
runToolbarAction(t.history.actions.boldApplied, () => {
|
|
2887
|
+
if (activeEditor && toggleSelectedVariableFormat(activeEditor, "bold")) {
|
|
2888
|
+
return;
|
|
2889
|
+
}
|
|
2383
2890
|
applyToBodyEditors(toggleBold);
|
|
2384
2891
|
});
|
|
2385
2892
|
}, [activeEditor, applyToBodyEditors, editorRegistry, globalSelectionActive, runToolbarAction, t.history.actions.boldApplied]);
|
|
2386
2893
|
const handleItalic = useCallback(() => {
|
|
2387
2894
|
debug("toolbar", `italic (globalSelection=${globalSelectionActive}, hasEditor=${!!activeEditor})`);
|
|
2388
2895
|
runToolbarAction(t.history.actions.italicApplied, () => {
|
|
2896
|
+
if (activeEditor && toggleSelectedVariableFormat(activeEditor, "italic")) {
|
|
2897
|
+
return;
|
|
2898
|
+
}
|
|
2389
2899
|
applyToBodyEditors(toggleItalic);
|
|
2390
2900
|
});
|
|
2391
2901
|
}, [activeEditor, applyToBodyEditors, globalSelectionActive, runToolbarAction, t.history.actions.italicApplied]);
|
|
2392
2902
|
const handleUnderline = useCallback(() => {
|
|
2393
2903
|
debug("toolbar", `underline (globalSelection=${globalSelectionActive}, hasEditor=${!!activeEditor})`);
|
|
2394
2904
|
runToolbarAction(t.history.actions.underlineApplied, () => {
|
|
2905
|
+
if (activeEditor && toggleSelectedVariableFormat(activeEditor, "underline")) {
|
|
2906
|
+
return;
|
|
2907
|
+
}
|
|
2395
2908
|
applyToBodyEditors(toggleUnderline);
|
|
2396
2909
|
});
|
|
2397
2910
|
}, [activeEditor, applyToBodyEditors, globalSelectionActive, runToolbarAction, t.history.actions.underlineApplied]);
|
|
2398
2911
|
const handleStrikethrough = useCallback(() => {
|
|
2399
2912
|
debug("toolbar", `strikethrough (globalSelection=${globalSelectionActive}, hasEditor=${!!activeEditor})`);
|
|
2400
2913
|
runToolbarAction(t.history.actions.strikethroughApplied, () => {
|
|
2914
|
+
if (activeEditor && toggleSelectedVariableFormat(activeEditor, "strikethrough")) {
|
|
2915
|
+
return;
|
|
2916
|
+
}
|
|
2401
2917
|
applyToBodyEditors(toggleStrikethrough);
|
|
2402
2918
|
});
|
|
2403
2919
|
}, [activeEditor, applyToBodyEditors, globalSelectionActive, runToolbarAction, t.history.actions.strikethroughApplied]);
|
|
@@ -2443,20 +2959,59 @@ const Toolbar = () => {
|
|
|
2443
2959
|
}, [applyToBodyEditors, runToolbarAction, t.history.actions.outdentedContent]);
|
|
2444
2960
|
const handleFontChange = useCallback(
|
|
2445
2961
|
(e) => {
|
|
2446
|
-
|
|
2447
|
-
|
|
2962
|
+
const fontFamily = e.target.value;
|
|
2963
|
+
runToolbarAction(interpolate(t.history.actions.fontChanged, { value: fontFamily }), () => {
|
|
2964
|
+
if (activeEditor && applyFontFamilyToSelectedVariables(activeEditor, fontFamily)) {
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2967
|
+
applyToBodyEditors((editor) => applyFontFamily(editor, fontFamily));
|
|
2448
2968
|
});
|
|
2449
2969
|
},
|
|
2450
|
-
[applyToBodyEditors, runToolbarAction, t.history.actions.fontChanged]
|
|
2970
|
+
[activeEditor, applyToBodyEditors, runToolbarAction, t.history.actions.fontChanged]
|
|
2451
2971
|
);
|
|
2452
2972
|
const handleFontSizeChange = useCallback(
|
|
2453
2973
|
(e) => {
|
|
2454
2974
|
const size = parseInt(e.target.value, 10);
|
|
2455
2975
|
runToolbarAction(interpolate(t.history.actions.fontSizeChanged, { value: String(size) }), () => {
|
|
2976
|
+
if (activeEditor && applyFontSizeToSelectedVariables(activeEditor, size)) {
|
|
2977
|
+
return;
|
|
2978
|
+
}
|
|
2456
2979
|
applyToBodyEditors((editor) => applyFontSize(editor, size));
|
|
2457
2980
|
});
|
|
2458
2981
|
},
|
|
2459
|
-
[applyToBodyEditors, runToolbarAction, t.history.actions.fontSizeChanged]
|
|
2982
|
+
[activeEditor, applyToBodyEditors, runToolbarAction, t.history.actions.fontSizeChanged]
|
|
2983
|
+
);
|
|
2984
|
+
const handleBlockTypeChange = useCallback(
|
|
2985
|
+
(e) => {
|
|
2986
|
+
const blockType = e.target.value;
|
|
2987
|
+
const labelMap = {
|
|
2988
|
+
paragraph: t.toolbar.paragraph,
|
|
2989
|
+
h1: t.toolbar.heading1,
|
|
2990
|
+
h2: t.toolbar.heading2,
|
|
2991
|
+
h3: t.toolbar.heading3,
|
|
2992
|
+
h4: t.toolbar.heading4,
|
|
2993
|
+
h5: t.toolbar.heading5,
|
|
2994
|
+
h6: t.toolbar.heading6
|
|
2995
|
+
};
|
|
2996
|
+
runToolbarAction(
|
|
2997
|
+
interpolate(t.history.actions.blockTypeChanged, { value: labelMap[blockType] }),
|
|
2998
|
+
() => {
|
|
2999
|
+
applyToBodyEditors((editor) => setBlockType(editor, blockType));
|
|
3000
|
+
}
|
|
3001
|
+
);
|
|
3002
|
+
},
|
|
3003
|
+
[
|
|
3004
|
+
applyToBodyEditors,
|
|
3005
|
+
runToolbarAction,
|
|
3006
|
+
t.history.actions.blockTypeChanged,
|
|
3007
|
+
t.toolbar.heading1,
|
|
3008
|
+
t.toolbar.heading2,
|
|
3009
|
+
t.toolbar.heading3,
|
|
3010
|
+
t.toolbar.heading4,
|
|
3011
|
+
t.toolbar.heading5,
|
|
3012
|
+
t.toolbar.heading6,
|
|
3013
|
+
t.toolbar.paragraph
|
|
3014
|
+
]
|
|
2460
3015
|
);
|
|
2461
3016
|
const handleToggleHistory = useCallback(() => {
|
|
2462
3017
|
setHistorySidebarOpen(!historySidebarOpen);
|
|
@@ -2490,6 +3045,26 @@ const Toolbar = () => {
|
|
|
2490
3045
|
)
|
|
2491
3046
|
] }),
|
|
2492
3047
|
/* @__PURE__ */ jsx(Divider, {}),
|
|
3048
|
+
/* @__PURE__ */ jsx("div", { className: "lex4-toolbar-group-gap lex4-toolbar-group-block", children: /* @__PURE__ */ jsxs(
|
|
3049
|
+
"select",
|
|
3050
|
+
{
|
|
3051
|
+
className: "lex4-toolbar-select lex4-toolbar-select-block",
|
|
3052
|
+
"data-testid": "block-type-selector",
|
|
3053
|
+
"aria-label": t.toolbar.blockType,
|
|
3054
|
+
value: activeBlockType,
|
|
3055
|
+
onChange: handleBlockTypeChange,
|
|
3056
|
+
children: [
|
|
3057
|
+
/* @__PURE__ */ jsx("option", { value: "paragraph", children: t.toolbar.paragraph }),
|
|
3058
|
+
/* @__PURE__ */ jsx("option", { value: "h1", children: t.toolbar.heading1 }),
|
|
3059
|
+
/* @__PURE__ */ jsx("option", { value: "h2", children: t.toolbar.heading2 }),
|
|
3060
|
+
/* @__PURE__ */ jsx("option", { value: "h3", children: t.toolbar.heading3 }),
|
|
3061
|
+
/* @__PURE__ */ jsx("option", { value: "h4", children: t.toolbar.heading4 }),
|
|
3062
|
+
/* @__PURE__ */ jsx("option", { value: "h5", children: t.toolbar.heading5 }),
|
|
3063
|
+
/* @__PURE__ */ jsx("option", { value: "h6", children: t.toolbar.heading6 })
|
|
3064
|
+
]
|
|
3065
|
+
}
|
|
3066
|
+
) }),
|
|
3067
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
2493
3068
|
/* @__PURE__ */ jsxs("div", { className: "lex4-toolbar-group-gap", children: [
|
|
2494
3069
|
/* @__PURE__ */ jsx(Type, { size: 14, className: "lex4-toolbar-icon" }),
|
|
2495
3070
|
/* @__PURE__ */ jsx(
|
|
@@ -2497,7 +3072,7 @@ const Toolbar = () => {
|
|
|
2497
3072
|
{
|
|
2498
3073
|
className: "lex4-toolbar-select",
|
|
2499
3074
|
"data-testid": "font-selector",
|
|
2500
|
-
|
|
3075
|
+
value: activeFontFamily,
|
|
2501
3076
|
onChange: handleFontChange,
|
|
2502
3077
|
children: SUPPORTED_FONTS.map((font) => /* @__PURE__ */ jsx("option", { value: font, style: { fontFamily: font }, children: font }, font))
|
|
2503
3078
|
}
|
|
@@ -2510,7 +3085,7 @@ const Toolbar = () => {
|
|
|
2510
3085
|
{
|
|
2511
3086
|
className: "lex4-toolbar-select lex4-toolbar-select-narrow",
|
|
2512
3087
|
"data-testid": "font-size-selector",
|
|
2513
|
-
|
|
3088
|
+
value: String(activeFontSize),
|
|
2514
3089
|
onChange: handleFontSizeChange,
|
|
2515
3090
|
children: SUPPORTED_FONT_SIZES.map((size) => /* @__PURE__ */ jsx("option", { value: size, children: size }, size))
|
|
2516
3091
|
}
|
|
@@ -2545,7 +3120,7 @@ const Toolbar = () => {
|
|
|
2545
3120
|
/* @__PURE__ */ jsx(CanvasControls, {}),
|
|
2546
3121
|
/* @__PURE__ */ jsxs("div", { className: "lex4-toolbar-end", children: [
|
|
2547
3122
|
toolbarEndItems.map((EndItem, idx) => /* @__PURE__ */ jsx(EndItem, {}, idx)),
|
|
2548
|
-
/* @__PURE__ */ jsxs(
|
|
3123
|
+
toolbarConfig.history.visible && /* @__PURE__ */ jsxs(
|
|
2549
3124
|
"button",
|
|
2550
3125
|
{
|
|
2551
3126
|
type: "button",
|
|
@@ -2557,7 +3132,7 @@ const Toolbar = () => {
|
|
|
2557
3132
|
"aria-label": historySidebarOpen ? t.toolbar.closeHistory : t.toolbar.openHistory,
|
|
2558
3133
|
children: [
|
|
2559
3134
|
/* @__PURE__ */ jsx(History, { size: 14 }),
|
|
2560
|
-
|
|
3135
|
+
toolbarConfig.history.showLabel && t.toolbar.history
|
|
2561
3136
|
]
|
|
2562
3137
|
}
|
|
2563
3138
|
)
|
|
@@ -2901,7 +3476,8 @@ const lexicalTheme = {
|
|
|
2901
3476
|
h2: "lex4-heading lex4-heading-h2",
|
|
2902
3477
|
h3: "lex4-heading lex4-heading-h3",
|
|
2903
3478
|
h4: "lex4-heading lex4-heading-h4",
|
|
2904
|
-
h5: "lex4-heading lex4-heading-h5"
|
|
3479
|
+
h5: "lex4-heading lex4-heading-h5",
|
|
3480
|
+
h6: "lex4-heading lex4-heading-h6"
|
|
2905
3481
|
},
|
|
2906
3482
|
text: {
|
|
2907
3483
|
bold: "lex4-text-bold",
|
|
@@ -4438,12 +5014,10 @@ function decodeFormatBitmask(format) {
|
|
|
4438
5014
|
return marks;
|
|
4439
5015
|
}
|
|
4440
5016
|
function extractFontFamily(style) {
|
|
4441
|
-
|
|
4442
|
-
return match ? match[1].trim().replace(/['"]/g, "") : void 0;
|
|
5017
|
+
return extractFontFamilyFromStyle(style);
|
|
4443
5018
|
}
|
|
4444
5019
|
function extractFontSizePt(style) {
|
|
4445
|
-
|
|
4446
|
-
return match ? parseFloat(match[1]) : void 0;
|
|
5020
|
+
return extractFontSizePtFromStyle(style);
|
|
4447
5021
|
}
|
|
4448
5022
|
function buildTextMarks(format, style) {
|
|
4449
5023
|
const formatMarks = decodeFormatBitmask(format);
|
|
@@ -4477,9 +5051,11 @@ function mapTextNode(node) {
|
|
|
4477
5051
|
};
|
|
4478
5052
|
}
|
|
4479
5053
|
function mapVariableNode(node) {
|
|
5054
|
+
const marks = buildTextMarks(node.format ?? 0, node.style);
|
|
4480
5055
|
return {
|
|
4481
5056
|
type: "variable",
|
|
4482
|
-
key: node.variableKey
|
|
5057
|
+
key: node.variableKey,
|
|
5058
|
+
...marks ? { marks } : {}
|
|
4483
5059
|
};
|
|
4484
5060
|
}
|
|
4485
5061
|
function mapLineBreak() {
|
|
@@ -4543,7 +5119,7 @@ function mapParagraph(node) {
|
|
|
4543
5119
|
function mapHeading(node) {
|
|
4544
5120
|
var _a;
|
|
4545
5121
|
const alignment = decodeAlignment(node.format);
|
|
4546
|
-
const tagMatch = (_a = node.tag) == null ? void 0 : _a.match(/^h(
|
|
5122
|
+
const tagMatch = (_a = node.tag) == null ? void 0 : _a.match(/^h([1-6])$/);
|
|
4547
5123
|
const level = tagMatch ? parseInt(tagMatch[1], 10) : 1;
|
|
4548
5124
|
return {
|
|
4549
5125
|
type: "heading",
|
|
@@ -4668,6 +5244,105 @@ function buildSavePayload(ast, options) {
|
|
|
4668
5244
|
function serializeDocumentJson(ast) {
|
|
4669
5245
|
return JSON.stringify(ast, null, 2);
|
|
4670
5246
|
}
|
|
5247
|
+
function appendChildren(parent, children = []) {
|
|
5248
|
+
const nodes = children.map(buildLexicalNode).filter((node) => node !== null);
|
|
5249
|
+
if (nodes.length > 0) {
|
|
5250
|
+
parent.append(...nodes);
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
function applyElementFormatting(node, serializedNode) {
|
|
5254
|
+
if (typeof serializedNode.format === "string" && ["left", "center", "right", "justify"].includes(serializedNode.format) && node.setFormat) {
|
|
5255
|
+
node.setFormat(serializedNode.format);
|
|
5256
|
+
}
|
|
5257
|
+
if (typeof serializedNode.indent === "number" && serializedNode.indent > 0 && node.setIndent) {
|
|
5258
|
+
node.setIndent(serializedNode.indent);
|
|
5259
|
+
}
|
|
5260
|
+
}
|
|
5261
|
+
function buildLexicalNode(serializedNode) {
|
|
5262
|
+
switch (serializedNode.type) {
|
|
5263
|
+
case "paragraph": {
|
|
5264
|
+
const node = $createParagraphNode();
|
|
5265
|
+
applyElementFormatting(node, serializedNode);
|
|
5266
|
+
appendChildren(node, serializedNode.children);
|
|
5267
|
+
return node;
|
|
5268
|
+
}
|
|
5269
|
+
case "heading": {
|
|
5270
|
+
const tag = typeof serializedNode.tag === "string" && /^h[1-6]$/.test(serializedNode.tag) ? serializedNode.tag : "h1";
|
|
5271
|
+
const node = $createHeadingNode(tag);
|
|
5272
|
+
applyElementFormatting(node, serializedNode);
|
|
5273
|
+
appendChildren(node, serializedNode.children);
|
|
5274
|
+
return node;
|
|
5275
|
+
}
|
|
5276
|
+
case "quote": {
|
|
5277
|
+
const node = $createQuoteNode();
|
|
5278
|
+
applyElementFormatting(node, serializedNode);
|
|
5279
|
+
appendChildren(node, serializedNode.children);
|
|
5280
|
+
return node;
|
|
5281
|
+
}
|
|
5282
|
+
case "list": {
|
|
5283
|
+
const listType = serializedNode.listType === "number" ? "number" : "bullet";
|
|
5284
|
+
const node = $createListNode(listType, typeof serializedNode.start === "number" ? serializedNode.start : 1);
|
|
5285
|
+
appendChildren(node, serializedNode.children);
|
|
5286
|
+
return node;
|
|
5287
|
+
}
|
|
5288
|
+
case "listitem": {
|
|
5289
|
+
const node = $createListItemNode();
|
|
5290
|
+
appendChildren(node, serializedNode.children);
|
|
5291
|
+
return node;
|
|
5292
|
+
}
|
|
5293
|
+
case "text": {
|
|
5294
|
+
const node = $createTextNode(serializedNode.text ?? "");
|
|
5295
|
+
if (typeof serializedNode.format === "number" && serializedNode.format > 0) {
|
|
5296
|
+
node.setFormat(serializedNode.format);
|
|
5297
|
+
}
|
|
5298
|
+
if (typeof serializedNode.style === "string" && serializedNode.style.trim() !== "") {
|
|
5299
|
+
node.setStyle(serializedNode.style);
|
|
5300
|
+
}
|
|
5301
|
+
return node;
|
|
5302
|
+
}
|
|
5303
|
+
case "linebreak":
|
|
5304
|
+
return $createLineBreakNode();
|
|
5305
|
+
case "variable-node":
|
|
5306
|
+
return $createVariableNode(
|
|
5307
|
+
serializedNode.variableKey ?? "",
|
|
5308
|
+
typeof serializedNode.format === "number" ? serializedNode.format : 0,
|
|
5309
|
+
typeof serializedNode.style === "string" ? serializedNode.style : ""
|
|
5310
|
+
);
|
|
5311
|
+
default:
|
|
5312
|
+
return null;
|
|
5313
|
+
}
|
|
5314
|
+
}
|
|
5315
|
+
function getBodyChildren(pageState) {
|
|
5316
|
+
const root = pageState == null ? void 0 : pageState.root;
|
|
5317
|
+
return (root == null ? void 0 : root.children) ?? [];
|
|
5318
|
+
}
|
|
5319
|
+
function insertDocumentContent(editor, document2) {
|
|
5320
|
+
let inserted = false;
|
|
5321
|
+
editor.update(() => {
|
|
5322
|
+
const nodes = document2.pages.flatMap((page) => getBodyChildren(page.bodyState)).map(buildLexicalNode).filter((node) => node !== null);
|
|
5323
|
+
if (nodes.length === 0) {
|
|
5324
|
+
return;
|
|
5325
|
+
}
|
|
5326
|
+
const selection = $getSelection();
|
|
5327
|
+
if ($isRangeSelection(selection)) {
|
|
5328
|
+
if (selection.isCollapsed()) {
|
|
5329
|
+
selection.insertParagraph();
|
|
5330
|
+
}
|
|
5331
|
+
const nextSelection = $getSelection();
|
|
5332
|
+
if ($isRangeSelection(nextSelection) || $isNodeSelection(nextSelection)) {
|
|
5333
|
+
nextSelection.insertNodes(nodes);
|
|
5334
|
+
} else {
|
|
5335
|
+
$insertNodes(nodes);
|
|
5336
|
+
}
|
|
5337
|
+
} else if ($isNodeSelection(selection)) {
|
|
5338
|
+
selection.insertNodes(nodes);
|
|
5339
|
+
} else {
|
|
5340
|
+
$insertNodes(nodes);
|
|
5341
|
+
}
|
|
5342
|
+
inserted = true;
|
|
5343
|
+
});
|
|
5344
|
+
return inserted;
|
|
5345
|
+
}
|
|
4671
5346
|
function selectEntireDocument(rootElement, selectionBuffer) {
|
|
4672
5347
|
if (!rootElement || !selectionBuffer) {
|
|
4673
5348
|
return;
|
|
@@ -4874,10 +5549,13 @@ const EditorWithHandle = forwardRef(({ captureHistoryShortcutsOnWindow, onSave,
|
|
|
4874
5549
|
const {
|
|
4875
5550
|
document: doc,
|
|
4876
5551
|
activeEditor,
|
|
5552
|
+
activeCaretPosition,
|
|
4877
5553
|
historySidebarOpen,
|
|
5554
|
+
runHistoryAction,
|
|
4878
5555
|
setHistorySidebarOpen
|
|
4879
5556
|
} = useDocument();
|
|
4880
5557
|
const { handleFactories } = useExtensions();
|
|
5558
|
+
const t = useTranslations();
|
|
4881
5559
|
const getDocument = useCallback(() => doc, [doc]);
|
|
4882
5560
|
const getActiveEditor = useCallback(() => activeEditor, [activeEditor]);
|
|
4883
5561
|
const extensionCtx = useExtensionContext(getDocument, getActiveEditor);
|
|
@@ -4888,6 +5566,23 @@ const EditorWithHandle = forwardRef(({ captureHistoryShortcutsOnWindow, onSave,
|
|
|
4888
5566
|
},
|
|
4889
5567
|
toggleHistorySidebar: () => {
|
|
4890
5568
|
setHistorySidebarOpen(!historySidebarOpen);
|
|
5569
|
+
},
|
|
5570
|
+
insertDocumentContent: (documentToInsert) => {
|
|
5571
|
+
if (!activeEditor || (activeCaretPosition == null ? void 0 : activeCaretPosition.region) !== "body") {
|
|
5572
|
+
return false;
|
|
5573
|
+
}
|
|
5574
|
+
let inserted = false;
|
|
5575
|
+
runHistoryAction(
|
|
5576
|
+
{
|
|
5577
|
+
label: t.history.actions.insertedDocumentContent,
|
|
5578
|
+
source: "toolbar",
|
|
5579
|
+
region: "document"
|
|
5580
|
+
},
|
|
5581
|
+
() => {
|
|
5582
|
+
inserted = insertDocumentContent(activeEditor, documentToInsert);
|
|
5583
|
+
}
|
|
5584
|
+
);
|
|
5585
|
+
return inserted;
|
|
4891
5586
|
}
|
|
4892
5587
|
};
|
|
4893
5588
|
for (const factory of handleFactories) {
|
|
@@ -4895,7 +5590,16 @@ const EditorWithHandle = forwardRef(({ captureHistoryShortcutsOnWindow, onSave,
|
|
|
4895
5590
|
Object.assign(handle, methods);
|
|
4896
5591
|
}
|
|
4897
5592
|
return handle;
|
|
4898
|
-
}, [
|
|
5593
|
+
}, [
|
|
5594
|
+
activeCaretPosition == null ? void 0 : activeCaretPosition.region,
|
|
5595
|
+
activeEditor,
|
|
5596
|
+
extensionCtx,
|
|
5597
|
+
handleFactories,
|
|
5598
|
+
historySidebarOpen,
|
|
5599
|
+
runHistoryAction,
|
|
5600
|
+
setHistorySidebarOpen,
|
|
5601
|
+
t.history.actions.insertedDocumentContent
|
|
5602
|
+
]);
|
|
4899
5603
|
return /* @__PURE__ */ jsx(
|
|
4900
5604
|
EditorChrome,
|
|
4901
5605
|
{
|
|
@@ -4913,9 +5617,10 @@ const Lex4Editor = forwardRef(({
|
|
|
4913
5617
|
onSave,
|
|
4914
5618
|
extensions,
|
|
4915
5619
|
translations,
|
|
5620
|
+
toolbar,
|
|
4916
5621
|
className
|
|
4917
5622
|
}, ref) => {
|
|
4918
|
-
return /* @__PURE__ */ jsx(TranslationsProvider, { translations, children: /* @__PURE__ */ jsx(ExtensionStateProvider, { children: /* @__PURE__ */ jsx(ExtensionProvider, { extensions, children: /* @__PURE__ */ jsx(
|
|
5623
|
+
return /* @__PURE__ */ jsx(TranslationsProvider, { translations, children: /* @__PURE__ */ jsx(ToolbarConfigProvider, { toolbar, children: /* @__PURE__ */ jsx(ExtensionStateProvider, { children: /* @__PURE__ */ jsx(ExtensionProvider, { extensions, children: /* @__PURE__ */ jsx(
|
|
4919
5624
|
DocumentProvider,
|
|
4920
5625
|
{
|
|
4921
5626
|
initialDocument,
|
|
@@ -4930,7 +5635,7 @@ const Lex4Editor = forwardRef(({
|
|
|
4930
5635
|
}
|
|
4931
5636
|
)
|
|
4932
5637
|
}
|
|
4933
|
-
) }) }) });
|
|
5638
|
+
) }) }) }) });
|
|
4934
5639
|
});
|
|
4935
5640
|
Lex4Editor.displayName = "Lex4Editor";
|
|
4936
5641
|
function useOverflowDetection(bodyHeight, onOverflow, debounceMs = 100) {
|
|
@@ -5024,120 +5729,6 @@ function astExtension() {
|
|
|
5024
5729
|
}
|
|
5025
5730
|
};
|
|
5026
5731
|
}
|
|
5027
|
-
const EMPTY_CONTEXT = {
|
|
5028
|
-
definitions: [],
|
|
5029
|
-
refreshDefinitions: () => {
|
|
5030
|
-
},
|
|
5031
|
-
getDefinition: () => void 0
|
|
5032
|
-
};
|
|
5033
|
-
const VariableContext = createContext(EMPTY_CONTEXT);
|
|
5034
|
-
const VariableProvider = ({
|
|
5035
|
-
initialDefinitions = [],
|
|
5036
|
-
children
|
|
5037
|
-
}) => {
|
|
5038
|
-
const [definitions, setDefinitions] = useState(initialDefinitions);
|
|
5039
|
-
const refresh = useCallback((newDefinitions) => {
|
|
5040
|
-
setDefinitions(newDefinitions);
|
|
5041
|
-
}, []);
|
|
5042
|
-
const getDefinition = useCallback(
|
|
5043
|
-
(key) => {
|
|
5044
|
-
return definitions.find((d) => d.key === key);
|
|
5045
|
-
},
|
|
5046
|
-
[definitions]
|
|
5047
|
-
);
|
|
5048
|
-
const value = useMemo(
|
|
5049
|
-
() => ({ definitions, refreshDefinitions: refresh, getDefinition }),
|
|
5050
|
-
[definitions, refresh, getDefinition]
|
|
5051
|
-
);
|
|
5052
|
-
return /* @__PURE__ */ jsx(VariableContext.Provider, { value, children });
|
|
5053
|
-
};
|
|
5054
|
-
function useVariables() {
|
|
5055
|
-
return useContext(VariableContext);
|
|
5056
|
-
}
|
|
5057
|
-
class VariableNode extends DecoratorNode {
|
|
5058
|
-
constructor(variableKey, key) {
|
|
5059
|
-
super(key);
|
|
5060
|
-
__publicField(this, "__variableKey");
|
|
5061
|
-
this.__variableKey = variableKey;
|
|
5062
|
-
}
|
|
5063
|
-
static getType() {
|
|
5064
|
-
return "variable-node";
|
|
5065
|
-
}
|
|
5066
|
-
static clone(node) {
|
|
5067
|
-
return new VariableNode(node.__variableKey, node.__key);
|
|
5068
|
-
}
|
|
5069
|
-
getVariableKey() {
|
|
5070
|
-
return this.__variableKey;
|
|
5071
|
-
}
|
|
5072
|
-
// -- Serialization --
|
|
5073
|
-
static importJSON(serializedNode) {
|
|
5074
|
-
return $createVariableNode(serializedNode.variableKey);
|
|
5075
|
-
}
|
|
5076
|
-
exportJSON() {
|
|
5077
|
-
return {
|
|
5078
|
-
type: "variable-node",
|
|
5079
|
-
version: 1,
|
|
5080
|
-
variableKey: this.__variableKey
|
|
5081
|
-
};
|
|
5082
|
-
}
|
|
5083
|
-
// -- DOM --
|
|
5084
|
-
createDOM() {
|
|
5085
|
-
const span = document.createElement("span");
|
|
5086
|
-
span.className = "lex4-variable";
|
|
5087
|
-
span.setAttribute("data-variable-key", this.__variableKey);
|
|
5088
|
-
span.setAttribute("data-testid", `variable-${this.__variableKey}`);
|
|
5089
|
-
span.contentEditable = "false";
|
|
5090
|
-
return span;
|
|
5091
|
-
}
|
|
5092
|
-
updateDOM() {
|
|
5093
|
-
return false;
|
|
5094
|
-
}
|
|
5095
|
-
exportDOM() {
|
|
5096
|
-
const span = document.createElement("span");
|
|
5097
|
-
span.setAttribute("data-variable-key", this.__variableKey);
|
|
5098
|
-
span.textContent = `{{${this.__variableKey}}}`;
|
|
5099
|
-
return { element: span };
|
|
5100
|
-
}
|
|
5101
|
-
static importDOM() {
|
|
5102
|
-
return null;
|
|
5103
|
-
}
|
|
5104
|
-
// -- Behavior --
|
|
5105
|
-
isInline() {
|
|
5106
|
-
return true;
|
|
5107
|
-
}
|
|
5108
|
-
isKeyboardSelectable() {
|
|
5109
|
-
return true;
|
|
5110
|
-
}
|
|
5111
|
-
getTextContent() {
|
|
5112
|
-
return `{{${this.__variableKey}}}`;
|
|
5113
|
-
}
|
|
5114
|
-
// -- Rendering --
|
|
5115
|
-
decorate() {
|
|
5116
|
-
return /* @__PURE__ */ jsx(VariableChip, { variableKey: this.__variableKey });
|
|
5117
|
-
}
|
|
5118
|
-
}
|
|
5119
|
-
function VariableChip({ variableKey }) {
|
|
5120
|
-
const { getDefinition } = useVariables();
|
|
5121
|
-
const def = getDefinition(variableKey);
|
|
5122
|
-
const label = (def == null ? void 0 : def.label) ?? variableKey;
|
|
5123
|
-
const group = def == null ? void 0 : def.group;
|
|
5124
|
-
return /* @__PURE__ */ jsx(
|
|
5125
|
-
"span",
|
|
5126
|
-
{
|
|
5127
|
-
className: "lex4-variable-chip",
|
|
5128
|
-
"data-testid": `variable-chip-${variableKey}`,
|
|
5129
|
-
"data-variable-group": group,
|
|
5130
|
-
title: variableKey,
|
|
5131
|
-
children: label
|
|
5132
|
-
}
|
|
5133
|
-
);
|
|
5134
|
-
}
|
|
5135
|
-
function $createVariableNode(variableKey) {
|
|
5136
|
-
return $applyNodeReplacement(new VariableNode(variableKey));
|
|
5137
|
-
}
|
|
5138
|
-
function $isVariableNode(node) {
|
|
5139
|
-
return node instanceof VariableNode;
|
|
5140
|
-
}
|
|
5141
5732
|
const INSERT_VARIABLE_COMMAND = createCommand("INSERT_VARIABLE");
|
|
5142
5733
|
const VariablePlugin = () => {
|
|
5143
5734
|
const [editor] = useLexicalComposerContext();
|
|
@@ -5398,7 +5989,11 @@ const VariablePanelStateProvider = ({ children }) => {
|
|
|
5398
5989
|
};
|
|
5399
5990
|
const VariableToolbarToggle = () => {
|
|
5400
5991
|
const { panelOpen, setPanelOpen } = useVariablePanelState();
|
|
5992
|
+
const toolbarConfig = useToolbarConfig();
|
|
5401
5993
|
const t = useTranslations();
|
|
5994
|
+
if (!toolbarConfig.variables.visible) {
|
|
5995
|
+
return null;
|
|
5996
|
+
}
|
|
5402
5997
|
return /* @__PURE__ */ jsxs(
|
|
5403
5998
|
"button",
|
|
5404
5999
|
{
|
|
@@ -5411,7 +6006,7 @@ const VariableToolbarToggle = () => {
|
|
|
5411
6006
|
"aria-label": panelOpen ? t.variables.closePanel : t.variables.openPanel,
|
|
5412
6007
|
children: [
|
|
5413
6008
|
/* @__PURE__ */ jsx(Braces, { size: 14 }),
|
|
5414
|
-
|
|
6009
|
+
toolbarConfig.variables.showLabel && t.variables.title
|
|
5415
6010
|
]
|
|
5416
6011
|
}
|
|
5417
6012
|
);
|