@yurikilian/lex4 1.6.0 → 1.8.0
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 +4 -2
- package/dist/components/BlockTypePicker.d.ts +1 -1
- package/dist/components/BlockTypePicker.d.ts.map +1 -1
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/context/document-provider.d.ts.map +1 -1
- package/dist/context/toolbar-style-snapshot.d.ts +4 -0
- package/dist/context/toolbar-style-snapshot.d.ts.map +1 -0
- package/dist/context/toolbar-style-store.d.ts +28 -0
- package/dist/context/toolbar-style-store.d.ts.map +1 -0
- package/dist/lex4-editor.cjs +544 -161
- package/dist/lex4-editor.cjs.map +1 -1
- package/dist/lex4-editor.js +547 -164
- package/dist/lex4-editor.js.map +1 -1
- package/dist/lexical/commands/block-commands.d.ts +1 -1
- package/dist/lexical/commands/block-commands.d.ts.map +1 -1
- package/dist/lexical/commands/block-types.d.ts +2 -0
- package/dist/lexical/commands/block-types.d.ts.map +1 -0
- package/dist/style.css +31 -27
- package/dist/utils/text-style.d.ts +6 -0
- package/dist/utils/text-style.d.ts.map +1 -1
- package/dist/variables/variable-formatting.d.ts +1 -0
- package/dist/variables/variable-formatting.d.ts.map +1 -1
- package/dist/variables/variable-node.d.ts.map +1 -1
- package/package.json +3 -2
package/dist/lex4-editor.js
CHANGED
|
@@ -2,11 +2,11 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
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
|
-
import React, { createContext, useContext, useMemo, useReducer, useState,
|
|
6
|
-
import { $
|
|
5
|
+
import React, { createContext, useContext, useMemo, useRef, useReducer, useState, useCallback, useEffect, forwardRef, createElement, useImperativeHandle } from "react";
|
|
6
|
+
import { $getSelection, $isRangeSelection, $isTextNode, $getRoot, $createRangeSelectionFromDom, FORMAT_ELEMENT_COMMAND, FORMAT_TEXT_COMMAND, OUTDENT_CONTENT_COMMAND, INDENT_CONTENT_COMMAND, $applyNodeReplacement, DecoratorNode, $createNodeSelection, $isNodeSelection, $setSelection, KEY_BACKSPACE_COMMAND, COMMAND_PRIORITY_LOW, KEY_DELETE_COMMAND, KEY_DOWN_COMMAND, $getNodeByKey, $isElementNode, $createParagraphNode, $selectAll, SELECTION_CHANGE_COMMAND, KEY_TAB_COMMAND, $isParagraphNode, FOCUS_COMMAND, $splitNode, $getNearestNodeFromDOMNode, CONTROLLED_TEXT_INSERTION_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
8
|
import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, ListNode, ListItemNode, $isListNode, $createListItemNode, $createListNode } from "@lexical/list";
|
|
9
|
-
import { $setBlocksType } from "@lexical/selection";
|
|
9
|
+
import { $patchStyleText, $setBlocksType } from "@lexical/selection";
|
|
10
10
|
import { $createHeadingNode, $isHeadingNode, HeadingNode, QuoteNode, $createQuoteNode } from "@lexical/rich-text";
|
|
11
11
|
import { useLexicalNodeSelection } from "@lexical/react/useLexicalNodeSelection";
|
|
12
12
|
import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
@@ -777,6 +777,115 @@ const TranslationsProvider = ({
|
|
|
777
777
|
);
|
|
778
778
|
return /* @__PURE__ */ jsx(TranslationsContext.Provider, { value: merged, children });
|
|
779
779
|
};
|
|
780
|
+
const createStoreImpl = (createState) => {
|
|
781
|
+
let state;
|
|
782
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
783
|
+
const setState = (partial, replace) => {
|
|
784
|
+
const nextState = typeof partial === "function" ? partial(state) : partial;
|
|
785
|
+
if (!Object.is(nextState, state)) {
|
|
786
|
+
const previousState = state;
|
|
787
|
+
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
|
|
788
|
+
listeners.forEach((listener) => listener(state, previousState));
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
const getState = () => state;
|
|
792
|
+
const getInitialState = () => initialState;
|
|
793
|
+
const subscribe = (listener) => {
|
|
794
|
+
listeners.add(listener);
|
|
795
|
+
return () => listeners.delete(listener);
|
|
796
|
+
};
|
|
797
|
+
const api = { setState, getState, getInitialState, subscribe };
|
|
798
|
+
const initialState = state = createState(setState, getState, api);
|
|
799
|
+
return api;
|
|
800
|
+
};
|
|
801
|
+
const createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl;
|
|
802
|
+
const identity = (arg) => arg;
|
|
803
|
+
function useStore(api, selector = identity) {
|
|
804
|
+
const slice = React.useSyncExternalStore(
|
|
805
|
+
api.subscribe,
|
|
806
|
+
React.useCallback(() => selector(api.getState()), [api, selector]),
|
|
807
|
+
React.useCallback(() => selector(api.getInitialState()), [api, selector])
|
|
808
|
+
);
|
|
809
|
+
React.useDebugValue(slice);
|
|
810
|
+
return slice;
|
|
811
|
+
}
|
|
812
|
+
const SUPPORTED_FONT_SIZES = [
|
|
813
|
+
8,
|
|
814
|
+
9,
|
|
815
|
+
10,
|
|
816
|
+
11,
|
|
817
|
+
12,
|
|
818
|
+
14,
|
|
819
|
+
16,
|
|
820
|
+
18,
|
|
821
|
+
20,
|
|
822
|
+
24,
|
|
823
|
+
28,
|
|
824
|
+
32,
|
|
825
|
+
36,
|
|
826
|
+
48,
|
|
827
|
+
72
|
|
828
|
+
];
|
|
829
|
+
const DEFAULT_FONT_SIZE = 12;
|
|
830
|
+
function applyFontSize(editor, size) {
|
|
831
|
+
editor.update(() => {
|
|
832
|
+
const selection = $getSelection();
|
|
833
|
+
if (!$isRangeSelection(selection)) return;
|
|
834
|
+
const nodes = selection.getNodes();
|
|
835
|
+
for (const node of nodes) {
|
|
836
|
+
if ($isTextNode(node)) {
|
|
837
|
+
const existing = node.getStyle();
|
|
838
|
+
const updated = mergeFontSize(existing, size);
|
|
839
|
+
node.setStyle(updated);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
function mergeFontSize(existingStyle, size) {
|
|
845
|
+
const stripped = existingStyle.replace(/font-size:\s*[^;]+;?\s*/g, "").trim();
|
|
846
|
+
const sizeDecl = `font-size: ${size}pt`;
|
|
847
|
+
return stripped ? `${stripped}; ${sizeDecl}` : sizeDecl;
|
|
848
|
+
}
|
|
849
|
+
const DEFAULT_TOOLBAR_STYLE_SNAPSHOT = {
|
|
850
|
+
blockType: "paragraph",
|
|
851
|
+
fontFamily: "Inter",
|
|
852
|
+
fontSize: DEFAULT_FONT_SIZE,
|
|
853
|
+
alignment: "left",
|
|
854
|
+
isBold: false,
|
|
855
|
+
isItalic: false,
|
|
856
|
+
isUnderline: false,
|
|
857
|
+
isStrikethrough: false,
|
|
858
|
+
hasSelectedVariable: false
|
|
859
|
+
};
|
|
860
|
+
function createToolbarStyleStore(initialSnapshot = DEFAULT_TOOLBAR_STYLE_SNAPSHOT) {
|
|
861
|
+
return createStore((set) => ({
|
|
862
|
+
...initialSnapshot,
|
|
863
|
+
setSnapshot: (snapshot) => set(snapshot),
|
|
864
|
+
reset: () => set(DEFAULT_TOOLBAR_STYLE_SNAPSHOT)
|
|
865
|
+
}));
|
|
866
|
+
}
|
|
867
|
+
const ToolbarStyleStoreContext = createContext(null);
|
|
868
|
+
const ToolbarStyleStoreProvider = ({ children }) => {
|
|
869
|
+
const storeRef = useRef(null);
|
|
870
|
+
if (!storeRef.current) {
|
|
871
|
+
storeRef.current = createToolbarStyleStore();
|
|
872
|
+
}
|
|
873
|
+
return /* @__PURE__ */ jsx(ToolbarStyleStoreContext.Provider, { value: storeRef.current, children });
|
|
874
|
+
};
|
|
875
|
+
function useToolbarStyleStore(selector) {
|
|
876
|
+
const store = useContext(ToolbarStyleStoreContext);
|
|
877
|
+
if (!store) {
|
|
878
|
+
throw new Error("useToolbarStyleStore must be used within a ToolbarStyleStoreProvider");
|
|
879
|
+
}
|
|
880
|
+
return useStore(store, selector);
|
|
881
|
+
}
|
|
882
|
+
function useToolbarStyleStoreApi() {
|
|
883
|
+
const store = useContext(ToolbarStyleStoreContext);
|
|
884
|
+
if (!store) {
|
|
885
|
+
throw new Error("useToolbarStyleStoreApi must be used within a ToolbarStyleStoreProvider");
|
|
886
|
+
}
|
|
887
|
+
return store;
|
|
888
|
+
}
|
|
780
889
|
const HISTORY_RESTORE_SUPPRESSION_MS = 100;
|
|
781
890
|
const HISTORY_BATCH_FLUSH_MS = 16;
|
|
782
891
|
function cloneDocumentSnapshot(document2) {
|
|
@@ -1333,7 +1442,7 @@ const DocumentProvider = ({
|
|
|
1333
1442
|
undo,
|
|
1334
1443
|
redo,
|
|
1335
1444
|
editorRegistry
|
|
1336
|
-
}, children });
|
|
1445
|
+
}, children: /* @__PURE__ */ jsx(ToolbarStyleStoreProvider, { children }) });
|
|
1337
1446
|
};
|
|
1338
1447
|
/**
|
|
1339
1448
|
* @license lucide-react v1.8.0 - ISC
|
|
@@ -2081,43 +2190,6 @@ function applyFontFamily(editor, fontFamily) {
|
|
|
2081
2190
|
}
|
|
2082
2191
|
});
|
|
2083
2192
|
}
|
|
2084
|
-
const SUPPORTED_FONT_SIZES = [
|
|
2085
|
-
8,
|
|
2086
|
-
9,
|
|
2087
|
-
10,
|
|
2088
|
-
11,
|
|
2089
|
-
12,
|
|
2090
|
-
14,
|
|
2091
|
-
16,
|
|
2092
|
-
18,
|
|
2093
|
-
20,
|
|
2094
|
-
24,
|
|
2095
|
-
28,
|
|
2096
|
-
32,
|
|
2097
|
-
36,
|
|
2098
|
-
48,
|
|
2099
|
-
72
|
|
2100
|
-
];
|
|
2101
|
-
const DEFAULT_FONT_SIZE = 12;
|
|
2102
|
-
function applyFontSize(editor, size) {
|
|
2103
|
-
editor.update(() => {
|
|
2104
|
-
const selection = $getSelection();
|
|
2105
|
-
if (!$isRangeSelection(selection)) return;
|
|
2106
|
-
const nodes = selection.getNodes();
|
|
2107
|
-
for (const node of nodes) {
|
|
2108
|
-
if ($isTextNode(node)) {
|
|
2109
|
-
const existing = node.getStyle();
|
|
2110
|
-
const updated = mergeFontSize(existing, size);
|
|
2111
|
-
node.setStyle(updated);
|
|
2112
|
-
}
|
|
2113
|
-
}
|
|
2114
|
-
});
|
|
2115
|
-
}
|
|
2116
|
-
function mergeFontSize(existingStyle, size) {
|
|
2117
|
-
const stripped = existingStyle.replace(/font-size:\s*[^;]+;?\s*/g, "").trim();
|
|
2118
|
-
const sizeDecl = `font-size: ${size}pt`;
|
|
2119
|
-
return stripped ? `${stripped}; ${sizeDecl}` : sizeDecl;
|
|
2120
|
-
}
|
|
2121
2193
|
function toggleFormat(editor, format) {
|
|
2122
2194
|
editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
|
|
2123
2195
|
}
|
|
@@ -2149,48 +2221,77 @@ function indentContent(editor) {
|
|
|
2149
2221
|
function outdentContent(editor) {
|
|
2150
2222
|
editor.dispatchCommand(OUTDENT_CONTENT_COMMAND, void 0);
|
|
2151
2223
|
}
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
}
|
|
2224
|
+
const INLINE_BLOCK_STYLE_PROPERTY = "--lex4-block-type";
|
|
2225
|
+
const INLINE_BLOCK_STYLE_PRESETS = {
|
|
2226
|
+
paragraph: {
|
|
2227
|
+
[INLINE_BLOCK_STYLE_PROPERTY]: "paragraph",
|
|
2228
|
+
"font-size": "12pt",
|
|
2229
|
+
"font-weight": "400"
|
|
2230
|
+
},
|
|
2231
|
+
h1: {
|
|
2232
|
+
[INLINE_BLOCK_STYLE_PROPERTY]: "h1",
|
|
2233
|
+
"font-size": "22.5pt",
|
|
2234
|
+
"font-weight": "700"
|
|
2235
|
+
},
|
|
2236
|
+
h2: {
|
|
2237
|
+
[INLINE_BLOCK_STYLE_PROPERTY]: "h2",
|
|
2238
|
+
"font-size": "18pt",
|
|
2239
|
+
"font-weight": "700"
|
|
2240
|
+
},
|
|
2241
|
+
h3: {
|
|
2242
|
+
[INLINE_BLOCK_STYLE_PROPERTY]: "h3",
|
|
2243
|
+
"font-size": "15pt",
|
|
2244
|
+
"font-weight": "600"
|
|
2245
|
+
},
|
|
2246
|
+
h4: {
|
|
2247
|
+
[INLINE_BLOCK_STYLE_PROPERTY]: "h4",
|
|
2248
|
+
"font-size": "13.5pt",
|
|
2249
|
+
"font-weight": "600"
|
|
2250
|
+
},
|
|
2251
|
+
h5: {
|
|
2252
|
+
[INLINE_BLOCK_STYLE_PROPERTY]: "h5",
|
|
2253
|
+
"font-size": "12pt",
|
|
2254
|
+
"font-weight": "500"
|
|
2255
|
+
},
|
|
2256
|
+
h6: {
|
|
2257
|
+
[INLINE_BLOCK_STYLE_PROPERTY]: "h6",
|
|
2258
|
+
"font-size": "11.25pt",
|
|
2259
|
+
"font-weight": "500"
|
|
2260
|
+
}
|
|
2261
|
+
};
|
|
2262
|
+
function escapeStyleProperty(property) {
|
|
2263
|
+
const escapedProperty = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2264
|
+
return escapedProperty;
|
|
2164
2265
|
}
|
|
2165
|
-
function
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
if ($isHeadingNode(topLevelElement)) {
|
|
2175
|
-
blockType = topLevelElement.getTag();
|
|
2176
|
-
}
|
|
2177
|
-
});
|
|
2178
|
-
return blockType;
|
|
2266
|
+
function stripStyleDeclaration(existingStyle, property) {
|
|
2267
|
+
const escapedProperty = escapeStyleProperty(property);
|
|
2268
|
+
return existingStyle.replace(
|
|
2269
|
+
new RegExp(`${escapedProperty}:\\s*[^;]+;?\\s*`, "g"),
|
|
2270
|
+
""
|
|
2271
|
+
).trim();
|
|
2272
|
+
}
|
|
2273
|
+
function isSupportedInlineBlockType(value) {
|
|
2274
|
+
return value === "paragraph" || value === "h1" || value === "h2" || value === "h3" || value === "h4" || value === "h5" || value === "h6";
|
|
2179
2275
|
}
|
|
2180
2276
|
function extractStyleValue(style, property) {
|
|
2181
|
-
const escapedProperty = property
|
|
2277
|
+
const escapedProperty = escapeStyleProperty(property);
|
|
2182
2278
|
const match = style.match(new RegExp(`${escapedProperty}:\\s*([^;]+)`));
|
|
2183
2279
|
return match ? match[1].trim().replace(/['"]/g, "") : void 0;
|
|
2184
2280
|
}
|
|
2281
|
+
function removeStyleDeclaration(existingStyle, property) {
|
|
2282
|
+
return stripStyleDeclaration(existingStyle, property);
|
|
2283
|
+
}
|
|
2185
2284
|
function mergeStyleDeclaration(existingStyle, property, value) {
|
|
2186
|
-
const
|
|
2187
|
-
const stripped = existingStyle.replace(
|
|
2188
|
-
new RegExp(`${escapedProperty}:\\s*[^;]+;?\\s*`, "g"),
|
|
2189
|
-
""
|
|
2190
|
-
).trim();
|
|
2285
|
+
const stripped = stripStyleDeclaration(existingStyle, property);
|
|
2191
2286
|
const declaration = `${property}: ${value}`;
|
|
2192
2287
|
return stripped ? `${stripped}; ${declaration}` : declaration;
|
|
2193
2288
|
}
|
|
2289
|
+
function mergeStyleDeclarations(existingStyle, declarations) {
|
|
2290
|
+
return Object.entries(declarations).reduce(
|
|
2291
|
+
(style, [property, value]) => mergeStyleDeclaration(style, property, value),
|
|
2292
|
+
existingStyle
|
|
2293
|
+
);
|
|
2294
|
+
}
|
|
2194
2295
|
function extractFontFamilyFromStyle(style) {
|
|
2195
2296
|
return extractStyleValue(style, "font-family");
|
|
2196
2297
|
}
|
|
@@ -2208,6 +2309,21 @@ function mergeFontFamilyStyle(existingStyle, fontFamily) {
|
|
|
2208
2309
|
function mergeFontSizeStyle(existingStyle, size) {
|
|
2209
2310
|
return mergeStyleDeclaration(existingStyle, "font-size", `${size}pt`);
|
|
2210
2311
|
}
|
|
2312
|
+
function extractInlineBlockTypeFromStyle(style) {
|
|
2313
|
+
const value = extractStyleValue(style, INLINE_BLOCK_STYLE_PROPERTY);
|
|
2314
|
+
return isSupportedInlineBlockType(value) ? value : void 0;
|
|
2315
|
+
}
|
|
2316
|
+
function createInlineBlockTypeStylePatch(blockType) {
|
|
2317
|
+
return INLINE_BLOCK_STYLE_PRESETS[blockType];
|
|
2318
|
+
}
|
|
2319
|
+
function mergeInlineBlockTypeStyle(existingStyle, blockType) {
|
|
2320
|
+
const baseStyle = [
|
|
2321
|
+
INLINE_BLOCK_STYLE_PROPERTY,
|
|
2322
|
+
"font-size",
|
|
2323
|
+
"font-weight"
|
|
2324
|
+
].reduce((style, property) => removeStyleDeclaration(style, property), existingStyle);
|
|
2325
|
+
return mergeStyleDeclarations(baseStyle, createInlineBlockTypeStylePatch(blockType));
|
|
2326
|
+
}
|
|
2211
2327
|
const EMPTY_CONTEXT = {
|
|
2212
2328
|
definitions: [],
|
|
2213
2329
|
refreshDefinitions: () => {
|
|
@@ -2295,6 +2411,7 @@ class VariableNode extends DecoratorNode {
|
|
|
2295
2411
|
const span = document.createElement("span");
|
|
2296
2412
|
span.className = "lex4-variable";
|
|
2297
2413
|
span.setAttribute("data-variable-key", this.__variableKey);
|
|
2414
|
+
span.setAttribute("data-node-key", this.__key);
|
|
2298
2415
|
span.setAttribute("data-testid", `variable-${this.__variableKey}`);
|
|
2299
2416
|
span.contentEditable = "false";
|
|
2300
2417
|
return span;
|
|
@@ -2342,16 +2459,18 @@ function VariableChip({
|
|
|
2342
2459
|
}) {
|
|
2343
2460
|
const { getDefinition } = useVariables();
|
|
2344
2461
|
const [editor] = useLexicalComposerContext();
|
|
2345
|
-
const [isSelected
|
|
2462
|
+
const [isSelected] = useLexicalNodeSelection(nodeKey);
|
|
2346
2463
|
const def = getDefinition(variableKey);
|
|
2347
2464
|
const label = (def == null ? void 0 : def.label) ?? variableKey;
|
|
2348
2465
|
const group = def == null ? void 0 : def.group;
|
|
2349
2466
|
const style = useMemo(() => {
|
|
2350
2467
|
const fontFamily = extractFontFamilyFromStyle(styleValue);
|
|
2351
2468
|
const fontSize = extractFontSizePtFromStyle(styleValue);
|
|
2469
|
+
const fontWeight = extractStyleValue(styleValue, "font-weight");
|
|
2352
2470
|
return {
|
|
2353
2471
|
...fontFamily ? { fontFamily } : {},
|
|
2354
|
-
...fontSize ? { fontSize: `${fontSize}pt` } : {}
|
|
2472
|
+
...fontSize ? { fontSize: `${fontSize}pt` } : {},
|
|
2473
|
+
...fontWeight ? { fontWeight } : {}
|
|
2355
2474
|
};
|
|
2356
2475
|
}, [styleValue]);
|
|
2357
2476
|
const className = [
|
|
@@ -2362,13 +2481,48 @@ function VariableChip({
|
|
|
2362
2481
|
format & 8 ? "lex4-text-underline" : "",
|
|
2363
2482
|
format & 4 ? "lex4-text-strikethrough" : ""
|
|
2364
2483
|
].filter(Boolean).join(" ");
|
|
2365
|
-
const
|
|
2484
|
+
const clearDomSelection = useCallback(() => {
|
|
2485
|
+
var _a;
|
|
2486
|
+
if (typeof window === "undefined") {
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
(_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
|
|
2490
|
+
}, []);
|
|
2491
|
+
const selectNode = useCallback((extendSelection) => {
|
|
2492
|
+
editor.focus();
|
|
2493
|
+
editor.update(() => {
|
|
2494
|
+
const nextSelection = $createNodeSelection();
|
|
2495
|
+
if (extendSelection) {
|
|
2496
|
+
const currentSelection = $getSelection();
|
|
2497
|
+
if ($isNodeSelection(currentSelection)) {
|
|
2498
|
+
for (const node of currentSelection.getNodes()) {
|
|
2499
|
+
if ($isVariableNode(node)) {
|
|
2500
|
+
nextSelection.add(node.getKey());
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
nextSelection.add(nodeKey);
|
|
2506
|
+
$setSelection(nextSelection);
|
|
2507
|
+
});
|
|
2508
|
+
clearDomSelection();
|
|
2509
|
+
}, [clearDomSelection, editor, nodeKey]);
|
|
2510
|
+
const handleMouseDown = useCallback((event) => {
|
|
2366
2511
|
event.preventDefault();
|
|
2367
|
-
|
|
2368
|
-
|
|
2512
|
+
event.stopPropagation();
|
|
2513
|
+
if (!isSelected || event.shiftKey) {
|
|
2514
|
+
selectNode(event.shiftKey);
|
|
2369
2515
|
}
|
|
2370
|
-
|
|
2371
|
-
|
|
2516
|
+
}, [isSelected, selectNode]);
|
|
2517
|
+
const handleClick = useCallback((event) => {
|
|
2518
|
+
event.preventDefault();
|
|
2519
|
+
event.stopPropagation();
|
|
2520
|
+
}, []);
|
|
2521
|
+
const handleMouseUp = useCallback((event) => {
|
|
2522
|
+
event.preventDefault();
|
|
2523
|
+
event.stopPropagation();
|
|
2524
|
+
clearDomSelection();
|
|
2525
|
+
}, [clearDomSelection]);
|
|
2372
2526
|
useEffect(() => {
|
|
2373
2527
|
const removeSelectedNodes = () => {
|
|
2374
2528
|
editor.update(() => {
|
|
@@ -2456,7 +2610,8 @@ function VariableChip({
|
|
|
2456
2610
|
"data-variable-group": group,
|
|
2457
2611
|
title: variableKey,
|
|
2458
2612
|
style,
|
|
2459
|
-
onMouseDown:
|
|
2613
|
+
onMouseDown: handleMouseDown,
|
|
2614
|
+
onMouseUp: handleMouseUp,
|
|
2460
2615
|
onClick: handleClick,
|
|
2461
2616
|
children: label
|
|
2462
2617
|
}
|
|
@@ -2468,41 +2623,58 @@ function $createVariableNode(variableKey, format = 0, style = "") {
|
|
|
2468
2623
|
function $isVariableNode(node) {
|
|
2469
2624
|
return node instanceof VariableNode;
|
|
2470
2625
|
}
|
|
2471
|
-
const FORMAT_MASKS = {
|
|
2626
|
+
const FORMAT_MASKS$1 = {
|
|
2472
2627
|
bold: 1,
|
|
2473
2628
|
italic: 2,
|
|
2474
2629
|
strikethrough: 4,
|
|
2475
2630
|
underline: 8
|
|
2476
2631
|
};
|
|
2477
|
-
function
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2632
|
+
function dedupeVariableNodes(nodes) {
|
|
2633
|
+
return Array.from(new Map(nodes.map((node) => [node.getKey(), node])).values());
|
|
2634
|
+
}
|
|
2635
|
+
function getSelectedVariableNodesFromSelection(selection) {
|
|
2636
|
+
if (!selection || typeof selection !== "object" || !("getNodes" in selection) || typeof selection.getNodes !== "function") {
|
|
2637
|
+
return [];
|
|
2638
|
+
}
|
|
2639
|
+
return dedupeVariableNodes(selection.getNodes().filter($isVariableNode));
|
|
2640
|
+
}
|
|
2641
|
+
function getVisuallySelectedVariableNodes(editor) {
|
|
2642
|
+
const rootElement = editor.getRootElement();
|
|
2643
|
+
if (!rootElement) {
|
|
2644
|
+
return [];
|
|
2645
|
+
}
|
|
2646
|
+
const nodes = [];
|
|
2647
|
+
rootElement.querySelectorAll(".lex4-variable-chip-selected").forEach((chip) => {
|
|
2648
|
+
const variableElement = chip.closest("[data-node-key]");
|
|
2649
|
+
const nodeKey = variableElement == null ? void 0 : variableElement.dataset.nodeKey;
|
|
2650
|
+
if (!nodeKey) {
|
|
2482
2651
|
return;
|
|
2483
2652
|
}
|
|
2484
|
-
const
|
|
2485
|
-
if (
|
|
2486
|
-
|
|
2653
|
+
const node = $getNodeByKey(nodeKey);
|
|
2654
|
+
if ($isVariableNode(node)) {
|
|
2655
|
+
nodes.push(node);
|
|
2487
2656
|
}
|
|
2488
|
-
updater(nodes);
|
|
2489
|
-
updated = true;
|
|
2490
2657
|
});
|
|
2491
|
-
return
|
|
2658
|
+
return dedupeVariableNodes(nodes);
|
|
2492
2659
|
}
|
|
2493
|
-
function
|
|
2494
|
-
let
|
|
2495
|
-
editor.
|
|
2496
|
-
const
|
|
2497
|
-
|
|
2660
|
+
function withSelectedVariableNodes(editor, updater) {
|
|
2661
|
+
let updated = false;
|
|
2662
|
+
editor.update(() => {
|
|
2663
|
+
const nodes = [
|
|
2664
|
+
...getSelectedVariableNodesFromSelection($getSelection()),
|
|
2665
|
+
...getVisuallySelectedVariableNodes(editor)
|
|
2666
|
+
];
|
|
2667
|
+
const uniqueNodes = dedupeVariableNodes(nodes);
|
|
2668
|
+
if (uniqueNodes.length === 0) {
|
|
2498
2669
|
return;
|
|
2499
2670
|
}
|
|
2500
|
-
|
|
2671
|
+
updater(uniqueNodes);
|
|
2672
|
+
updated = true;
|
|
2501
2673
|
});
|
|
2502
|
-
return
|
|
2674
|
+
return updated;
|
|
2503
2675
|
}
|
|
2504
2676
|
function toggleSelectedVariableFormat(editor, format) {
|
|
2505
|
-
const mask = FORMAT_MASKS[format];
|
|
2677
|
+
const mask = FORMAT_MASKS$1[format];
|
|
2506
2678
|
if (!mask) {
|
|
2507
2679
|
return false;
|
|
2508
2680
|
}
|
|
@@ -2528,24 +2700,159 @@ function applyFontSizeToSelectedVariables(editor, size) {
|
|
|
2528
2700
|
}
|
|
2529
2701
|
});
|
|
2530
2702
|
}
|
|
2531
|
-
function
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2703
|
+
function getElementBlockType$1(element) {
|
|
2704
|
+
if ($isHeadingNode(element)) {
|
|
2705
|
+
return element.getTag();
|
|
2706
|
+
}
|
|
2707
|
+
return "paragraph";
|
|
2708
|
+
}
|
|
2709
|
+
function getVariableTopLevelElement(variable) {
|
|
2710
|
+
const topLevelElement = variable.getTopLevelElementOrThrow();
|
|
2711
|
+
return $isElementNode(topLevelElement) ? topLevelElement : null;
|
|
2712
|
+
}
|
|
2713
|
+
function replaceTopLevelBlockType(element, blockType) {
|
|
2714
|
+
const currentType = getElementBlockType$1(element);
|
|
2715
|
+
if (currentType === blockType) {
|
|
2716
|
+
return;
|
|
2717
|
+
}
|
|
2718
|
+
const nextElement = blockType === "paragraph" ? $createParagraphNode() : $createHeadingNode(blockType);
|
|
2719
|
+
nextElement.setFormat(element.getFormatType());
|
|
2720
|
+
nextElement.setIndent(element.getIndent());
|
|
2721
|
+
const children = element.getChildren();
|
|
2722
|
+
for (const child of children) {
|
|
2723
|
+
nextElement.append(child);
|
|
2724
|
+
}
|
|
2725
|
+
element.replace(nextElement);
|
|
2726
|
+
}
|
|
2727
|
+
function isPartialSingleBlockSelection(selection) {
|
|
2728
|
+
if (selection.isCollapsed()) {
|
|
2729
|
+
return false;
|
|
2730
|
+
}
|
|
2731
|
+
const anchorTopLevel = selection.anchor.getNode().getTopLevelElementOrThrow();
|
|
2732
|
+
const focusTopLevel = selection.focus.getNode().getTopLevelElementOrThrow();
|
|
2733
|
+
if (!anchorTopLevel.is(focusTopLevel)) {
|
|
2734
|
+
return false;
|
|
2735
|
+
}
|
|
2736
|
+
const selectedText = selection.getTextContent().trim();
|
|
2737
|
+
const blockText = anchorTopLevel.getTextContent().trim();
|
|
2738
|
+
return selectedText.length > 0 && selectedText.length < blockText.length;
|
|
2739
|
+
}
|
|
2740
|
+
function applySemanticBlockType(selection, blockType) {
|
|
2741
|
+
if (blockType === "paragraph") {
|
|
2742
|
+
$setBlocksType(selection, () => $createParagraphNode());
|
|
2743
|
+
return;
|
|
2744
|
+
}
|
|
2745
|
+
$setBlocksType(selection, () => $createHeadingNode(blockType));
|
|
2746
|
+
}
|
|
2747
|
+
function selectedVariablesOccupyEntireBlock(variables, topLevelElement) {
|
|
2748
|
+
const selectedKeys = new Set(variables.map((variable) => variable.getKey()));
|
|
2749
|
+
const meaningfulChildren = topLevelElement.getChildren().filter(
|
|
2750
|
+
(child) => !($isTextNode(child) && child.getTextContent().trim() === "")
|
|
2751
|
+
);
|
|
2752
|
+
if (meaningfulChildren.length === 0) {
|
|
2753
|
+
return false;
|
|
2754
|
+
}
|
|
2755
|
+
return meaningfulChildren.every(
|
|
2756
|
+
(child) => $isVariableNode(child) && selectedKeys.has(child.getKey())
|
|
2757
|
+
);
|
|
2758
|
+
}
|
|
2759
|
+
function getStandaloneVariableChildren(topLevelElement) {
|
|
2760
|
+
const meaningfulChildren = topLevelElement.getChildren().filter(
|
|
2761
|
+
(child) => !($isTextNode(child) && child.getTextContent().trim() === "")
|
|
2762
|
+
);
|
|
2763
|
+
if (meaningfulChildren.length === 0 || !meaningfulChildren.every($isVariableNode)) {
|
|
2764
|
+
return null;
|
|
2765
|
+
}
|
|
2766
|
+
return meaningfulChildren;
|
|
2767
|
+
}
|
|
2768
|
+
function getSelectedVariableNodesFromRangeSelection(editor, selection) {
|
|
2769
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2770
|
+
const variables = [];
|
|
2771
|
+
for (const node of [
|
|
2772
|
+
selection.anchor.getNode(),
|
|
2773
|
+
selection.focus.getNode(),
|
|
2774
|
+
...selection.getNodes(),
|
|
2775
|
+
...getVisuallySelectedVariableNodes(editor)
|
|
2776
|
+
]) {
|
|
2777
|
+
if (!$isVariableNode(node) || seen.has(node.getKey())) {
|
|
2778
|
+
continue;
|
|
2779
|
+
}
|
|
2780
|
+
seen.add(node.getKey());
|
|
2781
|
+
variables.push(node);
|
|
2782
|
+
}
|
|
2783
|
+
return variables;
|
|
2784
|
+
}
|
|
2785
|
+
function setBlockType(editor, blockType) {
|
|
2786
|
+
editor.update(() => {
|
|
2787
|
+
const visuallySelectedVariables = getVisuallySelectedVariableNodes(editor);
|
|
2788
|
+
const currentSelection = $getSelection();
|
|
2789
|
+
const selection = $isNodeSelection(currentSelection) ? currentSelection : $createRangeSelectionFromDom(window.getSelection(), editor) ?? currentSelection;
|
|
2790
|
+
if ($isRangeSelection(selection)) {
|
|
2791
|
+
$setSelection(selection);
|
|
2792
|
+
}
|
|
2793
|
+
if ($isNodeSelection(selection)) {
|
|
2794
|
+
const variables = Array.from(new Map(
|
|
2795
|
+
[
|
|
2796
|
+
...selection.getNodes().filter($isVariableNode),
|
|
2797
|
+
...visuallySelectedVariables
|
|
2798
|
+
].map((variable) => [variable.getKey(), variable])
|
|
2799
|
+
).values());
|
|
2800
|
+
if (variables.length === 0) {
|
|
2801
|
+
return;
|
|
2802
|
+
}
|
|
2803
|
+
const firstTopLevelElement = getVariableTopLevelElement(variables[0]);
|
|
2804
|
+
if (!firstTopLevelElement) {
|
|
2805
|
+
return;
|
|
2806
|
+
}
|
|
2807
|
+
const sameTopLevelElement = variables.every(
|
|
2808
|
+
(variable) => {
|
|
2809
|
+
var _a;
|
|
2810
|
+
return ((_a = getVariableTopLevelElement(variable)) == null ? void 0 : _a.is(firstTopLevelElement)) ?? false;
|
|
2811
|
+
}
|
|
2812
|
+
);
|
|
2813
|
+
if (sameTopLevelElement && selectedVariablesOccupyEntireBlock(variables, firstTopLevelElement)) {
|
|
2814
|
+
for (const variable of variables) {
|
|
2815
|
+
variable.setStyle(mergeInlineBlockTypeStyle(variable.getStyle(), blockType));
|
|
2816
|
+
}
|
|
2817
|
+
replaceTopLevelBlockType(firstTopLevelElement, blockType);
|
|
2818
|
+
const nextSelection = $createNodeSelection();
|
|
2819
|
+
for (const variable of variables) {
|
|
2820
|
+
nextSelection.add(variable.getKey());
|
|
2821
|
+
}
|
|
2822
|
+
$setSelection(nextSelection);
|
|
2823
|
+
return;
|
|
2824
|
+
}
|
|
2825
|
+
for (const variable of variables) {
|
|
2826
|
+
variable.setStyle(mergeInlineBlockTypeStyle(variable.getStyle(), blockType));
|
|
2827
|
+
}
|
|
2536
2828
|
return;
|
|
2537
2829
|
}
|
|
2538
|
-
|
|
2539
|
-
|
|
2830
|
+
if (!$isRangeSelection(selection)) {
|
|
2831
|
+
if (visuallySelectedVariables.length === 0) {
|
|
2832
|
+
return;
|
|
2833
|
+
}
|
|
2834
|
+
for (const variable of visuallySelectedVariables) {
|
|
2835
|
+
variable.setStyle(mergeInlineBlockTypeStyle(variable.getStyle(), blockType));
|
|
2836
|
+
}
|
|
2540
2837
|
return;
|
|
2541
2838
|
}
|
|
2542
|
-
const
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2839
|
+
const anchorTopLevel = selection.anchor.getNode().getTopLevelElementOrThrow();
|
|
2840
|
+
const standaloneVariables = $isElementNode(anchorTopLevel) ? getStandaloneVariableChildren(anchorTopLevel) : null;
|
|
2841
|
+
const selectedVariables = getSelectedVariableNodesFromRangeSelection(editor, selection);
|
|
2842
|
+
if (isPartialSingleBlockSelection(selection)) {
|
|
2843
|
+
$patchStyleText(selection, createInlineBlockTypeStylePatch(blockType));
|
|
2844
|
+
for (const variable of selectedVariables) {
|
|
2845
|
+
variable.setStyle(mergeInlineBlockTypeStyle(variable.getStyle(), blockType));
|
|
2846
|
+
}
|
|
2847
|
+
return;
|
|
2848
|
+
}
|
|
2849
|
+
for (const variable of new Map(
|
|
2850
|
+
[...standaloneVariables ?? [], ...selectedVariables].map((variable2) => [variable2.getKey(), variable2])
|
|
2851
|
+
).values()) {
|
|
2852
|
+
variable.setStyle(mergeInlineBlockTypeStyle(variable.getStyle(), blockType));
|
|
2853
|
+
}
|
|
2854
|
+
applySemanticBlockType(selection, blockType);
|
|
2547
2855
|
});
|
|
2548
|
-
return formatting;
|
|
2549
2856
|
}
|
|
2550
2857
|
const BLOCK_TYPE_OPTIONS = [
|
|
2551
2858
|
{ value: "paragraph", shortLabel: "P" },
|
|
@@ -2962,6 +3269,108 @@ const CanvasControls = () => {
|
|
|
2962
3269
|
)
|
|
2963
3270
|
] });
|
|
2964
3271
|
};
|
|
3272
|
+
const FORMAT_MASKS = {
|
|
3273
|
+
bold: 1,
|
|
3274
|
+
italic: 2,
|
|
3275
|
+
strikethrough: 4,
|
|
3276
|
+
underline: 8
|
|
3277
|
+
};
|
|
3278
|
+
function normalizeFontFamily(fontFamily) {
|
|
3279
|
+
if (fontFamily && SUPPORTED_FONTS.includes(fontFamily)) {
|
|
3280
|
+
return fontFamily;
|
|
3281
|
+
}
|
|
3282
|
+
return "Inter";
|
|
3283
|
+
}
|
|
3284
|
+
function normalizeAlignment(alignment) {
|
|
3285
|
+
if (alignment === "center" || alignment === "right" || alignment === "justify") {
|
|
3286
|
+
return alignment;
|
|
3287
|
+
}
|
|
3288
|
+
return "left";
|
|
3289
|
+
}
|
|
3290
|
+
function getElementBlockType(node) {
|
|
3291
|
+
const topLevelElement = node.getTopLevelElementOrThrow();
|
|
3292
|
+
if ($isHeadingNode(topLevelElement)) {
|
|
3293
|
+
return topLevelElement.getTag();
|
|
3294
|
+
}
|
|
3295
|
+
return "paragraph";
|
|
3296
|
+
}
|
|
3297
|
+
function getElementAlignment(node) {
|
|
3298
|
+
const topLevelElement = node.getTopLevelElementOrThrow();
|
|
3299
|
+
if ($isElementNode(topLevelElement)) {
|
|
3300
|
+
return normalizeAlignment(topLevelElement.getFormatType());
|
|
3301
|
+
}
|
|
3302
|
+
return "left";
|
|
3303
|
+
}
|
|
3304
|
+
function getInlineStyleTarget(nodes, anchorNode) {
|
|
3305
|
+
if ($isTextNode(anchorNode) || $isVariableNode(anchorNode)) {
|
|
3306
|
+
return anchorNode;
|
|
3307
|
+
}
|
|
3308
|
+
return nodes.find((node) => $isTextNode(node) || $isVariableNode(node)) ?? null;
|
|
3309
|
+
}
|
|
3310
|
+
function getInlineStyleFromNode(node) {
|
|
3311
|
+
if ($isTextNode(node) || $isVariableNode(node)) {
|
|
3312
|
+
return node.getStyle();
|
|
3313
|
+
}
|
|
3314
|
+
return "";
|
|
3315
|
+
}
|
|
3316
|
+
function hasInlineFormat(node, format) {
|
|
3317
|
+
if ($isVariableNode(node)) {
|
|
3318
|
+
return (node.getFormat() & FORMAT_MASKS[format]) !== 0;
|
|
3319
|
+
}
|
|
3320
|
+
if ($isTextNode(node) && "hasFormat" in node && typeof node.hasFormat === "function") {
|
|
3321
|
+
return node.hasFormat(format);
|
|
3322
|
+
}
|
|
3323
|
+
if ($isTextNode(node) && "getFormat" in node && typeof node.getFormat === "function") {
|
|
3324
|
+
return (node.getFormat() & FORMAT_MASKS[format]) !== 0;
|
|
3325
|
+
}
|
|
3326
|
+
return false;
|
|
3327
|
+
}
|
|
3328
|
+
function readToolbarStyleSnapshot(editor, editorState = editor.getEditorState()) {
|
|
3329
|
+
let snapshot = DEFAULT_TOOLBAR_STYLE_SNAPSHOT;
|
|
3330
|
+
editorState.read(() => {
|
|
3331
|
+
const currentSelection = $getSelection();
|
|
3332
|
+
const selection = $isNodeSelection(currentSelection) ? currentSelection : $createRangeSelectionFromDom(window.getSelection(), editor) ?? currentSelection;
|
|
3333
|
+
if ($isNodeSelection(selection)) {
|
|
3334
|
+
const variableNodes = selection.getNodes().filter($isVariableNode);
|
|
3335
|
+
if (variableNodes.length === 0) {
|
|
3336
|
+
return;
|
|
3337
|
+
}
|
|
3338
|
+
const firstVariableNode = variableNodes[0];
|
|
3339
|
+
const style2 = firstVariableNode.getStyle();
|
|
3340
|
+
snapshot = {
|
|
3341
|
+
blockType: extractInlineBlockTypeFromStyle(style2) ?? getElementBlockType(firstVariableNode),
|
|
3342
|
+
fontFamily: normalizeFontFamily(extractFontFamilyFromStyle(style2)),
|
|
3343
|
+
fontSize: extractFontSizePtFromStyle(style2) ?? DEFAULT_FONT_SIZE,
|
|
3344
|
+
alignment: getElementAlignment(firstVariableNode),
|
|
3345
|
+
isBold: variableNodes.every((node) => (node.getFormat() & FORMAT_MASKS.bold) !== 0),
|
|
3346
|
+
isItalic: variableNodes.every((node) => (node.getFormat() & FORMAT_MASKS.italic) !== 0),
|
|
3347
|
+
isUnderline: variableNodes.every((node) => (node.getFormat() & FORMAT_MASKS.underline) !== 0),
|
|
3348
|
+
isStrikethrough: variableNodes.every((node) => (node.getFormat() & FORMAT_MASKS.strikethrough) !== 0),
|
|
3349
|
+
hasSelectedVariable: true
|
|
3350
|
+
};
|
|
3351
|
+
return;
|
|
3352
|
+
}
|
|
3353
|
+
if (!$isRangeSelection(selection)) {
|
|
3354
|
+
return;
|
|
3355
|
+
}
|
|
3356
|
+
const anchorNode = selection.anchor.getNode();
|
|
3357
|
+
const inlineStyleTarget = getInlineStyleTarget(selection.getNodes(), anchorNode);
|
|
3358
|
+
const style = selection.style || getInlineStyleFromNode(inlineStyleTarget);
|
|
3359
|
+
const isCollapsed = selection.isCollapsed();
|
|
3360
|
+
snapshot = {
|
|
3361
|
+
blockType: extractInlineBlockTypeFromStyle(style) ?? getElementBlockType(anchorNode),
|
|
3362
|
+
fontFamily: normalizeFontFamily(extractFontFamilyFromStyle(style)),
|
|
3363
|
+
fontSize: extractFontSizePtFromStyle(style) ?? DEFAULT_FONT_SIZE,
|
|
3364
|
+
alignment: getElementAlignment(anchorNode),
|
|
3365
|
+
isBold: selection.hasFormat("bold") || isCollapsed && hasInlineFormat(inlineStyleTarget, "bold"),
|
|
3366
|
+
isItalic: selection.hasFormat("italic") || isCollapsed && hasInlineFormat(inlineStyleTarget, "italic"),
|
|
3367
|
+
isUnderline: selection.hasFormat("underline") || isCollapsed && hasInlineFormat(inlineStyleTarget, "underline"),
|
|
3368
|
+
isStrikethrough: selection.hasFormat("strikethrough") || isCollapsed && hasInlineFormat(inlineStyleTarget, "strikethrough"),
|
|
3369
|
+
hasSelectedVariable: false
|
|
3370
|
+
};
|
|
3371
|
+
});
|
|
3372
|
+
return snapshot;
|
|
3373
|
+
}
|
|
2965
3374
|
const Toolbar = () => {
|
|
2966
3375
|
const {
|
|
2967
3376
|
activeEditor,
|
|
@@ -2978,15 +3387,15 @@ const Toolbar = () => {
|
|
|
2978
3387
|
const { toolbarItems, toolbarEndItems } = useExtensions();
|
|
2979
3388
|
const toolbarConfig = useToolbarConfig();
|
|
2980
3389
|
const t = useTranslations();
|
|
2981
|
-
const
|
|
2982
|
-
const
|
|
2983
|
-
const
|
|
2984
|
-
const
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
3390
|
+
const toolbarStyleStore = useToolbarStyleStoreApi();
|
|
3391
|
+
const activeBlockType = useToolbarStyleStore((state) => state.blockType);
|
|
3392
|
+
const activeFontFamily = useToolbarStyleStore((state) => state.fontFamily);
|
|
3393
|
+
const activeFontSize = useToolbarStyleStore((state) => state.fontSize);
|
|
3394
|
+
const activeAlignment = useToolbarStyleStore((state) => state.alignment);
|
|
3395
|
+
const isBoldActive = useToolbarStyleStore((state) => state.isBold);
|
|
3396
|
+
const isItalicActive = useToolbarStyleStore((state) => state.isItalic);
|
|
3397
|
+
const isUnderlineActive = useToolbarStyleStore((state) => state.isUnderline);
|
|
3398
|
+
const isStrikethroughActive = useToolbarStyleStore((state) => state.isStrikethrough);
|
|
2990
3399
|
const withBodySelection = useCallback(
|
|
2991
3400
|
(editor, action) => {
|
|
2992
3401
|
editor.update(() => {
|
|
@@ -3024,38 +3433,11 @@ const Toolbar = () => {
|
|
|
3024
3433
|
);
|
|
3025
3434
|
useEffect(() => {
|
|
3026
3435
|
if (!activeEditor) {
|
|
3027
|
-
|
|
3028
|
-
setActiveFontFamily("Calibri");
|
|
3029
|
-
setActiveFontSize(DEFAULT_FONT_SIZE);
|
|
3436
|
+
toolbarStyleStore.getState().reset();
|
|
3030
3437
|
return;
|
|
3031
3438
|
}
|
|
3032
|
-
const updateSelectionState = () => {
|
|
3033
|
-
|
|
3034
|
-
if (selectedVariables.length > 0) {
|
|
3035
|
-
const formatting = readSelectedVariableFormatting(activeEditor);
|
|
3036
|
-
setActiveBlockType("paragraph");
|
|
3037
|
-
setActiveFontFamily(normalizeFontFamily(formatting.fontFamily));
|
|
3038
|
-
setActiveFontSize(formatting.fontSize ?? DEFAULT_FONT_SIZE);
|
|
3039
|
-
return;
|
|
3040
|
-
}
|
|
3041
|
-
setActiveBlockType(getActiveBlockType(activeEditor));
|
|
3042
|
-
let nextFontFamily = "Calibri";
|
|
3043
|
-
let nextFontSize = DEFAULT_FONT_SIZE;
|
|
3044
|
-
activeEditor.getEditorState().read(() => {
|
|
3045
|
-
const selection = $getSelection();
|
|
3046
|
-
if (!$isRangeSelection(selection)) {
|
|
3047
|
-
return;
|
|
3048
|
-
}
|
|
3049
|
-
const textNode = selection.getNodes().find($isTextNode);
|
|
3050
|
-
if (!textNode) {
|
|
3051
|
-
return;
|
|
3052
|
-
}
|
|
3053
|
-
const style = textNode.getStyle();
|
|
3054
|
-
nextFontFamily = normalizeFontFamily(extractFontFamilyFromStyle(style));
|
|
3055
|
-
nextFontSize = extractFontSizePtFromStyle(style) ?? DEFAULT_FONT_SIZE;
|
|
3056
|
-
});
|
|
3057
|
-
setActiveFontFamily(nextFontFamily);
|
|
3058
|
-
setActiveFontSize(nextFontSize);
|
|
3439
|
+
const updateSelectionState = (editorState = activeEditor.getEditorState()) => {
|
|
3440
|
+
toolbarStyleStore.getState().setSnapshot(readToolbarStyleSnapshot(activeEditor, editorState));
|
|
3059
3441
|
};
|
|
3060
3442
|
updateSelectionState();
|
|
3061
3443
|
const unregisterSelectionChange = activeEditor.registerCommand(
|
|
@@ -3066,14 +3448,14 @@ const Toolbar = () => {
|
|
|
3066
3448
|
},
|
|
3067
3449
|
COMMAND_PRIORITY_LOW
|
|
3068
3450
|
);
|
|
3069
|
-
const unregisterUpdateListener = activeEditor.registerUpdateListener(() => {
|
|
3070
|
-
updateSelectionState();
|
|
3451
|
+
const unregisterUpdateListener = activeEditor.registerUpdateListener(({ editorState }) => {
|
|
3452
|
+
updateSelectionState(editorState);
|
|
3071
3453
|
});
|
|
3072
3454
|
return () => {
|
|
3073
3455
|
unregisterSelectionChange();
|
|
3074
3456
|
unregisterUpdateListener();
|
|
3075
3457
|
};
|
|
3076
|
-
}, [activeEditor,
|
|
3458
|
+
}, [activeEditor, toolbarStyleStore]);
|
|
3077
3459
|
const handleBold = useCallback(() => {
|
|
3078
3460
|
debug("toolbar", `bold (globalSelection=${globalSelectionActive}, editors=${editorRegistry.all().length}, hasEditor=${!!activeEditor})`);
|
|
3079
3461
|
runToolbarAction(t.history.actions.boldApplied, () => {
|
|
@@ -3258,17 +3640,17 @@ const Toolbar = () => {
|
|
|
3258
3640
|
] }),
|
|
3259
3641
|
/* @__PURE__ */ jsx(Divider, {}),
|
|
3260
3642
|
/* @__PURE__ */ jsxs("div", { className: "lex4-toolbar-group", "data-testid": "format-group", children: [
|
|
3261
|
-
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.bold, testId: "btn-bold", onClick: handleBold, children: /* @__PURE__ */ jsx(Bold, { size: 15 }) }),
|
|
3262
|
-
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.italic, testId: "btn-italic", onClick: handleItalic, children: /* @__PURE__ */ jsx(Italic, { size: 15 }) }),
|
|
3263
|
-
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.underline, testId: "btn-underline", onClick: handleUnderline, children: /* @__PURE__ */ jsx(Underline, { size: 15 }) }),
|
|
3264
|
-
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.strikethrough, testId: "btn-strike", onClick: handleStrikethrough, children: /* @__PURE__ */ jsx(Strikethrough, { size: 15 }) })
|
|
3643
|
+
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.bold, testId: "btn-bold", active: isBoldActive, onClick: handleBold, children: /* @__PURE__ */ jsx(Bold, { size: 15 }) }),
|
|
3644
|
+
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.italic, testId: "btn-italic", active: isItalicActive, onClick: handleItalic, children: /* @__PURE__ */ jsx(Italic, { size: 15 }) }),
|
|
3645
|
+
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.underline, testId: "btn-underline", active: isUnderlineActive, onClick: handleUnderline, children: /* @__PURE__ */ jsx(Underline, { size: 15 }) }),
|
|
3646
|
+
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.strikethrough, testId: "btn-strike", active: isStrikethroughActive, onClick: handleStrikethrough, children: /* @__PURE__ */ jsx(Strikethrough, { size: 15 }) })
|
|
3265
3647
|
] }),
|
|
3266
3648
|
/* @__PURE__ */ jsx(Divider, {}),
|
|
3267
3649
|
/* @__PURE__ */ jsxs("div", { className: "lex4-toolbar-group", "data-testid": "align-group", children: [
|
|
3268
|
-
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.alignLeft, testId: "btn-align-left", onClick: handleAlignLeft, children: /* @__PURE__ */ jsx(TextAlignStart, { size: 15 }) }),
|
|
3269
|
-
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.alignCenter, testId: "btn-align-center", onClick: handleAlignCenter, children: /* @__PURE__ */ jsx(TextAlignCenter, { size: 15 }) }),
|
|
3270
|
-
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.alignRight, testId: "btn-align-right", onClick: handleAlignRight, children: /* @__PURE__ */ jsx(TextAlignEnd, { size: 15 }) }),
|
|
3271
|
-
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.justify, testId: "btn-align-justify", onClick: handleAlignJustify, children: /* @__PURE__ */ jsx(TextAlignJustify, { size: 15 }) })
|
|
3650
|
+
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.alignLeft, testId: "btn-align-left", active: activeAlignment === "left", onClick: handleAlignLeft, children: /* @__PURE__ */ jsx(TextAlignStart, { size: 15 }) }),
|
|
3651
|
+
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.alignCenter, testId: "btn-align-center", active: activeAlignment === "center", onClick: handleAlignCenter, children: /* @__PURE__ */ jsx(TextAlignCenter, { size: 15 }) }),
|
|
3652
|
+
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.alignRight, testId: "btn-align-right", active: activeAlignment === "right", onClick: handleAlignRight, children: /* @__PURE__ */ jsx(TextAlignEnd, { size: 15 }) }),
|
|
3653
|
+
/* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.justify, testId: "btn-align-justify", active: activeAlignment === "justify", onClick: handleAlignJustify, children: /* @__PURE__ */ jsx(TextAlignJustify, { size: 15 }) })
|
|
3272
3654
|
] }),
|
|
3273
3655
|
/* @__PURE__ */ jsx(Divider, {}),
|
|
3274
3656
|
/* @__PURE__ */ jsxs("div", { className: "lex4-toolbar-group", "data-testid": "list-group", children: [
|
|
@@ -3319,6 +3701,7 @@ const ToolbarIconButton = ({
|
|
|
3319
3701
|
type: "button",
|
|
3320
3702
|
title,
|
|
3321
3703
|
"aria-label": title,
|
|
3704
|
+
"aria-pressed": active,
|
|
3322
3705
|
disabled,
|
|
3323
3706
|
onMouseDown: (e) => e.preventDefault(),
|
|
3324
3707
|
onClick,
|