@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.
- package/es/editor-kernel/react/useDecorators.js +14 -8
- package/es/headless/index.d.ts +1 -1
- package/es/headless/index.js +1 -1
- package/es/headless.d.ts +3 -18
- package/es/headless.js +711 -52
- package/es/index.d.ts +5 -5
- package/es/index.js +5 -5
- 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/command/diffCommand.d.ts +2 -17
- package/es/plugins/litexml/command/diffCommand.js +3 -9
- package/es/plugins/litexml/command/index.d.ts +2 -38
- package/es/plugins/litexml/command/index.js +3 -6
- package/es/plugins/litexml/command/symbols.d.ts +67 -0
- package/es/plugins/litexml/command/symbols.js +34 -0
- package/es/plugins/litexml/index.d.ts +1 -2
- package/es/plugins/litexml/plugin/index.js +8 -2
- package/es/plugins/litexml/react/DiffNodeToolbar/index.js +1 -1
- 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/es/symbols-DEEvsKq4.d.ts +67 -0
- 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: {
|
|
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
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
6460
|
-
|
|
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 :
|
|
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:
|
|
7254
|
+
colWidths: createDefaultTableColWidths(colLen),
|
|
6596
7255
|
direction: null,
|
|
6597
7256
|
format: "",
|
|
6598
7257
|
indent: 0,
|