@lobehub/editor 4.15.2 → 4.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/es/editor-kernel/react/useDecorators.js +14 -8
  2. package/es/headless/index.d.ts +1 -1
  3. package/es/headless/index.js +1 -1
  4. package/es/headless.d.ts +3 -18
  5. package/es/headless.js +711 -52
  6. package/es/index.d.ts +5 -5
  7. package/es/index.js +5 -5
  8. package/es/locale/index.d.ts +2 -0
  9. package/es/locale/index.js +5 -1
  10. package/es/plugins/auto-complete/plugin/index.js +3 -3
  11. package/es/plugins/block/index.d.ts +1 -1
  12. package/es/plugins/block/plugin/index.js +78 -2
  13. package/es/plugins/block/react/ReactBlockPlugin.js +172 -16
  14. package/es/plugins/block/react/drag/drag-utils.js +37 -10
  15. package/es/plugins/block/service/i-block-menu-service.d.ts +18 -1
  16. package/es/plugins/block/service/i-block-menu-service.js +24 -0
  17. package/es/plugins/block/service/index.d.ts +1 -1
  18. package/es/plugins/codeblock/plugin/index.js +25 -1
  19. package/es/plugins/common/plugin/register.js +2 -2
  20. package/es/plugins/litexml/command/diffCommand.d.ts +2 -17
  21. package/es/plugins/litexml/command/diffCommand.js +3 -9
  22. package/es/plugins/litexml/command/index.d.ts +2 -38
  23. package/es/plugins/litexml/command/index.js +3 -6
  24. package/es/plugins/litexml/command/symbols.d.ts +67 -0
  25. package/es/plugins/litexml/command/symbols.js +34 -0
  26. package/es/plugins/litexml/index.d.ts +1 -2
  27. package/es/plugins/litexml/plugin/index.js +8 -2
  28. package/es/plugins/litexml/react/DiffNodeToolbar/index.js +1 -1
  29. package/es/plugins/slash/plugin/index.js +1 -1
  30. package/es/plugins/slash/react/ReactSlashPlugin.js +4 -4
  31. package/es/plugins/table/command/index.d.ts +13 -1
  32. package/es/plugins/table/command/index.js +220 -39
  33. package/es/plugins/table/index.d.ts +3 -2
  34. package/es/plugins/table/node/index.d.ts +2 -0
  35. package/es/plugins/table/node/index.js +130 -2
  36. package/es/plugins/table/plugin/index.d.ts +6 -0
  37. package/es/plugins/table/plugin/index.js +193 -4
  38. package/es/plugins/table/react/TableActionMenu/ActionMenu.js +82 -6
  39. package/es/plugins/table/react/TableActionMenu/index.js +9 -4
  40. package/es/plugins/table/react/TableColController.js +354 -0
  41. package/es/plugins/table/react/TableController/hooks.js +201 -0
  42. package/es/plugins/table/react/TableController/style.js +264 -0
  43. package/es/plugins/table/react/TableController/utils.js +25 -0
  44. package/es/plugins/table/react/TableControllerButton.js +81 -0
  45. package/es/plugins/table/react/TableControllerMenu.js +123 -0
  46. package/es/plugins/table/react/TableInsertButton.js +25 -0
  47. package/es/plugins/table/react/TableResize/index.js +153 -78
  48. package/es/plugins/table/react/TableRowController.js +349 -0
  49. package/es/plugins/table/react/hooks.js +77 -0
  50. package/es/plugins/table/react/index.js +139 -16
  51. package/es/plugins/table/react/style.js +89 -8
  52. package/es/plugins/table/react/type.d.ts +2 -0
  53. package/es/plugins/table/react/useAutoFitPastedTable.js +189 -0
  54. package/es/plugins/table/service/i-table-controller-menu-service.d.ts +44 -0
  55. package/es/plugins/table/service/i-table-controller-menu-service.js +31 -0
  56. package/es/plugins/table/service/index.d.ts +1 -0
  57. package/es/plugins/table/utils/autoFitColumnWidth.js +87 -0
  58. package/es/plugins/table/utils/distributeColumnWidth.js +37 -0
  59. package/es/plugins/table/utils/index.js +102 -2
  60. package/es/react/EditorProvider/index.d.ts +2 -2
  61. package/es/renderer/LexicalDiff.d.ts +2 -2
  62. package/es/symbols-DEEvsKq4.d.ts +67 -0
  63. package/package.json +5 -1
package/es/headless.js CHANGED
@@ -1,9 +1,10 @@
1
+ import { LITEXML_APPLY_COMMAND, LITEXML_DIFFNODE_ALL_COMMAND, LITEXML_DIFFNODE_COMMAND, LITEXML_INSERT_COMMAND, LITEXML_MODIFY_COMMAND, LITEXML_REMOVE_COMMAND } from "./plugins/litexml/command/symbols.js";
1
2
  import { createHeadlessEditor as createHeadlessEditor$1 } from "@lexical/headless";
2
3
  import { createEmptyHistoryState, registerHistory } from "@lexical/history";
3
- import { $createTableNodeWithDimensions, $createTableSelection, $findTableNode, $isTableCellNode, $isTableNode, $isTableSelection, TableCellNode, TableNode, TableNode as TableNode$1, TableRowNode, registerTableCellUnmergeTransform, registerTablePlugin, registerTableSelectionObserver, setScrollableTablesActive } from "@lexical/table";
4
+ import { $computeTableMapSkipCellCheck, $createTableNodeWithDimensions, $createTableSelection, $deleteTableColumnAtSelection, $deleteTableRowAtSelection, $findTableNode, $insertTableColumnAtSelection, $insertTableRowAtSelection, $isSimpleTable, $isTableCellNode, $isTableNode, $isTableRowNode, $isTableSelection, TableCellNode, TableNode, TableNode as TableNode$1, TableRowNode, registerTableCellUnmergeTransform, registerTablePlugin, registerTableSelectionObserver, setScrollableTablesActive } from "@lexical/table";
4
5
  import { get, merge, template, templateSettings } from "es-toolkit/compat";
5
6
  import EventEmitter from "eventemitter3";
6
- import { $applyNodeReplacement, $caretFromPoint, $createLineBreakNode, $createNodeSelection, $createParagraphNode, $createRangeSelection, $createTextNode, $getCaretRange, $getCharacterOffsets, $getChildCaret, $getNearestNodeFromDOMNode, $getNodeByKey, $getPreviousSelection, $getRoot, $getSelection, $insertNodes, $isBlockElementNode, $isDecoratorNode, $isElementNode, $isLineBreakNode, $isNodeSelection, $isRangeSelection, $isRootNode, $isRootOrShadowRoot, $isTextNode, $isTextPointCaret, $nodesOfType, $normalizeSelection__EXPERIMENTAL, $parseSerializedNode, $setSelection, COLLABORATION_TAG, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, COMMAND_PRIORITY_NORMAL, CONTROLLED_TEXT_INSERTION_COMMAND, COPY_COMMAND, DecoratorNode, ElementNode, FORMAT_TEXT_COMMAND, HISTORIC_TAG, HISTORY_MERGE_TAG, HISTORY_PUSH_TAG, INDENT_CONTENT_COMMAND, INSERT_LINE_BREAK_COMMAND, INSERT_PARAGRAPH_COMMAND, INSERT_TAB_COMMAND, IS_BOLD, IS_CODE, IS_ITALIC, IS_STRIKETHROUGH, IS_SUBSCRIPT, IS_SUPERSCRIPT, IS_UNDERLINE, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DOWN_COMMAND, KEY_ENTER_COMMAND, KEY_TAB_COMMAND, OUTDENT_CONTENT_COMMAND, PASTE_COMMAND, ParagraphNode, REDO_COMMAND, SELECTION_CHANGE_COMMAND, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, TEXT_TYPE_TO_FORMAT, TabNode, TextNode, UNDO_COMMAND, createCommand, createEditor, getNearestEditorFromDOMNode, isHTMLElement, isModifierMatch, resetRandomKey } from "lexical";
7
+ import { $applyNodeReplacement, $caretFromPoint, $createLineBreakNode, $createNodeSelection, $createParagraphNode, $createRangeSelection, $createTextNode, $getCaretRange, $getCharacterOffsets, $getChildCaret, $getNearestNodeFromDOMNode, $getNodeByKey, $getPreviousSelection, $getRoot, $getSelection, $insertNodes, $isBlockElementNode, $isDecoratorNode, $isElementNode, $isLineBreakNode, $isNodeSelection, $isRangeSelection, $isRootNode, $isRootOrShadowRoot, $isTextNode, $isTextPointCaret, $nodesOfType, $normalizeSelection__EXPERIMENTAL, $parseSerializedNode, $setSelection, COLLABORATION_TAG, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, COMMAND_PRIORITY_NORMAL, CONTROLLED_TEXT_INSERTION_COMMAND, COPY_COMMAND, DecoratorNode, ElementNode, FORMAT_TEXT_COMMAND, HISTORIC_TAG, HISTORY_MERGE_TAG, HISTORY_PUSH_TAG, INDENT_CONTENT_COMMAND, INSERT_LINE_BREAK_COMMAND, INSERT_PARAGRAPH_COMMAND, INSERT_TAB_COMMAND, IS_BOLD, IS_CODE, IS_ITALIC, IS_STRIKETHROUGH, IS_SUBSCRIPT, IS_SUPERSCRIPT, IS_UNDERLINE, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DOWN_COMMAND, KEY_ENTER_COMMAND, KEY_TAB_COMMAND, OUTDENT_CONTENT_COMMAND, PASTE_COMMAND, ParagraphNode, REDO_COMMAND, SELECTION_CHANGE_COMMAND, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, TEXT_TYPE_TO_FORMAT, TabNode, TextNode, UNDO_COMMAND, createCommand, createEditor, getNearestEditorFromDOMNode, isHTMLElement, isModifierMatch, resetRandomKey, setDOMUnmanaged } from "lexical";
7
8
  import { $createHeadingNode, $createQuoteNode, $isHeadingNode, $isQuoteNode, HeadingNode, QuoteNode, registerRichText } from "@lexical/rich-text";
8
9
  import createDebug from "debug";
9
10
  import { $filter, $findMatchingParent, $getNearestBlockElementAncestorOrThrow, $getNearestNodeOfType, $insertNodeToNearestRoot, CAN_USE_DOM, IS_APPLE as isApple, addClassNamesToElement, calculateZoomLevel, isHTMLAnchorElement, isHTMLElement as isHTMLElement$1, mergeRegister } from "@lexical/utils";
@@ -20,7 +21,11 @@ import { $isCodeHighlightNode, $isCodeNode, CodeHighlightNode, CodeNode } from "
20
21
  import { bundledLanguagesInfo } from "shiki";
21
22
  //#region src/locale/index.ts
22
23
  var locale_default = {
23
- block: { delete: "Delete block" },
24
+ block: {
25
+ copy: "Copy",
26
+ delete: "Delete block",
27
+ select: "Select"
28
+ },
24
29
  cancel: "Cancel",
25
30
  codemirror: {
26
31
  copySuccess: "Code copied to clipboard",
@@ -1843,10 +1848,6 @@ function wrapBlockModify(oldBlock, editor, changeFn) {
1843
1848
  diffNode.append($cloneNode(newBlock, editor));
1844
1849
  newBlock.replace(diffNode, false);
1845
1850
  }
1846
- const LITEXML_MODIFY_COMMAND = createCommand("LITEXML_MODIFY_COMMAND");
1847
- const LITEXML_APPLY_COMMAND = createCommand("LITEXML_APPLY_COMMAND");
1848
- const LITEXML_REMOVE_COMMAND = createCommand("LITEXML_REMOVE_COMMAND");
1849
- const LITEXML_INSERT_COMMAND = createCommand("LITEXML_INSERT_COMMAND");
1850
1851
  function registerLiteXMLCommand(editor, dataSource) {
1851
1852
  return mergeRegister(editor.registerCommand(LITEXML_MODIFY_COMMAND, (payload) => {
1852
1853
  const resultPayload = payload.reduce((acc, cur) => {
@@ -2073,8 +2074,6 @@ function handleInsert(editor, payload, dataSource) {
2073
2074
  }
2074
2075
  //#endregion
2075
2076
  //#region src/plugins/litexml/command/diffCommand.ts
2076
- const LITEXML_DIFFNODE_COMMAND = createCommand("LITEXML_DIFFNODE_COMMAND");
2077
- const LITEXML_DIFFNODE_ALL_COMMAND = createCommand("LITEXML_DIFFNODE_ALL_COMMAND");
2078
2077
  function doAction(node, action) {
2079
2078
  if (node.diffType === "modify") {
2080
2079
  const children = node.getChildren();
@@ -3815,8 +3814,14 @@ const LitexmlPlugin = class extends KernelPlugin {
3815
3814
  this.register(editor.registerNodeTransform(DiffNode, (node) => {
3816
3815
  if (node.diffType === "modify" && node.getChildrenSize() === 1) node.setDiffType("remove");
3817
3816
  }));
3818
- this.register(editor.registerUpdateListener(({ editorState, prevEditorState }) => {
3817
+ this.register(editor.registerUpdateListener(({ editorState, prevEditorState, tags }) => {
3819
3818
  if (editorState === prevEditorState) return;
3819
+ if (tags.has(HISTORIC_TAG)) return;
3820
+ let shouldNormalize = false;
3821
+ editorState.read(() => {
3822
+ shouldNormalize = $nodesOfType(DiffNode).some((node) => node.diffType === "modify" && node.getChildrenSize() === 1);
3823
+ });
3824
+ if (!shouldNormalize) return;
3820
3825
  editor.update(() => {
3821
3826
  const diffNodes = $nodesOfType(DiffNode);
3822
3827
  for (const node of diffNodes) if (node.diffType === "modify" && node.getChildrenSize() === 1) node.setDiffType("remove");
@@ -4648,7 +4653,7 @@ function registerLastElement(editor) {
4648
4653
  root.append(paragraph);
4649
4654
  }
4650
4655
  isProcessing = false;
4651
- });
4656
+ }, { tag: HISTORIC_TAG });
4652
4657
  });
4653
4658
  }
4654
4659
  });
@@ -6395,75 +6400,544 @@ const ListPlugin = class extends KernelPlugin {
6395
6400
  }
6396
6401
  };
6397
6402
  //#endregion
6403
+ //#region src/plugins/block/service/i-block-menu-service.ts
6404
+ const IBlockMenuService = genServiceId("BlockMenuService");
6405
+ function createDefaultTableColWidths(columnCount, tableWidth = 750) {
6406
+ const safeColumnCount = Math.max(1, columnCount);
6407
+ const columnWidth = Math.floor(tableWidth / safeColumnCount);
6408
+ const colWidths = Array.from({ length: safeColumnCount }, () => columnWidth);
6409
+ colWidths[safeColumnCount - 1] = tableWidth - columnWidth * (safeColumnCount - 1);
6410
+ return colWidths;
6411
+ }
6412
+ function syncTableWidthDOM(editor, tableKey, colWidths) {
6413
+ const tableElement = editor.getElementByKey(tableKey);
6414
+ const table = tableElement instanceof HTMLTableElement ? tableElement : tableElement?.querySelector("table.editor_table, table");
6415
+ if (!(table instanceof HTMLTableElement)) return;
6416
+ table.style.width = `${colWidths.reduce((total, width) => total + width, 0)}px`;
6417
+ }
6418
+ //#endregion
6419
+ //#region src/plugins/table/utils/autoFitColumnWidth.ts
6420
+ const AUTO_FIT_MIN_COLUMN_WIDTH = 75;
6421
+ const MEASURE_CONTAINER_CLASS = "lobe-editor-table-auto-fit-measure";
6422
+ const getTableElement$1 = (editor, tableKey) => {
6423
+ const tableElement = editor.getElementByKey(tableKey);
6424
+ return tableElement instanceof HTMLTableElement ? tableElement : tableElement?.querySelector("table.editor_table, table");
6425
+ };
6426
+ const applyNoWrapMeasureStyle = (element) => {
6427
+ element.style.whiteSpace = "nowrap";
6428
+ element.style.wordBreak = "normal";
6429
+ element.style.overflowWrap = "normal";
6430
+ element.style.setProperty("text-wrap", "nowrap");
6431
+ };
6432
+ const createMeasureContainer = (tableElement) => {
6433
+ const container = document.createElement("div");
6434
+ container.className = MEASURE_CONTAINER_CLASS;
6435
+ container.style.insetBlockStart = "0";
6436
+ container.style.insetInlineStart = "-100000px";
6437
+ container.style.pointerEvents = "none";
6438
+ container.style.position = "absolute";
6439
+ container.style.visibility = "hidden";
6440
+ container.style.zIndex = "-1";
6441
+ (tableElement.parentElement ?? document.body).append(container);
6442
+ return container;
6443
+ };
6444
+ const measureCellNoWrapWidth = (cellElement, measureContainer) => {
6445
+ const table = document.createElement("table");
6446
+ const tbody = document.createElement("tbody");
6447
+ const row = document.createElement("tr");
6448
+ const clone = cellElement.cloneNode(true);
6449
+ table.className = "editor_table";
6450
+ table.style.borderCollapse = "collapse";
6451
+ table.style.borderSpacing = "0";
6452
+ table.style.tableLayout = "auto";
6453
+ table.style.width = "max-content";
6454
+ delete clone.dataset.lexicalKey;
6455
+ clone.style.blockSize = "auto";
6456
+ clone.style.display = "table-cell";
6457
+ clone.style.inlineSize = "max-content";
6458
+ clone.style.maxInlineSize = "none";
6459
+ clone.style.minInlineSize = "0";
6460
+ clone.style.overflow = "visible";
6461
+ clone.style.position = "static";
6462
+ clone.style.width = "max-content";
6463
+ applyNoWrapMeasureStyle(table);
6464
+ applyNoWrapMeasureStyle(clone);
6465
+ clone.querySelectorAll("*").forEach(applyNoWrapMeasureStyle);
6466
+ row.append(clone);
6467
+ tbody.append(row);
6468
+ table.append(tbody);
6469
+ measureContainer.append(table);
6470
+ const width = Math.ceil(Math.max(table.getBoundingClientRect().width, clone.getBoundingClientRect().width));
6471
+ table.remove();
6472
+ return width;
6473
+ };
6474
+ const getAutoFitTableColumnWidths = (editor, tableNode, columnIndexes) => {
6475
+ const tableElement = getTableElement$1(editor, tableNode.getKey());
6476
+ if (!tableElement || columnIndexes.length === 0) return null;
6477
+ const columnCount = tableNode.getColumnCount();
6478
+ const targetColumnIndexes = [...new Set(columnIndexes)].filter((index) => index >= 0 && index < columnCount);
6479
+ if (targetColumnIndexes.length === 0) return null;
6480
+ const measureContainer = createMeasureContainer(tableElement);
6481
+ try {
6482
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
6483
+ const nextColWidths = [...tableNode.getColWidths() || createDefaultTableColWidths(columnCount)];
6484
+ for (const columnIndex of targetColumnIndexes) {
6485
+ const measuredCellKeys = /* @__PURE__ */ new Set();
6486
+ let columnWidth = AUTO_FIT_MIN_COLUMN_WIDTH;
6487
+ for (const row of tableMap) {
6488
+ const cell = row[columnIndex]?.cell;
6489
+ if (!cell || cell.getColSpan() > 1 || measuredCellKeys.has(cell.getKey())) continue;
6490
+ const cellElement = editor.getElementByKey(cell.getKey());
6491
+ if (!(cellElement instanceof HTMLElement)) continue;
6492
+ measuredCellKeys.add(cell.getKey());
6493
+ columnWidth = Math.max(columnWidth, measureCellNoWrapWidth(cellElement, measureContainer));
6494
+ }
6495
+ nextColWidths[columnIndex] = columnWidth;
6496
+ }
6497
+ return nextColWidths;
6498
+ } finally {
6499
+ measureContainer.remove();
6500
+ }
6501
+ };
6502
+ //#endregion
6503
+ //#region src/plugins/table/utils/distributeColumnWidth.ts
6504
+ const DISTRIBUTE_MIN_COLUMN_WIDTH = 75;
6505
+ const getTableElement = (editor, tableKey) => {
6506
+ const tableElement = editor.getElementByKey(tableKey);
6507
+ return tableElement instanceof HTMLTableElement ? tableElement : tableElement?.querySelector("table.editor_table, table");
6508
+ };
6509
+ const getScrollContainerWidth = (tableElement) => {
6510
+ const container = tableElement.closest(".lobe-editor-table-scroll-wrapper") ?? tableElement.parentElement;
6511
+ if (!container) return 0;
6512
+ return container.clientWidth || container.getBoundingClientRect().width;
6513
+ };
6514
+ const getHorizontalBorderWidth = (tableElement) => {
6515
+ const firstRow = tableElement.rows[0];
6516
+ if (!firstRow) return 0;
6517
+ const cells = Array.from(firstRow.cells);
6518
+ if (cells.length === 0) return 0;
6519
+ return cells.reduce((total, cell, index) => {
6520
+ const style = getComputedStyle(cell);
6521
+ const borderInlineStartWidth = index === 0 ? Number.parseFloat(style.borderInlineStartWidth) || 0 : 0;
6522
+ const borderInlineEndWidth = Number.parseFloat(style.borderInlineEndWidth) || 0;
6523
+ return total + borderInlineStartWidth + borderInlineEndWidth;
6524
+ }, 0);
6525
+ };
6526
+ const getDistributedTableColumnWidths = (editor, tableNode) => {
6527
+ const columnCount = tableNode.getColumnCount();
6528
+ if (columnCount === 0) return null;
6529
+ const tableElement = getTableElement(editor, tableNode.getKey());
6530
+ if (!tableElement) return null;
6531
+ const minTableWidth = DISTRIBUTE_MIN_COLUMN_WIDTH * columnCount;
6532
+ const targetTableWidth = Math.max(getScrollContainerWidth(tableElement) - getHorizontalBorderWidth(tableElement), minTableWidth);
6533
+ const columnWidth = Math.floor(targetTableWidth / columnCount);
6534
+ const colWidths = Array.from({ length: columnCount }, () => columnWidth);
6535
+ colWidths[columnCount - 1] = targetTableWidth - columnWidth * (columnCount - 1);
6536
+ return colWidths;
6537
+ };
6538
+ //#endregion
6398
6539
  //#region src/plugins/table/command/index.ts
6399
6540
  const INSERT_TABLE_COMMAND = createCommand();
6400
6541
  const SELECT_TABLE_COMMAND = createCommand();
6542
+ const INSERT_TABLE_COLUMN_COMMAND = createCommand();
6543
+ const INSERT_TABLE_ROW_COMMAND = createCommand();
6544
+ const SYNC_TABLE_COLUMN_WIDTH_COMMAND = createCommand();
6545
+ const AUTO_FIT_TABLE_COLUMN_WIDTH_COMMAND = createCommand();
6546
+ const DISTRIBUTE_TABLE_COLUMN_WIDTH_COMMAND = createCommand();
6547
+ const MOVE_TABLE_COLUMN_COMMAND = createCommand();
6548
+ const MOVE_TABLE_ROW_COMMAND = createCommand();
6549
+ const resetTableScrollLeft = (editor, tableKey) => {
6550
+ const tableElement = editor.getElementByKey(tableKey);
6551
+ const scrollWrapper = (tableElement instanceof HTMLTableElement ? tableElement : tableElement?.querySelector("table.editor_table, table"))?.closest(".lobe-editor-table-scroll-wrapper");
6552
+ if (scrollWrapper) scrollWrapper.scrollLeft = 0;
6553
+ };
6554
+ const $selectFirstDescendant = (node) => {
6555
+ const firstDescendant = node.getFirstDescendant();
6556
+ if ($isTextNode(firstDescendant)) firstDescendant.select();
6557
+ else node.selectStart();
6558
+ };
6559
+ const getMoveRange = (selectedIndexes, targetIndex, insertAfter = false) => {
6560
+ if (selectedIndexes.length === 0) return null;
6561
+ const sortedIndexes = [...selectedIndexes].sort((a, b) => a - b);
6562
+ const from = sortedIndexes[0];
6563
+ const to = sortedIndexes.at(-1) ?? from;
6564
+ const count = to - from + 1;
6565
+ const insertionIndex = insertAfter ? targetIndex + 1 : targetIndex;
6566
+ if (insertionIndex >= from && insertionIndex <= to + 1) return null;
6567
+ return {
6568
+ count,
6569
+ from,
6570
+ target: insertionIndex > to ? insertionIndex - count : insertionIndex,
6571
+ to
6572
+ };
6573
+ };
6574
+ const $selectTableRows = (tableNode, from, to) => {
6575
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
6576
+ const firstRow = tableMap[from];
6577
+ const lastRow = tableMap[to];
6578
+ const firstCell = firstRow?.[0]?.cell;
6579
+ const lastCell = lastRow?.[lastRow.length - 1]?.cell;
6580
+ if (!firstCell || !lastCell) return false;
6581
+ const tableSelection = $createTableSelection();
6582
+ tableSelection.set(tableNode.getKey(), firstCell.getKey(), lastCell.getKey());
6583
+ $setSelection(tableSelection);
6584
+ return true;
6585
+ };
6586
+ const $selectTableColumns = (tableNode, from, to) => {
6587
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
6588
+ const firstCell = tableMap.find((row) => row[from])?.[from]?.cell;
6589
+ const lastCell = [...tableMap].reverse().find((row) => row[to])?.[to]?.cell;
6590
+ if (!firstCell || !lastCell) return false;
6591
+ const tableSelection = $createTableSelection();
6592
+ tableSelection.set(tableNode.getKey(), firstCell.getKey(), lastCell.getKey());
6593
+ $setSelection(tableSelection);
6594
+ return true;
6595
+ };
6596
+ const getRangeFromSelection = (selection, table, targetIndex, direction, crossAxisLength, anchorIndex) => {
6597
+ if (anchorIndex !== void 0) return {
6598
+ from: Math.min(anchorIndex, targetIndex),
6599
+ to: Math.max(anchorIndex, targetIndex)
6600
+ };
6601
+ if (!$isTableSelection(selection) || selection.tableKey !== table) return {
6602
+ from: 0,
6603
+ to: targetIndex
6604
+ };
6605
+ const shape = selection.getShape();
6606
+ if (!(direction === "row" ? shape.fromX === 0 && shape.toX === crossAxisLength - 1 : shape.fromY === 0 && shape.toY === crossAxisLength - 1)) return {
6607
+ from: 0,
6608
+ to: targetIndex
6609
+ };
6610
+ const from = direction === "row" ? shape.fromY : shape.fromX;
6611
+ const to = direction === "row" ? shape.toY : shape.toX;
6612
+ return {
6613
+ from: Math.min(from, targetIndex),
6614
+ to: Math.max(to, targetIndex)
6615
+ };
6616
+ };
6401
6617
  function registerTableCommand(editor) {
6402
6618
  return mergeRegister(editor.registerCommand(INSERT_TABLE_COMMAND, ({ rows, columns, includeHeaders }) => {
6403
6619
  const selection = $getSelection() || $getPreviousSelection();
6404
6620
  if (!selection || !$isRangeSelection(selection)) return false;
6405
- if ($findTableNode(selection.anchor.getNode())) return false;
6406
- const anchorNode = selection.anchor.getNode();
6407
- const tableNode = $createTableNodeWithDimensions(Number(rows), Number(columns), includeHeaders);
6621
+ const anchorNode = $getNodeByKey(selection.anchor.key);
6622
+ if (!anchorNode) return false;
6623
+ if ($findTableNode(anchorNode)) return false;
6624
+ const rowCount = Number(rows);
6625
+ const columnCount = Number(columns);
6626
+ const tableNode = $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders);
6627
+ tableNode.setColWidths(createDefaultTableColWidths(columnCount));
6408
6628
  if ($isElementNode(anchorNode) && anchorNode.isEmpty()) anchorNode.replace(tableNode);
6409
6629
  else $insertNodeToNearestRoot(tableNode);
6410
6630
  const firstDescendant = tableNode.getFirstDescendant();
6411
6631
  if ($isTextNode(firstDescendant)) firstDescendant.select();
6412
6632
  return true;
6413
- }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(SELECT_TABLE_COMMAND, ({ table, columnIndex, rowIndex }) => {
6414
- editor.update(() => {
6415
- const prevSelection = $getSelection();
6416
- const tableNode = $getNodeByKey(table);
6417
- if (!tableNode || !$isTableNode(tableNode)) return;
6418
- const tableSelection = $isTableSelection(prevSelection) ? prevSelection : $createTableSelection();
6419
- if (rowIndex !== void 0) {
6420
- const firstRow = tableNode.getChildren()[rowIndex];
6421
- if (!firstRow) return;
6422
- const firstCell = firstRow.getFirstChild();
6423
- const lastCell = firstRow.getLastChild();
6424
- if (!firstCell || !lastCell) return;
6425
- tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
6426
- $setSelection(tableSelection);
6427
- } else if (columnIndex !== void 0) {
6428
- const firstRow = tableNode.getFirstChild();
6429
- const lastRow = tableNode.getLastChild();
6430
- if (!firstRow || !lastRow) return;
6431
- const firstCell = firstRow.getChildren()[columnIndex];
6432
- const lastCell = lastRow.getChildren()[columnIndex];
6433
- if (!firstCell || !lastCell) return;
6434
- tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
6435
- $setSelection(tableSelection);
6436
- } else {
6437
- const firstRow = tableNode.getFirstChild();
6438
- const lastRow = tableNode.getLastChild();
6439
- if (!firstRow || !lastRow) return;
6440
- const firstCell = firstRow.getFirstChild();
6441
- const lastCell = lastRow.getLastChild();
6442
- if (!firstCell || !lastCell) return;
6443
- tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
6444
- $setSelection(tableSelection);
6445
- }
6633
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(INSERT_TABLE_COLUMN_COMMAND, ({ table, columnIndex, insertAfter = true }) => {
6634
+ const tableNode = $getNodeByKey(table);
6635
+ if (!tableNode || !$isTableNode(tableNode)) return false;
6636
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
6637
+ const firstCell = tableMap.find((row) => row[columnIndex])?.[columnIndex]?.cell;
6638
+ const lastCell = [...tableMap].reverse().find((row) => row[columnIndex])?.[columnIndex]?.cell;
6639
+ if (!firstCell || !lastCell) return false;
6640
+ const tableSelection = $createTableSelection();
6641
+ tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
6642
+ $setSelection(tableSelection);
6643
+ $insertTableColumnAtSelection(insertAfter);
6644
+ return true;
6645
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(INSERT_TABLE_ROW_COMMAND, ({ table, rowIndex, insertAfter = true }) => {
6646
+ const tableNode = $getNodeByKey(table);
6647
+ if (!tableNode || !$isTableNode(tableNode)) return false;
6648
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
6649
+ const row = tableMap[rowIndex];
6650
+ const firstCell = row?.[0]?.cell;
6651
+ const lastCell = row?.[row.length - 1]?.cell;
6652
+ if (!firstCell || !lastCell) return false;
6653
+ const tableSelection = $createTableSelection();
6654
+ tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
6655
+ $setSelection(tableSelection);
6656
+ const insertedRow = $insertTableRowAtSelection(insertAfter);
6657
+ if (insertedRow) $selectFirstDescendant(insertedRow);
6658
+ return true;
6659
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(SYNC_TABLE_COLUMN_WIDTH_COMMAND, ({ table, columnIndex }) => {
6660
+ const tableNode = $getNodeByKey(table);
6661
+ if (!tableNode || !$isTableNode(tableNode)) return false;
6662
+ const columnCount = tableNode.getColumnCount();
6663
+ const selectedWidth = (tableNode.getColWidths() || createDefaultTableColWidths(columnCount))[columnIndex];
6664
+ if (selectedWidth === void 0) return false;
6665
+ const nextColWidths = Array.from({ length: columnCount }, () => selectedWidth);
6666
+ tableNode.setColWidths(nextColWidths);
6667
+ requestAnimationFrame(() => {
6668
+ syncTableWidthDOM(editor, table, nextColWidths);
6446
6669
  });
6447
- return false;
6670
+ return true;
6671
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(AUTO_FIT_TABLE_COLUMN_WIDTH_COMMAND, ({ table, columnIndexes }) => {
6672
+ const tableNode = $getNodeByKey(table);
6673
+ if (!tableNode || !$isTableNode(tableNode)) return false;
6674
+ const nextColWidths = getAutoFitTableColumnWidths(editor, tableNode, columnIndexes);
6675
+ if (!nextColWidths) return false;
6676
+ tableNode.setColWidths(nextColWidths);
6677
+ requestAnimationFrame(() => {
6678
+ syncTableWidthDOM(editor, table, nextColWidths);
6679
+ });
6680
+ return true;
6681
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(DISTRIBUTE_TABLE_COLUMN_WIDTH_COMMAND, ({ table }) => {
6682
+ const tableNode = $getNodeByKey(table);
6683
+ if (!tableNode || !$isTableNode(tableNode)) return false;
6684
+ const nextColWidths = getDistributedTableColumnWidths(editor, tableNode);
6685
+ if (!nextColWidths) return false;
6686
+ tableNode.setColWidths(nextColWidths);
6687
+ requestAnimationFrame(() => {
6688
+ syncTableWidthDOM(editor, table, nextColWidths);
6689
+ resetTableScrollLeft(editor, table);
6690
+ });
6691
+ return true;
6692
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(MOVE_TABLE_COLUMN_COMMAND, ({ table, selectedColumns, columnIndex, insertAfter = false }) => {
6693
+ const tableNode = $getNodeByKey(table);
6694
+ if (!tableNode || !$isTableNode(tableNode) || !$isSimpleTable(tableNode)) return false;
6695
+ const moveRange = getMoveRange(selectedColumns, columnIndex, insertAfter);
6696
+ if (!moveRange) return false;
6697
+ const { count, from, target, to } = moveRange;
6698
+ tableNode.getChildren().filter($isTableRowNode).forEach((row) => {
6699
+ const cells = row.getChildren();
6700
+ const movedCells = cells.slice(from, to + 1);
6701
+ const nextCells = [...cells.slice(0, from), ...cells.slice(to + 1)];
6702
+ nextCells.splice(target, 0, ...movedCells);
6703
+ row.splice(0, cells.length, nextCells);
6704
+ });
6705
+ const colWidths = tableNode.getColWidths();
6706
+ if (colWidths && colWidths.length === tableNode.getColumnCount()) {
6707
+ const movedWidths = colWidths.slice(from, to + 1);
6708
+ const nextWidths = [...colWidths.slice(0, from), ...colWidths.slice(to + 1)];
6709
+ nextWidths.splice(target, 0, ...movedWidths);
6710
+ tableNode.setColWidths(nextWidths);
6711
+ }
6712
+ $selectTableColumns(tableNode, target, target + count - 1);
6713
+ return true;
6714
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(MOVE_TABLE_ROW_COMMAND, ({ table, selectedRows, rowIndex, insertAfter = false }) => {
6715
+ const tableNode = $getNodeByKey(table);
6716
+ if (!tableNode || !$isTableNode(tableNode) || !$isSimpleTable(tableNode)) return false;
6717
+ const moveRange = getMoveRange(selectedRows, rowIndex, insertAfter);
6718
+ if (!moveRange) return false;
6719
+ const { count, from, target, to } = moveRange;
6720
+ const rows = tableNode.getChildren();
6721
+ const movedRows = rows.slice(from, to + 1);
6722
+ const nextRows = [...rows.slice(0, from), ...rows.slice(to + 1)];
6723
+ nextRows.splice(target, 0, ...movedRows);
6724
+ tableNode.splice(0, rows.length, nextRows);
6725
+ $selectTableRows(tableNode, target, target + count - 1);
6726
+ return true;
6727
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(SELECT_TABLE_COMMAND, ({ table, anchorIndex, columnIndex, extend, rowIndex }) => {
6728
+ const prevSelection = $getSelection();
6729
+ const tableNode = $getNodeByKey(table);
6730
+ if (!tableNode || !$isTableNode(tableNode)) return false;
6731
+ const tableSelection = $isTableSelection(prevSelection) ? prevSelection : $createTableSelection();
6732
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
6733
+ if (rowIndex !== void 0) {
6734
+ const { from, to } = extend ? getRangeFromSelection(prevSelection, table, rowIndex, "row", tableNode.getColumnCount(), anchorIndex) : {
6735
+ from: rowIndex,
6736
+ to: rowIndex
6737
+ };
6738
+ const firstRow = tableMap[from];
6739
+ const lastRow = tableMap[to];
6740
+ const firstCell = firstRow?.[0]?.cell;
6741
+ const lastCell = lastRow?.[lastRow.length - 1]?.cell;
6742
+ if (!firstCell || !lastCell) return false;
6743
+ tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
6744
+ $setSelection(tableSelection);
6745
+ return true;
6746
+ }
6747
+ if (columnIndex !== void 0) {
6748
+ const { from, to } = extend ? getRangeFromSelection(prevSelection, table, columnIndex, "column", tableMap.length, anchorIndex) : {
6749
+ from: columnIndex,
6750
+ to: columnIndex
6751
+ };
6752
+ const firstCell = tableMap.find((row) => row[from])?.[from]?.cell;
6753
+ const lastCell = [...tableMap].reverse().find((row) => row[to])?.[to]?.cell;
6754
+ if (!firstCell || !lastCell) return false;
6755
+ tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
6756
+ $setSelection(tableSelection);
6757
+ return true;
6758
+ }
6759
+ const firstRow = tableMap[0];
6760
+ const lastRow = tableMap.at(-1);
6761
+ const firstCell = firstRow?.[0]?.cell;
6762
+ const lastCell = lastRow?.[lastRow.length - 1]?.cell;
6763
+ if (!firstCell || !lastCell) return false;
6764
+ tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
6765
+ $setSelection(tableSelection);
6766
+ return true;
6448
6767
  }, COMMAND_PRIORITY_EDITOR));
6449
6768
  }
6450
6769
  //#endregion
6451
6770
  //#region src/plugins/table/node/index.ts
6452
6771
  const OriginalCreateDOM = TableNode.prototype.createDOM;
6772
+ const OriginalUpdateDOM = TableNode.prototype.updateDOM;
6773
+ const SCROLL_INDICATOR_WIDTH = 24;
6774
+ function markTableControllerHost(element, withDecorator = false) {
6775
+ setDOMUnmanaged(element);
6776
+ if (withDecorator) element.dataset.lexicalDecorator = "true";
6777
+ }
6778
+ function updateTableScrollIndicators(scrollWrapper) {
6779
+ const maxScrollLeft = scrollWrapper.scrollWidth - scrollWrapper.clientWidth;
6780
+ const scrollLeft = scrollWrapper.scrollLeft;
6781
+ const hasOverflow = maxScrollLeft > 1;
6782
+ const showStart = hasOverflow && scrollLeft > 1;
6783
+ const showEnd = hasOverflow && scrollLeft < maxScrollLeft - 1;
6784
+ const startIndicator = scrollWrapper.querySelector(":scope > .lobe-editor-table-scroll-indicator-start");
6785
+ const endIndicator = scrollWrapper.querySelector(":scope > .lobe-editor-table-scroll-indicator-end");
6786
+ startIndicator?.classList.toggle("lobe-editor-table-scroll-indicator-visible", showStart);
6787
+ endIndicator?.classList.toggle("lobe-editor-table-scroll-indicator-visible", showEnd);
6788
+ if (startIndicator) startIndicator.style.transform = `translateX(${scrollLeft}px)`;
6789
+ if (endIndicator) endIndicator.style.transform = `translateX(${Math.max(scrollLeft + scrollWrapper.clientWidth - SCROLL_INDICATOR_WIDTH, 0)}px)`;
6790
+ }
6791
+ function ensureTableScrollIndicators(scrollWrapper) {
6792
+ const ensureIndicator = (className) => {
6793
+ const existingIndicator = scrollWrapper.querySelector(`:scope > .${className}`);
6794
+ if (existingIndicator instanceof HTMLElement) {
6795
+ setDOMUnmanaged(existingIndicator);
6796
+ return;
6797
+ }
6798
+ const indicator = document.createElement("span");
6799
+ indicator.className = `lobe-editor-table-scroll-indicator ${className}`;
6800
+ setDOMUnmanaged(indicator);
6801
+ scrollWrapper.append(indicator);
6802
+ };
6803
+ ensureIndicator("lobe-editor-table-scroll-indicator-start");
6804
+ ensureIndicator("lobe-editor-table-scroll-indicator-end");
6805
+ if (scrollWrapper.dataset.scrollIndicatorsReady === "true") {
6806
+ updateTableScrollIndicators(scrollWrapper);
6807
+ return;
6808
+ }
6809
+ scrollWrapper.dataset.scrollIndicatorsReady = "true";
6810
+ scrollWrapper.addEventListener("scroll", () => updateTableScrollIndicators(scrollWrapper), { passive: true });
6811
+ const resizeObserver = new ResizeObserver(() => updateTableScrollIndicators(scrollWrapper));
6812
+ resizeObserver.observe(scrollWrapper);
6813
+ resizeObserver.observe(scrollWrapper.querySelector("table") ?? scrollWrapper);
6814
+ requestAnimationFrame(() => updateTableScrollIndicators(scrollWrapper));
6815
+ }
6816
+ function ensureTableControllerDOM(element) {
6817
+ const table = element instanceof HTMLTableElement ? element : element.querySelector("table");
6818
+ if (!table) return;
6819
+ let scrollWrapper = table.closest(".lobe-editor-table-scroll-wrapper");
6820
+ if (!table.closest(".lobe-editor-table-scroll-wrapper")) {
6821
+ scrollWrapper = document.createElement("div");
6822
+ scrollWrapper.className = "lobe-editor-table-scroll-wrapper";
6823
+ table.parentElement?.insertBefore(scrollWrapper, table);
6824
+ scrollWrapper.append(table);
6825
+ }
6826
+ if (!scrollWrapper) return;
6827
+ const legacyToolbar = element.querySelector(":scope > .toolbar");
6828
+ if (legacyToolbar instanceof HTMLElement) {
6829
+ legacyToolbar.className = "toolbar-col";
6830
+ markTableControllerHost(legacyToolbar, true);
6831
+ scrollWrapper.append(legacyToolbar);
6832
+ }
6833
+ const ensureToolbar = (parent, className, withDecorator = false) => {
6834
+ const existingToolbar = parent.querySelector(`:scope > .${className}`);
6835
+ if (existingToolbar instanceof HTMLElement) {
6836
+ markTableControllerHost(existingToolbar, withDecorator);
6837
+ return;
6838
+ }
6839
+ if (!existingToolbar) {
6840
+ const toolbar = document.createElement("div");
6841
+ toolbar.className = className;
6842
+ markTableControllerHost(toolbar, withDecorator);
6843
+ parent.append(toolbar);
6844
+ }
6845
+ };
6846
+ const legacyDecoratedToolbar = scrollWrapper.querySelector(":scope > .toolbar[data-lexical-decorator]");
6847
+ if (legacyDecoratedToolbar instanceof HTMLElement) {
6848
+ legacyDecoratedToolbar.className = "toolbar-col";
6849
+ markTableControllerHost(legacyDecoratedToolbar, true);
6850
+ }
6851
+ const legacyPlainToolbar = scrollWrapper.querySelector(":scope > .toolbar:not([data-lexical-decorator])");
6852
+ if (legacyPlainToolbar instanceof HTMLElement) {
6853
+ legacyPlainToolbar.className = "toolbar-row";
6854
+ markTableControllerHost(legacyPlainToolbar, true);
6855
+ element.append(legacyPlainToolbar);
6856
+ }
6857
+ ensureToolbar(scrollWrapper, "toolbar-col", true);
6858
+ ensureToolbar(element, "toolbar-row", true);
6859
+ ensureTableScrollIndicators(scrollWrapper);
6860
+ }
6861
+ function reconcileTableDecorator(editor, node, decorator) {
6862
+ if (!decorator) return;
6863
+ if (typeof decorator === "function") {
6864
+ reconcileDecorator(editor, node.getKey(), decorator(node, editor));
6865
+ return;
6866
+ }
6867
+ if ("multi" in decorator) {
6868
+ const decorators = decorator.multi.map((item) => ({
6869
+ queryDOM: item.queryDOM,
6870
+ render: item.render(node, editor)
6871
+ }));
6872
+ reconcileDecorator(editor, node.getKey(), { multi: decorators });
6873
+ return;
6874
+ }
6875
+ reconcileDecorator(editor, node.getKey(), {
6876
+ queryDOM: decorator.queryDOM,
6877
+ render: decorator.render(node, editor)
6878
+ });
6879
+ }
6453
6880
  function patchTableNode() {
6881
+ if (TableNode.prototype.createDOM !== OriginalCreateDOM) return;
6454
6882
  Object.defineProperty(TableNode.prototype, "createDOM", {
6455
6883
  configurable: true,
6456
6884
  enumerable: false,
6457
6885
  value: function(config, editor) {
6458
6886
  const table = OriginalCreateDOM.call(this, config, editor);
6459
- const controller = document.createElement("div");
6460
- table.append(controller);
6887
+ ensureTableControllerDOM(table);
6888
+ const decorator = getKernelFromEditor(editor)?.getDecorator(TableNode.getType()) || null;
6889
+ reconcileTableDecorator(editor, this, decorator);
6890
+ return table;
6891
+ },
6892
+ writable: true
6893
+ });
6894
+ Object.defineProperty(TableNode.prototype, "updateDOM", {
6895
+ configurable: true,
6896
+ enumerable: false,
6897
+ value: function(_prevNode, _dom, _config) {
6898
+ const table = OriginalUpdateDOM.call(this, _prevNode, _dom, _config);
6899
+ ensureTableControllerDOM(_dom);
6900
+ const kernel = getKernelFromEditorConfig(_config);
6901
+ const editor = kernel?.getLexicalEditor();
6902
+ if (editor) {
6903
+ const decorator = kernel?.getDecorator(TableNode.getType()) || null;
6904
+ reconcileTableDecorator(editor, this, decorator);
6905
+ }
6461
6906
  return table;
6462
6907
  },
6463
6908
  writable: true
6464
6909
  });
6465
6910
  }
6466
6911
  //#endregion
6912
+ //#region src/plugins/table/service/i-table-controller-menu-service.ts
6913
+ const ITableControllerMenuService = genServiceId("TableControllerMenuService");
6914
+ var TableControllerMenuService = class {
6915
+ constructor() {
6916
+ this.items = /* @__PURE__ */ new Map();
6917
+ this.listeners = /* @__PURE__ */ new Set();
6918
+ }
6919
+ getItems(context) {
6920
+ return Array.from(this.items.values()).filter((item) => item.when ? item.when(context) : true).sort((a, b) => (a.order || 0) - (b.order || 0));
6921
+ }
6922
+ registerItem(item) {
6923
+ this.items.set(item.key, item);
6924
+ this.notify();
6925
+ return () => {
6926
+ this.items.delete(item.key);
6927
+ this.notify();
6928
+ };
6929
+ }
6930
+ subscribe(listener) {
6931
+ this.listeners.add(listener);
6932
+ return () => {
6933
+ this.listeners.delete(listener);
6934
+ };
6935
+ }
6936
+ notify() {
6937
+ for (const listener of this.listeners) listener();
6938
+ }
6939
+ };
6940
+ //#endregion
6467
6941
  //#region src/plugins/table/plugin/index.ts
6468
6942
  const tableCellProcessor = (before, content, after) => {
6469
6943
  return before + content.replace(/\n+$/, "").replaceAll(/\n+/g, "<br />") + after;
@@ -6471,6 +6945,13 @@ const tableCellProcessor = (before, content, after) => {
6471
6945
  function isHeadlessEditor(editor) {
6472
6946
  return editor._headless === true;
6473
6947
  }
6948
+ const getSelectedRange = (selectedIndexes) => {
6949
+ const sortedIndexes = [...selectedIndexes].sort((a, b) => a - b);
6950
+ return {
6951
+ end: sortedIndexes.at(-1) ?? 0,
6952
+ start: sortedIndexes[0] ?? 0
6953
+ };
6954
+ };
6474
6955
  const TablePlugin = class extends KernelPlugin {
6475
6956
  static {
6476
6957
  this.pluginName = "TablePlugin";
@@ -6479,11 +6960,26 @@ const TablePlugin = class extends KernelPlugin {
6479
6960
  super();
6480
6961
  this.kernel = kernel;
6481
6962
  patchTableNode();
6963
+ kernel.registerServiceHotReload(ITableControllerMenuService, new TableControllerMenuService());
6482
6964
  kernel.registerNodes([
6483
6965
  TableNode$1,
6484
6966
  TableRowNode,
6485
6967
  TableCellNode
6486
6968
  ]);
6969
+ if (options?.decoratorCol || options?.decoratorRow) {
6970
+ kernel.registerDecorator(TableNode$1.getType(), { multi: [...options.decoratorCol ? [{
6971
+ queryDOM: (el) => el.querySelector(".toolbar-col"),
6972
+ render: (node, editor) => {
6973
+ return options.decoratorCol?.(node, editor) || null;
6974
+ }
6975
+ }] : [], ...options.decoratorRow ? [{
6976
+ queryDOM: (el) => el.querySelector(".toolbar-row"),
6977
+ render: (node, editor) => {
6978
+ return options.decoratorRow?.(node, editor) || null;
6979
+ }
6980
+ }] : []] });
6981
+ this.registeredDecorators.add(TableNode$1.getType());
6982
+ }
6487
6983
  kernel.registerThemes({
6488
6984
  table: "editor_table",
6489
6985
  tableCell: "editor_table_cell",
@@ -6502,6 +6998,169 @@ const TablePlugin = class extends KernelPlugin {
6502
6998
  }
6503
6999
  this.registerMarkdown();
6504
7000
  this.registerLiteXml();
7001
+ this.registerControllerMenu();
7002
+ this.registerBlockSelect();
7003
+ }
7004
+ registerBlockSelect() {
7005
+ const blockMenuService = this.kernel.requireService(IBlockMenuService);
7006
+ if (!blockMenuService) return;
7007
+ this.register(blockMenuService.registerSelectHandler({
7008
+ key: "__table_block_select_handler",
7009
+ onSelect: (node) => {
7010
+ if (!$isTableNode(node)) return false;
7011
+ const [tableMap] = $computeTableMapSkipCellCheck(node, null, null);
7012
+ const firstCell = tableMap[0]?.[0]?.cell;
7013
+ const lastRow = [...tableMap].reverse().find((row) => row.length > 0);
7014
+ const lastCell = lastRow?.[lastRow.length - 1]?.cell;
7015
+ if (!firstCell || !lastCell) return false;
7016
+ const tableSelection = $createTableSelection();
7017
+ tableSelection.set(node.getKey(), firstCell.getKey(), lastCell.getKey());
7018
+ $setSelection(tableSelection);
7019
+ return true;
7020
+ },
7021
+ order: 100
7022
+ }));
7023
+ }
7024
+ registerControllerMenu() {
7025
+ const tableControllerMenuService = this.kernel.requireService(ITableControllerMenuService);
7026
+ if (!tableControllerMenuService) return;
7027
+ [
7028
+ tableControllerMenuService.registerItem({
7029
+ key: "__table_column_insert_before",
7030
+ label: "Insert before",
7031
+ onClick: ({ editor, node, selectedIndexes }) => {
7032
+ const { start } = getSelectedRange(selectedIndexes);
7033
+ editor.dispatchCommand(INSERT_TABLE_COLUMN_COMMAND, {
7034
+ columnIndex: start,
7035
+ insertAfter: false,
7036
+ table: node.getKey()
7037
+ });
7038
+ },
7039
+ order: 10,
7040
+ preview: "insert-before",
7041
+ when: ({ axis }) => axis === "column"
7042
+ }),
7043
+ tableControllerMenuService.registerItem({
7044
+ key: "__table_column_insert_after",
7045
+ label: "Insert after",
7046
+ onClick: ({ editor, node, selectedIndexes }) => {
7047
+ const { end } = getSelectedRange(selectedIndexes);
7048
+ editor.dispatchCommand(INSERT_TABLE_COLUMN_COMMAND, {
7049
+ columnIndex: end,
7050
+ insertAfter: true,
7051
+ table: node.getKey()
7052
+ });
7053
+ },
7054
+ order: 20,
7055
+ preview: "insert-after",
7056
+ when: ({ axis }) => axis === "column"
7057
+ }),
7058
+ tableControllerMenuService.registerItem({
7059
+ key: "__table_column_separator_delete",
7060
+ order: 40,
7061
+ type: "separator",
7062
+ when: ({ axis }) => axis === "column"
7063
+ }),
7064
+ tableControllerMenuService.registerItem({
7065
+ key: "__table_column_sync_width",
7066
+ label: "Sync width to all columns",
7067
+ onClick: ({ editor, node, selectedIndexes }) => {
7068
+ const columnIndex = selectedIndexes[0];
7069
+ if (columnIndex === void 0) return;
7070
+ editor.dispatchCommand(SYNC_TABLE_COLUMN_WIDTH_COMMAND, {
7071
+ columnIndex,
7072
+ table: node.getKey()
7073
+ });
7074
+ },
7075
+ order: 30,
7076
+ when: ({ axis, selectedIndexes }) => axis === "column" && selectedIndexes.length > 0
7077
+ }),
7078
+ tableControllerMenuService.registerItem({
7079
+ key: "__table_column_auto_fit_width",
7080
+ label: "Auto fit width",
7081
+ onClick: ({ editor, node, selectedIndexes }) => {
7082
+ editor.dispatchCommand(AUTO_FIT_TABLE_COLUMN_WIDTH_COMMAND, {
7083
+ columnIndexes: selectedIndexes,
7084
+ table: node.getKey()
7085
+ });
7086
+ },
7087
+ order: 35,
7088
+ when: ({ axis, selectedIndexes }) => axis === "column" && selectedIndexes.length > 0
7089
+ }),
7090
+ tableControllerMenuService.registerItem({
7091
+ key: "__table_column_distribute_width",
7092
+ label: "Distribute width",
7093
+ onClick: ({ editor, node }) => {
7094
+ editor.dispatchCommand(DISTRIBUTE_TABLE_COLUMN_WIDTH_COMMAND, { table: node.getKey() });
7095
+ },
7096
+ order: 36,
7097
+ when: ({ axis }) => axis === "column"
7098
+ }),
7099
+ tableControllerMenuService.registerItem({
7100
+ danger: true,
7101
+ key: "__table_column_delete",
7102
+ label: "Delete",
7103
+ onClick: ({ editor }) => {
7104
+ editor.update(() => {
7105
+ $deleteTableColumnAtSelection();
7106
+ });
7107
+ },
7108
+ order: 40,
7109
+ preview: "delete",
7110
+ when: ({ axis }) => axis === "column"
7111
+ }),
7112
+ tableControllerMenuService.registerItem({
7113
+ key: "__table_row_insert_above",
7114
+ label: "Insert above",
7115
+ onClick: ({ editor, node, selectedIndexes }) => {
7116
+ const { start } = getSelectedRange(selectedIndexes);
7117
+ editor.dispatchCommand(INSERT_TABLE_ROW_COMMAND, {
7118
+ insertAfter: false,
7119
+ rowIndex: start,
7120
+ table: node.getKey()
7121
+ });
7122
+ },
7123
+ order: 10,
7124
+ preview: "insert-before",
7125
+ when: ({ axis }) => axis === "row"
7126
+ }),
7127
+ tableControllerMenuService.registerItem({
7128
+ key: "__table_row_insert_below",
7129
+ label: "Insert below",
7130
+ onClick: ({ editor, node, selectedIndexes }) => {
7131
+ const { end } = getSelectedRange(selectedIndexes);
7132
+ editor.dispatchCommand(INSERT_TABLE_ROW_COMMAND, {
7133
+ insertAfter: true,
7134
+ rowIndex: end,
7135
+ table: node.getKey()
7136
+ });
7137
+ },
7138
+ order: 20,
7139
+ preview: "insert-after",
7140
+ when: ({ axis }) => axis === "row"
7141
+ }),
7142
+ tableControllerMenuService.registerItem({
7143
+ key: "__table_row_separator_delete",
7144
+ order: 30,
7145
+ type: "separator",
7146
+ when: ({ axis }) => axis === "row"
7147
+ }),
7148
+ tableControllerMenuService.registerItem({
7149
+ danger: true,
7150
+ key: "__table_row_delete",
7151
+ label: "Delete",
7152
+ onClick: ({ editor }) => {
7153
+ editor.update(() => {
7154
+ $deleteTableRowAtSelection();
7155
+ });
7156
+ },
7157
+ order: 40,
7158
+ preview: "delete",
7159
+ when: ({ axis }) => axis === "row"
7160
+ })
7161
+ ].forEach((unregister) => {
7162
+ this.register(unregister);
7163
+ });
6505
7164
  }
6506
7165
  registerLiteXml() {
6507
7166
  const litexmlService = this.kernel.requireService(ILitexmlService);
@@ -6536,7 +7195,7 @@ const TablePlugin = class extends KernelPlugin {
6536
7195
  for (const child of children) if ((child.children?.length || -1) > maxTdlen) maxTdlen = child.children.length;
6537
7196
  return INodeHelper.createElementNode(TableNode$1.getType(), {
6538
7197
  children,
6539
- colWidths: colWidths.length > 0 ? colWidths : new Array(maxTdlen).fill(750 / maxTdlen),
7198
+ colWidths: colWidths.length > 0 ? colWidths : createDefaultTableColWidths(maxTdlen),
6540
7199
  direction: null,
6541
7200
  format: "",
6542
7201
  indent: 0,
@@ -6592,7 +7251,7 @@ const TablePlugin = class extends KernelPlugin {
6592
7251
  const colLen = node.children[0]?.children.length || 1;
6593
7252
  return INodeHelper.createElementNode("table", {
6594
7253
  children,
6595
- colWidths: new Array(colLen).fill(750 / colLen),
7254
+ colWidths: createDefaultTableColWidths(colLen),
6596
7255
  direction: null,
6597
7256
  format: "",
6598
7257
  indent: 0,