@yurikilian/lex4 1.7.0 → 1.10.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.
@@ -3,9 +3,10 @@ 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, 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, KEY_BACKSPACE_COMMAND, COMMAND_PRIORITY_LOW, KEY_DELETE_COMMAND, KEY_DOWN_COMMAND, $isNodeSelection, $getNodeByKey, $setSelection, $createNodeSelection, $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";
6
+ import { $getSelection, $isRangeSelection, $isTextNode, $getRoot, $createRangeSelectionFromDom, FORMAT_ELEMENT_COMMAND, FORMAT_TEXT_COMMAND, $applyNodeReplacement, OUTDENT_CONTENT_COMMAND, INDENT_CONTENT_COMMAND, 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
- import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, ListNode, ListItemNode, $isListNode, $createListItemNode, $createListNode } from "@lexical/list";
8
+ import { ListNode, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, $createListNode, $isListNode, ListItemNode, $createListItemNode } from "@lexical/list";
9
+ import { $findMatchingParent } from "@lexical/utils";
9
10
  import { $patchStyleText, $setBlocksType } from "@lexical/selection";
10
11
  import { $createHeadingNode, $isHeadingNode, HeadingNode, QuoteNode, $createQuoteNode } from "@lexical/rich-text";
11
12
  import { useLexicalNodeSelection } from "@lexical/react/useLexicalNodeSelection";
@@ -471,6 +472,7 @@ const DEFAULT_TRANSLATIONS = {
471
472
  justify: "Justify",
472
473
  numberedList: "Numbered List",
473
474
  bulletList: "Bullet List",
475
+ alphabeticList: "Alphabetic List",
474
476
  indent: "Indent",
475
477
  outdent: "Outdent",
476
478
  history: "History",
@@ -510,6 +512,7 @@ const DEFAULT_TRANSLATIONS = {
510
512
  justifiedText: "Justified text",
511
513
  insertedNumberedList: "Inserted numbered list",
512
514
  insertedBulletList: "Inserted bullet list",
515
+ insertedAlphabeticList: "Inserted alphabetic list",
513
516
  indentedContent: "Indented content",
514
517
  outdentedContent: "Outdented content",
515
518
  fontChanged: "Font changed to {{value}}",
@@ -613,6 +616,7 @@ const PT_BR_TRANSLATIONS = {
613
616
  justify: "Justificar",
614
617
  numberedList: "Lista Numerada",
615
618
  bulletList: "Lista com Marcadores",
619
+ alphabeticList: "Lista Alfabética",
616
620
  indent: "Aumentar Recuo",
617
621
  outdent: "Diminuir Recuo",
618
622
  history: "Histórico",
@@ -652,6 +656,7 @@ const PT_BR_TRANSLATIONS = {
652
656
  justifiedText: "Texto justificado",
653
657
  insertedNumberedList: "Lista numerada inserida",
654
658
  insertedBulletList: "Lista com marcadores inserida",
659
+ insertedAlphabeticList: "Lista alfabética inserida",
655
660
  indentedContent: "Conteúdo recuado",
656
661
  outdentedContent: "Recuo reduzido",
657
662
  fontChanged: "Fonte alterada para {{value}}",
@@ -848,9 +853,10 @@ function mergeFontSize(existingStyle, size) {
848
853
  }
849
854
  const DEFAULT_TOOLBAR_STYLE_SNAPSHOT = {
850
855
  blockType: "paragraph",
851
- fontFamily: "Calibri",
856
+ fontFamily: "Inter",
852
857
  fontSize: DEFAULT_FONT_SIZE,
853
858
  alignment: "left",
859
+ activeList: "none",
854
860
  isBold: false,
855
861
  isItalic: false,
856
862
  isUnderline: false,
@@ -2208,13 +2214,145 @@ function toggleStrikethrough(editor) {
2208
2214
  function setAlignment(editor, alignment) {
2209
2215
  editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, alignment);
2210
2216
  }
2217
+ function decorateAlphaListDom(dom) {
2218
+ dom.classList.add("lex4-list-alpha");
2219
+ dom.setAttribute("data-lex4-list-variant", "alpha");
2220
+ }
2221
+ class AlphaListNode extends ListNode {
2222
+ static getType() {
2223
+ return "alpha-list";
2224
+ }
2225
+ static clone(node) {
2226
+ return new AlphaListNode(node.getStart(), node.__key);
2227
+ }
2228
+ static importJSON(serializedNode) {
2229
+ const node = $createAlphaListNode(
2230
+ typeof serializedNode.start === "number" ? serializedNode.start : 1
2231
+ );
2232
+ node.setFormat(serializedNode.format);
2233
+ node.setIndent(serializedNode.indent);
2234
+ node.setDirection(serializedNode.direction);
2235
+ return node;
2236
+ }
2237
+ constructor(start = 1, key) {
2238
+ super("number", start, key);
2239
+ }
2240
+ createDOM(config, editor) {
2241
+ const dom = super.createDOM(config, editor);
2242
+ decorateAlphaListDom(dom);
2243
+ return dom;
2244
+ }
2245
+ updateDOM(prevNode, dom, config) {
2246
+ const replaced = super.updateDOM(prevNode, dom, config);
2247
+ if (replaced) {
2248
+ return true;
2249
+ }
2250
+ decorateAlphaListDom(dom);
2251
+ return false;
2252
+ }
2253
+ exportJSON() {
2254
+ return {
2255
+ ...super.exportJSON(),
2256
+ type: "alpha-list",
2257
+ markerStyle: "alpha"
2258
+ };
2259
+ }
2260
+ }
2261
+ function $createAlphaListNode(start = 1) {
2262
+ return $applyNodeReplacement(new AlphaListNode(start));
2263
+ }
2264
+ function $isAlphaListNode(node) {
2265
+ return node instanceof AlphaListNode;
2266
+ }
2267
+ function getNearestListNode$1(node) {
2268
+ if ($isListNode(node)) {
2269
+ return node;
2270
+ }
2271
+ const listNode = $findMatchingParent(node, $isListNode);
2272
+ return $isListNode(listNode) ? listNode : null;
2273
+ }
2274
+ function getSelectedListNodes() {
2275
+ const selection = $getSelection();
2276
+ if (!selection) {
2277
+ return [];
2278
+ }
2279
+ const listNodes = /* @__PURE__ */ new Map();
2280
+ const nodes = selection.getNodes();
2281
+ if ($isRangeSelection(selection)) {
2282
+ nodes.push(selection.anchor.getNode(), selection.focus.getNode());
2283
+ }
2284
+ for (const node of nodes) {
2285
+ const listNode = getNearestListNode$1(node);
2286
+ if (listNode) {
2287
+ listNodes.set(listNode.getKey(), listNode);
2288
+ }
2289
+ }
2290
+ return Array.from(listNodes.values());
2291
+ }
2292
+ function replaceWithAlphaList(listNode) {
2293
+ if ($isAlphaListNode(listNode) || listNode.getListType() !== "number") {
2294
+ return;
2295
+ }
2296
+ const alphaList = $createAlphaListNode(listNode.getStart());
2297
+ alphaList.setFormat(listNode.getFormatType());
2298
+ alphaList.setIndent(listNode.getIndent());
2299
+ alphaList.setDirection(listNode.getDirection());
2300
+ alphaList.append(...listNode.getChildren());
2301
+ listNode.replace(alphaList);
2302
+ }
2303
+ function replaceWithPlainList(listNode, listType) {
2304
+ if (!$isAlphaListNode(listNode) && listNode.getListType() === listType) {
2305
+ return;
2306
+ }
2307
+ const plainList = $createListNode(
2308
+ listType,
2309
+ listType === "number" ? listNode.getStart() : 1
2310
+ );
2311
+ plainList.setFormat(listNode.getFormatType());
2312
+ plainList.setIndent(listNode.getIndent());
2313
+ plainList.setDirection(listNode.getDirection());
2314
+ plainList.append(...listNode.getChildren());
2315
+ listNode.replace(plainList);
2316
+ }
2317
+ function insertAlphaList(editor) {
2318
+ const hasAlphaListSelection = editor.getEditorState().read(
2319
+ () => getSelectedListNodes().some($isAlphaListNode)
2320
+ );
2321
+ if (hasAlphaListSelection) {
2322
+ removeList(editor);
2323
+ return;
2324
+ }
2325
+ editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, void 0);
2326
+ editor.update(() => {
2327
+ getSelectedListNodes().forEach(replaceWithAlphaList);
2328
+ });
2329
+ }
2330
+ function normalizeSelectedAlphaLists(editor, listType) {
2331
+ const hasAlphaListSelection = editor.getEditorState().read(
2332
+ () => getSelectedListNodes().some($isAlphaListNode)
2333
+ );
2334
+ if (!hasAlphaListSelection) {
2335
+ return false;
2336
+ }
2337
+ editor.update(() => {
2338
+ getSelectedListNodes().forEach((listNode) => replaceWithPlainList(listNode, listType));
2339
+ });
2340
+ return true;
2341
+ }
2211
2342
  function insertList(editor, type) {
2212
- if (type === "number") {
2343
+ if (type === "alpha") {
2344
+ insertAlphaList(editor);
2345
+ } else if (normalizeSelectedAlphaLists(editor, type)) {
2346
+ return;
2347
+ } else if (type === "number") {
2213
2348
  editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, void 0);
2214
2349
  } else {
2215
2350
  editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, void 0);
2216
2351
  }
2217
2352
  }
2353
+ function removeList(editor) {
2354
+ editor.dispatchCommand(REMOVE_LIST_COMMAND, void 0);
2355
+ }
2218
2356
  function indentContent(editor) {
2219
2357
  editor.dispatchCommand(INDENT_CONTENT_COMMAND, void 0);
2220
2358
  }
@@ -2411,6 +2549,7 @@ class VariableNode extends DecoratorNode {
2411
2549
  const span = document.createElement("span");
2412
2550
  span.className = "lex4-variable";
2413
2551
  span.setAttribute("data-variable-key", this.__variableKey);
2552
+ span.setAttribute("data-node-key", this.__key);
2414
2553
  span.setAttribute("data-testid", `variable-${this.__variableKey}`);
2415
2554
  span.contentEditable = "false";
2416
2555
  return span;
@@ -2458,7 +2597,7 @@ function VariableChip({
2458
2597
  }) {
2459
2598
  const { getDefinition } = useVariables();
2460
2599
  const [editor] = useLexicalComposerContext();
2461
- const [isSelected, setSelected, clearOtherSelections] = useLexicalNodeSelection(nodeKey);
2600
+ const [isSelected] = useLexicalNodeSelection(nodeKey);
2462
2601
  const def = getDefinition(variableKey);
2463
2602
  const label = (def == null ? void 0 : def.label) ?? variableKey;
2464
2603
  const group = def == null ? void 0 : def.group;
@@ -2480,13 +2619,48 @@ function VariableChip({
2480
2619
  format & 8 ? "lex4-text-underline" : "",
2481
2620
  format & 4 ? "lex4-text-strikethrough" : ""
2482
2621
  ].filter(Boolean).join(" ");
2483
- const handleClick = useCallback((event) => {
2622
+ const clearDomSelection = useCallback(() => {
2623
+ var _a;
2624
+ if (typeof window === "undefined") {
2625
+ return;
2626
+ }
2627
+ (_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
2628
+ }, []);
2629
+ const selectNode = useCallback((extendSelection) => {
2630
+ editor.focus();
2631
+ editor.update(() => {
2632
+ const nextSelection = $createNodeSelection();
2633
+ if (extendSelection) {
2634
+ const currentSelection = $getSelection();
2635
+ if ($isNodeSelection(currentSelection)) {
2636
+ for (const node of currentSelection.getNodes()) {
2637
+ if ($isVariableNode(node)) {
2638
+ nextSelection.add(node.getKey());
2639
+ }
2640
+ }
2641
+ }
2642
+ }
2643
+ nextSelection.add(nodeKey);
2644
+ $setSelection(nextSelection);
2645
+ });
2646
+ clearDomSelection();
2647
+ }, [clearDomSelection, editor, nodeKey]);
2648
+ const handleMouseDown = useCallback((event) => {
2484
2649
  event.preventDefault();
2485
- if (!event.shiftKey) {
2486
- clearOtherSelections();
2650
+ event.stopPropagation();
2651
+ if (!isSelected || event.shiftKey) {
2652
+ selectNode(event.shiftKey);
2487
2653
  }
2488
- setSelected(!isSelected);
2489
- }, [clearOtherSelections, isSelected, setSelected]);
2654
+ }, [isSelected, selectNode]);
2655
+ const handleClick = useCallback((event) => {
2656
+ event.preventDefault();
2657
+ event.stopPropagation();
2658
+ }, []);
2659
+ const handleMouseUp = useCallback((event) => {
2660
+ event.preventDefault();
2661
+ event.stopPropagation();
2662
+ clearDomSelection();
2663
+ }, [clearDomSelection]);
2490
2664
  useEffect(() => {
2491
2665
  const removeSelectedNodes = () => {
2492
2666
  editor.update(() => {
@@ -2574,7 +2748,8 @@ function VariableChip({
2574
2748
  "data-variable-group": group,
2575
2749
  title: variableKey,
2576
2750
  style,
2577
- onMouseDown: (event) => event.preventDefault(),
2751
+ onMouseDown: handleMouseDown,
2752
+ onMouseUp: handleMouseUp,
2578
2753
  onClick: handleClick,
2579
2754
  children: label
2580
2755
  }
@@ -2586,6 +2761,83 @@ function $createVariableNode(variableKey, format = 0, style = "") {
2586
2761
  function $isVariableNode(node) {
2587
2762
  return node instanceof VariableNode;
2588
2763
  }
2764
+ const FORMAT_MASKS$1 = {
2765
+ bold: 1,
2766
+ italic: 2,
2767
+ strikethrough: 4,
2768
+ underline: 8
2769
+ };
2770
+ function dedupeVariableNodes(nodes) {
2771
+ return Array.from(new Map(nodes.map((node) => [node.getKey(), node])).values());
2772
+ }
2773
+ function getSelectedVariableNodesFromSelection(selection) {
2774
+ if (!selection || typeof selection !== "object" || !("getNodes" in selection) || typeof selection.getNodes !== "function") {
2775
+ return [];
2776
+ }
2777
+ return dedupeVariableNodes(selection.getNodes().filter($isVariableNode));
2778
+ }
2779
+ function getVisuallySelectedVariableNodes(editor) {
2780
+ const rootElement = editor.getRootElement();
2781
+ if (!rootElement) {
2782
+ return [];
2783
+ }
2784
+ const nodes = [];
2785
+ rootElement.querySelectorAll(".lex4-variable-chip-selected").forEach((chip) => {
2786
+ const variableElement = chip.closest("[data-node-key]");
2787
+ const nodeKey = variableElement == null ? void 0 : variableElement.dataset.nodeKey;
2788
+ if (!nodeKey) {
2789
+ return;
2790
+ }
2791
+ const node = $getNodeByKey(nodeKey);
2792
+ if ($isVariableNode(node)) {
2793
+ nodes.push(node);
2794
+ }
2795
+ });
2796
+ return dedupeVariableNodes(nodes);
2797
+ }
2798
+ function withSelectedVariableNodes(editor, updater) {
2799
+ let updated = false;
2800
+ editor.update(() => {
2801
+ const nodes = [
2802
+ ...getSelectedVariableNodesFromSelection($getSelection()),
2803
+ ...getVisuallySelectedVariableNodes(editor)
2804
+ ];
2805
+ const uniqueNodes = dedupeVariableNodes(nodes);
2806
+ if (uniqueNodes.length === 0) {
2807
+ return;
2808
+ }
2809
+ updater(uniqueNodes);
2810
+ updated = true;
2811
+ });
2812
+ return updated;
2813
+ }
2814
+ function toggleSelectedVariableFormat(editor, format) {
2815
+ const mask = FORMAT_MASKS$1[format];
2816
+ if (!mask) {
2817
+ return false;
2818
+ }
2819
+ return withSelectedVariableNodes(editor, (nodes) => {
2820
+ const shouldEnable = nodes.some((node) => (node.getFormat() & mask) === 0);
2821
+ for (const node of nodes) {
2822
+ const nextFormat = shouldEnable ? node.getFormat() | mask : node.getFormat() & ~mask;
2823
+ node.setFormat(nextFormat);
2824
+ }
2825
+ });
2826
+ }
2827
+ function applyFontFamilyToSelectedVariables(editor, fontFamily) {
2828
+ return withSelectedVariableNodes(editor, (nodes) => {
2829
+ for (const node of nodes) {
2830
+ node.setStyle(mergeFontFamilyStyle(node.getStyle(), fontFamily));
2831
+ }
2832
+ });
2833
+ }
2834
+ function applyFontSizeToSelectedVariables(editor, size) {
2835
+ return withSelectedVariableNodes(editor, (nodes) => {
2836
+ for (const node of nodes) {
2837
+ node.setStyle(mergeFontSizeStyle(node.getStyle(), size));
2838
+ }
2839
+ });
2840
+ }
2589
2841
  function getElementBlockType$1(element) {
2590
2842
  if ($isHeadingNode(element)) {
2591
2843
  return element.getTag();
@@ -2651,15 +2903,38 @@ function getStandaloneVariableChildren(topLevelElement) {
2651
2903
  }
2652
2904
  return meaningfulChildren;
2653
2905
  }
2906
+ function getSelectedVariableNodesFromRangeSelection(editor, selection) {
2907
+ const seen = /* @__PURE__ */ new Set();
2908
+ const variables = [];
2909
+ for (const node of [
2910
+ selection.anchor.getNode(),
2911
+ selection.focus.getNode(),
2912
+ ...selection.getNodes(),
2913
+ ...getVisuallySelectedVariableNodes(editor)
2914
+ ]) {
2915
+ if (!$isVariableNode(node) || seen.has(node.getKey())) {
2916
+ continue;
2917
+ }
2918
+ seen.add(node.getKey());
2919
+ variables.push(node);
2920
+ }
2921
+ return variables;
2922
+ }
2654
2923
  function setBlockType(editor, blockType) {
2655
2924
  editor.update(() => {
2925
+ const visuallySelectedVariables = getVisuallySelectedVariableNodes(editor);
2656
2926
  const currentSelection = $getSelection();
2657
2927
  const selection = $isNodeSelection(currentSelection) ? currentSelection : $createRangeSelectionFromDom(window.getSelection(), editor) ?? currentSelection;
2658
2928
  if ($isRangeSelection(selection)) {
2659
2929
  $setSelection(selection);
2660
2930
  }
2661
2931
  if ($isNodeSelection(selection)) {
2662
- const variables = selection.getNodes().filter($isVariableNode);
2932
+ const variables = Array.from(new Map(
2933
+ [
2934
+ ...selection.getNodes().filter($isVariableNode),
2935
+ ...visuallySelectedVariables
2936
+ ].map((variable) => [variable.getKey(), variable])
2937
+ ).values());
2663
2938
  if (variables.length === 0) {
2664
2939
  return;
2665
2940
  }
@@ -2691,69 +2966,32 @@ function setBlockType(editor, blockType) {
2691
2966
  return;
2692
2967
  }
2693
2968
  if (!$isRangeSelection(selection)) {
2969
+ if (visuallySelectedVariables.length === 0) {
2970
+ return;
2971
+ }
2972
+ for (const variable of visuallySelectedVariables) {
2973
+ variable.setStyle(mergeInlineBlockTypeStyle(variable.getStyle(), blockType));
2974
+ }
2694
2975
  return;
2695
2976
  }
2696
2977
  const anchorTopLevel = selection.anchor.getNode().getTopLevelElementOrThrow();
2697
2978
  const standaloneVariables = $isElementNode(anchorTopLevel) ? getStandaloneVariableChildren(anchorTopLevel) : null;
2979
+ const selectedVariables = getSelectedVariableNodesFromRangeSelection(editor, selection);
2698
2980
  if (isPartialSingleBlockSelection(selection)) {
2699
2981
  $patchStyleText(selection, createInlineBlockTypeStylePatch(blockType));
2982
+ for (const variable of selectedVariables) {
2983
+ variable.setStyle(mergeInlineBlockTypeStyle(variable.getStyle(), blockType));
2984
+ }
2700
2985
  return;
2701
2986
  }
2702
- for (const variable of standaloneVariables ?? []) {
2987
+ for (const variable of new Map(
2988
+ [...standaloneVariables ?? [], ...selectedVariables].map((variable2) => [variable2.getKey(), variable2])
2989
+ ).values()) {
2703
2990
  variable.setStyle(mergeInlineBlockTypeStyle(variable.getStyle(), blockType));
2704
2991
  }
2705
2992
  applySemanticBlockType(selection, blockType);
2706
2993
  });
2707
2994
  }
2708
- const FORMAT_MASKS$1 = {
2709
- bold: 1,
2710
- italic: 2,
2711
- strikethrough: 4,
2712
- underline: 8
2713
- };
2714
- function withSelectedVariableNodes(editor, updater) {
2715
- let updated = false;
2716
- editor.update(() => {
2717
- const selection = $getSelection();
2718
- if (!$isNodeSelection(selection)) {
2719
- return;
2720
- }
2721
- const nodes = selection.getNodes().filter($isVariableNode);
2722
- if (nodes.length === 0) {
2723
- return;
2724
- }
2725
- updater(nodes);
2726
- updated = true;
2727
- });
2728
- return updated;
2729
- }
2730
- function toggleSelectedVariableFormat(editor, format) {
2731
- const mask = FORMAT_MASKS$1[format];
2732
- if (!mask) {
2733
- return false;
2734
- }
2735
- return withSelectedVariableNodes(editor, (nodes) => {
2736
- const shouldEnable = nodes.some((node) => (node.getFormat() & mask) === 0);
2737
- for (const node of nodes) {
2738
- const nextFormat = shouldEnable ? node.getFormat() | mask : node.getFormat() & ~mask;
2739
- node.setFormat(nextFormat);
2740
- }
2741
- });
2742
- }
2743
- function applyFontFamilyToSelectedVariables(editor, fontFamily) {
2744
- return withSelectedVariableNodes(editor, (nodes) => {
2745
- for (const node of nodes) {
2746
- node.setStyle(mergeFontFamilyStyle(node.getStyle(), fontFamily));
2747
- }
2748
- });
2749
- }
2750
- function applyFontSizeToSelectedVariables(editor, size) {
2751
- return withSelectedVariableNodes(editor, (nodes) => {
2752
- for (const node of nodes) {
2753
- node.setStyle(mergeFontSizeStyle(node.getStyle(), size));
2754
- }
2755
- });
2756
- }
2757
2995
  const BLOCK_TYPE_OPTIONS = [
2758
2996
  { value: "paragraph", shortLabel: "P" },
2759
2997
  { value: "h1", shortLabel: "H1" },
@@ -3179,7 +3417,7 @@ function normalizeFontFamily(fontFamily) {
3179
3417
  if (fontFamily && SUPPORTED_FONTS.includes(fontFamily)) {
3180
3418
  return fontFamily;
3181
3419
  }
3182
- return "Calibri";
3420
+ return "Inter";
3183
3421
  }
3184
3422
  function normalizeAlignment(alignment) {
3185
3423
  if (alignment === "center" || alignment === "right" || alignment === "justify") {
@@ -3201,6 +3439,40 @@ function getElementAlignment(node) {
3201
3439
  }
3202
3440
  return "left";
3203
3441
  }
3442
+ function getNearestListNode(node) {
3443
+ if ($isListNode(node)) {
3444
+ return node;
3445
+ }
3446
+ return $findMatchingParent(node, $isListNode);
3447
+ }
3448
+ function getNodeActiveList(node) {
3449
+ const listNode = getNearestListNode(node);
3450
+ if (!$isListNode(listNode)) {
3451
+ return "none";
3452
+ }
3453
+ if ($isAlphaListNode(listNode)) {
3454
+ return "alpha";
3455
+ }
3456
+ return listNode.getListType() === "number" ? "number" : listNode.getListType() === "bullet" ? "bullet" : "none";
3457
+ }
3458
+ function getActiveList(nodes, anchorNode) {
3459
+ const activeLists = /* @__PURE__ */ new Set();
3460
+ const anchorList = getNodeActiveList(anchorNode);
3461
+ if (anchorList !== "none") {
3462
+ activeLists.add(anchorList);
3463
+ }
3464
+ for (const node of nodes) {
3465
+ const activeList = getNodeActiveList(node);
3466
+ if (activeList === "none") {
3467
+ continue;
3468
+ }
3469
+ activeLists.add(activeList);
3470
+ if (activeLists.size > 1) {
3471
+ return "none";
3472
+ }
3473
+ }
3474
+ return activeLists.values().next().value ?? "none";
3475
+ }
3204
3476
  function getInlineStyleTarget(nodes, anchorNode) {
3205
3477
  if ($isTextNode(anchorNode) || $isVariableNode(anchorNode)) {
3206
3478
  return anchorNode;
@@ -3229,7 +3501,7 @@ function readToolbarStyleSnapshot(editor, editorState = editor.getEditorState())
3229
3501
  let snapshot = DEFAULT_TOOLBAR_STYLE_SNAPSHOT;
3230
3502
  editorState.read(() => {
3231
3503
  const currentSelection = $getSelection();
3232
- const selection = $isNodeSelection(currentSelection) ? currentSelection : $createRangeSelectionFromDom(window.getSelection(), editor) ?? currentSelection;
3504
+ const selection = $isNodeSelection(currentSelection) || $isRangeSelection(currentSelection) ? currentSelection : $createRangeSelectionFromDom(window.getSelection(), editor) ?? currentSelection;
3233
3505
  if ($isNodeSelection(selection)) {
3234
3506
  const variableNodes = selection.getNodes().filter($isVariableNode);
3235
3507
  if (variableNodes.length === 0) {
@@ -3242,6 +3514,7 @@ function readToolbarStyleSnapshot(editor, editorState = editor.getEditorState())
3242
3514
  fontFamily: normalizeFontFamily(extractFontFamilyFromStyle(style2)),
3243
3515
  fontSize: extractFontSizePtFromStyle(style2) ?? DEFAULT_FONT_SIZE,
3244
3516
  alignment: getElementAlignment(firstVariableNode),
3517
+ activeList: getActiveList(variableNodes, firstVariableNode),
3245
3518
  isBold: variableNodes.every((node) => (node.getFormat() & FORMAT_MASKS.bold) !== 0),
3246
3519
  isItalic: variableNodes.every((node) => (node.getFormat() & FORMAT_MASKS.italic) !== 0),
3247
3520
  isUnderline: variableNodes.every((node) => (node.getFormat() & FORMAT_MASKS.underline) !== 0),
@@ -3262,6 +3535,7 @@ function readToolbarStyleSnapshot(editor, editorState = editor.getEditorState())
3262
3535
  fontFamily: normalizeFontFamily(extractFontFamilyFromStyle(style)),
3263
3536
  fontSize: extractFontSizePtFromStyle(style) ?? DEFAULT_FONT_SIZE,
3264
3537
  alignment: getElementAlignment(anchorNode),
3538
+ activeList: getActiveList(selection.getNodes(), anchorNode),
3265
3539
  isBold: selection.hasFormat("bold") || isCollapsed && hasInlineFormat(inlineStyleTarget, "bold"),
3266
3540
  isItalic: selection.hasFormat("italic") || isCollapsed && hasInlineFormat(inlineStyleTarget, "italic"),
3267
3541
  isUnderline: selection.hasFormat("underline") || isCollapsed && hasInlineFormat(inlineStyleTarget, "underline"),
@@ -3292,6 +3566,7 @@ const Toolbar = () => {
3292
3566
  const activeFontFamily = useToolbarStyleStore((state) => state.fontFamily);
3293
3567
  const activeFontSize = useToolbarStyleStore((state) => state.fontSize);
3294
3568
  const activeAlignment = useToolbarStyleStore((state) => state.alignment);
3569
+ const activeList = useToolbarStyleStore((state) => state.activeList);
3295
3570
  const isBoldActive = useToolbarStyleStore((state) => state.isBold);
3296
3571
  const isItalicActive = useToolbarStyleStore((state) => state.isItalic);
3297
3572
  const isUnderlineActive = useToolbarStyleStore((state) => state.isUnderline);
@@ -3320,16 +3595,27 @@ const Toolbar = () => {
3320
3595
  );
3321
3596
  const runToolbarAction = useCallback(
3322
3597
  (label, callback) => {
3598
+ const refreshSnapshot = () => {
3599
+ if (!activeEditor) {
3600
+ return;
3601
+ }
3602
+ queueMicrotask(() => {
3603
+ toolbarStyleStore.getState().setSnapshot(readToolbarStyleSnapshot(activeEditor));
3604
+ });
3605
+ };
3323
3606
  runHistoryAction(
3324
3607
  {
3325
3608
  label,
3326
3609
  source: "toolbar",
3327
3610
  region: "document"
3328
3611
  },
3329
- callback
3612
+ () => {
3613
+ callback();
3614
+ refreshSnapshot();
3615
+ }
3330
3616
  );
3331
3617
  },
3332
- [runHistoryAction]
3618
+ [activeEditor, runHistoryAction, toolbarStyleStore]
3333
3619
  );
3334
3620
  useEffect(() => {
3335
3621
  if (!activeEditor) {
@@ -3422,6 +3708,11 @@ const Toolbar = () => {
3422
3708
  applyToBodyEditors((editor) => insertList(editor, "bullet"));
3423
3709
  });
3424
3710
  }, [applyToBodyEditors, runToolbarAction, t.history.actions.insertedBulletList]);
3711
+ const handleListAlpha = useCallback(() => {
3712
+ runToolbarAction(t.history.actions.insertedAlphabeticList, () => {
3713
+ applyToBodyEditors((editor) => insertList(editor, "alpha"));
3714
+ });
3715
+ }, [applyToBodyEditors, runToolbarAction, t.history.actions.insertedAlphabeticList]);
3425
3716
  const handleIndent = useCallback(() => {
3426
3717
  runToolbarAction(t.history.actions.indentedContent, () => {
3427
3718
  applyToBodyEditors(indentContent);
@@ -3554,8 +3845,9 @@ const Toolbar = () => {
3554
3845
  ] }),
3555
3846
  /* @__PURE__ */ jsx(Divider, {}),
3556
3847
  /* @__PURE__ */ jsxs("div", { className: "lex4-toolbar-group", "data-testid": "list-group", children: [
3557
- /* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.numberedList, testId: "btn-list-number", onClick: handleListNumber, children: /* @__PURE__ */ jsx(ListOrdered, { size: 15 }) }),
3558
- /* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.bulletList, testId: "btn-list-bullet", onClick: handleListBullet, children: /* @__PURE__ */ jsx(List, { size: 15 }) }),
3848
+ /* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.numberedList, testId: "btn-list-number", active: activeList === "number", onClick: handleListNumber, children: /* @__PURE__ */ jsx(ListOrdered, { size: 15 }) }),
3849
+ /* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.bulletList, testId: "btn-list-bullet", active: activeList === "bullet", onClick: handleListBullet, children: /* @__PURE__ */ jsx(List, { size: 15 }) }),
3850
+ /* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.alphabeticList, testId: "btn-list-alpha", active: activeList === "alpha", onClick: handleListAlpha, children: /* @__PURE__ */ jsx("span", { className: "lex4-toolbar-text-icon", children: "a)" }) }),
3559
3851
  /* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.indent, testId: "btn-indent", onClick: handleIndent, children: /* @__PURE__ */ jsx(ListIndentIncrease, { size: 15 }) }),
3560
3852
  /* @__PURE__ */ jsx(ToolbarIconButton, { title: t.toolbar.outdent, testId: "btn-outdent", onClick: handleOutdent, children: /* @__PURE__ */ jsx(ListIndentDecrease, { size: 15 }) })
3561
3853
  ] }),
@@ -3946,7 +4238,7 @@ const lexicalTheme = {
3946
4238
  },
3947
4239
  quote: "lex4-quote"
3948
4240
  };
3949
- const DEFAULT_NODES = [HeadingNode, QuoteNode, ListNode, ListItemNode];
4241
+ const DEFAULT_NODES = [HeadingNode, QuoteNode, ListNode, ListItemNode, AlphaListNode];
3950
4242
  function createEditorConfig(mode, pageId, extraNodes = [], themeOverrides = {}) {
3951
4243
  const namespace = pageId ? `lex4-${mode}-${pageId}` : `lex4-${mode}`;
3952
4244
  return {
@@ -5564,6 +5856,7 @@ function mapBlockNode(node) {
5564
5856
  case "heading":
5565
5857
  return mapHeading(node);
5566
5858
  case "list":
5859
+ case "alpha-list":
5567
5860
  return mapList(node);
5568
5861
  case "quote":
5569
5862
  return mapBlockQuote(node);
@@ -5597,7 +5890,7 @@ function mapHeading(node) {
5597
5890
  };
5598
5891
  }
5599
5892
  function mapList(node) {
5600
- const listType = node.listType === "number" ? "ordered" : "unordered";
5893
+ const listType = node.type === "alpha-list" ? "ordered-alpha" : node.listType === "number" ? "ordered" : "unordered";
5601
5894
  const items = (node.children ?? []).filter((c) => c.type === "listitem").map(mapListItem);
5602
5895
  return {
5603
5896
  type: "list",
@@ -5609,7 +5902,7 @@ function mapListItem(node) {
5609
5902
  const inlineChildren = [];
5610
5903
  let nestedList;
5611
5904
  for (const child of node.children ?? []) {
5612
- if (child.type === "list") {
5905
+ if (child.type === "list" || child.type === "alpha-list") {
5613
5906
  nestedList = mapList(child);
5614
5907
  } else {
5615
5908
  const mapped = mapInlineNodes([child]);
@@ -5753,6 +6046,13 @@ function buildLexicalNode(serializedNode) {
5753
6046
  appendChildren(node, serializedNode.children);
5754
6047
  return node;
5755
6048
  }
6049
+ case "alpha-list": {
6050
+ const node = $createAlphaListNode(
6051
+ typeof serializedNode.start === "number" ? serializedNode.start : 1
6052
+ );
6053
+ appendChildren(node, serializedNode.children);
6054
+ return node;
6055
+ }
5756
6056
  case "listitem": {
5757
6057
  const node = $createListItemNode();
5758
6058
  appendChildren(node, serializedNode.children);
@@ -6262,8 +6562,12 @@ const VariablePanel = ({ open, onClose }) => {
6262
6562
  const { activeEditor, runHistoryAction } = useDocument();
6263
6563
  const t = useTranslations();
6264
6564
  const [filter, setFilter] = useState("");
6565
+ const [collapsedGroups, setCollapsedGroups] = useState({});
6265
6566
  const [creating, setCreating] = useState(false);
6266
6567
  const [createError, setCreateError] = useState(null);
6568
+ const toggleGroup = useCallback((group) => {
6569
+ setCollapsedGroups((current) => ({ ...current, [group]: !current[group] }));
6570
+ }, []);
6267
6571
  const [draft, setDraft] = useState({
6268
6572
  label: "",
6269
6573
  key: "",
@@ -6377,23 +6681,50 @@ const VariablePanel = ({ open, onClose }) => {
6377
6681
  ] }) }),
6378
6682
  /* @__PURE__ */ jsxs("div", { className: "lex4-variable-list", children: [
6379
6683
  Object.keys(grouped).length === 0 && /* @__PURE__ */ jsx("div", { className: "lex4-variable-list-empty", children: t.variables.noVariablesFound }),
6380
- Object.entries(grouped).map(([group, defs]) => /* @__PURE__ */ jsxs("div", { className: "lex4-variable-group", "data-variable-group": group, children: [
6381
- /* @__PURE__ */ jsx("div", { className: "lex4-variable-group-label", children: group }),
6382
- /* @__PURE__ */ jsx("div", { className: "lex4-variable-group-items", children: defs.map((def) => /* @__PURE__ */ jsx(
6383
- "button",
6684
+ Object.entries(grouped).map(([group, defs]) => {
6685
+ const isCollapsed = !filter && Boolean(collapsedGroups[group]);
6686
+ return /* @__PURE__ */ jsxs(
6687
+ "div",
6384
6688
  {
6385
- type: "button",
6386
- className: "lex4-variable-list-item",
6387
- "data-testid": `variable-panel-${def.key}`,
6689
+ className: `lex4-variable-group${isCollapsed ? " is-collapsed" : ""}`,
6388
6690
  "data-variable-group": group,
6389
- onClick: () => handleInsert(def.key),
6390
- disabled: !activeEditor,
6391
- title: def.key,
6392
- children: def.label
6691
+ children: [
6692
+ /* @__PURE__ */ jsxs(
6693
+ "button",
6694
+ {
6695
+ type: "button",
6696
+ className: "lex4-variable-group-header",
6697
+ "data-testid": `variable-panel-group-${group}`,
6698
+ "aria-expanded": !isCollapsed,
6699
+ onClick: () => toggleGroup(group),
6700
+ children: [
6701
+ /* @__PURE__ */ jsxs("span", { className: "lex4-variable-group-header-left", children: [
6702
+ /* @__PURE__ */ jsx(ChevronDown, { size: 12, className: "lex4-variable-group-chevron" }),
6703
+ /* @__PURE__ */ jsx("span", { className: "lex4-variable-group-label", children: group })
6704
+ ] }),
6705
+ /* @__PURE__ */ jsx("span", { className: "lex4-variable-group-count", children: defs.length })
6706
+ ]
6707
+ }
6708
+ ),
6709
+ /* @__PURE__ */ jsx("div", { className: "lex4-variable-group-items", children: defs.map((def) => /* @__PURE__ */ jsx(
6710
+ "button",
6711
+ {
6712
+ type: "button",
6713
+ className: "lex4-variable-list-item",
6714
+ "data-testid": `variable-panel-${def.key}`,
6715
+ "data-variable-group": group,
6716
+ onClick: () => handleInsert(def.key),
6717
+ disabled: !activeEditor,
6718
+ title: def.key,
6719
+ children: /* @__PURE__ */ jsx("span", { className: "lex4-variable-list-item-label", children: def.label })
6720
+ },
6721
+ def.key
6722
+ )) })
6723
+ ]
6393
6724
  },
6394
- def.key
6395
- )) })
6396
- ] }, group))
6725
+ group
6726
+ );
6727
+ })
6397
6728
  ] }),
6398
6729
  /* @__PURE__ */ jsx("div", { className: "lex4-variable-create", children: creating ? /* @__PURE__ */ jsxs("form", { className: "lex4-variable-create-form", onSubmit: handleCreateVariable, children: [
6399
6730
  /* @__PURE__ */ jsx("div", { className: "lex4-variable-create-title", children: t.variables.createVariableTitle }),