@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
|
@@ -3,9 +3,13 @@ import { KernelPlugin, init_plugin } from "../../../editor-kernel/plugin.js";
|
|
|
3
3
|
import { ILitexmlService } from "../../litexml/service/litexml-service.js";
|
|
4
4
|
import { IMarkdownShortCutService } from "../../markdown/service/shortcut.js";
|
|
5
5
|
import { cx } from "../../../utils/cx.js";
|
|
6
|
-
import {
|
|
6
|
+
import { IBlockMenuService } from "../../block/service/i-block-menu-service.js";
|
|
7
|
+
import { createDefaultTableColWidths } from "../utils/index.js";
|
|
8
|
+
import { AUTO_FIT_TABLE_COLUMN_WIDTH_COMMAND, DISTRIBUTE_TABLE_COLUMN_WIDTH_COMMAND, INSERT_TABLE_COLUMN_COMMAND, INSERT_TABLE_ROW_COMMAND, SYNC_TABLE_COLUMN_WIDTH_COMMAND, registerTableCommand } from "../command/index.js";
|
|
7
9
|
import { TableNode as TableNode$1, patchTableNode } from "../node/index.js";
|
|
8
|
-
import {
|
|
10
|
+
import { ITableControllerMenuService, TableControllerMenuService } from "../service/i-table-controller-menu-service.js";
|
|
11
|
+
import { $computeTableMapSkipCellCheck, $createTableSelection, $deleteTableColumnAtSelection, $deleteTableRowAtSelection, $isTableNode, TableCellNode, TableRowNode, registerTableCellUnmergeTransform, registerTablePlugin, registerTableSelectionObserver, setScrollableTablesActive } from "@lexical/table";
|
|
12
|
+
import { $setSelection } from "lexical";
|
|
9
13
|
//#region src/plugins/table/plugin/index.ts
|
|
10
14
|
init_helper();
|
|
11
15
|
init_plugin();
|
|
@@ -15,6 +19,13 @@ const tableCellProcessor = (before, content, after) => {
|
|
|
15
19
|
function isHeadlessEditor(editor) {
|
|
16
20
|
return editor._headless === true;
|
|
17
21
|
}
|
|
22
|
+
const getSelectedRange = (selectedIndexes) => {
|
|
23
|
+
const sortedIndexes = [...selectedIndexes].sort((a, b) => a - b);
|
|
24
|
+
return {
|
|
25
|
+
end: sortedIndexes.at(-1) ?? 0,
|
|
26
|
+
start: sortedIndexes[0] ?? 0
|
|
27
|
+
};
|
|
28
|
+
};
|
|
18
29
|
const TablePlugin = class extends KernelPlugin {
|
|
19
30
|
static {
|
|
20
31
|
this.pluginName = "TablePlugin";
|
|
@@ -23,11 +34,26 @@ const TablePlugin = class extends KernelPlugin {
|
|
|
23
34
|
super();
|
|
24
35
|
this.kernel = kernel;
|
|
25
36
|
patchTableNode();
|
|
37
|
+
kernel.registerServiceHotReload(ITableControllerMenuService, new TableControllerMenuService());
|
|
26
38
|
kernel.registerNodes([
|
|
27
39
|
TableNode$1,
|
|
28
40
|
TableRowNode,
|
|
29
41
|
TableCellNode
|
|
30
42
|
]);
|
|
43
|
+
if (options?.decoratorCol || options?.decoratorRow) {
|
|
44
|
+
kernel.registerDecorator(TableNode$1.getType(), { multi: [...options.decoratorCol ? [{
|
|
45
|
+
queryDOM: (el) => el.querySelector(".toolbar-col"),
|
|
46
|
+
render: (node, editor) => {
|
|
47
|
+
return options.decoratorCol?.(node, editor) || null;
|
|
48
|
+
}
|
|
49
|
+
}] : [], ...options.decoratorRow ? [{
|
|
50
|
+
queryDOM: (el) => el.querySelector(".toolbar-row"),
|
|
51
|
+
render: (node, editor) => {
|
|
52
|
+
return options.decoratorRow?.(node, editor) || null;
|
|
53
|
+
}
|
|
54
|
+
}] : []] });
|
|
55
|
+
this.registeredDecorators.add(TableNode$1.getType());
|
|
56
|
+
}
|
|
31
57
|
kernel.registerThemes({
|
|
32
58
|
table: "editor_table",
|
|
33
59
|
tableCell: "editor_table_cell",
|
|
@@ -46,6 +72,169 @@ const TablePlugin = class extends KernelPlugin {
|
|
|
46
72
|
}
|
|
47
73
|
this.registerMarkdown();
|
|
48
74
|
this.registerLiteXml();
|
|
75
|
+
this.registerControllerMenu();
|
|
76
|
+
this.registerBlockSelect();
|
|
77
|
+
}
|
|
78
|
+
registerBlockSelect() {
|
|
79
|
+
const blockMenuService = this.kernel.requireService(IBlockMenuService);
|
|
80
|
+
if (!blockMenuService) return;
|
|
81
|
+
this.register(blockMenuService.registerSelectHandler({
|
|
82
|
+
key: "__table_block_select_handler",
|
|
83
|
+
onSelect: (node) => {
|
|
84
|
+
if (!$isTableNode(node)) return false;
|
|
85
|
+
const [tableMap] = $computeTableMapSkipCellCheck(node, null, null);
|
|
86
|
+
const firstCell = tableMap[0]?.[0]?.cell;
|
|
87
|
+
const lastRow = [...tableMap].reverse().find((row) => row.length > 0);
|
|
88
|
+
const lastCell = lastRow?.[lastRow.length - 1]?.cell;
|
|
89
|
+
if (!firstCell || !lastCell) return false;
|
|
90
|
+
const tableSelection = $createTableSelection();
|
|
91
|
+
tableSelection.set(node.getKey(), firstCell.getKey(), lastCell.getKey());
|
|
92
|
+
$setSelection(tableSelection);
|
|
93
|
+
return true;
|
|
94
|
+
},
|
|
95
|
+
order: 100
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
registerControllerMenu() {
|
|
99
|
+
const tableControllerMenuService = this.kernel.requireService(ITableControllerMenuService);
|
|
100
|
+
if (!tableControllerMenuService) return;
|
|
101
|
+
[
|
|
102
|
+
tableControllerMenuService.registerItem({
|
|
103
|
+
key: "__table_column_insert_before",
|
|
104
|
+
label: "Insert before",
|
|
105
|
+
onClick: ({ editor, node, selectedIndexes }) => {
|
|
106
|
+
const { start } = getSelectedRange(selectedIndexes);
|
|
107
|
+
editor.dispatchCommand(INSERT_TABLE_COLUMN_COMMAND, {
|
|
108
|
+
columnIndex: start,
|
|
109
|
+
insertAfter: false,
|
|
110
|
+
table: node.getKey()
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
order: 10,
|
|
114
|
+
preview: "insert-before",
|
|
115
|
+
when: ({ axis }) => axis === "column"
|
|
116
|
+
}),
|
|
117
|
+
tableControllerMenuService.registerItem({
|
|
118
|
+
key: "__table_column_insert_after",
|
|
119
|
+
label: "Insert after",
|
|
120
|
+
onClick: ({ editor, node, selectedIndexes }) => {
|
|
121
|
+
const { end } = getSelectedRange(selectedIndexes);
|
|
122
|
+
editor.dispatchCommand(INSERT_TABLE_COLUMN_COMMAND, {
|
|
123
|
+
columnIndex: end,
|
|
124
|
+
insertAfter: true,
|
|
125
|
+
table: node.getKey()
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
order: 20,
|
|
129
|
+
preview: "insert-after",
|
|
130
|
+
when: ({ axis }) => axis === "column"
|
|
131
|
+
}),
|
|
132
|
+
tableControllerMenuService.registerItem({
|
|
133
|
+
key: "__table_column_separator_delete",
|
|
134
|
+
order: 40,
|
|
135
|
+
type: "separator",
|
|
136
|
+
when: ({ axis }) => axis === "column"
|
|
137
|
+
}),
|
|
138
|
+
tableControllerMenuService.registerItem({
|
|
139
|
+
key: "__table_column_sync_width",
|
|
140
|
+
label: "Sync width to all columns",
|
|
141
|
+
onClick: ({ editor, node, selectedIndexes }) => {
|
|
142
|
+
const columnIndex = selectedIndexes[0];
|
|
143
|
+
if (columnIndex === void 0) return;
|
|
144
|
+
editor.dispatchCommand(SYNC_TABLE_COLUMN_WIDTH_COMMAND, {
|
|
145
|
+
columnIndex,
|
|
146
|
+
table: node.getKey()
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
order: 30,
|
|
150
|
+
when: ({ axis, selectedIndexes }) => axis === "column" && selectedIndexes.length > 0
|
|
151
|
+
}),
|
|
152
|
+
tableControllerMenuService.registerItem({
|
|
153
|
+
key: "__table_column_auto_fit_width",
|
|
154
|
+
label: "Auto fit width",
|
|
155
|
+
onClick: ({ editor, node, selectedIndexes }) => {
|
|
156
|
+
editor.dispatchCommand(AUTO_FIT_TABLE_COLUMN_WIDTH_COMMAND, {
|
|
157
|
+
columnIndexes: selectedIndexes,
|
|
158
|
+
table: node.getKey()
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
order: 35,
|
|
162
|
+
when: ({ axis, selectedIndexes }) => axis === "column" && selectedIndexes.length > 0
|
|
163
|
+
}),
|
|
164
|
+
tableControllerMenuService.registerItem({
|
|
165
|
+
key: "__table_column_distribute_width",
|
|
166
|
+
label: "Distribute width",
|
|
167
|
+
onClick: ({ editor, node }) => {
|
|
168
|
+
editor.dispatchCommand(DISTRIBUTE_TABLE_COLUMN_WIDTH_COMMAND, { table: node.getKey() });
|
|
169
|
+
},
|
|
170
|
+
order: 36,
|
|
171
|
+
when: ({ axis }) => axis === "column"
|
|
172
|
+
}),
|
|
173
|
+
tableControllerMenuService.registerItem({
|
|
174
|
+
danger: true,
|
|
175
|
+
key: "__table_column_delete",
|
|
176
|
+
label: "Delete",
|
|
177
|
+
onClick: ({ editor }) => {
|
|
178
|
+
editor.update(() => {
|
|
179
|
+
$deleteTableColumnAtSelection();
|
|
180
|
+
});
|
|
181
|
+
},
|
|
182
|
+
order: 40,
|
|
183
|
+
preview: "delete",
|
|
184
|
+
when: ({ axis }) => axis === "column"
|
|
185
|
+
}),
|
|
186
|
+
tableControllerMenuService.registerItem({
|
|
187
|
+
key: "__table_row_insert_above",
|
|
188
|
+
label: "Insert above",
|
|
189
|
+
onClick: ({ editor, node, selectedIndexes }) => {
|
|
190
|
+
const { start } = getSelectedRange(selectedIndexes);
|
|
191
|
+
editor.dispatchCommand(INSERT_TABLE_ROW_COMMAND, {
|
|
192
|
+
insertAfter: false,
|
|
193
|
+
rowIndex: start,
|
|
194
|
+
table: node.getKey()
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
order: 10,
|
|
198
|
+
preview: "insert-before",
|
|
199
|
+
when: ({ axis }) => axis === "row"
|
|
200
|
+
}),
|
|
201
|
+
tableControllerMenuService.registerItem({
|
|
202
|
+
key: "__table_row_insert_below",
|
|
203
|
+
label: "Insert below",
|
|
204
|
+
onClick: ({ editor, node, selectedIndexes }) => {
|
|
205
|
+
const { end } = getSelectedRange(selectedIndexes);
|
|
206
|
+
editor.dispatchCommand(INSERT_TABLE_ROW_COMMAND, {
|
|
207
|
+
insertAfter: true,
|
|
208
|
+
rowIndex: end,
|
|
209
|
+
table: node.getKey()
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
order: 20,
|
|
213
|
+
preview: "insert-after",
|
|
214
|
+
when: ({ axis }) => axis === "row"
|
|
215
|
+
}),
|
|
216
|
+
tableControllerMenuService.registerItem({
|
|
217
|
+
key: "__table_row_separator_delete",
|
|
218
|
+
order: 30,
|
|
219
|
+
type: "separator",
|
|
220
|
+
when: ({ axis }) => axis === "row"
|
|
221
|
+
}),
|
|
222
|
+
tableControllerMenuService.registerItem({
|
|
223
|
+
danger: true,
|
|
224
|
+
key: "__table_row_delete",
|
|
225
|
+
label: "Delete",
|
|
226
|
+
onClick: ({ editor }) => {
|
|
227
|
+
editor.update(() => {
|
|
228
|
+
$deleteTableRowAtSelection();
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
order: 40,
|
|
232
|
+
preview: "delete",
|
|
233
|
+
when: ({ axis }) => axis === "row"
|
|
234
|
+
})
|
|
235
|
+
].forEach((unregister) => {
|
|
236
|
+
this.register(unregister);
|
|
237
|
+
});
|
|
49
238
|
}
|
|
50
239
|
registerLiteXml() {
|
|
51
240
|
const litexmlService = this.kernel.requireService(ILitexmlService);
|
|
@@ -80,7 +269,7 @@ const TablePlugin = class extends KernelPlugin {
|
|
|
80
269
|
for (const child of children) if ((child.children?.length || -1) > maxTdlen) maxTdlen = child.children.length;
|
|
81
270
|
return INodeHelper.createElementNode(TableNode$1.getType(), {
|
|
82
271
|
children,
|
|
83
|
-
colWidths: colWidths.length > 0 ? colWidths :
|
|
272
|
+
colWidths: colWidths.length > 0 ? colWidths : createDefaultTableColWidths(maxTdlen),
|
|
84
273
|
direction: null,
|
|
85
274
|
format: "",
|
|
86
275
|
indent: 0,
|
|
@@ -136,7 +325,7 @@ const TablePlugin = class extends KernelPlugin {
|
|
|
136
325
|
const colLen = node.children[0]?.children.length || 1;
|
|
137
326
|
return INodeHelper.createElementNode("table", {
|
|
138
327
|
children,
|
|
139
|
-
colWidths:
|
|
328
|
+
colWidths: createDefaultTableColWidths(colLen),
|
|
140
329
|
direction: null,
|
|
141
330
|
format: "",
|
|
142
331
|
indent: 0,
|
|
@@ -2,7 +2,7 @@ import { useTranslation } from "../../../../editor-kernel/react/useTranslation.j
|
|
|
2
2
|
import { $canUnmerge, $selectLastDescendant, computeSelectionCount, currentCellBackgroundColor } from "./utils.js";
|
|
3
3
|
import { Dropdown } from "@lobehub/ui";
|
|
4
4
|
import { Grid2X2XIcon, PanelBottomCloseIcon, PanelLeftCloseIcon, PanelRightCloseIcon, PanelTopCloseIcon, TableColumnsSplitIcon, TableRowsSplitIcon } from "lucide-react";
|
|
5
|
-
import { memo, useCallback, useEffect, useMemo, useState } from "react";
|
|
5
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
import { $computeTableMapSkipCellCheck, $deleteTableColumnAtSelection, $deleteTableRowAtSelection, $getTableColumnIndexFromTableCellNode, $getTableNodeFromLexicalNodeOrThrow, $getTableRowIndexFromTableCellNode, $insertTableColumnAtSelection, $insertTableRowAtSelection, $isTableCellNode, $isTableSelection, $mergeCells, $unmergeCell, TableCellHeaderStates, TableCellNode, getTableElement, getTableObserverFromTableElement } from "@lexical/table";
|
|
8
8
|
import { $getSelection, $setSelection } from "lexical";
|
|
@@ -14,8 +14,13 @@ import { $getSelection, $setSelection } from "lexical";
|
|
|
14
14
|
* LICENSE file in the root directory of this source tree.
|
|
15
15
|
*
|
|
16
16
|
*/
|
|
17
|
+
const TABLE_DELETE_PREVIEW_CLASS = "lobe-editor-table-delete-preview";
|
|
18
|
+
const range = (from, to) => {
|
|
19
|
+
return Array.from({ length: to - from + 1 }, (_, index) => from + index);
|
|
20
|
+
};
|
|
17
21
|
const TableActionMenu = memo(({ editor, tableCellNode: _tableCellNode, cellMerge, children }) => {
|
|
18
22
|
const [tableCellNode, updateTableCellNode] = useState(_tableCellNode);
|
|
23
|
+
const deletePreviewElementsRef = useRef([]);
|
|
19
24
|
const [selectionCounts, updateSelectionCounts] = useState({
|
|
20
25
|
columns: 1,
|
|
21
26
|
rows: 1
|
|
@@ -24,6 +29,62 @@ const TableActionMenu = memo(({ editor, tableCellNode: _tableCellNode, cellMerge
|
|
|
24
29
|
const [canUnmergeCell, setCanUnmergeCell] = useState(false);
|
|
25
30
|
const [, setBackgroundColor] = useState(() => currentCellBackgroundColor(editor) || "");
|
|
26
31
|
const t = useTranslation();
|
|
32
|
+
const clearDeletePreview = useCallback(() => {
|
|
33
|
+
deletePreviewElementsRef.current.forEach((element) => {
|
|
34
|
+
element.classList.remove(TABLE_DELETE_PREVIEW_CLASS);
|
|
35
|
+
});
|
|
36
|
+
document.querySelectorAll(`.${TABLE_DELETE_PREVIEW_CLASS}`).forEach((element) => {
|
|
37
|
+
element.classList.remove(TABLE_DELETE_PREVIEW_CLASS);
|
|
38
|
+
});
|
|
39
|
+
deletePreviewElementsRef.current = [];
|
|
40
|
+
}, []);
|
|
41
|
+
const showDeletePreview = useCallback((target) => {
|
|
42
|
+
clearDeletePreview();
|
|
43
|
+
editor.getEditorState().read(() => {
|
|
44
|
+
if (!tableCellNode.isAttached()) return;
|
|
45
|
+
const latestTableCellNode = tableCellNode.getLatest();
|
|
46
|
+
if (!$isTableCellNode(latestTableCellNode)) return;
|
|
47
|
+
const tableNode = $getTableNodeFromLexicalNodeOrThrow(latestTableCellNode);
|
|
48
|
+
const [gridMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
|
|
49
|
+
const selection = $getSelection();
|
|
50
|
+
const previewCellKeys = /* @__PURE__ */ new Set();
|
|
51
|
+
if (target === "columns") {
|
|
52
|
+
const selectedColumns = $isTableSelection(selection) && selection.tableKey === tableNode.getKey() ? range(selection.getShape().fromX, selection.getShape().toX) : [];
|
|
53
|
+
const columnIndexes = selectedColumns.length > 0 ? selectedColumns : [$getTableColumnIndexFromTableCellNode(latestTableCellNode)];
|
|
54
|
+
for (const row of gridMap) for (const columnIndex of columnIndexes) {
|
|
55
|
+
const cell = row[columnIndex]?.cell;
|
|
56
|
+
if (cell) previewCellKeys.add(cell.getKey());
|
|
57
|
+
}
|
|
58
|
+
} else if (target === "rows") {
|
|
59
|
+
const selectedRows = $isTableSelection(selection) && selection.tableKey === tableNode.getKey() ? range(selection.getShape().fromY, selection.getShape().toY) : [];
|
|
60
|
+
const rowIndexes = selectedRows.length > 0 ? selectedRows : [$getTableRowIndexFromTableCellNode(latestTableCellNode)];
|
|
61
|
+
for (const rowIndex of rowIndexes) {
|
|
62
|
+
const row = gridMap[rowIndex];
|
|
63
|
+
if (!row) continue;
|
|
64
|
+
for (const mapCell of row) if (mapCell?.cell) previewCellKeys.add(mapCell.cell.getKey());
|
|
65
|
+
}
|
|
66
|
+
} else for (const row of gridMap) for (const mapCell of row) if (mapCell?.cell) previewCellKeys.add(mapCell.cell.getKey());
|
|
67
|
+
for (const cellKey of previewCellKeys) {
|
|
68
|
+
const element = editor.getElementByKey(cellKey);
|
|
69
|
+
if (element instanceof HTMLElement) {
|
|
70
|
+
element.classList.add(TABLE_DELETE_PREVIEW_CLASS);
|
|
71
|
+
deletePreviewElementsRef.current.push(element);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}, [
|
|
76
|
+
clearDeletePreview,
|
|
77
|
+
editor,
|
|
78
|
+
tableCellNode
|
|
79
|
+
]);
|
|
80
|
+
const renderDeleteMenuLabel = useCallback((label, target) => {
|
|
81
|
+
return /* @__PURE__ */ jsx("span", {
|
|
82
|
+
onMouseEnter: () => showDeletePreview(target),
|
|
83
|
+
onMouseLeave: clearDeletePreview,
|
|
84
|
+
style: { display: "block" },
|
|
85
|
+
children: label
|
|
86
|
+
});
|
|
87
|
+
}, [clearDeletePreview, showDeletePreview]);
|
|
27
88
|
useEffect(() => {
|
|
28
89
|
return editor.registerMutationListener(TableCellNode, (nodeMutations) => {
|
|
29
90
|
if (nodeMutations.get(tableCellNode.getKey()) === "updated") {
|
|
@@ -45,6 +106,16 @@ const TableActionMenu = memo(({ editor, tableCellNode: _tableCellNode, cellMerge
|
|
|
45
106
|
setCanUnmergeCell($canUnmerge());
|
|
46
107
|
});
|
|
47
108
|
}, [editor]);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
return () => {
|
|
111
|
+
clearDeletePreview();
|
|
112
|
+
};
|
|
113
|
+
}, [clearDeletePreview]);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
return editor.registerUpdateListener(() => {
|
|
116
|
+
clearDeletePreview();
|
|
117
|
+
});
|
|
118
|
+
}, [clearDeletePreview, editor]);
|
|
48
119
|
const clearTableSelection = useCallback(() => {
|
|
49
120
|
editor.update(() => {
|
|
50
121
|
if (tableCellNode.isAttached()) {
|
|
@@ -83,25 +154,29 @@ const TableActionMenu = memo(({ editor, tableCellNode: _tableCellNode, cellMerge
|
|
|
83
154
|
});
|
|
84
155
|
}, [editor, selectionCounts.columns]);
|
|
85
156
|
const deleteTableRowAtSelection = useCallback(() => {
|
|
157
|
+
clearDeletePreview();
|
|
86
158
|
editor.update(() => {
|
|
87
159
|
$deleteTableRowAtSelection();
|
|
88
160
|
});
|
|
89
|
-
}, [editor]);
|
|
161
|
+
}, [clearDeletePreview, editor]);
|
|
90
162
|
const deleteTableAtSelection = useCallback(() => {
|
|
163
|
+
clearDeletePreview();
|
|
91
164
|
editor.update(() => {
|
|
92
165
|
$getTableNodeFromLexicalNodeOrThrow(tableCellNode).remove();
|
|
93
166
|
clearTableSelection();
|
|
94
167
|
});
|
|
95
168
|
}, [
|
|
169
|
+
clearDeletePreview,
|
|
96
170
|
editor,
|
|
97
171
|
tableCellNode,
|
|
98
172
|
clearTableSelection
|
|
99
173
|
]);
|
|
100
174
|
const deleteTableColumnAtSelection = useCallback(() => {
|
|
175
|
+
clearDeletePreview();
|
|
101
176
|
editor.update(() => {
|
|
102
177
|
$deleteTableColumnAtSelection();
|
|
103
178
|
});
|
|
104
|
-
}, [editor]);
|
|
179
|
+
}, [clearDeletePreview, editor]);
|
|
105
180
|
const toggleTableRowIsHeader = useCallback(() => {
|
|
106
181
|
editor.update(() => {
|
|
107
182
|
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
|
|
@@ -178,20 +253,20 @@ const TableActionMenu = memo(({ editor, tableCellNode: _tableCellNode, cellMerge
|
|
|
178
253
|
{
|
|
179
254
|
icon: TableColumnsSplitIcon,
|
|
180
255
|
key: "table-delete-columns",
|
|
181
|
-
label: t(`table.deleteColumn`),
|
|
256
|
+
label: renderDeleteMenuLabel(t(`table.deleteColumn`), "columns"),
|
|
182
257
|
onClick: () => deleteTableColumnAtSelection()
|
|
183
258
|
},
|
|
184
259
|
{
|
|
185
260
|
icon: TableRowsSplitIcon,
|
|
186
261
|
key: "table-delete-rows",
|
|
187
|
-
label: t(`table.deleteRow`),
|
|
262
|
+
label: renderDeleteMenuLabel(t(`table.deleteRow`), "rows"),
|
|
188
263
|
onClick: () => deleteTableRowAtSelection()
|
|
189
264
|
},
|
|
190
265
|
{ type: "divider" },
|
|
191
266
|
{
|
|
192
267
|
icon: Grid2X2XIcon,
|
|
193
268
|
key: "table-delete",
|
|
194
|
-
label: t(`table.delete`),
|
|
269
|
+
label: renderDeleteMenuLabel(t(`table.delete`), "table"),
|
|
195
270
|
onClick: () => deleteTableAtSelection()
|
|
196
271
|
}
|
|
197
272
|
];
|
|
@@ -209,6 +284,7 @@ const TableActionMenu = memo(({ editor, tableCellNode: _tableCellNode, cellMerge
|
|
|
209
284
|
deleteTableColumnAtSelection,
|
|
210
285
|
deleteTableRowAtSelection,
|
|
211
286
|
deleteTableAtSelection,
|
|
287
|
+
renderDeleteMenuLabel,
|
|
212
288
|
toggleTableRowIsHeader,
|
|
213
289
|
toggleTableColumnIsHeader
|
|
214
290
|
]) },
|
|
@@ -7,7 +7,7 @@ import { ChevronDown } from "lucide-react";
|
|
|
7
7
|
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
|
8
8
|
import { jsx } from "react/jsx-runtime";
|
|
9
9
|
import { $getTableCellNodeFromLexicalNode, $getTableNodeFromLexicalNodeOrThrow, $isTableCellNode, $isTableSelection, getTableElement, getTableObserverFromTableElement } from "@lexical/table";
|
|
10
|
-
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, SELECTION_CHANGE_COMMAND, getDOMSelection } from "lexical";
|
|
10
|
+
import { $getNodeByKey, $getSelection, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, SELECTION_CHANGE_COMMAND, getDOMSelection } from "lexical";
|
|
11
11
|
import { mergeRegister } from "@lexical/utils";
|
|
12
12
|
//#region src/plugins/table/react/TableActionMenu/index.tsx
|
|
13
13
|
/**
|
|
@@ -48,7 +48,9 @@ const TableActionMenu = memo(({ cellMerge, editor }) => {
|
|
|
48
48
|
let tableObserver = null;
|
|
49
49
|
let tableCellParentNodeDOM = null;
|
|
50
50
|
if ($isRangeSelection(selection) && rootElement !== null && nativeSelection !== null && rootElement.contains(nativeSelection.anchorNode)) {
|
|
51
|
-
const
|
|
51
|
+
const anchorNode = $getNodeByKey(selection.anchor.key);
|
|
52
|
+
if (!anchorNode) return disable();
|
|
53
|
+
const tableCellNodeFromSelection = $getTableCellNodeFromLexicalNode(anchorNode);
|
|
52
54
|
if (!tableCellNodeFromSelection) return disable();
|
|
53
55
|
tableCellParentNodeDOM = editor.getElementByKey(tableCellNodeFromSelection.getKey());
|
|
54
56
|
if (!tableCellParentNodeDOM || !tableCellNodeFromSelection.isAttached()) return disable();
|
|
@@ -59,8 +61,10 @@ const TableActionMenu = memo(({ cellMerge, editor }) => {
|
|
|
59
61
|
tableObserver = getTableObserverFromTableElement(tableElement);
|
|
60
62
|
setTableMenuCellNode(tableCellNodeFromSelection);
|
|
61
63
|
} else if ($isTableSelection(selection)) {
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
+
const selectionAnchorNode = $getNodeByKey(selection.anchor.key);
|
|
65
|
+
if (!selectionAnchorNode) return disable();
|
|
66
|
+
const anchorNode = $getTableCellNodeFromLexicalNode(selectionAnchorNode);
|
|
67
|
+
if (!$isTableCellNode(anchorNode)) return disable();
|
|
64
68
|
const tableNode = $getTableNodeFromLexicalNodeOrThrow(anchorNode);
|
|
65
69
|
const tableElement = getTableElement(tableNode, editor.getElementByKey(tableNode.getKey()));
|
|
66
70
|
if (tableElement === null) throw new Error("TableActionMenu: Expected to find tableElement in DOM");
|
|
@@ -68,6 +72,7 @@ const TableActionMenu = memo(({ cellMerge, editor }) => {
|
|
|
68
72
|
tableCellParentNodeDOM = editor.getElementByKey(anchorNode.getKey());
|
|
69
73
|
if (tableCellParentNodeDOM === null) return disable();
|
|
70
74
|
if (checkTableCellOverflow(tableCellParentNodeDOM)) return disable();
|
|
75
|
+
setTableMenuCellNode(anchorNode);
|
|
71
76
|
} else if (!activeElement) return disable();
|
|
72
77
|
if (tableObserver === null || tableCellParentNodeDOM === null) return disable();
|
|
73
78
|
const enabled = !tableObserver || !tableObserver.isSelecting;
|