@lexical/table 0.1.13 → 0.1.16
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/LexicalTable.d.ts +221 -0
- package/LexicalTable.dev.js +673 -475
- package/LexicalTable.prod.js +32 -24
- package/package.json +5 -2
package/LexicalTable.dev.js
CHANGED
@@ -6,58 +6,89 @@
|
|
6
6
|
*/
|
7
7
|
'use strict';
|
8
8
|
|
9
|
+
var utils = require('@lexical/utils');
|
9
10
|
var lexical = require('lexical');
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
*/
|
19
|
-
function addClassNamesToElement(element, ...classNames) {
|
20
|
-
classNames.forEach(className => {
|
21
|
-
if (className != null && typeof className === 'string') {
|
22
|
-
element.classList.add(...className.split(' '));
|
23
|
-
}
|
24
|
-
});
|
25
|
-
}
|
26
|
-
|
27
|
-
/**
|
28
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
29
|
-
*
|
30
|
-
* This source code is licensed under the MIT license found in the
|
31
|
-
* LICENSE file in the root directory of this source tree.
|
32
|
-
*
|
33
|
-
*
|
34
|
-
*/
|
12
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
13
|
+
const TableCellHeaderStates = {
|
14
|
+
NO_STATUS: 0,
|
15
|
+
ROW: 1,
|
16
|
+
COLUMN: 2,
|
17
|
+
BOTH: 3
|
18
|
+
};
|
35
19
|
class TableCellNode extends lexical.GridCellNode {
|
36
20
|
static getType() {
|
37
21
|
return 'tablecell';
|
38
22
|
}
|
39
23
|
|
40
24
|
static clone(node) {
|
41
|
-
return new TableCellNode(
|
25
|
+
return new TableCellNode(node.__headerState, node.__colSpan, node.__width, node.__key);
|
42
26
|
}
|
43
27
|
|
44
|
-
constructor(
|
28
|
+
constructor(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width, key) {
|
45
29
|
super(colSpan, key);
|
46
|
-
this.
|
47
|
-
|
48
|
-
|
49
|
-
getTag() {
|
50
|
-
return this.__isHeader ? 'th' : 'td';
|
30
|
+
this.__headerState = headerState;
|
31
|
+
this.__width = width;
|
51
32
|
}
|
52
33
|
|
53
34
|
createDOM(config) {
|
54
35
|
const element = document.createElement(this.getTag());
|
55
|
-
|
36
|
+
|
37
|
+
if (this.__width) {
|
38
|
+
element.style.width = `${this.__width}px`;
|
39
|
+
}
|
40
|
+
|
41
|
+
utils.addClassNamesToElement(element, config.theme.tableCell, this.hasHeader() && config.theme.tableCellHeader);
|
56
42
|
return element;
|
57
43
|
}
|
58
44
|
|
59
|
-
|
60
|
-
return
|
45
|
+
getTag() {
|
46
|
+
return this.hasHeader() ? 'th' : 'td';
|
47
|
+
}
|
48
|
+
|
49
|
+
setHeaderStyles(headerState) {
|
50
|
+
const self = this.getWritable();
|
51
|
+
self.__headerState = headerState;
|
52
|
+
return this.__headerState;
|
53
|
+
}
|
54
|
+
|
55
|
+
getHeaderStyles() {
|
56
|
+
return this.getLatest().__headerState;
|
57
|
+
}
|
58
|
+
|
59
|
+
setWidth(width) {
|
60
|
+
const self = this.getWritable();
|
61
|
+
self.__width = width;
|
62
|
+
return this.__width;
|
63
|
+
}
|
64
|
+
|
65
|
+
getWidth() {
|
66
|
+
return this.getLatest().__width;
|
67
|
+
}
|
68
|
+
|
69
|
+
toggleHeaderStyle(headerStateToToggle) {
|
70
|
+
const self = this.getWritable();
|
71
|
+
|
72
|
+
if ((self.__headerState & headerStateToToggle) === headerStateToToggle) {
|
73
|
+
self.__headerState -= headerStateToToggle;
|
74
|
+
} else {
|
75
|
+
self.__headerState += headerStateToToggle;
|
76
|
+
}
|
77
|
+
|
78
|
+
self.__headerState = self.__headerState;
|
79
|
+
return self;
|
80
|
+
}
|
81
|
+
|
82
|
+
hasHeaderState(headerState) {
|
83
|
+
return (this.getHeaderStyles() & headerState) === headerState;
|
84
|
+
}
|
85
|
+
|
86
|
+
hasHeader() {
|
87
|
+
return this.getLatest().__headerState !== TableCellHeaderStates.NO_STATUS;
|
88
|
+
}
|
89
|
+
|
90
|
+
updateDOM(prevNode) {
|
91
|
+
return prevNode.__headerState !== this.__headerState || prevNode.__width !== this.__width;
|
61
92
|
}
|
62
93
|
|
63
94
|
collapseAtStart() {
|
@@ -69,8 +100,8 @@ class TableCellNode extends lexical.GridCellNode {
|
|
69
100
|
}
|
70
101
|
|
71
102
|
}
|
72
|
-
function $createTableCellNode(
|
73
|
-
return new TableCellNode(
|
103
|
+
function $createTableCellNode(headerState, colSpan = 1, width) {
|
104
|
+
return new TableCellNode(headerState, colSpan, width);
|
74
105
|
}
|
75
106
|
function $isTableCellNode(node) {
|
76
107
|
return node instanceof TableCellNode;
|
@@ -84,29 +115,8 @@ function $isTableCellNode(node) {
|
|
84
115
|
*
|
85
116
|
*
|
86
117
|
*/
|
87
|
-
|
88
|
-
let curr = startingNode;
|
89
|
-
|
90
|
-
while (curr !== lexical.$getRoot() && curr != null) {
|
91
|
-
if (findFn(curr)) {
|
92
|
-
return curr;
|
93
|
-
}
|
118
|
+
const getSelection = () => window.getSelection();
|
94
119
|
|
95
|
-
curr = curr.getParent();
|
96
|
-
}
|
97
|
-
|
98
|
-
return null;
|
99
|
-
}
|
100
|
-
|
101
|
-
/**
|
102
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
103
|
-
*
|
104
|
-
* This source code is licensed under the MIT license found in the
|
105
|
-
* LICENSE file in the root directory of this source tree.
|
106
|
-
*
|
107
|
-
*
|
108
|
-
*/
|
109
|
-
const getSelection = window.getSelection;
|
110
120
|
var getDOMSelection = getSelection;
|
111
121
|
|
112
122
|
/**
|
@@ -117,189 +127,307 @@ var getDOMSelection = getSelection;
|
|
117
127
|
*
|
118
128
|
*
|
119
129
|
*/
|
120
|
-
const LowPriority = 1;
|
121
|
-
const CriticalPriority = 4;
|
122
130
|
const removeHighlightStyle = document.createElement('style');
|
123
131
|
removeHighlightStyle.appendChild(document.createTextNode('::selection{background-color: transparent}'));
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
132
|
+
class TableSelection {
|
133
|
+
constructor(editor, tableNodeKey) {
|
134
|
+
this.isMouseDown = false;
|
135
|
+
this.isHighlightingCells = false;
|
136
|
+
this.startX = -1;
|
137
|
+
this.startY = -1;
|
138
|
+
this.currentX = -1;
|
139
|
+
this.currentY = -1;
|
140
|
+
this.listenersToRemove = new Set();
|
141
|
+
this.tableNodeKey = tableNodeKey;
|
142
|
+
this.editor = editor;
|
143
|
+
this.grid = {
|
144
|
+
cells: [],
|
145
|
+
columns: 0,
|
146
|
+
rows: 0
|
147
|
+
};
|
148
|
+
this.gridSelection = null;
|
149
|
+
this.anchorCellNodeKey = null;
|
150
|
+
this.focusCellNodeKey = null;
|
151
|
+
this.trackTableGrid();
|
152
|
+
}
|
137
153
|
|
138
|
-
|
139
|
-
|
154
|
+
getGrid() {
|
155
|
+
return this.grid;
|
156
|
+
}
|
140
157
|
|
141
|
-
|
158
|
+
removeListeners() {
|
159
|
+
Array.from(this.listenersToRemove).forEach(removeListener => removeListener());
|
142
160
|
}
|
143
161
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
const grid = {
|
149
|
-
cells,
|
150
|
-
columns: 0,
|
151
|
-
rows: 0
|
152
|
-
};
|
162
|
+
trackTableGrid() {
|
163
|
+
const observer = new MutationObserver(records => {
|
164
|
+
this.editor.update(() => {
|
165
|
+
let gridNeedsRedraw = false;
|
153
166
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
cells.length = 0;
|
159
|
-
|
160
|
-
while (currentNode != null) {
|
161
|
-
const nodeMame = currentNode.nodeName;
|
162
|
-
|
163
|
-
if (nodeMame === 'TD' || nodeMame === 'TH') {
|
164
|
-
// $FlowFixMe: TD is always an HTMLElement
|
165
|
-
const elem = currentNode;
|
166
|
-
const cell = {
|
167
|
-
elem,
|
168
|
-
highlighted: false,
|
169
|
-
x,
|
170
|
-
y
|
171
|
-
}; // $FlowFixMe: internal field
|
167
|
+
for (let i = 0; i < records.length; i++) {
|
168
|
+
const record = records[i];
|
169
|
+
const target = record.target;
|
170
|
+
const nodeName = target.nodeName;
|
172
171
|
|
173
|
-
|
172
|
+
if (nodeName === 'TABLE' || nodeName === 'TR') {
|
173
|
+
gridNeedsRedraw = true;
|
174
|
+
break;
|
175
|
+
}
|
176
|
+
}
|
174
177
|
|
175
|
-
if (
|
176
|
-
|
178
|
+
if (!gridNeedsRedraw) {
|
179
|
+
return;
|
177
180
|
}
|
178
181
|
|
179
|
-
|
180
|
-
} else {
|
181
|
-
const child = currentNode.firstChild;
|
182
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
182
183
|
|
183
|
-
if (
|
184
|
-
|
185
|
-
continue;
|
184
|
+
if (!tableElement) {
|
185
|
+
throw new Error('Expected to find TableElement in DOM');
|
186
186
|
}
|
187
|
+
|
188
|
+
this.grid = getTableGrid(tableElement);
|
189
|
+
});
|
190
|
+
});
|
191
|
+
this.editor.update(() => {
|
192
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
193
|
+
|
194
|
+
if (!tableElement) {
|
195
|
+
throw new Error('Expected to find TableElement in DOM');
|
187
196
|
}
|
188
197
|
|
189
|
-
|
198
|
+
this.grid = getTableGrid(tableElement);
|
199
|
+
observer.observe(tableElement, {
|
200
|
+
childList: true,
|
201
|
+
subtree: true
|
202
|
+
});
|
203
|
+
});
|
204
|
+
}
|
190
205
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
206
|
+
clearHighlight() {
|
207
|
+
this.editor.update(() => {
|
208
|
+
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
209
|
+
|
210
|
+
if (!$isTableNode(tableNode)) {
|
211
|
+
throw new Error('Expected TableNode.');
|
195
212
|
}
|
196
213
|
|
197
|
-
const
|
214
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
215
|
+
|
216
|
+
if (!tableElement) {
|
217
|
+
throw new Error('Expected to find TableElement in DOM');
|
218
|
+
}
|
219
|
+
|
220
|
+
const grid = getTableGrid(tableElement);
|
221
|
+
this.isHighlightingCells = false;
|
222
|
+
this.isMouseDown = false;
|
223
|
+
this.startX = -1;
|
224
|
+
this.startY = -1;
|
225
|
+
this.currentX = -1;
|
226
|
+
this.currentY = -1;
|
227
|
+
$updateDOMForSelection(grid, null);
|
228
|
+
this.gridSelection = null;
|
229
|
+
lexical.$setSelection(null);
|
230
|
+
const parent = removeHighlightStyle.parentNode;
|
198
231
|
|
199
232
|
if (parent != null) {
|
200
|
-
|
233
|
+
parent.removeChild(removeHighlightStyle);
|
234
|
+
}
|
235
|
+
});
|
236
|
+
}
|
201
237
|
|
202
|
-
|
203
|
-
|
204
|
-
|
238
|
+
adjustFocusCellForSelection(cell, ignoreStart = false) {
|
239
|
+
this.editor.update(() => {
|
240
|
+
this.isMouseDown = true;
|
241
|
+
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
205
242
|
|
206
|
-
|
207
|
-
|
208
|
-
currentNode = parentSibling;
|
243
|
+
if (!$isTableNode(tableNode)) {
|
244
|
+
throw new Error('Expected TableNode.');
|
209
245
|
}
|
210
|
-
}
|
211
246
|
|
212
|
-
|
213
|
-
grid.rows = y + 1;
|
214
|
-
tableNode.setGrid(grid);
|
215
|
-
};
|
247
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
216
248
|
|
217
|
-
|
218
|
-
|
219
|
-
|
249
|
+
if (!tableElement) {
|
250
|
+
throw new Error('Expected to find TableElement in DOM');
|
251
|
+
}
|
252
|
+
|
253
|
+
const cellX = cell.x;
|
254
|
+
const cellY = cell.y;
|
220
255
|
|
221
|
-
|
222
|
-
const
|
223
|
-
const
|
224
|
-
const nodeName = target.nodeName;
|
256
|
+
if (!this.isHighlightingCells && (this.startX !== cellX || this.startY !== cellY || ignoreStart)) {
|
257
|
+
const domSelection = getDOMSelection();
|
258
|
+
const anchorNode = domSelection.anchorNode;
|
225
259
|
|
226
|
-
if (
|
227
|
-
|
228
|
-
|
260
|
+
if (anchorNode !== null) {
|
261
|
+
// Collapse the selection
|
262
|
+
domSelection.setBaseAndExtent(anchorNode, 0, anchorNode, 0);
|
229
263
|
}
|
230
|
-
}
|
231
264
|
|
232
|
-
|
265
|
+
this.isHighlightingCells = true;
|
266
|
+
|
267
|
+
if (document.body) {
|
268
|
+
document.body.appendChild(removeHighlightStyle);
|
269
|
+
}
|
270
|
+
} else if (cellX === this.currentX && cellY === this.currentY) {
|
233
271
|
return;
|
234
272
|
}
|
235
273
|
|
236
|
-
|
274
|
+
this.currentX = cellX;
|
275
|
+
this.currentY = cellY;
|
276
|
+
|
277
|
+
if (this.isHighlightingCells) {
|
278
|
+
const focusTableCellNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
279
|
+
|
280
|
+
if (this.gridSelection != null && this.anchorCellNodeKey != null && $isTableCellNode(focusTableCellNode)) {
|
281
|
+
const focusNodeKey = focusTableCellNode.getKey();
|
282
|
+
this.gridSelection = lexical.$createGridSelection();
|
283
|
+
this.focusCellNodeKey = focusNodeKey;
|
284
|
+
this.gridSelection.set(this.tableNodeKey, // $FlowFixMe This is not null, as you can see in the statement above.
|
285
|
+
this.anchorCellNodeKey, this.focusCellNodeKey);
|
286
|
+
lexical.$setSelection(this.gridSelection);
|
287
|
+
$updateDOMForSelection(this.grid, this.gridSelection);
|
288
|
+
}
|
289
|
+
}
|
237
290
|
});
|
238
|
-
}
|
239
|
-
observer.observe(tableElement, {
|
240
|
-
childList: true,
|
241
|
-
subtree: true
|
242
|
-
});
|
243
|
-
calcSize();
|
244
|
-
return grid;
|
245
|
-
}
|
246
|
-
function updateCells(fromX, toX, fromY, toY, cells) {
|
247
|
-
const highlighted = [];
|
291
|
+
}
|
248
292
|
|
249
|
-
|
250
|
-
|
293
|
+
setAnchorCellForSelection(cell) {
|
294
|
+
this.editor.update(() => {
|
295
|
+
this.startX = cell.x;
|
296
|
+
this.startY = cell.y;
|
297
|
+
this.isMouseDown = true;
|
298
|
+
const anchorTableCellNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
299
|
+
|
300
|
+
if ($isTableCellNode(anchorTableCellNode)) {
|
301
|
+
const anchorNodeKey = anchorTableCellNode.getKey();
|
302
|
+
this.gridSelection = lexical.$createGridSelection();
|
303
|
+
this.anchorCellNodeKey = anchorNodeKey;
|
304
|
+
}
|
305
|
+
});
|
306
|
+
document.addEventListener('mouseup', () => {
|
307
|
+
this.isMouseDown = false;
|
308
|
+
}, {
|
309
|
+
capture: true,
|
310
|
+
once: true
|
311
|
+
});
|
312
|
+
}
|
251
313
|
|
252
|
-
|
253
|
-
|
254
|
-
const
|
314
|
+
formatCells(type) {
|
315
|
+
this.editor.update(() => {
|
316
|
+
const selection = lexical.$getSelection();
|
255
317
|
|
256
|
-
if (
|
257
|
-
|
258
|
-
|
259
|
-
elemStyle.setProperty('background-color', 'rgb(163, 187, 255)');
|
260
|
-
elemStyle.setProperty('caret-color', 'transparent');
|
318
|
+
if (!lexical.$isGridSelection(selection)) {
|
319
|
+
{
|
320
|
+
throw Error(`Expected grid selection`);
|
261
321
|
}
|
322
|
+
} // This is to make Flow play ball.
|
262
323
|
|
263
|
-
highlighted.push(cell);
|
264
|
-
} else if (cell.highlighted) {
|
265
|
-
cell.highlighted = false;
|
266
|
-
elemStyle.removeProperty('background-color');
|
267
|
-
elemStyle.removeProperty('caret-color');
|
268
324
|
|
269
|
-
|
270
|
-
|
325
|
+
const formatSelection = lexical.$createRangeSelection();
|
326
|
+
const anchor = formatSelection.anchor;
|
327
|
+
const focus = formatSelection.focus;
|
328
|
+
selection.getNodes().forEach(cellNode => {
|
329
|
+
if (lexical.$isElementNode(cellNode) && cellNode.getTextContentSize() !== 0) {
|
330
|
+
anchor.set(cellNode.getKey(), 0, 'element');
|
331
|
+
focus.set(cellNode.getKey(), cellNode.getChildrenSize(), 'element');
|
332
|
+
formatSelection.formatText(type);
|
271
333
|
}
|
334
|
+
});
|
335
|
+
lexical.$setSelection(selection);
|
336
|
+
});
|
337
|
+
}
|
338
|
+
|
339
|
+
clearText() {
|
340
|
+
this.editor.update(() => {
|
341
|
+
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
342
|
+
|
343
|
+
if (!$isTableNode(tableNode)) {
|
344
|
+
throw new Error('Expected TableNode.');
|
272
345
|
}
|
273
|
-
|
346
|
+
|
347
|
+
const selection = lexical.$getSelection();
|
348
|
+
|
349
|
+
if (!lexical.$isGridSelection(selection)) {
|
350
|
+
{
|
351
|
+
throw Error(`Expected grid selection`);
|
352
|
+
}
|
353
|
+
}
|
354
|
+
|
355
|
+
const selectedNodes = selection.getNodes();
|
356
|
+
|
357
|
+
if (selectedNodes.length === this.grid.columns * this.grid.rows) {
|
358
|
+
tableNode.selectPrevious(); // Delete entire table
|
359
|
+
|
360
|
+
tableNode.remove();
|
361
|
+
this.clearHighlight();
|
362
|
+
return;
|
363
|
+
}
|
364
|
+
|
365
|
+
selectedNodes.forEach(cellNode => {
|
366
|
+
if (lexical.$isElementNode(cellNode)) {
|
367
|
+
const paragraphNode = lexical.$createParagraphNode();
|
368
|
+
const textNode = lexical.$createTextNode();
|
369
|
+
paragraphNode.append(textNode);
|
370
|
+
cellNode.append(paragraphNode);
|
371
|
+
cellNode.getChildren().forEach(child => {
|
372
|
+
if (child !== paragraphNode) {
|
373
|
+
child.remove();
|
374
|
+
}
|
375
|
+
});
|
376
|
+
}
|
377
|
+
});
|
378
|
+
$updateDOMForSelection(this.grid, null);
|
379
|
+
lexical.$setSelection(null);
|
380
|
+
});
|
274
381
|
}
|
275
382
|
|
276
|
-
return highlighted;
|
277
383
|
}
|
278
|
-
|
384
|
+
|
385
|
+
/**
|
386
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
387
|
+
*
|
388
|
+
* This source code is licensed under the MIT license found in the
|
389
|
+
* LICENSE file in the root directory of this source tree.
|
390
|
+
*
|
391
|
+
*
|
392
|
+
*/
|
393
|
+
const CriticalPriority = 4;
|
394
|
+
const LEXICAL_ELEMENT_KEY = '__lexicalTableSelection';
|
395
|
+
function applyTableHandlers(tableNode, tableElement, editor) {
|
279
396
|
const rootElement = editor.getRootElement();
|
280
397
|
|
281
398
|
if (rootElement === null) {
|
282
399
|
throw new Error('No root element.');
|
283
400
|
}
|
284
401
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
402
|
+
const tableSelection = new TableSelection(editor, tableNode.getKey());
|
403
|
+
attachTableSelectionToTableElement(tableElement, tableSelection);
|
404
|
+
tableElement.addEventListener('dblclick', event => {
|
405
|
+
// $FlowFixMe: event.target is always a Node on the DOM
|
406
|
+
const cell = getCellFromTarget(event.target);
|
407
|
+
|
408
|
+
if (cell !== null) {
|
409
|
+
event.preventDefault();
|
410
|
+
event.stopImmediatePropagation();
|
411
|
+
event.stopPropagation();
|
412
|
+
tableSelection.setAnchorCellForSelection(cell);
|
413
|
+
tableSelection.adjustFocusCellForSelection(cell, true);
|
414
|
+
tableSelection.isMouseDown = false;
|
415
|
+
}
|
416
|
+
}); // This is the anchor of the selection.
|
296
417
|
|
297
|
-
|
298
|
-
|
299
|
-
|
418
|
+
tableElement.addEventListener('mousedown', event => {
|
419
|
+
setTimeout(() => {
|
420
|
+
// $FlowFixMe: event.target is always a Node on the DOM
|
421
|
+
const cell = getCellFromTarget(event.target);
|
422
|
+
|
423
|
+
if (cell !== null) {
|
424
|
+
tableSelection.setAnchorCellForSelection(cell);
|
425
|
+
}
|
426
|
+
}, 0);
|
427
|
+
}); // This is adjusting the focus of the selection.
|
300
428
|
|
301
429
|
tableElement.addEventListener('mousemove', event => {
|
302
|
-
if (
|
430
|
+
if (tableSelection.isMouseDown) {
|
303
431
|
// $FlowFixMe: event.target is always a Node on the DOM
|
304
432
|
const cell = getCellFromTarget(event.target);
|
305
433
|
|
@@ -307,285 +435,306 @@ function $applyCustomTableHandlers(tableNode, tableElement, editor) {
|
|
307
435
|
const cellX = cell.x;
|
308
436
|
const cellY = cell.y;
|
309
437
|
|
310
|
-
if (
|
438
|
+
if (tableSelection.isMouseDown && (tableSelection.startX !== cellX || tableSelection.startY !== cellY || tableSelection.isHighlightingCells)) {
|
311
439
|
event.preventDefault();
|
312
|
-
|
313
|
-
const anchorNode = domSelection.anchorNode;
|
314
|
-
|
315
|
-
if (anchorNode !== null) {
|
316
|
-
// Collapse the selection
|
317
|
-
domSelection.setBaseAndExtent(anchorNode, 0, anchorNode, 0);
|
318
|
-
}
|
319
|
-
|
320
|
-
isHighlightingCells = true;
|
321
|
-
|
322
|
-
if (document.body) {
|
323
|
-
document.body.appendChild(removeHighlightStyle);
|
324
|
-
}
|
325
|
-
|
326
|
-
if (deleteCharacterListener === null) {
|
327
|
-
deleteCharacterListener = editor.addListener('command', (type, payload) => {
|
328
|
-
if (type === 'deleteCharacter') {
|
329
|
-
if (highlightedCells.length === grid.columns * grid.rows) {
|
330
|
-
tableNode.selectPrevious(); // Delete entire table
|
331
|
-
|
332
|
-
tableNode.remove();
|
333
|
-
clearHighlight();
|
334
|
-
return true;
|
335
|
-
}
|
336
|
-
|
337
|
-
highlightedCells.forEach(({
|
338
|
-
elem
|
339
|
-
}) => {
|
340
|
-
const cellNode = lexical.$getNearestNodeFromDOMNode(elem);
|
341
|
-
|
342
|
-
if (lexical.$isElementNode(cellNode)) {
|
343
|
-
const paragraphNode = lexical.$createParagraphNode();
|
344
|
-
const textNode = lexical.$createTextNode();
|
345
|
-
paragraphNode.append(textNode);
|
346
|
-
cellNode.append(paragraphNode);
|
347
|
-
cellNode.getChildren().forEach(child => {
|
348
|
-
if (child !== paragraphNode) {
|
349
|
-
child.remove();
|
350
|
-
}
|
351
|
-
});
|
352
|
-
}
|
353
|
-
});
|
354
|
-
tableNode.setSelectionState(null);
|
355
|
-
lexical.$setSelection(null);
|
356
|
-
return true;
|
357
|
-
} else if (type === 'formatText') {
|
358
|
-
formatCells(payload);
|
359
|
-
return true;
|
360
|
-
} else if (type === 'insertText') {
|
361
|
-
clearHighlight();
|
362
|
-
return false;
|
363
|
-
}
|
364
|
-
|
365
|
-
return false;
|
366
|
-
}, LowPriority);
|
367
|
-
editorListeners.add(deleteCharacterListener);
|
368
|
-
}
|
369
|
-
} else if (cellX === currentX && cellY === currentY) {
|
370
|
-
return;
|
371
|
-
}
|
372
|
-
|
373
|
-
currentX = cellX;
|
374
|
-
currentY = cellY;
|
375
|
-
|
376
|
-
if (isHighlightingCells) {
|
377
|
-
const fromX = Math.min(startX, currentX);
|
378
|
-
const toX = Math.max(startX, currentX);
|
379
|
-
const fromY = Math.min(startY, currentY);
|
380
|
-
const toY = Math.max(startY, currentY);
|
381
|
-
editor.update(() => {
|
382
|
-
highlightedCells = tableNode.setSelectionState({
|
383
|
-
fromX,
|
384
|
-
fromY,
|
385
|
-
toX,
|
386
|
-
toY
|
387
|
-
});
|
388
|
-
});
|
440
|
+
tableSelection.adjustFocusCellForSelection(cell);
|
389
441
|
}
|
390
442
|
}
|
391
443
|
}
|
392
444
|
});
|
445
|
+
tableElement.addEventListener('mouseup', event => {
|
446
|
+
if (tableSelection.isMouseDown) {
|
447
|
+
tableSelection.isMouseDown = false;
|
448
|
+
}
|
449
|
+
}); // Select entire table at this point, when grid selection is ready.
|
393
450
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
startY = -1;
|
400
|
-
currentX = -1;
|
401
|
-
currentY = -1;
|
402
|
-
editor.update(() => {
|
403
|
-
tableNode.setSelectionState(null);
|
404
|
-
});
|
405
|
-
highlightedCells = [];
|
406
|
-
|
407
|
-
if (deleteCharacterListener !== null) {
|
408
|
-
deleteCharacterListener();
|
409
|
-
deleteCharacterListener = null;
|
410
|
-
editorListeners.delete(deleteCharacterListener);
|
411
|
-
}
|
451
|
+
tableElement.addEventListener('mouseleave', event => {
|
452
|
+
if (tableSelection.isMouseDown) {
|
453
|
+
return;
|
454
|
+
}
|
455
|
+
}); // Clear selection when clicking outside of dom.
|
412
456
|
|
413
|
-
|
457
|
+
const mouseDownCallback = e => {
|
458
|
+
editor.update(() => {
|
459
|
+
const selection = lexical.$getSelection();
|
414
460
|
|
415
|
-
if (
|
416
|
-
|
461
|
+
if (lexical.$isGridSelection(selection) && selection.gridKey === tableSelection.tableNodeKey && rootElement.contains(e.target)) {
|
462
|
+
return tableSelection.clearHighlight();
|
417
463
|
}
|
418
464
|
});
|
419
465
|
};
|
420
466
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
});
|
467
|
+
window.addEventListener('mousedown', mouseDownCallback);
|
468
|
+
tableSelection.listenersToRemove.add(() => window.removeEventListener('mousedown', mouseDownCallback));
|
469
|
+
tableSelection.listenersToRemove.add(editor.addListener('command', (type, payload) => {
|
470
|
+
const selection = lexical.$getSelection();
|
426
471
|
|
427
|
-
|
428
|
-
|
472
|
+
if (lexical.$isGridSelection(selection)) {
|
473
|
+
if (type === 'deleteCharacter' || type === 'keyBackspace') {
|
474
|
+
const event = payload;
|
475
|
+
event.preventDefault();
|
476
|
+
event.stopPropagation();
|
477
|
+
tableSelection.clearText();
|
478
|
+
return true;
|
479
|
+
} else if (type === 'formatText') {
|
480
|
+
tableSelection.formatCells(payload);
|
481
|
+
return true;
|
482
|
+
} else if (type === 'insertText') {
|
483
|
+
tableSelection.clearHighlight();
|
484
|
+
return false;
|
485
|
+
}
|
486
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
487
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
429
488
|
|
430
|
-
|
431
|
-
|
432
|
-
|
489
|
+
if (!$isTableCellNode(tableCellNode)) {
|
490
|
+
return false;
|
491
|
+
}
|
433
492
|
|
493
|
+
if (type === 'deleteCharacter') {
|
494
|
+
if (selection.isCollapsed() && selection.anchor.offset === 0 && selection.anchor.getNode().getPreviousSiblings().length === 0) {
|
495
|
+
return true;
|
496
|
+
}
|
497
|
+
}
|
434
498
|
|
435
|
-
|
436
|
-
|
437
|
-
const focus = formatSelection.focus;
|
438
|
-
highlightedCells.forEach(highlightedCell => {
|
439
|
-
const cellNode = lexical.$getNearestNodeFromDOMNode(highlightedCell.elem);
|
499
|
+
if (type === 'keyTab') {
|
500
|
+
const event = payload;
|
440
501
|
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
502
|
+
if (selection.isCollapsed()) {
|
503
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
504
|
+
event.preventDefault();
|
505
|
+
selectGridNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, !event.shiftKey && type === 'keyTab' ? 'forward' : 'backward');
|
506
|
+
return true;
|
507
|
+
}
|
445
508
|
}
|
446
|
-
}); // Collapse selection
|
447
509
|
|
448
|
-
|
449
|
-
|
450
|
-
lexical.$setSelection(selection);
|
451
|
-
};
|
510
|
+
if (type === 'keyArrowDown' || type === 'keyArrowUp' || type === 'keyArrowLeft' || type === 'keyArrowRight') {
|
511
|
+
const event = payload;
|
452
512
|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
clearHighlight();
|
457
|
-
}
|
513
|
+
if (selection.isCollapsed()) {
|
514
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
515
|
+
const elementParentNode = utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
458
516
|
|
459
|
-
|
517
|
+
if (elementParentNode == null) {
|
518
|
+
throw new Error('Expected BlockNode Parent');
|
519
|
+
}
|
520
|
+
|
521
|
+
const firstChild = tableCellNode.getFirstChild();
|
522
|
+
const lastChild = tableCellNode.getLastChild();
|
523
|
+
const isSelectionInFirstBlock = firstChild && elementParentNode.isParentOf(firstChild) || elementParentNode === firstChild;
|
524
|
+
const isSelectionInLastBlock = lastChild && elementParentNode.isParentOf(lastChild) || elementParentNode === lastChild;
|
525
|
+
|
526
|
+
if (type === 'keyArrowUp' && isSelectionInFirstBlock || type === 'keyArrowDown' && isSelectionInLastBlock) {
|
527
|
+
event.preventDefault();
|
528
|
+
event.stopImmediatePropagation();
|
529
|
+
event.stopPropagation();
|
530
|
+
selectGridNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, type === 'keyArrowUp' ? 'up' : 'down');
|
531
|
+
return true;
|
532
|
+
}
|
533
|
+
|
534
|
+
if (type === 'keyArrowLeft' && selection.anchor.offset === 0 || type === 'keyArrowRight' && selection.anchor.offset === selection.anchor.getNode().getTextContentSize()) {
|
535
|
+
event.preventDefault();
|
536
|
+
event.stopImmediatePropagation();
|
537
|
+
event.stopPropagation();
|
538
|
+
selectGridNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, type === 'keyArrowLeft' ? 'backward' : 'forward');
|
539
|
+
return true;
|
540
|
+
}
|
541
|
+
}
|
542
|
+
}
|
460
543
|
}
|
461
544
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
545
|
+
return false;
|
546
|
+
}, CriticalPriority));
|
547
|
+
return tableSelection;
|
548
|
+
}
|
549
|
+
function attachTableSelectionToTableElement(tableElement, tableSelection) {
|
550
|
+
// $FlowFixMe
|
551
|
+
tableElement[LEXICAL_ELEMENT_KEY] = tableSelection;
|
552
|
+
}
|
553
|
+
function getTableSelectionFromTableElement(tableElement) {
|
554
|
+
// $FlowFixMe
|
555
|
+
return tableElement[LEXICAL_ELEMENT_KEY];
|
556
|
+
}
|
557
|
+
function getCellFromTarget(node) {
|
558
|
+
let currentNode = node;
|
466
559
|
|
560
|
+
while (currentNode != null) {
|
561
|
+
const nodeName = currentNode.nodeName;
|
467
562
|
|
468
|
-
|
563
|
+
if (nodeName === 'TD' || nodeName === 'TH') {
|
564
|
+
// $FlowFixMe: internal field
|
565
|
+
const cell = currentNode._cell;
|
469
566
|
|
470
|
-
if (cell
|
471
|
-
|
472
|
-
startX = cell.x;
|
473
|
-
startY = cell.y;
|
474
|
-
document.addEventListener('mouseup', () => {
|
475
|
-
isSelected = false;
|
476
|
-
}, {
|
477
|
-
capture: true,
|
478
|
-
once: true
|
479
|
-
});
|
567
|
+
if (cell === undefined) {
|
568
|
+
return null;
|
480
569
|
}
|
481
|
-
|
482
|
-
|
483
|
-
window.addEventListener('click', e => {
|
484
|
-
if (highlightedCells.length > 0 && !tableElement.contains(e.target) && rootElement.contains(e.target)) {
|
485
|
-
editor.update(() => {
|
486
|
-
tableNode.setSelectionState(null);
|
487
|
-
});
|
570
|
+
|
571
|
+
return cell;
|
488
572
|
}
|
489
|
-
});
|
490
573
|
|
491
|
-
|
492
|
-
|
493
|
-
case 'backward':
|
494
|
-
case 'forward':
|
495
|
-
{
|
496
|
-
const isForward = direction === 'forward';
|
574
|
+
currentNode = currentNode.parentNode;
|
575
|
+
}
|
497
576
|
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
577
|
+
return null;
|
578
|
+
}
|
579
|
+
function getTableGrid(tableElement) {
|
580
|
+
const cells = [];
|
581
|
+
const grid = {
|
582
|
+
cells,
|
583
|
+
columns: 0,
|
584
|
+
rows: 0
|
585
|
+
};
|
586
|
+
let currentNode = tableElement.firstChild;
|
587
|
+
let x = 0;
|
588
|
+
let y = 0;
|
589
|
+
cells.length = 0;
|
509
590
|
|
510
|
-
|
511
|
-
|
591
|
+
while (currentNode != null) {
|
592
|
+
const nodeMame = currentNode.nodeName;
|
593
|
+
|
594
|
+
if (nodeMame === 'TD' || nodeMame === 'TH') {
|
595
|
+
// $FlowFixMe: TD is always an HTMLElement
|
596
|
+
const elem = currentNode;
|
597
|
+
const cell = {
|
598
|
+
elem,
|
599
|
+
highlighted: false,
|
600
|
+
x,
|
601
|
+
y
|
602
|
+
}; // $FlowFixMe: internal field
|
603
|
+
|
604
|
+
currentNode._cell = cell;
|
605
|
+
|
606
|
+
if (cells[y] === undefined) {
|
607
|
+
cells[y] = [];
|
608
|
+
}
|
512
609
|
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
tableNode.getCellNodeFromCords(x, y - 1).select();
|
517
|
-
} else {
|
518
|
-
tableNode.selectPrevious();
|
519
|
-
}
|
610
|
+
cells[y][x] = cell;
|
611
|
+
} else {
|
612
|
+
const child = currentNode.firstChild;
|
520
613
|
|
521
|
-
|
522
|
-
|
614
|
+
if (child != null) {
|
615
|
+
currentNode = child;
|
616
|
+
continue;
|
617
|
+
}
|
618
|
+
}
|
523
619
|
|
524
|
-
|
525
|
-
{
|
526
|
-
if (y !== grid.rows - 1) {
|
527
|
-
tableNode.getCellNodeFromCords(x, y + 1).select();
|
528
|
-
} else {
|
529
|
-
tableNode.selectNext();
|
530
|
-
}
|
620
|
+
const sibling = currentNode.nextSibling;
|
531
621
|
|
532
|
-
|
533
|
-
|
622
|
+
if (sibling != null) {
|
623
|
+
x++;
|
624
|
+
currentNode = sibling;
|
625
|
+
continue;
|
534
626
|
}
|
535
627
|
|
536
|
-
|
537
|
-
};
|
628
|
+
const parent = currentNode.parentNode;
|
538
629
|
|
539
|
-
|
540
|
-
|
630
|
+
if (parent != null) {
|
631
|
+
const parentSibling = parent.nextSibling;
|
632
|
+
|
633
|
+
if (parentSibling == null) {
|
634
|
+
break;
|
635
|
+
}
|
541
636
|
|
542
|
-
|
543
|
-
|
637
|
+
y++;
|
638
|
+
x = 0;
|
639
|
+
currentNode = parentSibling;
|
544
640
|
}
|
641
|
+
}
|
545
642
|
|
546
|
-
|
643
|
+
grid.columns = x + 1;
|
644
|
+
grid.rows = y + 1;
|
645
|
+
return grid;
|
646
|
+
}
|
647
|
+
function $updateDOMForSelection(grid, gridSelection) {
|
648
|
+
const highlightedCells = [];
|
649
|
+
const {
|
650
|
+
cells
|
651
|
+
} = grid;
|
652
|
+
const selectedCellNodes = new Set(gridSelection ? gridSelection.getNodes() : []);
|
547
653
|
|
548
|
-
|
549
|
-
|
550
|
-
}
|
654
|
+
for (let y = 0; y < cells.length; y++) {
|
655
|
+
const row = cells[y];
|
551
656
|
|
552
|
-
|
553
|
-
|
554
|
-
|
657
|
+
for (let x = 0; x < row.length; x++) {
|
658
|
+
const cell = row[x];
|
659
|
+
const elemStyle = cell.elem.style;
|
660
|
+
const lexicalNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
661
|
+
|
662
|
+
if (lexicalNode && selectedCellNodes.has(lexicalNode)) {
|
663
|
+
cell.highlighted = true;
|
664
|
+
elemStyle.setProperty('background-color', 'rgb(163, 187, 255)');
|
665
|
+
elemStyle.setProperty('caret-color', 'transparent');
|
666
|
+
highlightedCells.push(cell);
|
667
|
+
} else {
|
668
|
+
cell.highlighted = false;
|
669
|
+
elemStyle.removeProperty('background-color');
|
670
|
+
elemStyle.removeProperty('caret-color');
|
671
|
+
|
672
|
+
if (!cell.elem.getAttribute('style')) {
|
673
|
+
cell.elem.removeAttribute('style');
|
674
|
+
}
|
555
675
|
}
|
556
676
|
}
|
677
|
+
}
|
557
678
|
|
558
|
-
|
559
|
-
|
679
|
+
return highlightedCells;
|
680
|
+
}
|
681
|
+
|
682
|
+
const selectGridNodeInDirection = (tableSelection, tableNode, x, y, direction) => {
|
683
|
+
switch (direction) {
|
684
|
+
case 'backward':
|
685
|
+
case 'forward':
|
686
|
+
{
|
687
|
+
const isForward = direction === 'forward';
|
688
|
+
|
689
|
+
if (x !== (isForward ? tableSelection.grid.columns - 1 : 0)) {
|
690
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x + (isForward ? 1 : -1), y, tableSelection.grid));
|
691
|
+
} else {
|
692
|
+
if (y !== (isForward ? tableSelection.grid.rows - 1 : 0)) {
|
693
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(isForward ? 0 : tableSelection.grid.columns - 1, y + (isForward ? 1 : -1), tableSelection.grid));
|
694
|
+
} else if (!isForward) {
|
695
|
+
tableNode.selectPrevious();
|
696
|
+
} else {
|
697
|
+
tableNode.selectNext();
|
698
|
+
}
|
699
|
+
}
|
560
700
|
|
561
|
-
if (selection.isCollapsed() && highlightedCells.length === 0) {
|
562
|
-
const currentCords = tableNode.getCordsFromCellNode(tableCellNode);
|
563
|
-
event.preventDefault();
|
564
|
-
selectGridNodeInDirection(currentCords.x, currentCords.y, !event.shiftKey && type === 'keyTab' ? 'forward' : 'backward');
|
565
701
|
return true;
|
566
702
|
}
|
567
|
-
}
|
568
703
|
|
569
|
-
|
570
|
-
|
704
|
+
case 'up':
|
705
|
+
{
|
706
|
+
if (y !== 0) {
|
707
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y - 1, tableSelection.grid));
|
708
|
+
} else {
|
709
|
+
tableNode.selectPrevious();
|
710
|
+
}
|
571
711
|
|
572
|
-
|
573
|
-
|
574
|
-
const elementParentNode = $findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
712
|
+
return true;
|
713
|
+
}
|
575
714
|
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
715
|
+
case 'down':
|
716
|
+
{
|
717
|
+
if (y !== tableSelection.grid.rows - 1) {
|
718
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y + 1, tableSelection.grid));
|
719
|
+
} else {
|
720
|
+
tableNode.selectNext();
|
581
721
|
}
|
722
|
+
|
723
|
+
return true;
|
582
724
|
}
|
583
|
-
|
725
|
+
}
|
584
726
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
727
|
+
return false;
|
728
|
+
};
|
729
|
+
|
730
|
+
function selectTableCellNode(tableCell) {
|
731
|
+
const possibleParagraph = tableCell.getChildren().find(n => lexical.$isParagraphNode(n));
|
732
|
+
|
733
|
+
if (lexical.$isParagraphNode(possibleParagraph)) {
|
734
|
+
possibleParagraph.selectEnd();
|
735
|
+
} else {
|
736
|
+
tableCell.selectEnd();
|
737
|
+
}
|
589
738
|
}
|
590
739
|
|
591
740
|
/**
|
@@ -601,21 +750,17 @@ class TableNode extends lexical.GridNode {
|
|
601
750
|
return 'table';
|
602
751
|
}
|
603
752
|
|
604
|
-
static clone(node
|
605
|
-
|
606
|
-
// They shouldn't really be on the table node IMO.
|
607
|
-
return new TableNode(node.__key, node.__selectionShape, node.__grid);
|
753
|
+
static clone(node) {
|
754
|
+
return new TableNode(node.__key);
|
608
755
|
}
|
609
756
|
|
610
|
-
constructor(key
|
757
|
+
constructor(key) {
|
611
758
|
super(key);
|
612
|
-
this.__selectionShape = selectionShape;
|
613
|
-
this.__grid = grid;
|
614
759
|
}
|
615
760
|
|
616
761
|
createDOM(config, editor) {
|
617
762
|
const element = document.createElement('table');
|
618
|
-
addClassNamesToElement(element, config.theme.table);
|
763
|
+
utils.addClassNamesToElement(element, config.theme.table);
|
619
764
|
return element;
|
620
765
|
}
|
621
766
|
|
@@ -631,26 +776,7 @@ class TableNode extends lexical.GridNode {
|
|
631
776
|
return false;
|
632
777
|
}
|
633
778
|
|
634
|
-
|
635
|
-
const self = this.getWritable();
|
636
|
-
self.__selectionShape = selectionShape;
|
637
|
-
const grid = this.getGrid();
|
638
|
-
if (grid == null) return [];
|
639
|
-
|
640
|
-
if (!selectionShape) {
|
641
|
-
return updateCells(-1, -1, -1, -1, grid.cells);
|
642
|
-
}
|
643
|
-
|
644
|
-
return updateCells(selectionShape.fromX, selectionShape.toX, selectionShape.fromY, selectionShape.toY, grid.cells);
|
645
|
-
}
|
646
|
-
|
647
|
-
getSelectionState() {
|
648
|
-
return this.getLatest().__selectionShape;
|
649
|
-
}
|
650
|
-
|
651
|
-
getCordsFromCellNode(tableCellNode) {
|
652
|
-
const grid = this.getGrid();
|
653
|
-
|
779
|
+
getCordsFromCellNode(tableCellNode, grid) {
|
654
780
|
if (!grid) {
|
655
781
|
throw Error(`Grid not found.`);
|
656
782
|
}
|
@@ -685,9 +811,7 @@ class TableNode extends lexical.GridNode {
|
|
685
811
|
throw new Error('Cell not found in table.');
|
686
812
|
}
|
687
813
|
|
688
|
-
getCellNodeFromCords(x, y) {
|
689
|
-
const grid = this.getGrid();
|
690
|
-
|
814
|
+
getCellNodeFromCords(x, y, grid) {
|
691
815
|
if (!grid) {
|
692
816
|
throw Error(`Grid not found.`);
|
693
817
|
}
|
@@ -698,13 +822,13 @@ class TableNode extends lexical.GridNode {
|
|
698
822
|
const row = cells[y];
|
699
823
|
|
700
824
|
if (row == null) {
|
701
|
-
|
825
|
+
return null;
|
702
826
|
}
|
703
827
|
|
704
828
|
const cell = row[x];
|
705
829
|
|
706
830
|
if (cell == null) {
|
707
|
-
|
831
|
+
return null;
|
708
832
|
}
|
709
833
|
|
710
834
|
const node = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
@@ -713,17 +837,17 @@ class TableNode extends lexical.GridNode {
|
|
713
837
|
return node;
|
714
838
|
}
|
715
839
|
|
716
|
-
|
840
|
+
return null;
|
717
841
|
}
|
718
842
|
|
719
|
-
|
720
|
-
const
|
721
|
-
self.__grid = grid;
|
722
|
-
return self;
|
723
|
-
}
|
843
|
+
getCellNodeFromCordsOrThrow(x, y, grid) {
|
844
|
+
const node = this.getCellNodeFromCords(x, y, grid);
|
724
845
|
|
725
|
-
|
726
|
-
|
846
|
+
if (!node) {
|
847
|
+
throw new Error('Node at cords not TableCellNode.');
|
848
|
+
}
|
849
|
+
|
850
|
+
return node;
|
727
851
|
}
|
728
852
|
|
729
853
|
canSelectBefore() {
|
@@ -731,6 +855,15 @@ class TableNode extends lexical.GridNode {
|
|
731
855
|
}
|
732
856
|
|
733
857
|
}
|
858
|
+
function $getElementGridForTableNode(editor, tableNode) {
|
859
|
+
const tableElement = editor.getElementByKey(tableNode.getKey());
|
860
|
+
|
861
|
+
if (tableElement == null) {
|
862
|
+
throw new Error('Table Element Not Found');
|
863
|
+
}
|
864
|
+
|
865
|
+
return getTableGrid(tableElement);
|
866
|
+
}
|
734
867
|
function $createTableNode() {
|
735
868
|
return new TableNode();
|
736
869
|
}
|
@@ -752,21 +885,37 @@ class TableRowNode extends lexical.GridRowNode {
|
|
752
885
|
}
|
753
886
|
|
754
887
|
static clone(node) {
|
755
|
-
return new TableRowNode(node.__key);
|
888
|
+
return new TableRowNode(node.__height, node.__key);
|
756
889
|
}
|
757
890
|
|
758
|
-
constructor(key) {
|
891
|
+
constructor(height, key) {
|
759
892
|
super(key);
|
893
|
+
this.__height = height;
|
760
894
|
}
|
761
895
|
|
762
896
|
createDOM(config) {
|
763
897
|
const element = document.createElement('tr');
|
764
|
-
|
898
|
+
|
899
|
+
if (this.__height) {
|
900
|
+
element.style.height = `${this.__height}px`;
|
901
|
+
}
|
902
|
+
|
903
|
+
utils.addClassNamesToElement(element, config.theme.tableRow);
|
765
904
|
return element;
|
766
905
|
}
|
767
906
|
|
768
|
-
|
769
|
-
|
907
|
+
setHeight(height) {
|
908
|
+
const self = this.getWritable();
|
909
|
+
self.__height = height;
|
910
|
+
return this.__height;
|
911
|
+
}
|
912
|
+
|
913
|
+
getHeight() {
|
914
|
+
return this.getLatest().__height;
|
915
|
+
}
|
916
|
+
|
917
|
+
updateDOM(prevNode) {
|
918
|
+
return prevNode.__height !== this.__height;
|
770
919
|
}
|
771
920
|
|
772
921
|
canBeEmpty() {
|
@@ -774,8 +923,8 @@ class TableRowNode extends lexical.GridRowNode {
|
|
774
923
|
}
|
775
924
|
|
776
925
|
}
|
777
|
-
function $createTableRowNode() {
|
778
|
-
return new TableRowNode();
|
926
|
+
function $createTableRowNode(height) {
|
927
|
+
return new TableRowNode(height);
|
779
928
|
}
|
780
929
|
function $isTableRowNode(node) {
|
781
930
|
return node instanceof TableRowNode;
|
@@ -789,14 +938,21 @@ function $isTableRowNode(node) {
|
|
789
938
|
*
|
790
939
|
*
|
791
940
|
*/
|
792
|
-
function $createTableNodeWithDimensions(rowCount, columnCount,
|
941
|
+
function $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders = true) {
|
793
942
|
const tableNode = $createTableNode();
|
794
943
|
|
795
944
|
for (let iRow = 0; iRow < rowCount; iRow++) {
|
796
945
|
const tableRowNode = $createTableRowNode();
|
797
946
|
|
798
947
|
for (let iColumn = 0; iColumn < columnCount; iColumn++) {
|
799
|
-
|
948
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
949
|
+
|
950
|
+
if (includeHeaders) {
|
951
|
+
if (iRow === 0) headerState |= TableCellHeaderStates.ROW;
|
952
|
+
if (iColumn === 0) headerState |= TableCellHeaderStates.COLUMN;
|
953
|
+
}
|
954
|
+
|
955
|
+
const tableCellNode = $createTableCellNode(headerState);
|
800
956
|
const paragraphNode = lexical.$createParagraphNode();
|
801
957
|
paragraphNode.append(lexical.$createTextNode());
|
802
958
|
tableCellNode.append(paragraphNode);
|
@@ -809,7 +965,7 @@ function $createTableNodeWithDimensions(rowCount, columnCount, includeHeader = t
|
|
809
965
|
return tableNode;
|
810
966
|
}
|
811
967
|
function $getTableCellNodeFromLexicalNode(startingNode) {
|
812
|
-
const node =
|
968
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableCellNode(n));
|
813
969
|
|
814
970
|
if ($isTableCellNode(node)) {
|
815
971
|
return node;
|
@@ -818,7 +974,7 @@ function $getTableCellNodeFromLexicalNode(startingNode) {
|
|
818
974
|
return null;
|
819
975
|
}
|
820
976
|
function $getTableRowNodeFromTableCellNodeOrThrow(startingNode) {
|
821
|
-
const node =
|
977
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableRowNode(n));
|
822
978
|
|
823
979
|
if ($isTableRowNode(node)) {
|
824
980
|
return node;
|
@@ -827,7 +983,7 @@ function $getTableRowNodeFromTableCellNodeOrThrow(startingNode) {
|
|
827
983
|
throw new Error('Expected table cell to be inside of table row.');
|
828
984
|
}
|
829
985
|
function $getTableNodeFromLexicalNodeOrThrow(startingNode) {
|
830
|
-
const node =
|
986
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableNode(n));
|
831
987
|
|
832
988
|
if ($isTableNode(node)) {
|
833
989
|
return node;
|
@@ -844,6 +1000,19 @@ function $getTableColumnIndexFromTableCellNode(tableCellNode) {
|
|
844
1000
|
const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);
|
845
1001
|
return tableRowNode.getChildren().findIndex(n => n.is(tableCellNode));
|
846
1002
|
}
|
1003
|
+
function $getTableCellSiblingsFromTableCellNode(tableCellNode, grid) {
|
1004
|
+
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
|
1005
|
+
const {
|
1006
|
+
x,
|
1007
|
+
y
|
1008
|
+
} = tableNode.getCordsFromCellNode(tableCellNode, grid);
|
1009
|
+
return {
|
1010
|
+
above: tableNode.getCellNodeFromCords(x, y - 1, grid),
|
1011
|
+
below: tableNode.getCellNodeFromCords(x, y + 1, grid),
|
1012
|
+
left: tableNode.getCellNodeFromCords(x - 1, y, grid),
|
1013
|
+
right: tableNode.getCellNodeFromCords(x + 1, y, grid)
|
1014
|
+
};
|
1015
|
+
}
|
847
1016
|
function $removeTableRowAtIndex(tableNode, indexToDelete) {
|
848
1017
|
const tableRows = tableNode.getChildren();
|
849
1018
|
|
@@ -855,7 +1024,7 @@ function $removeTableRowAtIndex(tableNode, indexToDelete) {
|
|
855
1024
|
targetRowNode.remove();
|
856
1025
|
return tableNode;
|
857
1026
|
}
|
858
|
-
function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCount) {
|
1027
|
+
function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCount, grid) {
|
859
1028
|
const tableRows = tableNode.getChildren();
|
860
1029
|
|
861
1030
|
if (targetIndex >= tableRows.length || targetIndex < 0) {
|
@@ -865,12 +1034,30 @@ function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCo
|
|
865
1034
|
const targetRowNode = tableRows[targetIndex];
|
866
1035
|
|
867
1036
|
if ($isTableRowNode(targetRowNode)) {
|
868
|
-
for (let
|
869
|
-
const
|
1037
|
+
for (let r = 0; r < rowCount; r++) {
|
1038
|
+
const tableRowCells = targetRowNode.getChildren();
|
1039
|
+
const tableColumnCount = tableRowCells.length;
|
870
1040
|
const newTableRowNode = $createTableRowNode();
|
871
1041
|
|
872
|
-
for (let
|
873
|
-
const
|
1042
|
+
for (let c = 0; c < tableColumnCount; c++) {
|
1043
|
+
const tableCellFromTargetRow = tableRowCells[c];
|
1044
|
+
|
1045
|
+
if (!$isTableCellNode(tableCellFromTargetRow)) {
|
1046
|
+
throw Error(`Expected table cell`);
|
1047
|
+
}
|
1048
|
+
|
1049
|
+
const {
|
1050
|
+
above,
|
1051
|
+
below
|
1052
|
+
} = $getTableCellSiblingsFromTableCellNode(tableCellFromTargetRow, grid);
|
1053
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
1054
|
+
const width = above && above.getWidth() || below && below.getWidth() || null;
|
1055
|
+
|
1056
|
+
if (above && above.hasHeaderState(TableCellHeaderStates.COLUMN) || below && below.hasHeaderState(TableCellHeaderStates.COLUMN)) {
|
1057
|
+
headerState |= TableCellHeaderStates.COLUMN;
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
const tableCellNode = $createTableCellNode(headerState, 1, width);
|
874
1061
|
tableCellNode.append(lexical.$createParagraphNode());
|
875
1062
|
newTableRowNode.append(tableCellNode);
|
876
1063
|
}
|
@@ -890,12 +1077,18 @@ function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCo
|
|
890
1077
|
function $insertTableColumn(tableNode, targetIndex, shouldInsertAfter = true, columnCount) {
|
891
1078
|
const tableRows = tableNode.getChildren();
|
892
1079
|
|
893
|
-
for (let
|
894
|
-
const currentTableRowNode = tableRows[
|
1080
|
+
for (let r = 0; r < tableRows.length; r++) {
|
1081
|
+
const currentTableRowNode = tableRows[r];
|
895
1082
|
|
896
1083
|
if ($isTableRowNode(currentTableRowNode)) {
|
897
|
-
for (let
|
898
|
-
|
1084
|
+
for (let c = 0; c < columnCount; c++) {
|
1085
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
1086
|
+
|
1087
|
+
if (r === 0) {
|
1088
|
+
headerState |= TableCellHeaderStates.ROW;
|
1089
|
+
}
|
1090
|
+
|
1091
|
+
const newTableCell = $createTableCellNode(headerState);
|
899
1092
|
newTableCell.append(lexical.$createParagraphNode());
|
900
1093
|
const tableRowChildren = currentTableRowNode.getChildren();
|
901
1094
|
|
@@ -936,12 +1129,12 @@ function $deleteTableColumn(tableNode, targetIndex) {
|
|
936
1129
|
return tableNode;
|
937
1130
|
}
|
938
1131
|
|
939
|
-
exports.$applyCustomTableHandlers = $applyCustomTableHandlers;
|
940
1132
|
exports.$createTableCellNode = $createTableCellNode;
|
941
1133
|
exports.$createTableNode = $createTableNode;
|
942
1134
|
exports.$createTableNodeWithDimensions = $createTableNodeWithDimensions;
|
943
1135
|
exports.$createTableRowNode = $createTableRowNode;
|
944
1136
|
exports.$deleteTableColumn = $deleteTableColumn;
|
1137
|
+
exports.$getElementGridForTableNode = $getElementGridForTableNode;
|
945
1138
|
exports.$getTableCellNodeFromLexicalNode = $getTableCellNodeFromLexicalNode;
|
946
1139
|
exports.$getTableColumnIndexFromTableCellNode = $getTableColumnIndexFromTableCellNode;
|
947
1140
|
exports.$getTableNodeFromLexicalNodeOrThrow = $getTableNodeFromLexicalNodeOrThrow;
|
@@ -953,6 +1146,11 @@ exports.$isTableCellNode = $isTableCellNode;
|
|
953
1146
|
exports.$isTableNode = $isTableNode;
|
954
1147
|
exports.$isTableRowNode = $isTableRowNode;
|
955
1148
|
exports.$removeTableRowAtIndex = $removeTableRowAtIndex;
|
1149
|
+
exports.TableCellHeaderStates = TableCellHeaderStates;
|
956
1150
|
exports.TableCellNode = TableCellNode;
|
957
1151
|
exports.TableNode = TableNode;
|
958
1152
|
exports.TableRowNode = TableRowNode;
|
1153
|
+
exports.TableSelection = TableSelection;
|
1154
|
+
exports.applyTableHandlers = applyTableHandlers;
|
1155
|
+
exports.getCellFromTarget = getCellFromTarget;
|
1156
|
+
exports.getTableSelectionFromTableElement = getTableSelectionFromTableElement;
|