@yurikilian/lex4 0.2.2 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,10 +2,10 @@ 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, useReducer, useState, useRef, useMemo, 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, $selectAll, KEY_TAB_COMMAND, COMMAND_PRIORITY_LOW, $isElementNode, $isParagraphNode, $setSelection, FOCUS_COMMAND, CONTROLLED_TEXT_INSERTION_COMMAND, KEY_DOWN_COMMAND, PASTE_COMMAND, KEY_ENTER_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_CRITICAL, $applyNodeReplacement, DecoratorNode, createCommand, $insertNodes, COMMAND_PRIORITY_EDITOR } from "lexical";
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, $selectAll, KEY_TAB_COMMAND, COMMAND_PRIORITY_LOW, $isElementNode, $isParagraphNode, $setSelection, FOCUS_COMMAND, $splitNode, $getNearestNodeFromDOMNode, CONTROLLED_TEXT_INSERTION_COMMAND, KEY_DOWN_COMMAND, PASTE_COMMAND, KEY_ENTER_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_CRITICAL, $applyNodeReplacement, DecoratorNode, createCommand, $insertNodes, 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 } from "@lexical/list";
8
+ import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, ListNode, ListItemNode, $isListNode } from "@lexical/list";
9
9
  import { LexicalComposer } from "@lexical/react/LexicalComposer";
10
10
  import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
11
11
  import { ContentEditable } from "@lexical/react/LexicalContentEditable";
@@ -452,6 +452,258 @@ function jumpToHistoryEntry(history, entryIndex) {
452
452
  caretSelection: ((_b = nextHistory.entries[nextHistory.cursor - 1]) == null ? void 0 : _b.caretSelection) ?? null
453
453
  };
454
454
  }
455
+ const DEFAULT_TRANSLATIONS = {
456
+ toolbar: {
457
+ undo: "Undo",
458
+ redo: "Redo",
459
+ bold: "Bold (Ctrl+B)",
460
+ italic: "Italic (Ctrl+I)",
461
+ underline: "Underline (Ctrl+U)",
462
+ strikethrough: "Strikethrough",
463
+ alignLeft: "Align Left",
464
+ alignCenter: "Align Center",
465
+ alignRight: "Align Right",
466
+ justify: "Justify",
467
+ numberedList: "Numbered List",
468
+ bulletList: "Bullet List",
469
+ indent: "Indent",
470
+ outdent: "Outdent",
471
+ openHistory: "Open History",
472
+ closeHistory: "Close History"
473
+ },
474
+ history: {
475
+ title: "History",
476
+ subtitle: "Word-style session history (last 100 actions)",
477
+ empty: "No history yet.",
478
+ clearHistory: "Clear History",
479
+ actions: {
480
+ enabledHeadersFooters: "Enabled headers and footers",
481
+ disabledHeadersFooters: "Disabled headers and footers",
482
+ copiedHeaderToAll: "Copied header to all pages",
483
+ copiedFooterToAll: "Copied footer to all pages",
484
+ clearedHeader: "Cleared header",
485
+ clearedFooter: "Cleared footer",
486
+ clearedAllHeaders: "Cleared all headers",
487
+ clearedAllFooters: "Cleared all footers",
488
+ pageCounterSet: "Page counter set to {{value}}",
489
+ boldApplied: "Bold applied",
490
+ italicApplied: "Italic applied",
491
+ underlineApplied: "Underline applied",
492
+ strikethroughApplied: "Strikethrough applied",
493
+ alignedLeft: "Aligned left",
494
+ alignedCenter: "Aligned center",
495
+ alignedRight: "Aligned right",
496
+ justifiedText: "Justified text",
497
+ insertedNumberedList: "Inserted numbered list",
498
+ insertedBulletList: "Inserted bullet list",
499
+ indentedContent: "Indented content",
500
+ outdentedContent: "Outdented content",
501
+ fontChanged: "Font changed to {{value}}",
502
+ fontSizeChanged: "Font size changed to {{value}}pt"
503
+ }
504
+ },
505
+ variables: {
506
+ title: "Variables",
507
+ available: "{{count}} available",
508
+ refreshVariables: "Refresh variables",
509
+ searchPlaceholder: "Search variables...",
510
+ noVariablesFound: "No variables found",
511
+ insertVariable: "Insert variable {{key}}",
512
+ openPanel: "Open Variables",
513
+ closePanel: "Close Variables"
514
+ },
515
+ header: {
516
+ placeholder: "Header"
517
+ },
518
+ footer: {
519
+ placeholder: "Footer"
520
+ },
521
+ body: {
522
+ placeholder: "Start typing..."
523
+ },
524
+ pageCounter: {
525
+ format: "Page {{current}} of {{total}}"
526
+ },
527
+ regions: {
528
+ body: "body",
529
+ header: "header",
530
+ footer: "footer",
531
+ document: "document",
532
+ toolbar: "toolbar",
533
+ overflow: "overflow",
534
+ history: "history",
535
+ page: "Page {{page}}"
536
+ },
537
+ headerFooter: {
538
+ label: "Headers & Footers"
539
+ },
540
+ sidebar: {
541
+ close: "Close sidebar"
542
+ },
543
+ historyLabels: {
544
+ typedText: "Typed text",
545
+ pastedContent: "Pasted content",
546
+ insertedLineBreak: "Inserted line break",
547
+ deletedBackward: "Deleted backward",
548
+ deletedForward: "Deleted forward",
549
+ formattedText: "Formatted text",
550
+ formattedParagraph: "Formatted paragraph",
551
+ editedBody: "Edited body",
552
+ editedHeader: "Edited header",
553
+ editedFooter: "Edited footer",
554
+ clearedDocumentBody: "Cleared document body",
555
+ resizedHeader: "Resized header",
556
+ resizedFooter: "Resized footer",
557
+ addedPage: "Added page",
558
+ removedPage: "Removed page",
559
+ documentReflow: "Document reflow",
560
+ updatedDocument: "Updated document"
561
+ }
562
+ };
563
+ const PT_BR_TRANSLATIONS = {
564
+ toolbar: {
565
+ undo: "Desfazer",
566
+ redo: "Refazer",
567
+ bold: "Negrito (Ctrl+B)",
568
+ italic: "Itálico (Ctrl+I)",
569
+ underline: "Sublinhado (Ctrl+U)",
570
+ strikethrough: "Tachado",
571
+ alignLeft: "Alinhar à Esquerda",
572
+ alignCenter: "Centralizar",
573
+ alignRight: "Alinhar à Direita",
574
+ justify: "Justificar",
575
+ numberedList: "Lista Numerada",
576
+ bulletList: "Lista com Marcadores",
577
+ indent: "Aumentar Recuo",
578
+ outdent: "Diminuir Recuo",
579
+ openHistory: "Abrir Histórico",
580
+ closeHistory: "Fechar Histórico"
581
+ },
582
+ history: {
583
+ title: "Histórico",
584
+ subtitle: "Histórico de sessão (últimas 100 ações)",
585
+ empty: "Nenhum histórico ainda.",
586
+ clearHistory: "Limpar Histórico",
587
+ actions: {
588
+ enabledHeadersFooters: "Cabeçalhos e rodapés ativados",
589
+ disabledHeadersFooters: "Cabeçalhos e rodapés desativados",
590
+ copiedHeaderToAll: "Cabeçalho copiado para todas as páginas",
591
+ copiedFooterToAll: "Rodapé copiado para todas as páginas",
592
+ clearedHeader: "Cabeçalho limpo",
593
+ clearedFooter: "Rodapé limpo",
594
+ clearedAllHeaders: "Todos os cabeçalhos limpos",
595
+ clearedAllFooters: "Todos os rodapés limpos",
596
+ pageCounterSet: "Contador de páginas definido como {{value}}",
597
+ boldApplied: "Negrito aplicado",
598
+ italicApplied: "Itálico aplicado",
599
+ underlineApplied: "Sublinhado aplicado",
600
+ strikethroughApplied: "Tachado aplicado",
601
+ alignedLeft: "Alinhado à esquerda",
602
+ alignedCenter: "Centralizado",
603
+ alignedRight: "Alinhado à direita",
604
+ justifiedText: "Texto justificado",
605
+ insertedNumberedList: "Lista numerada inserida",
606
+ insertedBulletList: "Lista com marcadores inserida",
607
+ indentedContent: "Conteúdo recuado",
608
+ outdentedContent: "Recuo reduzido",
609
+ fontChanged: "Fonte alterada para {{value}}",
610
+ fontSizeChanged: "Tamanho da fonte alterado para {{value}}pt"
611
+ }
612
+ },
613
+ variables: {
614
+ title: "Variáveis",
615
+ available: "{{count}} disponíveis",
616
+ refreshVariables: "Atualizar variáveis",
617
+ searchPlaceholder: "Buscar variáveis...",
618
+ noVariablesFound: "Nenhuma variável encontrada",
619
+ insertVariable: "Inserir variável {{key}}",
620
+ openPanel: "Abrir Variáveis",
621
+ closePanel: "Fechar Variáveis"
622
+ },
623
+ header: {
624
+ placeholder: "Cabeçalho"
625
+ },
626
+ footer: {
627
+ placeholder: "Rodapé"
628
+ },
629
+ body: {
630
+ placeholder: "Comece a digitar..."
631
+ },
632
+ pageCounter: {
633
+ format: "Página {{current}} de {{total}}"
634
+ },
635
+ regions: {
636
+ body: "corpo",
637
+ header: "cabeçalho",
638
+ footer: "rodapé",
639
+ document: "documento",
640
+ toolbar: "barra de ferramentas",
641
+ overflow: "estouro",
642
+ history: "histórico",
643
+ page: "Página {{page}}"
644
+ },
645
+ headerFooter: {
646
+ label: "Cabeçalhos e Rodapés"
647
+ },
648
+ sidebar: {
649
+ close: "Fechar barra lateral"
650
+ },
651
+ historyLabels: {
652
+ typedText: "Texto digitado",
653
+ pastedContent: "Conteúdo colado",
654
+ insertedLineBreak: "Quebra de linha inserida",
655
+ deletedBackward: "Exclusão para trás",
656
+ deletedForward: "Exclusão para frente",
657
+ formattedText: "Texto formatado",
658
+ formattedParagraph: "Parágrafo formatado",
659
+ editedBody: "Corpo editado",
660
+ editedHeader: "Cabeçalho editado",
661
+ editedFooter: "Rodapé editado",
662
+ clearedDocumentBody: "Corpo do documento limpo",
663
+ resizedHeader: "Cabeçalho redimensionado",
664
+ resizedFooter: "Rodapé redimensionado",
665
+ addedPage: "Página adicionada",
666
+ removedPage: "Página removida",
667
+ documentReflow: "Redistribuição do documento",
668
+ updatedDocument: "Documento atualizado"
669
+ }
670
+ };
671
+ function deepMerge(target, source) {
672
+ if (typeof target !== "object" || target === null) {
673
+ return source ?? target;
674
+ }
675
+ const result = { ...target };
676
+ for (const key of Object.keys(source)) {
677
+ const sourceVal = source[key];
678
+ const targetVal = target[key];
679
+ if (sourceVal !== void 0 && typeof sourceVal === "object" && sourceVal !== null && !Array.isArray(sourceVal) && typeof targetVal === "object" && targetVal !== null) {
680
+ result[key] = deepMerge(targetVal, sourceVal);
681
+ } else if (sourceVal !== void 0) {
682
+ result[key] = sourceVal;
683
+ }
684
+ }
685
+ return result;
686
+ }
687
+ const TranslationsContext = createContext(DEFAULT_TRANSLATIONS);
688
+ function useTranslations() {
689
+ return useContext(TranslationsContext);
690
+ }
691
+ function interpolate(template, params) {
692
+ return template.replace(
693
+ /\{\{(\w+)\}\}/g,
694
+ (_, key) => String(params[key] ?? `{{${key}}}`)
695
+ );
696
+ }
697
+ const TranslationsProvider = ({
698
+ translations,
699
+ children
700
+ }) => {
701
+ const merged = useMemo(
702
+ () => translations ? deepMerge(DEFAULT_TRANSLATIONS, translations) : DEFAULT_TRANSLATIONS,
703
+ [translations]
704
+ );
705
+ return /* @__PURE__ */ jsx(TranslationsContext.Provider, { value: merged, children });
706
+ };
455
707
  const HISTORY_RESTORE_SUPPRESSION_MS = 100;
456
708
  const HISTORY_BATCH_FLUSH_MS = 16;
457
709
  function cloneDocumentSnapshot(document2) {
@@ -524,12 +776,15 @@ function getPageNumber(document2, pageId) {
524
776
  const index = document2.pages.findIndex((page) => page.id === pageId);
525
777
  return index >= 0 ? index + 1 : null;
526
778
  }
527
- function describeAction(action, document2) {
779
+ function describeAction(action, document2, t) {
780
+ const pageSuffix = (pageId) => {
781
+ const num = getPageNumber(document2, pageId);
782
+ return num ? ` - ${interpolate(t.regions.page, { page: num })}` : "";
783
+ };
528
784
  switch (action.type) {
529
785
  case "UPDATE_PAGE_BODY": {
530
- const pageNumber = getPageNumber(document2, action.pageId);
531
786
  return {
532
- label: pageNumber ? `Edited body - Page ${pageNumber}` : "Edited body",
787
+ label: t.historyLabels.editedBody + pageSuffix(action.pageId),
533
788
  source: "body",
534
789
  pageId: action.pageId,
535
790
  region: "body"
@@ -537,9 +792,8 @@ function describeAction(action, document2) {
537
792
  }
538
793
  case "UPDATE_PAGE_HEADER":
539
794
  case "UPDATE_PAGE_HEADER_CONTENT": {
540
- const pageNumber = getPageNumber(document2, action.pageId);
541
795
  return {
542
- label: pageNumber ? `Edited header - Page ${pageNumber}` : "Edited header",
796
+ label: t.historyLabels.editedHeader + pageSuffix(action.pageId),
543
797
  source: "header",
544
798
  pageId: action.pageId,
545
799
  region: "header"
@@ -547,9 +801,8 @@ function describeAction(action, document2) {
547
801
  }
548
802
  case "UPDATE_PAGE_FOOTER":
549
803
  case "UPDATE_PAGE_FOOTER_CONTENT": {
550
- const pageNumber = getPageNumber(document2, action.pageId);
551
804
  return {
552
- label: pageNumber ? `Edited footer - Page ${pageNumber}` : "Edited footer",
805
+ label: t.historyLabels.editedFooter + pageSuffix(action.pageId),
553
806
  source: "footer",
554
807
  pageId: action.pageId,
555
808
  region: "footer"
@@ -557,43 +810,41 @@ function describeAction(action, document2) {
557
810
  }
558
811
  case "SET_HEADER_FOOTER_ENABLED":
559
812
  return {
560
- label: action.enabled ? "Enabled headers and footers" : "Disabled headers and footers",
813
+ label: action.enabled ? t.history.actions.enabledHeadersFooters : t.history.actions.disabledHeadersFooters,
561
814
  source: "document",
562
815
  region: "document"
563
816
  };
564
817
  case "SET_PAGE_COUNTER_MODE":
565
818
  return {
566
- label: `Page counter set to ${action.mode}`,
819
+ label: interpolate(t.history.actions.pageCounterSet, { value: action.mode }),
567
820
  source: "document",
568
821
  region: "document"
569
822
  };
570
823
  case "COPY_HEADER_TO_ALL":
571
824
  return {
572
- label: "Copied header to all pages",
825
+ label: t.history.actions.copiedHeaderToAll,
573
826
  source: "toolbar",
574
827
  pageId: action.sourcePageId,
575
828
  region: "header"
576
829
  };
577
830
  case "COPY_FOOTER_TO_ALL":
578
831
  return {
579
- label: "Copied footer to all pages",
832
+ label: t.history.actions.copiedFooterToAll,
580
833
  source: "toolbar",
581
834
  pageId: action.sourcePageId,
582
835
  region: "footer"
583
836
  };
584
837
  case "CLEAR_HEADER": {
585
- const pageNumber = getPageNumber(document2, action.pageId);
586
838
  return {
587
- label: pageNumber ? `Cleared header - Page ${pageNumber}` : "Cleared header",
839
+ label: t.history.actions.clearedHeader + pageSuffix(action.pageId),
588
840
  source: "toolbar",
589
841
  pageId: action.pageId,
590
842
  region: "header"
591
843
  };
592
844
  }
593
845
  case "CLEAR_FOOTER": {
594
- const pageNumber = getPageNumber(document2, action.pageId);
595
846
  return {
596
- label: pageNumber ? `Cleared footer - Page ${pageNumber}` : "Cleared footer",
847
+ label: t.history.actions.clearedFooter + pageSuffix(action.pageId),
597
848
  source: "toolbar",
598
849
  pageId: action.pageId,
599
850
  region: "footer"
@@ -601,35 +852,33 @@ function describeAction(action, document2) {
601
852
  }
602
853
  case "CLEAR_ALL_HEADERS":
603
854
  return {
604
- label: "Cleared all headers",
855
+ label: t.history.actions.clearedAllHeaders,
605
856
  source: "toolbar",
606
857
  region: "header"
607
858
  };
608
859
  case "CLEAR_ALL_FOOTERS":
609
860
  return {
610
- label: "Cleared all footers",
861
+ label: t.history.actions.clearedAllFooters,
611
862
  source: "toolbar",
612
863
  region: "footer"
613
864
  };
614
865
  case "CLEAR_DOCUMENT_CONTENT":
615
866
  return {
616
- label: "Cleared document body",
867
+ label: t.historyLabels.clearedDocumentBody,
617
868
  source: "document",
618
869
  region: "document"
619
870
  };
620
871
  case "SET_HEADER_HEIGHT": {
621
- const pageNumber = getPageNumber(document2, action.pageId);
622
872
  return {
623
- label: pageNumber ? `Resized header - Page ${pageNumber}` : "Resized header",
873
+ label: t.historyLabels.resizedHeader + pageSuffix(action.pageId),
624
874
  source: "header",
625
875
  pageId: action.pageId,
626
876
  region: "header"
627
877
  };
628
878
  }
629
879
  case "SET_FOOTER_HEIGHT": {
630
- const pageNumber = getPageNumber(document2, action.pageId);
631
880
  return {
632
- label: pageNumber ? `Resized footer - Page ${pageNumber}` : "Resized footer",
881
+ label: t.historyLabels.resizedFooter + pageSuffix(action.pageId),
633
882
  source: "footer",
634
883
  pageId: action.pageId,
635
884
  region: "footer"
@@ -637,25 +886,25 @@ function describeAction(action, document2) {
637
886
  }
638
887
  case "ADD_PAGE":
639
888
  return {
640
- label: "Added page",
889
+ label: t.historyLabels.addedPage,
641
890
  source: "overflow",
642
891
  region: "document"
643
892
  };
644
893
  case "REMOVE_PAGE":
645
894
  return {
646
- label: "Removed page",
895
+ label: t.historyLabels.removedPage,
647
896
  source: "overflow",
648
897
  region: "document"
649
898
  };
650
899
  case "SET_DOCUMENT":
651
900
  return {
652
- label: "Document reflow",
901
+ label: t.historyLabels.documentReflow,
653
902
  source: "overflow",
654
903
  region: "document"
655
904
  };
656
905
  default:
657
906
  return {
658
- label: "Updated document",
907
+ label: t.historyLabels.updatedDocument,
659
908
  source: "document",
660
909
  region: "document"
661
910
  };
@@ -682,6 +931,7 @@ const DocumentProvider = ({
682
931
  const [globalSelectionActive, setGlobalSelectionActive] = useState(false);
683
932
  const [historySidebarOpen, setHistorySidebarOpen] = useState(true);
684
933
  const [focusAtEndVersion, setFocusAtEndVersion] = useState(0);
934
+ const t = useTranslations();
685
935
  const activeEditorRef = useRef(null);
686
936
  const activeCaretPositionRef = useRef(null);
687
937
  const pendingCaretPositionRef = useRef(null);
@@ -875,7 +1125,7 @@ const DocumentProvider = ({
875
1125
  };
876
1126
  scheduleHistoryBatchFlush();
877
1127
  } else {
878
- const descriptor = describeAction(action, currentDocument);
1128
+ const descriptor = describeAction(action, currentDocument, t);
879
1129
  setHistoryState((previousHistory) => {
880
1130
  const nextHistory = recordHistoryEntry(
881
1131
  previousHistory,
@@ -1474,194 +1724,6 @@ const __iconNode = [
1474
1724
  ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
1475
1725
  ];
1476
1726
  const X = createLucideIcon("x", __iconNode);
1477
- const DEFAULT_TRANSLATIONS = {
1478
- toolbar: {
1479
- undo: "Undo",
1480
- redo: "Redo",
1481
- bold: "Bold (Ctrl+B)",
1482
- italic: "Italic (Ctrl+I)",
1483
- underline: "Underline (Ctrl+U)",
1484
- strikethrough: "Strikethrough",
1485
- alignLeft: "Align Left",
1486
- alignCenter: "Align Center",
1487
- alignRight: "Align Right",
1488
- justify: "Justify",
1489
- numberedList: "Numbered List",
1490
- bulletList: "Bullet List",
1491
- indent: "Indent",
1492
- outdent: "Outdent",
1493
- openHistory: "Open History",
1494
- closeHistory: "Close History"
1495
- },
1496
- history: {
1497
- title: "History",
1498
- subtitle: "Word-style session history (last 100 actions)",
1499
- empty: "No history yet.",
1500
- clearHistory: "Clear History",
1501
- actions: {
1502
- enabledHeadersFooters: "Enabled headers and footers",
1503
- disabledHeadersFooters: "Disabled headers and footers",
1504
- copiedHeaderToAll: "Copied header to all pages",
1505
- copiedFooterToAll: "Copied footer to all pages",
1506
- clearedHeader: "Cleared header",
1507
- clearedFooter: "Cleared footer",
1508
- clearedAllHeaders: "Cleared all headers",
1509
- clearedAllFooters: "Cleared all footers",
1510
- pageCounterSet: "Page counter set to {{value}}",
1511
- boldApplied: "Bold applied",
1512
- italicApplied: "Italic applied",
1513
- underlineApplied: "Underline applied",
1514
- strikethroughApplied: "Strikethrough applied",
1515
- alignedLeft: "Aligned left",
1516
- alignedCenter: "Aligned center",
1517
- alignedRight: "Aligned right",
1518
- justifiedText: "Justified text",
1519
- insertedNumberedList: "Inserted numbered list",
1520
- insertedBulletList: "Inserted bullet list",
1521
- indentedContent: "Indented content",
1522
- outdentedContent: "Outdented content",
1523
- fontChanged: "Font changed to {{value}}",
1524
- fontSizeChanged: "Font size changed to {{value}}pt"
1525
- }
1526
- },
1527
- variables: {
1528
- title: "Variables",
1529
- available: "{{count}} available",
1530
- refreshVariables: "Refresh variables",
1531
- searchPlaceholder: "Search variables...",
1532
- noVariablesFound: "No variables found",
1533
- insertVariable: "Insert variable {{key}}",
1534
- openPanel: "Open Variables",
1535
- closePanel: "Close Variables"
1536
- },
1537
- header: {
1538
- placeholder: "Header"
1539
- },
1540
- footer: {
1541
- placeholder: "Footer"
1542
- },
1543
- body: {
1544
- placeholder: "Start typing..."
1545
- },
1546
- headerFooter: {
1547
- label: "Headers & Footers"
1548
- },
1549
- sidebar: {
1550
- close: "Close sidebar"
1551
- }
1552
- };
1553
- const PT_BR_TRANSLATIONS = {
1554
- toolbar: {
1555
- undo: "Desfazer",
1556
- redo: "Refazer",
1557
- bold: "Negrito (Ctrl+B)",
1558
- italic: "Itálico (Ctrl+I)",
1559
- underline: "Sublinhado (Ctrl+U)",
1560
- strikethrough: "Tachado",
1561
- alignLeft: "Alinhar à Esquerda",
1562
- alignCenter: "Centralizar",
1563
- alignRight: "Alinhar à Direita",
1564
- justify: "Justificar",
1565
- numberedList: "Lista Numerada",
1566
- bulletList: "Lista com Marcadores",
1567
- indent: "Aumentar Recuo",
1568
- outdent: "Diminuir Recuo",
1569
- openHistory: "Abrir Histórico",
1570
- closeHistory: "Fechar Histórico"
1571
- },
1572
- history: {
1573
- title: "Histórico",
1574
- subtitle: "Histórico de sessão (últimas 100 ações)",
1575
- empty: "Nenhum histórico ainda.",
1576
- clearHistory: "Limpar Histórico",
1577
- actions: {
1578
- enabledHeadersFooters: "Cabeçalhos e rodapés ativados",
1579
- disabledHeadersFooters: "Cabeçalhos e rodapés desativados",
1580
- copiedHeaderToAll: "Cabeçalho copiado para todas as páginas",
1581
- copiedFooterToAll: "Rodapé copiado para todas as páginas",
1582
- clearedHeader: "Cabeçalho limpo",
1583
- clearedFooter: "Rodapé limpo",
1584
- clearedAllHeaders: "Todos os cabeçalhos limpos",
1585
- clearedAllFooters: "Todos os rodapés limpos",
1586
- pageCounterSet: "Contador de páginas definido como {{value}}",
1587
- boldApplied: "Negrito aplicado",
1588
- italicApplied: "Itálico aplicado",
1589
- underlineApplied: "Sublinhado aplicado",
1590
- strikethroughApplied: "Tachado aplicado",
1591
- alignedLeft: "Alinhado à esquerda",
1592
- alignedCenter: "Centralizado",
1593
- alignedRight: "Alinhado à direita",
1594
- justifiedText: "Texto justificado",
1595
- insertedNumberedList: "Lista numerada inserida",
1596
- insertedBulletList: "Lista com marcadores inserida",
1597
- indentedContent: "Conteúdo recuado",
1598
- outdentedContent: "Recuo reduzido",
1599
- fontChanged: "Fonte alterada para {{value}}",
1600
- fontSizeChanged: "Tamanho da fonte alterado para {{value}}pt"
1601
- }
1602
- },
1603
- variables: {
1604
- title: "Variáveis",
1605
- available: "{{count}} disponíveis",
1606
- refreshVariables: "Atualizar variáveis",
1607
- searchPlaceholder: "Buscar variáveis...",
1608
- noVariablesFound: "Nenhuma variável encontrada",
1609
- insertVariable: "Inserir variável {{key}}",
1610
- openPanel: "Abrir Variáveis",
1611
- closePanel: "Fechar Variáveis"
1612
- },
1613
- header: {
1614
- placeholder: "Cabeçalho"
1615
- },
1616
- footer: {
1617
- placeholder: "Rodapé"
1618
- },
1619
- body: {
1620
- placeholder: "Comece a digitar..."
1621
- },
1622
- headerFooter: {
1623
- label: "Cabeçalhos e Rodapés"
1624
- },
1625
- sidebar: {
1626
- close: "Fechar barra lateral"
1627
- }
1628
- };
1629
- function deepMerge(target, source) {
1630
- if (typeof target !== "object" || target === null) {
1631
- return source ?? target;
1632
- }
1633
- const result = { ...target };
1634
- for (const key of Object.keys(source)) {
1635
- const sourceVal = source[key];
1636
- const targetVal = target[key];
1637
- if (sourceVal !== void 0 && typeof sourceVal === "object" && sourceVal !== null && !Array.isArray(sourceVal) && typeof targetVal === "object" && targetVal !== null) {
1638
- result[key] = deepMerge(targetVal, sourceVal);
1639
- } else if (sourceVal !== void 0) {
1640
- result[key] = sourceVal;
1641
- }
1642
- }
1643
- return result;
1644
- }
1645
- const TranslationsContext = createContext(DEFAULT_TRANSLATIONS);
1646
- function useTranslations() {
1647
- return useContext(TranslationsContext);
1648
- }
1649
- function interpolate(template, params) {
1650
- return template.replace(
1651
- /\{\{(\w+)\}\}/g,
1652
- (_, key) => String(params[key] ?? `{{${key}}}`)
1653
- );
1654
- }
1655
- const TranslationsProvider = ({
1656
- translations,
1657
- children
1658
- }) => {
1659
- const merged = useMemo(
1660
- () => translations ? deepMerge(DEFAULT_TRANSLATIONS, translations) : DEFAULT_TRANSLATIONS,
1661
- [translations]
1662
- );
1663
- return /* @__PURE__ */ jsx(TranslationsContext.Provider, { value: merged, children });
1664
- };
1665
1727
  const EditorSidebar = ({
1666
1728
  title,
1667
1729
  subtitle,
@@ -1768,7 +1830,7 @@ const HistorySidebar = () => {
1768
1830
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
1769
1831
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
1770
1832
  /* @__PURE__ */ jsx("div", { className: `text-xs ${isCurrent ? "font-semibold text-blue-700" : "text-gray-900"}`, children: entry.label }),
1771
- /* @__PURE__ */ jsx("div", { className: "mt-0.5 text-xs text-gray-400", children: entry.source })
1833
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5 text-xs text-gray-400", children: t.regions[entry.source] ?? entry.source })
1772
1834
  ] }),
1773
1835
  /* @__PURE__ */ jsx("div", { className: "shrink-0 text-xs text-gray-400", children: formatTimestamp(entry.timestamp) })
1774
1836
  ] })
@@ -2513,6 +2575,19 @@ function mergeEditorStates(stateA, stateB) {
2513
2575
  if (all.length === 0) return null;
2514
2576
  return createEditorStateFromNodes(all);
2515
2577
  }
2578
+ function splitBlockNode(block, childOffset) {
2579
+ const children = block.children ?? [];
2580
+ if (childOffset <= 0) return [null, structuredClone(block)];
2581
+ if (childOffset >= children.length) return [structuredClone(block), null];
2582
+ const before = children.slice(0, childOffset);
2583
+ const after = children.slice(childOffset);
2584
+ const makeCopy = (kids) => {
2585
+ const copy = structuredClone(block);
2586
+ copy.children = kids;
2587
+ return copy;
2588
+ };
2589
+ return [makeCopy(before), makeCopy(after)];
2590
+ }
2516
2591
  function usePagination(document2, dispatch) {
2517
2592
  const reflowingRef = useRef(false);
2518
2593
  const pendingReflowRef = useRef(false);
@@ -2547,7 +2622,61 @@ function usePagination(document2, dispatch) {
2547
2622
  const footerH = document2.headerFooterEnabled ? page.footerHeight : 0;
2548
2623
  const bodyHeight = computeBodyHeight(headerH, footerH);
2549
2624
  const nodes = getTopLevelNodes(page.bodyState);
2550
- if (nodes.length <= 1) return;
2625
+ if (nodes.length <= 1) {
2626
+ if (nodes.length === 1) {
2627
+ const singleNode = nodes[0];
2628
+ const children = singleNode.children;
2629
+ if (children && children.length > 1) {
2630
+ const estimatedLineHeight = 24;
2631
+ const maxChildren = Math.max(1, Math.floor(bodyHeight / estimatedLineHeight));
2632
+ if (maxChildren < children.length) {
2633
+ const [keepBlock, overflowBlock] = splitBlockNode(singleNode, maxChildren);
2634
+ if (keepBlock && overflowBlock) {
2635
+ const keepState2 = createEditorStateFromNodes([keepBlock]);
2636
+ const overflowState2 = createEditorStateFromNodes([overflowBlock]);
2637
+ const nextPage2 = pages[pageIndex + 1];
2638
+ if (nextPage2) {
2639
+ const mergedBody = mergeEditorStates(overflowState2, nextPage2.bodyState);
2640
+ dispatch({
2641
+ type: "SET_DOCUMENT",
2642
+ document: {
2643
+ ...document2,
2644
+ pages: pages.map((p, i) => {
2645
+ if (i === pageIndex) return { ...p, bodyState: keepState2 };
2646
+ if (i === pageIndex + 1) return { ...p, bodyState: mergedBody };
2647
+ return p;
2648
+ })
2649
+ }
2650
+ });
2651
+ } else {
2652
+ const newPage = {
2653
+ ...createPageFromTemplate({
2654
+ headerState: document2.defaultHeaderState,
2655
+ footerState: document2.defaultFooterState,
2656
+ headerHeight: document2.defaultHeaderHeight,
2657
+ footerHeight: document2.defaultFooterHeight
2658
+ }),
2659
+ bodyState: overflowState2
2660
+ };
2661
+ dispatch({
2662
+ type: "SET_DOCUMENT",
2663
+ document: {
2664
+ ...document2,
2665
+ pages: [
2666
+ ...pages.map(
2667
+ (p, i) => i === pageIndex ? { ...p, bodyState: keepState2 } : p
2668
+ ),
2669
+ newPage
2670
+ ]
2671
+ }
2672
+ });
2673
+ }
2674
+ }
2675
+ }
2676
+ }
2677
+ }
2678
+ return;
2679
+ }
2551
2680
  const fitCount = estimateNodesFitting(page.bodyState, bodyHeight);
2552
2681
  if (fitCount >= nodes.length) return;
2553
2682
  const [keepState, overflowState] = splitEditorState(page.bodyState, fitCount);
@@ -2917,6 +3046,213 @@ const ActiveEditorPlugin = ({
2917
3046
  }, [editor, onFocus, pageId, region, setActiveEditor, setActivePageId]);
2918
3047
  return null;
2919
3048
  };
3049
+ function findMidBlockSplitPoint(blockElement, availableHeight) {
3050
+ const blockRect = blockElement.getBoundingClientRect();
3051
+ const maxBottom = blockRect.top + availableHeight;
3052
+ const textNodes = [];
3053
+ const walker = document.createTreeWalker(blockElement, NodeFilter.SHOW_TEXT);
3054
+ let walkNode;
3055
+ while (walkNode = walker.nextNode()) {
3056
+ if (walkNode.length > 0) {
3057
+ textNodes.push(walkNode);
3058
+ }
3059
+ }
3060
+ if (textNodes.length === 0) return null;
3061
+ const range = document.createRange();
3062
+ for (const textNode of textNodes) {
3063
+ range.selectNodeContents(textNode);
3064
+ const nodeRect = range.getBoundingClientRect();
3065
+ if (nodeRect.bottom <= maxBottom) {
3066
+ continue;
3067
+ }
3068
+ if (nodeRect.top >= maxBottom) {
3069
+ return backupToWordBoundary(textNode, 0);
3070
+ }
3071
+ let low = 0;
3072
+ let high = textNode.length;
3073
+ while (low < high) {
3074
+ const mid = Math.floor((low + high) / 2);
3075
+ range.setStart(textNode, 0);
3076
+ range.setEnd(textNode, mid + 1);
3077
+ const testRect = range.getBoundingClientRect();
3078
+ if (testRect.bottom > maxBottom) {
3079
+ high = mid;
3080
+ } else {
3081
+ low = mid + 1;
3082
+ }
3083
+ }
3084
+ return backupToWordBoundary(textNode, low);
3085
+ }
3086
+ return null;
3087
+ }
3088
+ function backupToWordBoundary(textNode, offset) {
3089
+ const text = textNode.textContent || "";
3090
+ if (offset <= 0 || offset >= text.length) {
3091
+ if (offset > 0 && offset < text.length) {
3092
+ return { textNode, offset };
3093
+ }
3094
+ if (offset > 0) return { textNode, offset };
3095
+ return null;
3096
+ }
3097
+ let adjusted = offset;
3098
+ while (adjusted > 0 && !/\s/.test(text[adjusted - 1])) {
3099
+ adjusted--;
3100
+ }
3101
+ if (adjusted <= 0) {
3102
+ adjusted = offset;
3103
+ }
3104
+ return { textNode, offset: adjusted };
3105
+ }
3106
+ function serializeNodeTree$1(node) {
3107
+ const json = node.exportJSON();
3108
+ if ($isElementNode(node)) {
3109
+ json.children = node.getChildren().map(serializeNodeTree$1);
3110
+ }
3111
+ return json;
3112
+ }
3113
+ function findListSplitIndex(listElement, availableHeight) {
3114
+ const listRect = listElement.getBoundingClientRect();
3115
+ const maxBottom = listRect.top + availableHeight;
3116
+ const children = Array.from(listElement.children);
3117
+ for (let i = 0; i < children.length; i++) {
3118
+ const child = children[i];
3119
+ const childRect = child.getBoundingClientRect();
3120
+ if (childRect.bottom > maxBottom && i > 0) {
3121
+ return i;
3122
+ }
3123
+ }
3124
+ return -1;
3125
+ }
3126
+ function performMidBlockSplit(rootElement, availableHeight, overflowBlockIndex) {
3127
+ const root = $getRoot();
3128
+ const allChildren = root.getChildren();
3129
+ const blockNode = allChildren[overflowBlockIndex];
3130
+ if (!blockNode || !$isElementNode(blockNode)) {
3131
+ debugWarn("overflow", "target node is not an ElementNode");
3132
+ return null;
3133
+ }
3134
+ const blockElements = Array.from(rootElement.children);
3135
+ const blockElement = blockElements[overflowBlockIndex];
3136
+ if (!blockElement) {
3137
+ debugWarn("overflow", "no DOM element for block index");
3138
+ return null;
3139
+ }
3140
+ const blockTop = blockElement.offsetTop;
3141
+ const heightForBlock = availableHeight - blockTop;
3142
+ if (heightForBlock <= 0) {
3143
+ debugWarn("overflow", "no space for block");
3144
+ return null;
3145
+ }
3146
+ if ($isListNode(blockNode)) {
3147
+ return splitListNode(blockNode, blockElement, heightForBlock);
3148
+ }
3149
+ return splitParagraphNode(blockNode, blockElement, heightForBlock);
3150
+ }
3151
+ function splitListNode(listNode, listElement, availableHeight) {
3152
+ const splitIndex = findListSplitIndex(listElement, availableHeight);
3153
+ if (splitIndex <= 0) {
3154
+ debug("overflow", "cannot split list — first item exceeds height");
3155
+ return null;
3156
+ }
3157
+ const [, overflowList] = $splitNode(listNode, splitIndex);
3158
+ const overflowNodes = [];
3159
+ const toRemove = [];
3160
+ overflowNodes.push(serializeNodeTree$1(overflowList));
3161
+ toRemove.push(overflowList);
3162
+ let nextSibling = overflowList.getNextSibling();
3163
+ while (nextSibling) {
3164
+ overflowNodes.push(serializeNodeTree$1(nextSibling));
3165
+ toRemove.push(nextSibling);
3166
+ nextSibling = nextSibling.getNextSibling();
3167
+ }
3168
+ for (const node of toRemove) {
3169
+ node.remove();
3170
+ }
3171
+ debug("overflow", `split list at item ${splitIndex}, extracted ${overflowNodes.length} overflow nodes`);
3172
+ return overflowNodes;
3173
+ }
3174
+ function splitParagraphNode(blockNode, blockElement, availableHeight) {
3175
+ const splitPoint = findMidBlockSplitPoint(blockElement, availableHeight);
3176
+ if (!splitPoint) {
3177
+ debug("overflow", "no valid split point found in paragraph");
3178
+ return null;
3179
+ }
3180
+ const lexicalNode = $getNearestNodeFromDOMNode(splitPoint.textNode);
3181
+ if (!lexicalNode || !$isTextNode(lexicalNode)) {
3182
+ debugWarn("overflow", "could not map DOM text node to Lexical TextNode");
3183
+ return null;
3184
+ }
3185
+ const [, afterText] = lexicalNode.splitText(splitPoint.offset);
3186
+ if (!afterText) {
3187
+ debugWarn("overflow", "splitText returned no second half");
3188
+ return null;
3189
+ }
3190
+ const parent = afterText.getParent();
3191
+ if (!parent || !$isElementNode(parent)) {
3192
+ debugWarn("overflow", "split text has no element parent");
3193
+ return null;
3194
+ }
3195
+ let directChild = afterText;
3196
+ let directChildParent = parent;
3197
+ while (directChildParent && directChildParent.getKey() !== blockNode.getKey()) {
3198
+ directChild = directChildParent;
3199
+ const next = directChildParent.getParent();
3200
+ if (!next || !$isElementNode(next)) {
3201
+ debugWarn("overflow", "could not find block node in parent chain");
3202
+ return null;
3203
+ }
3204
+ directChildParent = next;
3205
+ }
3206
+ const splitChildIndex = blockNode.getChildren().indexOf(directChild);
3207
+ if (splitChildIndex <= 0) {
3208
+ debug("overflow", "split index is 0 or not found — nothing to keep on this page");
3209
+ return null;
3210
+ }
3211
+ if (directChild !== afterText) {
3212
+ let current = parent;
3213
+ let childToSplitAt = afterText;
3214
+ while (current.getKey() !== blockNode.getKey()) {
3215
+ const childIdx = current.getChildren().indexOf(childToSplitAt);
3216
+ if (childIdx > 0) {
3217
+ $splitNode(current, childIdx);
3218
+ }
3219
+ childToSplitAt = current;
3220
+ const next = current.getParent();
3221
+ if (!next || !$isElementNode(next)) break;
3222
+ current = next;
3223
+ }
3224
+ }
3225
+ let finalSplitChild = afterText;
3226
+ let p = afterText.getParent();
3227
+ while (p && p.getKey() !== blockNode.getKey()) {
3228
+ finalSplitChild = p;
3229
+ p = p.getParent();
3230
+ }
3231
+ const finalSplitIndex = blockNode.getChildren().indexOf(finalSplitChild);
3232
+ if (finalSplitIndex <= 0) {
3233
+ debug("overflow", "final split index is 0 or not found — nothing to keep on this page");
3234
+ return null;
3235
+ }
3236
+ const [, overflowBlock] = $splitNode(blockNode, finalSplitIndex);
3237
+ const overflowNodes = [];
3238
+ const toRemove = [];
3239
+ overflowNodes.push(serializeNodeTree$1(overflowBlock));
3240
+ toRemove.push(overflowBlock);
3241
+ let nextSibling = overflowBlock.getNextSibling();
3242
+ while (nextSibling) {
3243
+ overflowNodes.push(serializeNodeTree$1(nextSibling));
3244
+ toRemove.push(nextSibling);
3245
+ nextSibling = nextSibling.getNextSibling();
3246
+ }
3247
+ for (const node of toRemove) {
3248
+ node.remove();
3249
+ }
3250
+ debug(
3251
+ "overflow",
3252
+ `split paragraph at offset ${splitPoint.offset}, extracted ${overflowNodes.length} overflow nodes`
3253
+ );
3254
+ return overflowNodes;
3255
+ }
2920
3256
  function serializeNodeTree(node) {
2921
3257
  const json = node.exportJSON();
2922
3258
  if ($isElementNode(node)) {
@@ -2945,18 +3281,51 @@ const OverflowPlugin = ({
2945
3281
  const children = Array.from(rootElement.children);
2946
3282
  if (children.length === 0) return;
2947
3283
  if (children.length <= 1) {
2948
- debug("overflow", `single block overflows (content=${contentHeight}px > available=${availableHeight}px) — cannot split`);
3284
+ debug("overflow", `single block overflows (content=${contentHeight}px > available=${availableHeight}px) — attempting mid-block split`);
3285
+ processingRef.current = true;
3286
+ editor.update(
3287
+ () => {
3288
+ const overflowNodes = performMidBlockSplit(rootElement, availableHeight, 0);
3289
+ if (!overflowNodes || overflowNodes.length === 0) {
3290
+ debug("overflow", "mid-block split not possible for single block");
3291
+ processingRef.current = false;
3292
+ return;
3293
+ }
3294
+ const overflowState = {
3295
+ root: {
3296
+ children: overflowNodes,
3297
+ direction: null,
3298
+ format: "",
3299
+ indent: 0,
3300
+ type: "root",
3301
+ version: 1
3302
+ }
3303
+ };
3304
+ debug("overflow", `mid-block split extracted ${overflowNodes.length} overflow nodes from single block`);
3305
+ setTimeout(() => {
3306
+ onOverflowRef.current(overflowState, cause);
3307
+ processingRef.current = false;
3308
+ }, 0);
3309
+ },
3310
+ { tag: "overflow-split" }
3311
+ );
2949
3312
  return;
2950
3313
  }
2951
3314
  processingRef.current = true;
2952
3315
  debug("overflow", `OVERFLOW detected: content=${contentHeight}px available=${availableHeight}px children=${children.length}`);
2953
3316
  let splitIndex = children.length;
3317
+ let firstBlockOverflows = false;
2954
3318
  for (let i = 0; i < children.length; i++) {
2955
3319
  const child = children[i];
2956
3320
  const childBottom = child.offsetTop + child.offsetHeight;
2957
- if (childBottom > availableHeight && i > 0) {
2958
- splitIndex = i;
2959
- debug("overflow", `split at index ${i} (childBottom=${childBottom}px > ${availableHeight}px)`);
3321
+ if (childBottom > availableHeight) {
3322
+ if (i === 0) {
3323
+ firstBlockOverflows = true;
3324
+ splitIndex = 1;
3325
+ } else {
3326
+ splitIndex = i;
3327
+ }
3328
+ debug("overflow", `split at index ${i === 0 ? "0 (mid-block)" : i} (childBottom=${childBottom}px > ${availableHeight}px)`);
2960
3329
  break;
2961
3330
  }
2962
3331
  }
@@ -2974,15 +3343,37 @@ const OverflowPlugin = ({
2974
3343
  processingRef.current = false;
2975
3344
  return;
2976
3345
  }
2977
- const overflowNodes = [];
2978
- const toRemove = allChildren.slice(splitIndex);
2979
- for (const node of toRemove) {
2980
- overflowNodes.push(serializeNodeTree(node));
3346
+ let overflowNodes = [];
3347
+ if (firstBlockOverflows) {
3348
+ const midBlockOverflow = performMidBlockSplit(rootElement, availableHeight, 0);
3349
+ if (midBlockOverflow && midBlockOverflow.length > 0) {
3350
+ overflowNodes.push(...midBlockOverflow);
3351
+ debug("overflow", `mid-block split on first block extracted ${midBlockOverflow.length} nodes`);
3352
+ } else {
3353
+ debug("overflow", "mid-block split failed on first block — keeping it whole");
3354
+ }
3355
+ const freshChildren = root.getChildren();
3356
+ const toRemove = freshChildren.slice(1);
3357
+ for (const node of toRemove) {
3358
+ overflowNodes.push(serializeNodeTree(node));
3359
+ }
3360
+ for (const node of toRemove) {
3361
+ node.remove();
3362
+ }
3363
+ } else {
3364
+ const toRemove = allChildren.slice(splitIndex);
3365
+ for (const node of toRemove) {
3366
+ overflowNodes.push(serializeNodeTree(node));
3367
+ }
3368
+ for (const node of toRemove) {
3369
+ node.remove();
3370
+ }
2981
3371
  }
2982
- for (const node of toRemove) {
2983
- node.remove();
3372
+ if (overflowNodes.length === 0) {
3373
+ processingRef.current = false;
3374
+ return;
2984
3375
  }
2985
- debug("overflow", `extracted ${overflowNodes.length} overflow nodes, kept ${splitIndex} nodes on current page`);
3376
+ debug("overflow", `extracted ${overflowNodes.length} overflow nodes total`);
2986
3377
  const overflowState = {
2987
3378
  root: {
2988
3379
  children: overflowNodes,
@@ -3063,16 +3454,10 @@ const OverflowPlugin = ({
3063
3454
  }, [editor]);
3064
3455
  return null;
3065
3456
  };
3066
- function createPageLabel(region, pageNumber) {
3067
- if (region === "body") {
3068
- return pageNumber ? `Page ${pageNumber}` : "Body";
3069
- }
3070
- const regionLabel = region.charAt(0).toUpperCase() + region.slice(1);
3071
- return pageNumber ? `${regionLabel} Page ${pageNumber}` : regionLabel;
3072
- }
3073
3457
  const HistoryCapturePlugin = ({ pageId, region }) => {
3074
3458
  const [editor] = useLexicalComposerContext();
3075
3459
  const { document: document2, queueHistoryAction } = useDocument();
3460
+ const t = useTranslations();
3076
3461
  const context = useMemo(() => {
3077
3462
  const pageNumber = document2.pages.findIndex((page) => page.id === pageId);
3078
3463
  return {
@@ -3080,9 +3465,18 @@ const HistoryCapturePlugin = ({ pageId, region }) => {
3080
3465
  source: region
3081
3466
  };
3082
3467
  }, [document2.pages, pageId, region]);
3468
+ const createPageLabel = useMemo(() => {
3469
+ return (r, pageNumber) => {
3470
+ if (r === "body") {
3471
+ return pageNumber ? interpolate(t.regions.page, { page: pageNumber }) : t.regions.body;
3472
+ }
3473
+ const regionLabel = r === "header" ? t.regions.header : t.regions.footer;
3474
+ return pageNumber ? `${regionLabel} ${interpolate(t.regions.page, { page: pageNumber })}` : regionLabel;
3475
+ };
3476
+ }, [t]);
3083
3477
  useEffect(() => {
3084
- const buildDescriptor = (prefix) => ({
3085
- label: `${prefix} - ${createPageLabel(region, context.pageNumber)}`,
3478
+ const buildDescriptor = (label) => ({
3479
+ label: `${label} - ${createPageLabel(region, context.pageNumber)}`,
3086
3480
  source: context.source,
3087
3481
  pageId,
3088
3482
  region
@@ -3090,15 +3484,15 @@ const HistoryCapturePlugin = ({ pageId, region }) => {
3090
3484
  return editor.registerCommand(
3091
3485
  CONTROLLED_TEXT_INSERTION_COMMAND,
3092
3486
  () => {
3093
- queueHistoryAction(buildDescriptor("Typed text"));
3487
+ queueHistoryAction(buildDescriptor(t.historyLabels.typedText));
3094
3488
  return false;
3095
3489
  },
3096
3490
  COMMAND_PRIORITY_LOW
3097
3491
  );
3098
- }, [context.pageNumber, context.source, editor, pageId, queueHistoryAction, region]);
3492
+ }, [context.pageNumber, context.source, createPageLabel, editor, pageId, queueHistoryAction, region, t]);
3099
3493
  useEffect(() => {
3100
- const buildDescriptor = (prefix) => ({
3101
- label: `${prefix} - ${createPageLabel(region, context.pageNumber)}`,
3494
+ const buildDescriptor = (label) => ({
3495
+ label: `${label} - ${createPageLabel(region, context.pageNumber)}`,
3102
3496
  source: context.source,
3103
3497
  pageId,
3104
3498
  region
@@ -3112,15 +3506,15 @@ const HistoryCapturePlugin = ({ pageId, region }) => {
3112
3506
  if (event.key.length !== 1) {
3113
3507
  return false;
3114
3508
  }
3115
- queueHistoryAction(buildDescriptor("Typed text"));
3509
+ queueHistoryAction(buildDescriptor(t.historyLabels.typedText));
3116
3510
  return false;
3117
3511
  },
3118
3512
  COMMAND_PRIORITY_LOW
3119
3513
  );
3120
- }, [context.pageNumber, context.source, editor, pageId, queueHistoryAction, region]);
3514
+ }, [context.pageNumber, context.source, createPageLabel, editor, pageId, queueHistoryAction, region, t]);
3121
3515
  useEffect(() => {
3122
- const buildDescriptor = (prefix) => ({
3123
- label: `${prefix} - ${createPageLabel(region, context.pageNumber)}`,
3516
+ const buildDescriptor = (label) => ({
3517
+ label: `${label} - ${createPageLabel(region, context.pageNumber)}`,
3124
3518
  source: context.source,
3125
3519
  pageId,
3126
3520
  region
@@ -3133,15 +3527,15 @@ const HistoryCapturePlugin = ({ pageId, region }) => {
3133
3527
  if (text.trim().length === 0) {
3134
3528
  return false;
3135
3529
  }
3136
- queueHistoryAction(buildDescriptor("Pasted content"));
3530
+ queueHistoryAction(buildDescriptor(t.historyLabels.pastedContent));
3137
3531
  return false;
3138
3532
  },
3139
3533
  COMMAND_PRIORITY_LOW
3140
3534
  );
3141
- }, [context.pageNumber, context.source, editor, pageId, queueHistoryAction, region]);
3535
+ }, [context.pageNumber, context.source, createPageLabel, editor, pageId, queueHistoryAction, region, t]);
3142
3536
  useEffect(() => {
3143
- const buildDescriptor = (prefix) => ({
3144
- label: `${prefix} - ${createPageLabel(region, context.pageNumber)}`,
3537
+ const buildDescriptor = (label) => ({
3538
+ label: `${label} - ${createPageLabel(region, context.pageNumber)}`,
3145
3539
  source: context.source,
3146
3540
  pageId,
3147
3541
  region
@@ -3149,15 +3543,15 @@ const HistoryCapturePlugin = ({ pageId, region }) => {
3149
3543
  return editor.registerCommand(
3150
3544
  KEY_ENTER_COMMAND,
3151
3545
  () => {
3152
- queueHistoryAction(buildDescriptor("Inserted line break"));
3546
+ queueHistoryAction(buildDescriptor(t.historyLabels.insertedLineBreak));
3153
3547
  return false;
3154
3548
  },
3155
3549
  COMMAND_PRIORITY_LOW
3156
3550
  );
3157
- }, [context.pageNumber, context.source, editor, pageId, queueHistoryAction, region]);
3551
+ }, [context.pageNumber, context.source, createPageLabel, editor, pageId, queueHistoryAction, region, t]);
3158
3552
  useEffect(() => {
3159
- const buildDescriptor = (prefix) => ({
3160
- label: `${prefix} - ${createPageLabel(region, context.pageNumber)}`,
3553
+ const buildDescriptor = (label) => ({
3554
+ label: `${label} - ${createPageLabel(region, context.pageNumber)}`,
3161
3555
  source: context.source,
3162
3556
  pageId,
3163
3557
  region
@@ -3165,15 +3559,15 @@ const HistoryCapturePlugin = ({ pageId, region }) => {
3165
3559
  return editor.registerCommand(
3166
3560
  KEY_BACKSPACE_COMMAND,
3167
3561
  () => {
3168
- queueHistoryAction(buildDescriptor("Deleted backward"));
3562
+ queueHistoryAction(buildDescriptor(t.historyLabels.deletedBackward));
3169
3563
  return false;
3170
3564
  },
3171
3565
  COMMAND_PRIORITY_LOW
3172
3566
  );
3173
- }, [context.pageNumber, context.source, editor, pageId, queueHistoryAction, region]);
3567
+ }, [context.pageNumber, context.source, createPageLabel, editor, pageId, queueHistoryAction, region, t]);
3174
3568
  useEffect(() => {
3175
- const buildDescriptor = (prefix) => ({
3176
- label: `${prefix} - ${createPageLabel(region, context.pageNumber)}`,
3569
+ const buildDescriptor = (label) => ({
3570
+ label: `${label} - ${createPageLabel(region, context.pageNumber)}`,
3177
3571
  source: context.source,
3178
3572
  pageId,
3179
3573
  region
@@ -3181,15 +3575,15 @@ const HistoryCapturePlugin = ({ pageId, region }) => {
3181
3575
  return editor.registerCommand(
3182
3576
  KEY_DELETE_COMMAND,
3183
3577
  () => {
3184
- queueHistoryAction(buildDescriptor("Deleted forward"));
3578
+ queueHistoryAction(buildDescriptor(t.historyLabels.deletedForward));
3185
3579
  return false;
3186
3580
  },
3187
3581
  COMMAND_PRIORITY_LOW
3188
3582
  );
3189
- }, [context.pageNumber, context.source, editor, pageId, queueHistoryAction, region]);
3583
+ }, [context.pageNumber, context.source, createPageLabel, editor, pageId, queueHistoryAction, region, t]);
3190
3584
  useEffect(() => {
3191
- const buildDescriptor = (prefix) => ({
3192
- label: `${prefix} - ${createPageLabel(region, context.pageNumber)}`,
3585
+ const buildDescriptor = (label) => ({
3586
+ label: `${label} - ${createPageLabel(region, context.pageNumber)}`,
3193
3587
  source: context.source,
3194
3588
  pageId,
3195
3589
  region
@@ -3197,15 +3591,15 @@ const HistoryCapturePlugin = ({ pageId, region }) => {
3197
3591
  return editor.registerCommand(
3198
3592
  FORMAT_TEXT_COMMAND,
3199
3593
  () => {
3200
- queueHistoryAction(buildDescriptor("Formatted text"));
3594
+ queueHistoryAction(buildDescriptor(t.historyLabels.formattedText));
3201
3595
  return false;
3202
3596
  },
3203
3597
  COMMAND_PRIORITY_LOW
3204
3598
  );
3205
- }, [context.pageNumber, context.source, editor, pageId, queueHistoryAction, region]);
3599
+ }, [context.pageNumber, context.source, createPageLabel, editor, pageId, queueHistoryAction, region, t]);
3206
3600
  useEffect(() => {
3207
- const buildDescriptor = (prefix) => ({
3208
- label: `${prefix} - ${createPageLabel(region, context.pageNumber)}`,
3601
+ const buildDescriptor = (label) => ({
3602
+ label: `${label} - ${createPageLabel(region, context.pageNumber)}`,
3209
3603
  source: context.source,
3210
3604
  pageId,
3211
3605
  region
@@ -3213,12 +3607,12 @@ const HistoryCapturePlugin = ({ pageId, region }) => {
3213
3607
  return editor.registerCommand(
3214
3608
  FORMAT_ELEMENT_COMMAND,
3215
3609
  () => {
3216
- queueHistoryAction(buildDescriptor("Formatted paragraph"));
3610
+ queueHistoryAction(buildDescriptor(t.historyLabels.formattedParagraph));
3217
3611
  return false;
3218
3612
  },
3219
3613
  COMMAND_PRIORITY_LOW
3220
3614
  );
3221
- }, [context.pageNumber, context.source, editor, pageId, queueHistoryAction, region]);
3615
+ }, [context.pageNumber, context.source, createPageLabel, editor, pageId, queueHistoryAction, region, t]);
3222
3616
  return null;
3223
3617
  };
3224
3618
  function getCollapsedTextPosition(rootElement) {
@@ -3631,10 +4025,14 @@ const PageView = React.memo(({
3631
4025
  onMoveToNextPage
3632
4026
  }) => {
3633
4027
  const { document: document2, dispatch, setActivePageId } = useDocument();
4028
+ const t = useTranslations();
3634
4029
  const page = document2.pages.find((p) => p.id === pageId);
3635
4030
  const showHeaderFooter = document2.headerFooterEnabled;
3636
4031
  const pageCounterMode = document2.pageCounterMode;
3637
- const pageCounterLabel = `Page ${pageIndex + 1} of ${document2.pages.length}`;
4032
+ const pageCounterLabel = interpolate(t.pageCounter.format, {
4033
+ current: pageIndex + 1,
4034
+ total: document2.pages.length
4035
+ });
3638
4036
  if (!page) return null;
3639
4037
  const handleBodyChange = useCallback(
3640
4038
  (bodyState) => {
@@ -3725,6 +4123,7 @@ const DocumentView = () => {
3725
4123
  setActiveEditor,
3726
4124
  setActivePageId
3727
4125
  } = useDocument();
4126
+ const t = useTranslations();
3728
4127
  const { handlePageUnderflow, reflowAll } = usePagination(document2, dispatch);
3729
4128
  const previousBodyHeightsRef = useRef(null);
3730
4129
  const pasteOverflowSequenceRef = useRef(false);
@@ -3889,7 +4288,7 @@ const DocumentView = () => {
3889
4288
  }
3890
4289
  runHistoryAction(
3891
4290
  {
3892
- label: `Deleted backward - Page ${pageIndex + 1}`,
4291
+ label: `${t.historyLabels.deletedBackward} - ${interpolate(t.regions.page, { page: pageIndex + 1 })}`,
3893
4292
  source: "body",
3894
4293
  pageId,
3895
4294
  region: "body"
@@ -3911,7 +4310,7 @@ const DocumentView = () => {
3911
4310
  }
3912
4311
  runHistoryAction(
3913
4312
  {
3914
- label: `Deleted forward - Page ${pageIndex + 1}`,
4313
+ label: `${t.historyLabels.deletedForward} - ${interpolate(t.regions.page, { page: pageIndex + 1 })}`,
3915
4314
  source: "body",
3916
4315
  pageId,
3917
4316
  region: "body"
@@ -4144,7 +4543,7 @@ const EditorChrome = ({
4144
4543
  }
4145
4544
  ),
4146
4545
  /* @__PURE__ */ jsx(Toolbar, {}),
4147
- /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 overflow-hidden bg-gray-700", children: [
4546
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 overflow-hidden bg-gray-200", children: [
4148
4547
  /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 overflow-auto", children: /* @__PURE__ */ jsx(DocumentView, {}) }),
4149
4548
  sidePanels.map((Panel, idx) => /* @__PURE__ */ jsx(Panel, {}, idx)),
4150
4549
  /* @__PURE__ */ jsx(HistorySidebar, {})