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