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