@lobehub/editor 4.15.2 → 4.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/es/editor-kernel/react/useDecorators.js +14 -8
  2. package/es/headless/index.d.ts +1 -1
  3. package/es/headless/index.js +1 -1
  4. package/es/headless.d.ts +3 -18
  5. package/es/headless.js +711 -52
  6. package/es/index.d.ts +5 -5
  7. package/es/index.js +5 -5
  8. package/es/locale/index.d.ts +2 -0
  9. package/es/locale/index.js +5 -1
  10. package/es/plugins/auto-complete/plugin/index.js +3 -3
  11. package/es/plugins/block/index.d.ts +1 -1
  12. package/es/plugins/block/plugin/index.js +78 -2
  13. package/es/plugins/block/react/ReactBlockPlugin.js +172 -16
  14. package/es/plugins/block/react/drag/drag-utils.js +37 -10
  15. package/es/plugins/block/service/i-block-menu-service.d.ts +18 -1
  16. package/es/plugins/block/service/i-block-menu-service.js +24 -0
  17. package/es/plugins/block/service/index.d.ts +1 -1
  18. package/es/plugins/codeblock/plugin/index.js +25 -1
  19. package/es/plugins/common/plugin/register.js +2 -2
  20. package/es/plugins/litexml/command/diffCommand.d.ts +2 -17
  21. package/es/plugins/litexml/command/diffCommand.js +3 -9
  22. package/es/plugins/litexml/command/index.d.ts +2 -38
  23. package/es/plugins/litexml/command/index.js +3 -6
  24. package/es/plugins/litexml/command/symbols.d.ts +67 -0
  25. package/es/plugins/litexml/command/symbols.js +34 -0
  26. package/es/plugins/litexml/index.d.ts +1 -2
  27. package/es/plugins/litexml/plugin/index.js +8 -2
  28. package/es/plugins/litexml/react/DiffNodeToolbar/index.js +1 -1
  29. package/es/plugins/slash/plugin/index.js +1 -1
  30. package/es/plugins/slash/react/ReactSlashPlugin.js +4 -4
  31. package/es/plugins/table/command/index.d.ts +13 -1
  32. package/es/plugins/table/command/index.js +220 -39
  33. package/es/plugins/table/index.d.ts +3 -2
  34. package/es/plugins/table/node/index.d.ts +2 -0
  35. package/es/plugins/table/node/index.js +130 -2
  36. package/es/plugins/table/plugin/index.d.ts +6 -0
  37. package/es/plugins/table/plugin/index.js +193 -4
  38. package/es/plugins/table/react/TableActionMenu/ActionMenu.js +82 -6
  39. package/es/plugins/table/react/TableActionMenu/index.js +9 -4
  40. package/es/plugins/table/react/TableColController.js +354 -0
  41. package/es/plugins/table/react/TableController/hooks.js +201 -0
  42. package/es/plugins/table/react/TableController/style.js +264 -0
  43. package/es/plugins/table/react/TableController/utils.js +25 -0
  44. package/es/plugins/table/react/TableControllerButton.js +81 -0
  45. package/es/plugins/table/react/TableControllerMenu.js +123 -0
  46. package/es/plugins/table/react/TableInsertButton.js +25 -0
  47. package/es/plugins/table/react/TableResize/index.js +153 -78
  48. package/es/plugins/table/react/TableRowController.js +349 -0
  49. package/es/plugins/table/react/hooks.js +77 -0
  50. package/es/plugins/table/react/index.js +139 -16
  51. package/es/plugins/table/react/style.js +89 -8
  52. package/es/plugins/table/react/type.d.ts +2 -0
  53. package/es/plugins/table/react/useAutoFitPastedTable.js +189 -0
  54. package/es/plugins/table/service/i-table-controller-menu-service.d.ts +44 -0
  55. package/es/plugins/table/service/i-table-controller-menu-service.js +31 -0
  56. package/es/plugins/table/service/index.d.ts +1 -0
  57. package/es/plugins/table/utils/autoFitColumnWidth.js +87 -0
  58. package/es/plugins/table/utils/distributeColumnWidth.js +37 -0
  59. package/es/plugins/table/utils/index.js +102 -2
  60. package/es/react/EditorProvider/index.d.ts +2 -2
  61. package/es/renderer/LexicalDiff.d.ts +2 -2
  62. package/es/symbols-DEEvsKq4.d.ts +67 -0
  63. package/package.json +5 -1
@@ -1,57 +1,238 @@
1
- import { $createTableNodeWithDimensions, $createTableSelection, $findTableNode, $isTableNode, $isTableSelection } from "@lexical/table";
1
+ import { createDefaultTableColWidths, syncTableWidthDOM } from "../utils/index.js";
2
+ import { getAutoFitTableColumnWidths } from "../utils/autoFitColumnWidth.js";
3
+ import { getDistributedTableColumnWidths } from "../utils/distributeColumnWidth.js";
4
+ import { $computeTableMapSkipCellCheck, $createTableNodeWithDimensions, $createTableSelection, $findTableNode, $insertTableColumnAtSelection, $insertTableRowAtSelection, $isSimpleTable, $isTableNode, $isTableRowNode, $isTableSelection } from "@lexical/table";
2
5
  import { $getNodeByKey, $getPreviousSelection, $getSelection, $isElementNode, $isRangeSelection, $isTextNode, $setSelection, COMMAND_PRIORITY_EDITOR, createCommand } from "lexical";
3
6
  import { $insertNodeToNearestRoot, mergeRegister } from "@lexical/utils";
4
7
  //#region src/plugins/table/command/index.ts
5
8
  const INSERT_TABLE_COMMAND = createCommand();
6
9
  const SELECT_TABLE_COMMAND = createCommand();
10
+ const INSERT_TABLE_COLUMN_COMMAND = createCommand();
11
+ const INSERT_TABLE_ROW_COMMAND = createCommand();
12
+ const SYNC_TABLE_COLUMN_WIDTH_COMMAND = createCommand();
13
+ const AUTO_FIT_TABLE_COLUMN_WIDTH_COMMAND = createCommand();
14
+ const DISTRIBUTE_TABLE_COLUMN_WIDTH_COMMAND = createCommand();
15
+ const MOVE_TABLE_COLUMN_COMMAND = createCommand();
16
+ const MOVE_TABLE_ROW_COMMAND = createCommand();
17
+ const resetTableScrollLeft = (editor, tableKey) => {
18
+ const tableElement = editor.getElementByKey(tableKey);
19
+ const scrollWrapper = (tableElement instanceof HTMLTableElement ? tableElement : tableElement?.querySelector("table.editor_table, table"))?.closest(".lobe-editor-table-scroll-wrapper");
20
+ if (scrollWrapper) scrollWrapper.scrollLeft = 0;
21
+ };
22
+ const $selectFirstDescendant = (node) => {
23
+ const firstDescendant = node.getFirstDescendant();
24
+ if ($isTextNode(firstDescendant)) firstDescendant.select();
25
+ else node.selectStart();
26
+ };
27
+ const getMoveRange = (selectedIndexes, targetIndex, insertAfter = false) => {
28
+ if (selectedIndexes.length === 0) return null;
29
+ const sortedIndexes = [...selectedIndexes].sort((a, b) => a - b);
30
+ const from = sortedIndexes[0];
31
+ const to = sortedIndexes.at(-1) ?? from;
32
+ const count = to - from + 1;
33
+ const insertionIndex = insertAfter ? targetIndex + 1 : targetIndex;
34
+ if (insertionIndex >= from && insertionIndex <= to + 1) return null;
35
+ return {
36
+ count,
37
+ from,
38
+ target: insertionIndex > to ? insertionIndex - count : insertionIndex,
39
+ to
40
+ };
41
+ };
42
+ const $selectTableRows = (tableNode, from, to) => {
43
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
44
+ const firstRow = tableMap[from];
45
+ const lastRow = tableMap[to];
46
+ const firstCell = firstRow?.[0]?.cell;
47
+ const lastCell = lastRow?.[lastRow.length - 1]?.cell;
48
+ if (!firstCell || !lastCell) return false;
49
+ const tableSelection = $createTableSelection();
50
+ tableSelection.set(tableNode.getKey(), firstCell.getKey(), lastCell.getKey());
51
+ $setSelection(tableSelection);
52
+ return true;
53
+ };
54
+ const $selectTableColumns = (tableNode, from, to) => {
55
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
56
+ const firstCell = tableMap.find((row) => row[from])?.[from]?.cell;
57
+ const lastCell = [...tableMap].reverse().find((row) => row[to])?.[to]?.cell;
58
+ if (!firstCell || !lastCell) return false;
59
+ const tableSelection = $createTableSelection();
60
+ tableSelection.set(tableNode.getKey(), firstCell.getKey(), lastCell.getKey());
61
+ $setSelection(tableSelection);
62
+ return true;
63
+ };
64
+ const getRangeFromSelection = (selection, table, targetIndex, direction, crossAxisLength, anchorIndex) => {
65
+ if (anchorIndex !== void 0) return {
66
+ from: Math.min(anchorIndex, targetIndex),
67
+ to: Math.max(anchorIndex, targetIndex)
68
+ };
69
+ if (!$isTableSelection(selection) || selection.tableKey !== table) return {
70
+ from: 0,
71
+ to: targetIndex
72
+ };
73
+ const shape = selection.getShape();
74
+ if (!(direction === "row" ? shape.fromX === 0 && shape.toX === crossAxisLength - 1 : shape.fromY === 0 && shape.toY === crossAxisLength - 1)) return {
75
+ from: 0,
76
+ to: targetIndex
77
+ };
78
+ const from = direction === "row" ? shape.fromY : shape.fromX;
79
+ const to = direction === "row" ? shape.toY : shape.toX;
80
+ return {
81
+ from: Math.min(from, targetIndex),
82
+ to: Math.max(to, targetIndex)
83
+ };
84
+ };
7
85
  function registerTableCommand(editor) {
8
86
  return mergeRegister(editor.registerCommand(INSERT_TABLE_COMMAND, ({ rows, columns, includeHeaders }) => {
9
87
  const selection = $getSelection() || $getPreviousSelection();
10
88
  if (!selection || !$isRangeSelection(selection)) return false;
11
- if ($findTableNode(selection.anchor.getNode())) return false;
12
- const anchorNode = selection.anchor.getNode();
13
- const tableNode = $createTableNodeWithDimensions(Number(rows), Number(columns), includeHeaders);
89
+ const anchorNode = $getNodeByKey(selection.anchor.key);
90
+ if (!anchorNode) return false;
91
+ if ($findTableNode(anchorNode)) return false;
92
+ const rowCount = Number(rows);
93
+ const columnCount = Number(columns);
94
+ const tableNode = $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders);
95
+ tableNode.setColWidths(createDefaultTableColWidths(columnCount));
14
96
  if ($isElementNode(anchorNode) && anchorNode.isEmpty()) anchorNode.replace(tableNode);
15
97
  else $insertNodeToNearestRoot(tableNode);
16
98
  const firstDescendant = tableNode.getFirstDescendant();
17
99
  if ($isTextNode(firstDescendant)) firstDescendant.select();
18
100
  return true;
19
- }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(SELECT_TABLE_COMMAND, ({ table, columnIndex, rowIndex }) => {
20
- editor.update(() => {
21
- const prevSelection = $getSelection();
22
- const tableNode = $getNodeByKey(table);
23
- if (!tableNode || !$isTableNode(tableNode)) return;
24
- const tableSelection = $isTableSelection(prevSelection) ? prevSelection : $createTableSelection();
25
- if (rowIndex !== void 0) {
26
- const firstRow = tableNode.getChildren()[rowIndex];
27
- if (!firstRow) return;
28
- const firstCell = firstRow.getFirstChild();
29
- const lastCell = firstRow.getLastChild();
30
- if (!firstCell || !lastCell) return;
31
- tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
32
- $setSelection(tableSelection);
33
- } else if (columnIndex !== void 0) {
34
- const firstRow = tableNode.getFirstChild();
35
- const lastRow = tableNode.getLastChild();
36
- if (!firstRow || !lastRow) return;
37
- const firstCell = firstRow.getChildren()[columnIndex];
38
- const lastCell = lastRow.getChildren()[columnIndex];
39
- if (!firstCell || !lastCell) return;
40
- tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
41
- $setSelection(tableSelection);
42
- } else {
43
- const firstRow = tableNode.getFirstChild();
44
- const lastRow = tableNode.getLastChild();
45
- if (!firstRow || !lastRow) return;
46
- const firstCell = firstRow.getFirstChild();
47
- const lastCell = lastRow.getLastChild();
48
- if (!firstCell || !lastCell) return;
49
- tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
50
- $setSelection(tableSelection);
51
- }
101
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(INSERT_TABLE_COLUMN_COMMAND, ({ table, columnIndex, insertAfter = true }) => {
102
+ const tableNode = $getNodeByKey(table);
103
+ if (!tableNode || !$isTableNode(tableNode)) return false;
104
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
105
+ const firstCell = tableMap.find((row) => row[columnIndex])?.[columnIndex]?.cell;
106
+ const lastCell = [...tableMap].reverse().find((row) => row[columnIndex])?.[columnIndex]?.cell;
107
+ if (!firstCell || !lastCell) return false;
108
+ const tableSelection = $createTableSelection();
109
+ tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
110
+ $setSelection(tableSelection);
111
+ $insertTableColumnAtSelection(insertAfter);
112
+ return true;
113
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(INSERT_TABLE_ROW_COMMAND, ({ table, rowIndex, insertAfter = true }) => {
114
+ const tableNode = $getNodeByKey(table);
115
+ if (!tableNode || !$isTableNode(tableNode)) return false;
116
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
117
+ const row = tableMap[rowIndex];
118
+ const firstCell = row?.[0]?.cell;
119
+ const lastCell = row?.[row.length - 1]?.cell;
120
+ if (!firstCell || !lastCell) return false;
121
+ const tableSelection = $createTableSelection();
122
+ tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
123
+ $setSelection(tableSelection);
124
+ const insertedRow = $insertTableRowAtSelection(insertAfter);
125
+ if (insertedRow) $selectFirstDescendant(insertedRow);
126
+ return true;
127
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(SYNC_TABLE_COLUMN_WIDTH_COMMAND, ({ table, columnIndex }) => {
128
+ const tableNode = $getNodeByKey(table);
129
+ if (!tableNode || !$isTableNode(tableNode)) return false;
130
+ const columnCount = tableNode.getColumnCount();
131
+ const selectedWidth = (tableNode.getColWidths() || createDefaultTableColWidths(columnCount))[columnIndex];
132
+ if (selectedWidth === void 0) return false;
133
+ const nextColWidths = Array.from({ length: columnCount }, () => selectedWidth);
134
+ tableNode.setColWidths(nextColWidths);
135
+ requestAnimationFrame(() => {
136
+ syncTableWidthDOM(editor, table, nextColWidths);
137
+ });
138
+ return true;
139
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(AUTO_FIT_TABLE_COLUMN_WIDTH_COMMAND, ({ table, columnIndexes }) => {
140
+ const tableNode = $getNodeByKey(table);
141
+ if (!tableNode || !$isTableNode(tableNode)) return false;
142
+ const nextColWidths = getAutoFitTableColumnWidths(editor, tableNode, columnIndexes);
143
+ if (!nextColWidths) return false;
144
+ tableNode.setColWidths(nextColWidths);
145
+ requestAnimationFrame(() => {
146
+ syncTableWidthDOM(editor, table, nextColWidths);
147
+ });
148
+ return true;
149
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(DISTRIBUTE_TABLE_COLUMN_WIDTH_COMMAND, ({ table }) => {
150
+ const tableNode = $getNodeByKey(table);
151
+ if (!tableNode || !$isTableNode(tableNode)) return false;
152
+ const nextColWidths = getDistributedTableColumnWidths(editor, tableNode);
153
+ if (!nextColWidths) return false;
154
+ tableNode.setColWidths(nextColWidths);
155
+ requestAnimationFrame(() => {
156
+ syncTableWidthDOM(editor, table, nextColWidths);
157
+ resetTableScrollLeft(editor, table);
52
158
  });
53
- return false;
159
+ return true;
160
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(MOVE_TABLE_COLUMN_COMMAND, ({ table, selectedColumns, columnIndex, insertAfter = false }) => {
161
+ const tableNode = $getNodeByKey(table);
162
+ if (!tableNode || !$isTableNode(tableNode) || !$isSimpleTable(tableNode)) return false;
163
+ const moveRange = getMoveRange(selectedColumns, columnIndex, insertAfter);
164
+ if (!moveRange) return false;
165
+ const { count, from, target, to } = moveRange;
166
+ tableNode.getChildren().filter($isTableRowNode).forEach((row) => {
167
+ const cells = row.getChildren();
168
+ const movedCells = cells.slice(from, to + 1);
169
+ const nextCells = [...cells.slice(0, from), ...cells.slice(to + 1)];
170
+ nextCells.splice(target, 0, ...movedCells);
171
+ row.splice(0, cells.length, nextCells);
172
+ });
173
+ const colWidths = tableNode.getColWidths();
174
+ if (colWidths && colWidths.length === tableNode.getColumnCount()) {
175
+ const movedWidths = colWidths.slice(from, to + 1);
176
+ const nextWidths = [...colWidths.slice(0, from), ...colWidths.slice(to + 1)];
177
+ nextWidths.splice(target, 0, ...movedWidths);
178
+ tableNode.setColWidths(nextWidths);
179
+ }
180
+ $selectTableColumns(tableNode, target, target + count - 1);
181
+ return true;
182
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(MOVE_TABLE_ROW_COMMAND, ({ table, selectedRows, rowIndex, insertAfter = false }) => {
183
+ const tableNode = $getNodeByKey(table);
184
+ if (!tableNode || !$isTableNode(tableNode) || !$isSimpleTable(tableNode)) return false;
185
+ const moveRange = getMoveRange(selectedRows, rowIndex, insertAfter);
186
+ if (!moveRange) return false;
187
+ const { count, from, target, to } = moveRange;
188
+ const rows = tableNode.getChildren();
189
+ const movedRows = rows.slice(from, to + 1);
190
+ const nextRows = [...rows.slice(0, from), ...rows.slice(to + 1)];
191
+ nextRows.splice(target, 0, ...movedRows);
192
+ tableNode.splice(0, rows.length, nextRows);
193
+ $selectTableRows(tableNode, target, target + count - 1);
194
+ return true;
195
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(SELECT_TABLE_COMMAND, ({ table, anchorIndex, columnIndex, extend, rowIndex }) => {
196
+ const prevSelection = $getSelection();
197
+ const tableNode = $getNodeByKey(table);
198
+ if (!tableNode || !$isTableNode(tableNode)) return false;
199
+ const tableSelection = $isTableSelection(prevSelection) ? prevSelection : $createTableSelection();
200
+ const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null);
201
+ if (rowIndex !== void 0) {
202
+ const { from, to } = extend ? getRangeFromSelection(prevSelection, table, rowIndex, "row", tableNode.getColumnCount(), anchorIndex) : {
203
+ from: rowIndex,
204
+ to: rowIndex
205
+ };
206
+ const firstRow = tableMap[from];
207
+ const lastRow = tableMap[to];
208
+ const firstCell = firstRow?.[0]?.cell;
209
+ const lastCell = lastRow?.[lastRow.length - 1]?.cell;
210
+ if (!firstCell || !lastCell) return false;
211
+ tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
212
+ $setSelection(tableSelection);
213
+ return true;
214
+ }
215
+ if (columnIndex !== void 0) {
216
+ const { from, to } = extend ? getRangeFromSelection(prevSelection, table, columnIndex, "column", tableMap.length, anchorIndex) : {
217
+ from: columnIndex,
218
+ to: columnIndex
219
+ };
220
+ const firstCell = tableMap.find((row) => row[from])?.[from]?.cell;
221
+ const lastCell = [...tableMap].reverse().find((row) => row[to])?.[to]?.cell;
222
+ if (!firstCell || !lastCell) return false;
223
+ tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
224
+ $setSelection(tableSelection);
225
+ return true;
226
+ }
227
+ const firstRow = tableMap[0];
228
+ const lastRow = tableMap.at(-1);
229
+ const firstCell = firstRow?.[0]?.cell;
230
+ const lastCell = lastRow?.[lastRow.length - 1]?.cell;
231
+ if (!firstCell || !lastCell) return false;
232
+ tableSelection.set(table, firstCell.getKey(), lastCell.getKey());
233
+ $setSelection(tableSelection);
234
+ return true;
54
235
  }, COMMAND_PRIORITY_EDITOR));
55
236
  }
56
237
  //#endregion
57
- export { INSERT_TABLE_COMMAND, SELECT_TABLE_COMMAND, registerTableCommand };
238
+ export { AUTO_FIT_TABLE_COLUMN_WIDTH_COMMAND, DISTRIBUTE_TABLE_COLUMN_WIDTH_COMMAND, INSERT_TABLE_COLUMN_COMMAND, INSERT_TABLE_COMMAND, INSERT_TABLE_ROW_COMMAND, MOVE_TABLE_COLUMN_COMMAND, MOVE_TABLE_ROW_COMMAND, SELECT_TABLE_COMMAND, SYNC_TABLE_COLUMN_WIDTH_COMMAND, registerTableCommand };
@@ -1,3 +1,4 @@
1
- import { INSERT_TABLE_COMMAND, SELECT_TABLE_COMMAND } from "./command/index.js";
1
+ import { INSERT_TABLE_COLUMN_COMMAND, INSERT_TABLE_COMMAND, INSERT_TABLE_ROW_COMMAND, SELECT_TABLE_COMMAND } from "./command/index.js";
2
2
  import { TablePlugin, TablePluginOptions } from "./plugin/index.js";
3
- import { ReactTablePlugin } from "./react/index.js";
3
+ import { ReactTablePlugin } from "./react/index.js";
4
+ import { ITableControllerMenuActionItem, ITableControllerMenuItem, ITableControllerMenuRenderContext, ITableControllerMenuSeparatorItem, ITableControllerMenuService, TableControllerMenuAxis, TableControllerMenuService } from "./service/i-table-controller-menu-service.js";
@@ -0,0 +1,2 @@
1
+ import { TableNode as TableNode$1 } from "@lexical/table";
2
+ export { TableNode$1 as TableNode };
@@ -1,14 +1,142 @@
1
+ import { getKernelFromEditor, getKernelFromEditorConfig, reconcileDecorator } from "../../../editor-kernel/utils.js";
1
2
  import { TableNode, TableNode as TableNode$1 } from "@lexical/table";
3
+ import { setDOMUnmanaged } from "lexical";
2
4
  //#region src/plugins/table/node/index.ts
3
5
  const OriginalCreateDOM = TableNode.prototype.createDOM;
6
+ const OriginalUpdateDOM = TableNode.prototype.updateDOM;
7
+ const SCROLL_INDICATOR_WIDTH = 24;
8
+ function markTableControllerHost(element, withDecorator = false) {
9
+ setDOMUnmanaged(element);
10
+ if (withDecorator) element.dataset.lexicalDecorator = "true";
11
+ }
12
+ function updateTableScrollIndicators(scrollWrapper) {
13
+ const maxScrollLeft = scrollWrapper.scrollWidth - scrollWrapper.clientWidth;
14
+ const scrollLeft = scrollWrapper.scrollLeft;
15
+ const hasOverflow = maxScrollLeft > 1;
16
+ const showStart = hasOverflow && scrollLeft > 1;
17
+ const showEnd = hasOverflow && scrollLeft < maxScrollLeft - 1;
18
+ const startIndicator = scrollWrapper.querySelector(":scope > .lobe-editor-table-scroll-indicator-start");
19
+ const endIndicator = scrollWrapper.querySelector(":scope > .lobe-editor-table-scroll-indicator-end");
20
+ startIndicator?.classList.toggle("lobe-editor-table-scroll-indicator-visible", showStart);
21
+ endIndicator?.classList.toggle("lobe-editor-table-scroll-indicator-visible", showEnd);
22
+ if (startIndicator) startIndicator.style.transform = `translateX(${scrollLeft}px)`;
23
+ if (endIndicator) endIndicator.style.transform = `translateX(${Math.max(scrollLeft + scrollWrapper.clientWidth - SCROLL_INDICATOR_WIDTH, 0)}px)`;
24
+ }
25
+ function ensureTableScrollIndicators(scrollWrapper) {
26
+ const ensureIndicator = (className) => {
27
+ const existingIndicator = scrollWrapper.querySelector(`:scope > .${className}`);
28
+ if (existingIndicator instanceof HTMLElement) {
29
+ setDOMUnmanaged(existingIndicator);
30
+ return;
31
+ }
32
+ const indicator = document.createElement("span");
33
+ indicator.className = `lobe-editor-table-scroll-indicator ${className}`;
34
+ setDOMUnmanaged(indicator);
35
+ scrollWrapper.append(indicator);
36
+ };
37
+ ensureIndicator("lobe-editor-table-scroll-indicator-start");
38
+ ensureIndicator("lobe-editor-table-scroll-indicator-end");
39
+ if (scrollWrapper.dataset.scrollIndicatorsReady === "true") {
40
+ updateTableScrollIndicators(scrollWrapper);
41
+ return;
42
+ }
43
+ scrollWrapper.dataset.scrollIndicatorsReady = "true";
44
+ scrollWrapper.addEventListener("scroll", () => updateTableScrollIndicators(scrollWrapper), { passive: true });
45
+ const resizeObserver = new ResizeObserver(() => updateTableScrollIndicators(scrollWrapper));
46
+ resizeObserver.observe(scrollWrapper);
47
+ resizeObserver.observe(scrollWrapper.querySelector("table") ?? scrollWrapper);
48
+ requestAnimationFrame(() => updateTableScrollIndicators(scrollWrapper));
49
+ }
50
+ function ensureTableControllerDOM(element) {
51
+ const table = element instanceof HTMLTableElement ? element : element.querySelector("table");
52
+ if (!table) return;
53
+ let scrollWrapper = table.closest(".lobe-editor-table-scroll-wrapper");
54
+ if (!table.closest(".lobe-editor-table-scroll-wrapper")) {
55
+ scrollWrapper = document.createElement("div");
56
+ scrollWrapper.className = "lobe-editor-table-scroll-wrapper";
57
+ table.parentElement?.insertBefore(scrollWrapper, table);
58
+ scrollWrapper.append(table);
59
+ }
60
+ if (!scrollWrapper) return;
61
+ const legacyToolbar = element.querySelector(":scope > .toolbar");
62
+ if (legacyToolbar instanceof HTMLElement) {
63
+ legacyToolbar.className = "toolbar-col";
64
+ markTableControllerHost(legacyToolbar, true);
65
+ scrollWrapper.append(legacyToolbar);
66
+ }
67
+ const ensureToolbar = (parent, className, withDecorator = false) => {
68
+ const existingToolbar = parent.querySelector(`:scope > .${className}`);
69
+ if (existingToolbar instanceof HTMLElement) {
70
+ markTableControllerHost(existingToolbar, withDecorator);
71
+ return;
72
+ }
73
+ if (!existingToolbar) {
74
+ const toolbar = document.createElement("div");
75
+ toolbar.className = className;
76
+ markTableControllerHost(toolbar, withDecorator);
77
+ parent.append(toolbar);
78
+ }
79
+ };
80
+ const legacyDecoratedToolbar = scrollWrapper.querySelector(":scope > .toolbar[data-lexical-decorator]");
81
+ if (legacyDecoratedToolbar instanceof HTMLElement) {
82
+ legacyDecoratedToolbar.className = "toolbar-col";
83
+ markTableControllerHost(legacyDecoratedToolbar, true);
84
+ }
85
+ const legacyPlainToolbar = scrollWrapper.querySelector(":scope > .toolbar:not([data-lexical-decorator])");
86
+ if (legacyPlainToolbar instanceof HTMLElement) {
87
+ legacyPlainToolbar.className = "toolbar-row";
88
+ markTableControllerHost(legacyPlainToolbar, true);
89
+ element.append(legacyPlainToolbar);
90
+ }
91
+ ensureToolbar(scrollWrapper, "toolbar-col", true);
92
+ ensureToolbar(element, "toolbar-row", true);
93
+ ensureTableScrollIndicators(scrollWrapper);
94
+ }
95
+ function reconcileTableDecorator(editor, node, decorator) {
96
+ if (!decorator) return;
97
+ if (typeof decorator === "function") {
98
+ reconcileDecorator(editor, node.getKey(), decorator(node, editor));
99
+ return;
100
+ }
101
+ if ("multi" in decorator) {
102
+ const decorators = decorator.multi.map((item) => ({
103
+ queryDOM: item.queryDOM,
104
+ render: item.render(node, editor)
105
+ }));
106
+ reconcileDecorator(editor, node.getKey(), { multi: decorators });
107
+ return;
108
+ }
109
+ reconcileDecorator(editor, node.getKey(), {
110
+ queryDOM: decorator.queryDOM,
111
+ render: decorator.render(node, editor)
112
+ });
113
+ }
4
114
  function patchTableNode() {
115
+ if (TableNode.prototype.createDOM !== OriginalCreateDOM) return;
5
116
  Object.defineProperty(TableNode.prototype, "createDOM", {
6
117
  configurable: true,
7
118
  enumerable: false,
8
119
  value: function(config, editor) {
9
120
  const table = OriginalCreateDOM.call(this, config, editor);
10
- const controller = document.createElement("div");
11
- table.append(controller);
121
+ ensureTableControllerDOM(table);
122
+ const decorator = getKernelFromEditor(editor)?.getDecorator(TableNode.getType()) || null;
123
+ reconcileTableDecorator(editor, this, decorator);
124
+ return table;
125
+ },
126
+ writable: true
127
+ });
128
+ Object.defineProperty(TableNode.prototype, "updateDOM", {
129
+ configurable: true,
130
+ enumerable: false,
131
+ value: function(_prevNode, _dom, _config) {
132
+ const table = OriginalUpdateDOM.call(this, _prevNode, _dom, _config);
133
+ ensureTableControllerDOM(_dom);
134
+ const kernel = getKernelFromEditorConfig(_config);
135
+ const editor = kernel?.getLexicalEditor();
136
+ if (editor) {
137
+ const decorator = kernel?.getDecorator(TableNode.getType()) || null;
138
+ reconcileTableDecorator(editor, this, decorator);
139
+ }
12
140
  return table;
13
141
  },
14
142
  writable: true
@@ -1,6 +1,12 @@
1
1
  import { IEditorPluginConstructor } from "../../../types/kernel.js";
2
+ import { TableNode } from "../node/index.js";
3
+ import { ReactNode } from "react";
4
+ import { LexicalEditor } from "lexical";
5
+
2
6
  //#region src/plugins/table/plugin/index.d.ts
3
7
  interface TablePluginOptions {
8
+ decoratorCol?: (node: TableNode, editor: LexicalEditor) => ReactNode;
9
+ decoratorRow?: (node: TableNode, editor: LexicalEditor) => ReactNode;
4
10
  theme?: string;
5
11
  }
6
12
  declare const TablePlugin: IEditorPluginConstructor<TablePluginOptions>;