@lexical/table 0.1.12 → 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 +674 -460
- 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,19 +115,9 @@ function $isTableCellNode(node) {
|
|
84
115
|
*
|
85
116
|
*
|
86
117
|
*/
|
87
|
-
|
88
|
-
let curr = startingNode;
|
118
|
+
const getSelection = () => window.getSelection();
|
89
119
|
|
90
|
-
|
91
|
-
if (findFn(curr)) {
|
92
|
-
return curr;
|
93
|
-
}
|
94
|
-
|
95
|
-
curr = curr.getParent();
|
96
|
-
}
|
97
|
-
|
98
|
-
return null;
|
99
|
-
}
|
120
|
+
var getDOMSelection = getSelection;
|
100
121
|
|
101
122
|
/**
|
102
123
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
@@ -106,189 +127,307 @@ function $findMatchingParent(startingNode, findFn) {
|
|
106
127
|
*
|
107
128
|
*
|
108
129
|
*/
|
109
|
-
const LowPriority = 1;
|
110
|
-
const CriticalPriority = 4;
|
111
130
|
const removeHighlightStyle = document.createElement('style');
|
112
131
|
removeHighlightStyle.appendChild(document.createTextNode('::selection{background-color: transparent}'));
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
+
}
|
126
153
|
|
127
|
-
|
128
|
-
|
154
|
+
getGrid() {
|
155
|
+
return this.grid;
|
156
|
+
}
|
129
157
|
|
130
|
-
|
158
|
+
removeListeners() {
|
159
|
+
Array.from(this.listenersToRemove).forEach(removeListener => removeListener());
|
131
160
|
}
|
132
161
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
const grid = {
|
138
|
-
cells,
|
139
|
-
columns: 0,
|
140
|
-
rows: 0
|
141
|
-
};
|
162
|
+
trackTableGrid() {
|
163
|
+
const observer = new MutationObserver(records => {
|
164
|
+
this.editor.update(() => {
|
165
|
+
let gridNeedsRedraw = false;
|
142
166
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
cells.length = 0;
|
148
|
-
|
149
|
-
while (currentNode != null) {
|
150
|
-
const nodeMame = currentNode.nodeName;
|
151
|
-
|
152
|
-
if (nodeMame === 'TD' || nodeMame === 'TH') {
|
153
|
-
// $FlowFixMe: TD is always an HTMLElement
|
154
|
-
const elem = currentNode;
|
155
|
-
const cell = {
|
156
|
-
elem,
|
157
|
-
highlighted: false,
|
158
|
-
x,
|
159
|
-
y
|
160
|
-
}; // $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;
|
161
171
|
|
162
|
-
|
172
|
+
if (nodeName === 'TABLE' || nodeName === 'TR') {
|
173
|
+
gridNeedsRedraw = true;
|
174
|
+
break;
|
175
|
+
}
|
176
|
+
}
|
163
177
|
|
164
|
-
if (
|
165
|
-
|
178
|
+
if (!gridNeedsRedraw) {
|
179
|
+
return;
|
166
180
|
}
|
167
181
|
|
168
|
-
|
169
|
-
} else {
|
170
|
-
const child = currentNode.firstChild;
|
182
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
171
183
|
|
172
|
-
if (
|
173
|
-
|
174
|
-
continue;
|
184
|
+
if (!tableElement) {
|
185
|
+
throw new Error('Expected to find TableElement in DOM');
|
175
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');
|
176
196
|
}
|
177
197
|
|
178
|
-
|
198
|
+
this.grid = getTableGrid(tableElement);
|
199
|
+
observer.observe(tableElement, {
|
200
|
+
childList: true,
|
201
|
+
subtree: true
|
202
|
+
});
|
203
|
+
});
|
204
|
+
}
|
179
205
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
206
|
+
clearHighlight() {
|
207
|
+
this.editor.update(() => {
|
208
|
+
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
209
|
+
|
210
|
+
if (!$isTableNode(tableNode)) {
|
211
|
+
throw new Error('Expected TableNode.');
|
184
212
|
}
|
185
213
|
|
186
|
-
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;
|
187
231
|
|
188
232
|
if (parent != null) {
|
189
|
-
|
233
|
+
parent.removeChild(removeHighlightStyle);
|
234
|
+
}
|
235
|
+
});
|
236
|
+
}
|
190
237
|
|
191
|
-
|
192
|
-
|
193
|
-
|
238
|
+
adjustFocusCellForSelection(cell, ignoreStart = false) {
|
239
|
+
this.editor.update(() => {
|
240
|
+
this.isMouseDown = true;
|
241
|
+
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
194
242
|
|
195
|
-
|
196
|
-
|
197
|
-
currentNode = parentSibling;
|
243
|
+
if (!$isTableNode(tableNode)) {
|
244
|
+
throw new Error('Expected TableNode.');
|
198
245
|
}
|
199
|
-
}
|
200
246
|
|
201
|
-
|
202
|
-
grid.rows = y + 1;
|
203
|
-
tableNode.setGrid(grid);
|
204
|
-
};
|
247
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
205
248
|
|
206
|
-
|
207
|
-
|
208
|
-
|
249
|
+
if (!tableElement) {
|
250
|
+
throw new Error('Expected to find TableElement in DOM');
|
251
|
+
}
|
209
252
|
|
210
|
-
|
211
|
-
|
212
|
-
const target = record.target;
|
213
|
-
const nodeName = target.nodeName;
|
253
|
+
const cellX = cell.x;
|
254
|
+
const cellY = cell.y;
|
214
255
|
|
215
|
-
|
216
|
-
|
217
|
-
|
256
|
+
if (!this.isHighlightingCells && (this.startX !== cellX || this.startY !== cellY || ignoreStart)) {
|
257
|
+
const domSelection = getDOMSelection();
|
258
|
+
const anchorNode = domSelection.anchorNode;
|
259
|
+
|
260
|
+
if (anchorNode !== null) {
|
261
|
+
// Collapse the selection
|
262
|
+
domSelection.setBaseAndExtent(anchorNode, 0, anchorNode, 0);
|
218
263
|
}
|
219
|
-
}
|
220
264
|
|
221
|
-
|
265
|
+
this.isHighlightingCells = true;
|
266
|
+
|
267
|
+
if (document.body) {
|
268
|
+
document.body.appendChild(removeHighlightStyle);
|
269
|
+
}
|
270
|
+
} else if (cellX === this.currentX && cellY === this.currentY) {
|
222
271
|
return;
|
223
272
|
}
|
224
273
|
|
225
|
-
|
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
|
+
}
|
226
290
|
});
|
227
|
-
}
|
228
|
-
observer.observe(tableElement, {
|
229
|
-
childList: true,
|
230
|
-
subtree: true
|
231
|
-
});
|
232
|
-
calcSize();
|
233
|
-
return grid;
|
234
|
-
}
|
235
|
-
function updateCells(fromX, toX, fromY, toY, cells) {
|
236
|
-
const highlighted = [];
|
291
|
+
}
|
237
292
|
|
238
|
-
|
239
|
-
|
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
|
+
}
|
240
313
|
|
241
|
-
|
242
|
-
|
243
|
-
const
|
314
|
+
formatCells(type) {
|
315
|
+
this.editor.update(() => {
|
316
|
+
const selection = lexical.$getSelection();
|
244
317
|
|
245
|
-
if (
|
246
|
-
|
247
|
-
|
248
|
-
elemStyle.setProperty('background-color', 'rgb(163, 187, 255)');
|
249
|
-
elemStyle.setProperty('caret-color', 'transparent');
|
318
|
+
if (!lexical.$isGridSelection(selection)) {
|
319
|
+
{
|
320
|
+
throw Error(`Expected grid selection`);
|
250
321
|
}
|
322
|
+
} // This is to make Flow play ball.
|
251
323
|
|
252
|
-
highlighted.push(cell);
|
253
|
-
} else if (cell.highlighted) {
|
254
|
-
cell.highlighted = false;
|
255
|
-
elemStyle.removeProperty('background-color');
|
256
|
-
elemStyle.removeProperty('caret-color');
|
257
324
|
|
258
|
-
|
259
|
-
|
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);
|
260
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.');
|
261
345
|
}
|
262
|
-
|
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
|
+
});
|
263
381
|
}
|
264
382
|
|
265
|
-
return highlighted;
|
266
383
|
}
|
267
|
-
|
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) {
|
268
396
|
const rootElement = editor.getRootElement();
|
269
397
|
|
270
398
|
if (rootElement === null) {
|
271
399
|
throw new Error('No root element.');
|
272
400
|
}
|
273
401
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
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.
|
285
417
|
|
286
|
-
|
287
|
-
|
288
|
-
|
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.
|
289
428
|
|
290
429
|
tableElement.addEventListener('mousemove', event => {
|
291
|
-
if (
|
430
|
+
if (tableSelection.isMouseDown) {
|
292
431
|
// $FlowFixMe: event.target is always a Node on the DOM
|
293
432
|
const cell = getCellFromTarget(event.target);
|
294
433
|
|
@@ -296,280 +435,306 @@ function $applyCustomTableHandlers(tableNode, tableElement, editor) {
|
|
296
435
|
const cellX = cell.x;
|
297
436
|
const cellY = cell.y;
|
298
437
|
|
299
|
-
if (
|
438
|
+
if (tableSelection.isMouseDown && (tableSelection.startX !== cellX || tableSelection.startY !== cellY || tableSelection.isHighlightingCells)) {
|
300
439
|
event.preventDefault();
|
301
|
-
|
302
|
-
|
303
|
-
windowSelection.setBaseAndExtent(windowSelection.anchorNode, 0, windowSelection.anchorNode, 0);
|
304
|
-
isHighlightingCells = true;
|
305
|
-
|
306
|
-
if (document.body) {
|
307
|
-
document.body.appendChild(removeHighlightStyle);
|
308
|
-
}
|
309
|
-
|
310
|
-
if (deleteCharacterListener === null) {
|
311
|
-
deleteCharacterListener = editor.addListener('command', (type, payload) => {
|
312
|
-
if (type === 'deleteCharacter') {
|
313
|
-
if (highlightedCells.length === grid.columns * grid.rows) {
|
314
|
-
tableNode.selectPrevious(); // Delete entire table
|
315
|
-
|
316
|
-
tableNode.remove();
|
317
|
-
clearHighlight();
|
318
|
-
return true;
|
319
|
-
}
|
320
|
-
|
321
|
-
highlightedCells.forEach(({
|
322
|
-
elem
|
323
|
-
}) => {
|
324
|
-
const cellNode = lexical.$getNearestNodeFromDOMNode(elem);
|
325
|
-
|
326
|
-
if (lexical.$isElementNode(cellNode)) {
|
327
|
-
const paragraphNode = lexical.$createParagraphNode();
|
328
|
-
const textNode = lexical.$createTextNode();
|
329
|
-
paragraphNode.append(textNode);
|
330
|
-
cellNode.append(paragraphNode);
|
331
|
-
cellNode.getChildren().forEach(child => {
|
332
|
-
if (child !== paragraphNode) {
|
333
|
-
child.remove();
|
334
|
-
}
|
335
|
-
});
|
336
|
-
}
|
337
|
-
});
|
338
|
-
tableNode.setSelectionState(null);
|
339
|
-
lexical.$setSelection(null);
|
340
|
-
return true;
|
341
|
-
} else if (type === 'formatText') {
|
342
|
-
formatCells(payload);
|
343
|
-
return true;
|
344
|
-
} else if (type === 'insertText') {
|
345
|
-
clearHighlight();
|
346
|
-
return false;
|
347
|
-
}
|
348
|
-
|
349
|
-
return false;
|
350
|
-
}, LowPriority);
|
351
|
-
editorListeners.add(deleteCharacterListener);
|
352
|
-
}
|
353
|
-
} else if (cellX === currentX && cellY === currentY) {
|
354
|
-
return;
|
355
|
-
}
|
356
|
-
|
357
|
-
currentX = cellX;
|
358
|
-
currentY = cellY;
|
359
|
-
|
360
|
-
if (isHighlightingCells) {
|
361
|
-
const fromX = Math.min(startX, currentX);
|
362
|
-
const toX = Math.max(startX, currentX);
|
363
|
-
const fromY = Math.min(startY, currentY);
|
364
|
-
const toY = Math.max(startY, currentY);
|
365
|
-
editor.update(() => {
|
366
|
-
highlightedCells = tableNode.setSelectionState({
|
367
|
-
fromX,
|
368
|
-
fromY,
|
369
|
-
toX,
|
370
|
-
toY
|
371
|
-
});
|
372
|
-
});
|
440
|
+
tableSelection.adjustFocusCellForSelection(cell);
|
373
441
|
}
|
374
442
|
}
|
375
443
|
}
|
376
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.
|
377
450
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
startY = -1;
|
384
|
-
currentX = -1;
|
385
|
-
currentY = -1;
|
386
|
-
editor.update(() => {
|
387
|
-
tableNode.setSelectionState(null);
|
388
|
-
});
|
389
|
-
highlightedCells = [];
|
390
|
-
|
391
|
-
if (deleteCharacterListener !== null) {
|
392
|
-
deleteCharacterListener();
|
393
|
-
deleteCharacterListener = null;
|
394
|
-
editorListeners.delete(deleteCharacterListener);
|
395
|
-
}
|
451
|
+
tableElement.addEventListener('mouseleave', event => {
|
452
|
+
if (tableSelection.isMouseDown) {
|
453
|
+
return;
|
454
|
+
}
|
455
|
+
}); // Clear selection when clicking outside of dom.
|
396
456
|
|
397
|
-
|
457
|
+
const mouseDownCallback = e => {
|
458
|
+
editor.update(() => {
|
459
|
+
const selection = lexical.$getSelection();
|
398
460
|
|
399
|
-
if (
|
400
|
-
|
461
|
+
if (lexical.$isGridSelection(selection) && selection.gridKey === tableSelection.tableNodeKey && rootElement.contains(e.target)) {
|
462
|
+
return tableSelection.clearHighlight();
|
401
463
|
}
|
402
464
|
});
|
403
465
|
};
|
404
466
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
});
|
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();
|
410
471
|
|
411
|
-
|
412
|
-
|
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));
|
413
488
|
|
414
|
-
|
415
|
-
|
416
|
-
|
489
|
+
if (!$isTableCellNode(tableCellNode)) {
|
490
|
+
return false;
|
491
|
+
}
|
417
492
|
|
493
|
+
if (type === 'deleteCharacter') {
|
494
|
+
if (selection.isCollapsed() && selection.anchor.offset === 0 && selection.anchor.getNode().getPreviousSiblings().length === 0) {
|
495
|
+
return true;
|
496
|
+
}
|
497
|
+
}
|
418
498
|
|
419
|
-
|
420
|
-
|
421
|
-
const focus = formatSelection.focus;
|
422
|
-
highlightedCells.forEach(highlightedCell => {
|
423
|
-
const cellNode = lexical.$getNearestNodeFromDOMNode(highlightedCell.elem);
|
499
|
+
if (type === 'keyTab') {
|
500
|
+
const event = payload;
|
424
501
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
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
|
+
}
|
429
508
|
}
|
430
|
-
}); // Collapse selection
|
431
509
|
|
432
|
-
|
433
|
-
|
434
|
-
lexical.$setSelection(selection);
|
435
|
-
};
|
510
|
+
if (type === 'keyArrowDown' || type === 'keyArrowUp' || type === 'keyArrowLeft' || type === 'keyArrowRight') {
|
511
|
+
const event = payload;
|
436
512
|
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
clearHighlight();
|
441
|
-
}
|
513
|
+
if (selection.isCollapsed()) {
|
514
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
515
|
+
const elementParentNode = utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
442
516
|
|
443
|
-
|
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
|
+
}
|
444
543
|
}
|
445
544
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
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;
|
450
559
|
|
560
|
+
while (currentNode != null) {
|
561
|
+
const nodeName = currentNode.nodeName;
|
451
562
|
|
452
|
-
|
563
|
+
if (nodeName === 'TD' || nodeName === 'TH') {
|
564
|
+
// $FlowFixMe: internal field
|
565
|
+
const cell = currentNode._cell;
|
453
566
|
|
454
|
-
if (cell
|
455
|
-
|
456
|
-
startX = cell.x;
|
457
|
-
startY = cell.y;
|
458
|
-
document.addEventListener('mouseup', () => {
|
459
|
-
isSelected = false;
|
460
|
-
}, {
|
461
|
-
capture: true,
|
462
|
-
once: true
|
463
|
-
});
|
567
|
+
if (cell === undefined) {
|
568
|
+
return null;
|
464
569
|
}
|
465
|
-
|
466
|
-
|
467
|
-
window.addEventListener('click', e => {
|
468
|
-
if (highlightedCells.length > 0 && !tableElement.contains(e.target) && rootElement.contains(e.target)) {
|
469
|
-
editor.update(() => {
|
470
|
-
tableNode.setSelectionState(null);
|
471
|
-
});
|
570
|
+
|
571
|
+
return cell;
|
472
572
|
}
|
473
|
-
});
|
474
573
|
|
475
|
-
|
476
|
-
|
477
|
-
case 'backward':
|
478
|
-
case 'forward':
|
479
|
-
{
|
480
|
-
const isForward = direction === 'forward';
|
574
|
+
currentNode = currentNode.parentNode;
|
575
|
+
}
|
481
576
|
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
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;
|
493
590
|
|
494
|
-
|
495
|
-
|
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
|
+
}
|
496
609
|
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
tableNode.getCellNodeFromCords(x, y - 1).select();
|
501
|
-
} else {
|
502
|
-
tableNode.selectPrevious();
|
503
|
-
}
|
610
|
+
cells[y][x] = cell;
|
611
|
+
} else {
|
612
|
+
const child = currentNode.firstChild;
|
504
613
|
|
505
|
-
|
506
|
-
|
614
|
+
if (child != null) {
|
615
|
+
currentNode = child;
|
616
|
+
continue;
|
617
|
+
}
|
618
|
+
}
|
507
619
|
|
508
|
-
|
509
|
-
{
|
510
|
-
if (y !== grid.rows - 1) {
|
511
|
-
tableNode.getCellNodeFromCords(x, y + 1).select();
|
512
|
-
} else {
|
513
|
-
tableNode.selectNext();
|
514
|
-
}
|
620
|
+
const sibling = currentNode.nextSibling;
|
515
621
|
|
516
|
-
|
517
|
-
|
622
|
+
if (sibling != null) {
|
623
|
+
x++;
|
624
|
+
currentNode = sibling;
|
625
|
+
continue;
|
518
626
|
}
|
519
627
|
|
520
|
-
|
521
|
-
};
|
628
|
+
const parent = currentNode.parentNode;
|
522
629
|
|
523
|
-
|
524
|
-
|
630
|
+
if (parent != null) {
|
631
|
+
const parentSibling = parent.nextSibling;
|
632
|
+
|
633
|
+
if (parentSibling == null) {
|
634
|
+
break;
|
635
|
+
}
|
525
636
|
|
526
|
-
|
527
|
-
|
637
|
+
y++;
|
638
|
+
x = 0;
|
639
|
+
currentNode = parentSibling;
|
528
640
|
}
|
641
|
+
}
|
529
642
|
|
530
|
-
|
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() : []);
|
531
653
|
|
532
|
-
|
533
|
-
|
534
|
-
}
|
654
|
+
for (let y = 0; y < cells.length; y++) {
|
655
|
+
const row = cells[y];
|
535
656
|
|
536
|
-
|
537
|
-
|
538
|
-
|
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
|
+
}
|
539
675
|
}
|
540
676
|
}
|
677
|
+
}
|
541
678
|
|
542
|
-
|
543
|
-
|
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
|
+
}
|
544
700
|
|
545
|
-
if (selection.isCollapsed() && highlightedCells.length === 0) {
|
546
|
-
const currentCords = tableNode.getCordsFromCellNode(tableCellNode);
|
547
|
-
event.preventDefault();
|
548
|
-
selectGridNodeInDirection(currentCords.x, currentCords.y, !event.shiftKey && type === 'keyTab' ? 'forward' : 'backward');
|
549
701
|
return true;
|
550
702
|
}
|
551
|
-
}
|
552
703
|
|
553
|
-
|
554
|
-
|
704
|
+
case 'up':
|
705
|
+
{
|
706
|
+
if (y !== 0) {
|
707
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y - 1, tableSelection.grid));
|
708
|
+
} else {
|
709
|
+
tableNode.selectPrevious();
|
710
|
+
}
|
555
711
|
|
556
|
-
|
557
|
-
|
558
|
-
const elementParentNode = $findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
712
|
+
return true;
|
713
|
+
}
|
559
714
|
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
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();
|
565
721
|
}
|
722
|
+
|
723
|
+
return true;
|
566
724
|
}
|
567
|
-
|
725
|
+
}
|
568
726
|
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
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
|
+
}
|
573
738
|
}
|
574
739
|
|
575
740
|
/**
|
@@ -585,21 +750,17 @@ class TableNode extends lexical.GridNode {
|
|
585
750
|
return 'table';
|
586
751
|
}
|
587
752
|
|
588
|
-
static clone(node
|
589
|
-
|
590
|
-
// They shouldn't really be on the table node IMO.
|
591
|
-
return new TableNode(node.__key, node.__selectionShape, node.__grid);
|
753
|
+
static clone(node) {
|
754
|
+
return new TableNode(node.__key);
|
592
755
|
}
|
593
756
|
|
594
|
-
constructor(key
|
757
|
+
constructor(key) {
|
595
758
|
super(key);
|
596
|
-
this.__selectionShape = selectionShape;
|
597
|
-
this.__grid = grid;
|
598
759
|
}
|
599
760
|
|
600
761
|
createDOM(config, editor) {
|
601
762
|
const element = document.createElement('table');
|
602
|
-
addClassNamesToElement(element, config.theme.table);
|
763
|
+
utils.addClassNamesToElement(element, config.theme.table);
|
603
764
|
return element;
|
604
765
|
}
|
605
766
|
|
@@ -615,26 +776,7 @@ class TableNode extends lexical.GridNode {
|
|
615
776
|
return false;
|
616
777
|
}
|
617
778
|
|
618
|
-
|
619
|
-
const self = this.getWritable();
|
620
|
-
self.__selectionShape = selectionShape;
|
621
|
-
const grid = this.getGrid();
|
622
|
-
if (grid == null) return [];
|
623
|
-
|
624
|
-
if (!selectionShape) {
|
625
|
-
return updateCells(-1, -1, -1, -1, grid.cells);
|
626
|
-
}
|
627
|
-
|
628
|
-
return updateCells(selectionShape.fromX, selectionShape.toX, selectionShape.fromY, selectionShape.toY, grid.cells);
|
629
|
-
}
|
630
|
-
|
631
|
-
getSelectionState() {
|
632
|
-
return this.getLatest().__selectionShape;
|
633
|
-
}
|
634
|
-
|
635
|
-
getCordsFromCellNode(tableCellNode) {
|
636
|
-
const grid = this.getGrid();
|
637
|
-
|
779
|
+
getCordsFromCellNode(tableCellNode, grid) {
|
638
780
|
if (!grid) {
|
639
781
|
throw Error(`Grid not found.`);
|
640
782
|
}
|
@@ -669,9 +811,7 @@ class TableNode extends lexical.GridNode {
|
|
669
811
|
throw new Error('Cell not found in table.');
|
670
812
|
}
|
671
813
|
|
672
|
-
getCellNodeFromCords(x, y) {
|
673
|
-
const grid = this.getGrid();
|
674
|
-
|
814
|
+
getCellNodeFromCords(x, y, grid) {
|
675
815
|
if (!grid) {
|
676
816
|
throw Error(`Grid not found.`);
|
677
817
|
}
|
@@ -682,13 +822,13 @@ class TableNode extends lexical.GridNode {
|
|
682
822
|
const row = cells[y];
|
683
823
|
|
684
824
|
if (row == null) {
|
685
|
-
|
825
|
+
return null;
|
686
826
|
}
|
687
827
|
|
688
828
|
const cell = row[x];
|
689
829
|
|
690
830
|
if (cell == null) {
|
691
|
-
|
831
|
+
return null;
|
692
832
|
}
|
693
833
|
|
694
834
|
const node = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
@@ -697,17 +837,17 @@ class TableNode extends lexical.GridNode {
|
|
697
837
|
return node;
|
698
838
|
}
|
699
839
|
|
700
|
-
|
840
|
+
return null;
|
701
841
|
}
|
702
842
|
|
703
|
-
|
704
|
-
const
|
705
|
-
self.__grid = grid;
|
706
|
-
return self;
|
707
|
-
}
|
843
|
+
getCellNodeFromCordsOrThrow(x, y, grid) {
|
844
|
+
const node = this.getCellNodeFromCords(x, y, grid);
|
708
845
|
|
709
|
-
|
710
|
-
|
846
|
+
if (!node) {
|
847
|
+
throw new Error('Node at cords not TableCellNode.');
|
848
|
+
}
|
849
|
+
|
850
|
+
return node;
|
711
851
|
}
|
712
852
|
|
713
853
|
canSelectBefore() {
|
@@ -715,6 +855,15 @@ class TableNode extends lexical.GridNode {
|
|
715
855
|
}
|
716
856
|
|
717
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
|
+
}
|
718
867
|
function $createTableNode() {
|
719
868
|
return new TableNode();
|
720
869
|
}
|
@@ -736,21 +885,37 @@ class TableRowNode extends lexical.GridRowNode {
|
|
736
885
|
}
|
737
886
|
|
738
887
|
static clone(node) {
|
739
|
-
return new TableRowNode(node.__key);
|
888
|
+
return new TableRowNode(node.__height, node.__key);
|
740
889
|
}
|
741
890
|
|
742
|
-
constructor(key) {
|
891
|
+
constructor(height, key) {
|
743
892
|
super(key);
|
893
|
+
this.__height = height;
|
744
894
|
}
|
745
895
|
|
746
896
|
createDOM(config) {
|
747
897
|
const element = document.createElement('tr');
|
748
|
-
|
898
|
+
|
899
|
+
if (this.__height) {
|
900
|
+
element.style.height = `${this.__height}px`;
|
901
|
+
}
|
902
|
+
|
903
|
+
utils.addClassNamesToElement(element, config.theme.tableRow);
|
749
904
|
return element;
|
750
905
|
}
|
751
906
|
|
752
|
-
|
753
|
-
|
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;
|
754
919
|
}
|
755
920
|
|
756
921
|
canBeEmpty() {
|
@@ -758,8 +923,8 @@ class TableRowNode extends lexical.GridRowNode {
|
|
758
923
|
}
|
759
924
|
|
760
925
|
}
|
761
|
-
function $createTableRowNode() {
|
762
|
-
return new TableRowNode();
|
926
|
+
function $createTableRowNode(height) {
|
927
|
+
return new TableRowNode(height);
|
763
928
|
}
|
764
929
|
function $isTableRowNode(node) {
|
765
930
|
return node instanceof TableRowNode;
|
@@ -773,14 +938,21 @@ function $isTableRowNode(node) {
|
|
773
938
|
*
|
774
939
|
*
|
775
940
|
*/
|
776
|
-
function $createTableNodeWithDimensions(rowCount, columnCount,
|
941
|
+
function $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders = true) {
|
777
942
|
const tableNode = $createTableNode();
|
778
943
|
|
779
944
|
for (let iRow = 0; iRow < rowCount; iRow++) {
|
780
945
|
const tableRowNode = $createTableRowNode();
|
781
946
|
|
782
947
|
for (let iColumn = 0; iColumn < columnCount; iColumn++) {
|
783
|
-
|
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);
|
784
956
|
const paragraphNode = lexical.$createParagraphNode();
|
785
957
|
paragraphNode.append(lexical.$createTextNode());
|
786
958
|
tableCellNode.append(paragraphNode);
|
@@ -793,7 +965,7 @@ function $createTableNodeWithDimensions(rowCount, columnCount, includeHeader = t
|
|
793
965
|
return tableNode;
|
794
966
|
}
|
795
967
|
function $getTableCellNodeFromLexicalNode(startingNode) {
|
796
|
-
const node =
|
968
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableCellNode(n));
|
797
969
|
|
798
970
|
if ($isTableCellNode(node)) {
|
799
971
|
return node;
|
@@ -802,7 +974,7 @@ function $getTableCellNodeFromLexicalNode(startingNode) {
|
|
802
974
|
return null;
|
803
975
|
}
|
804
976
|
function $getTableRowNodeFromTableCellNodeOrThrow(startingNode) {
|
805
|
-
const node =
|
977
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableRowNode(n));
|
806
978
|
|
807
979
|
if ($isTableRowNode(node)) {
|
808
980
|
return node;
|
@@ -811,7 +983,7 @@ function $getTableRowNodeFromTableCellNodeOrThrow(startingNode) {
|
|
811
983
|
throw new Error('Expected table cell to be inside of table row.');
|
812
984
|
}
|
813
985
|
function $getTableNodeFromLexicalNodeOrThrow(startingNode) {
|
814
|
-
const node =
|
986
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableNode(n));
|
815
987
|
|
816
988
|
if ($isTableNode(node)) {
|
817
989
|
return node;
|
@@ -828,6 +1000,19 @@ function $getTableColumnIndexFromTableCellNode(tableCellNode) {
|
|
828
1000
|
const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);
|
829
1001
|
return tableRowNode.getChildren().findIndex(n => n.is(tableCellNode));
|
830
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
|
+
}
|
831
1016
|
function $removeTableRowAtIndex(tableNode, indexToDelete) {
|
832
1017
|
const tableRows = tableNode.getChildren();
|
833
1018
|
|
@@ -839,7 +1024,7 @@ function $removeTableRowAtIndex(tableNode, indexToDelete) {
|
|
839
1024
|
targetRowNode.remove();
|
840
1025
|
return tableNode;
|
841
1026
|
}
|
842
|
-
function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCount) {
|
1027
|
+
function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCount, grid) {
|
843
1028
|
const tableRows = tableNode.getChildren();
|
844
1029
|
|
845
1030
|
if (targetIndex >= tableRows.length || targetIndex < 0) {
|
@@ -849,12 +1034,30 @@ function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCo
|
|
849
1034
|
const targetRowNode = tableRows[targetIndex];
|
850
1035
|
|
851
1036
|
if ($isTableRowNode(targetRowNode)) {
|
852
|
-
for (let
|
853
|
-
const
|
1037
|
+
for (let r = 0; r < rowCount; r++) {
|
1038
|
+
const tableRowCells = targetRowNode.getChildren();
|
1039
|
+
const tableColumnCount = tableRowCells.length;
|
854
1040
|
const newTableRowNode = $createTableRowNode();
|
855
1041
|
|
856
|
-
for (let
|
857
|
-
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);
|
858
1061
|
tableCellNode.append(lexical.$createParagraphNode());
|
859
1062
|
newTableRowNode.append(tableCellNode);
|
860
1063
|
}
|
@@ -874,12 +1077,18 @@ function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCo
|
|
874
1077
|
function $insertTableColumn(tableNode, targetIndex, shouldInsertAfter = true, columnCount) {
|
875
1078
|
const tableRows = tableNode.getChildren();
|
876
1079
|
|
877
|
-
for (let
|
878
|
-
const currentTableRowNode = tableRows[
|
1080
|
+
for (let r = 0; r < tableRows.length; r++) {
|
1081
|
+
const currentTableRowNode = tableRows[r];
|
879
1082
|
|
880
1083
|
if ($isTableRowNode(currentTableRowNode)) {
|
881
|
-
for (let
|
882
|
-
|
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);
|
883
1092
|
newTableCell.append(lexical.$createParagraphNode());
|
884
1093
|
const tableRowChildren = currentTableRowNode.getChildren();
|
885
1094
|
|
@@ -920,12 +1129,12 @@ function $deleteTableColumn(tableNode, targetIndex) {
|
|
920
1129
|
return tableNode;
|
921
1130
|
}
|
922
1131
|
|
923
|
-
exports.$applyCustomTableHandlers = $applyCustomTableHandlers;
|
924
1132
|
exports.$createTableCellNode = $createTableCellNode;
|
925
1133
|
exports.$createTableNode = $createTableNode;
|
926
1134
|
exports.$createTableNodeWithDimensions = $createTableNodeWithDimensions;
|
927
1135
|
exports.$createTableRowNode = $createTableRowNode;
|
928
1136
|
exports.$deleteTableColumn = $deleteTableColumn;
|
1137
|
+
exports.$getElementGridForTableNode = $getElementGridForTableNode;
|
929
1138
|
exports.$getTableCellNodeFromLexicalNode = $getTableCellNodeFromLexicalNode;
|
930
1139
|
exports.$getTableColumnIndexFromTableCellNode = $getTableColumnIndexFromTableCellNode;
|
931
1140
|
exports.$getTableNodeFromLexicalNodeOrThrow = $getTableNodeFromLexicalNodeOrThrow;
|
@@ -937,6 +1146,11 @@ exports.$isTableCellNode = $isTableCellNode;
|
|
937
1146
|
exports.$isTableNode = $isTableNode;
|
938
1147
|
exports.$isTableRowNode = $isTableRowNode;
|
939
1148
|
exports.$removeTableRowAtIndex = $removeTableRowAtIndex;
|
1149
|
+
exports.TableCellHeaderStates = TableCellHeaderStates;
|
940
1150
|
exports.TableCellNode = TableCellNode;
|
941
1151
|
exports.TableNode = TableNode;
|
942
1152
|
exports.TableRowNode = TableRowNode;
|
1153
|
+
exports.TableSelection = TableSelection;
|
1154
|
+
exports.applyTableHandlers = applyTableHandlers;
|
1155
|
+
exports.getCellFromTarget = getCellFromTarget;
|
1156
|
+
exports.getTableSelectionFromTableElement = getTableSelectionFromTableElement;
|