@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.
@@ -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
- * Copyright (c) Meta Platforms, Inc. and affiliates.
13
- *
14
- * This source code is licensed under the MIT license found in the
15
- * LICENSE file in the root directory of this source tree.
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(new Set(node.__headerStyles), node.__colSpan, node.__key);
25
+ return new TableCellNode(node.__headerState, node.__colSpan, node.__width, node.__key);
42
26
  }
43
27
 
44
- constructor(headerStyles, colSpan = 1, key) {
28
+ constructor(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width, key) {
45
29
  super(colSpan, key);
46
- this.__headerStyles = headerStyles || new Set();
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
- addClassNamesToElement(element, config.theme.tableCell, this.hasHeader() && config.theme.TableCellHeaderStyles);
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(headerStyles) {
49
+ setHeaderStyles(headerState) {
60
50
  const self = this.getWritable();
61
- self.__headerStyles = new Set(headerStyles);
62
- return this.__headerStyles;
51
+ self.__headerState = headerState;
52
+ return this.__headerState;
63
53
  }
64
54
 
65
55
  getHeaderStyles() {
66
- return this.getLatest().__headerStyles;
56
+ return this.getLatest().__headerState;
67
57
  }
68
58
 
69
- toggleHeaderStyle(key) {
59
+ setWidth(width) {
70
60
  const self = this.getWritable();
71
- const newHeaderValue = self.getHeaderStyles();
61
+ self.__width = width;
62
+ return this.__width;
63
+ }
64
+
65
+ getWidth() {
66
+ return this.getLatest().__width;
67
+ }
72
68
 
73
- if (newHeaderValue.has(key)) {
74
- newHeaderValue.delete(key);
69
+ toggleHeaderStyle(headerStateToToggle) {
70
+ const self = this.getWritable();
71
+
72
+ if ((self.__headerState & headerStateToToggle) === headerStateToToggle) {
73
+ self.__headerState -= headerStateToToggle;
75
74
  } else {
76
- newHeaderValue.add(key);
75
+ self.__headerState += headerStateToToggle;
77
76
  }
78
77
 
79
- self.__headerStyles = new Set(newHeaderValue);
78
+ self.__headerState = self.__headerState;
80
79
  return self;
81
80
  }
82
81
 
83
- hasHeader() {
84
- const headerStyles = this.getLatest().__headerStyles;
82
+ hasHeaderState(headerState) {
83
+ return (this.getHeaderStyles() & headerState) === headerState;
84
+ }
85
85
 
86
- return headerStyles.size > 0;
86
+ hasHeader() {
87
+ return this.getLatest().__headerState !== TableCellHeaderStates.NO_STATUS;
87
88
  }
88
89
 
89
90
  updateDOM(prevNode) {
90
- return prevNode.__headerStyles.size !== this.__headerStyles.size;
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(headerStyles) {
103
- return new TableCellNode(headerStyles);
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
- function getCellFromTarget(node) {
156
- let currentNode = node;
157
-
158
- while (currentNode != null) {
159
- const nodeName = currentNode.nodeName;
160
-
161
- if (nodeName === 'TD' || nodeName === 'TH') {
162
- // $FlowFixMe: internal field
163
- const cell = currentNode._cell;
164
-
165
- if (cell === undefined) {
166
- return null;
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
- return cell;
170
- }
154
+ getGrid() {
155
+ return this.grid;
156
+ }
171
157
 
172
- currentNode = currentNode.parentNode;
158
+ removeListeners() {
159
+ Array.from(this.listenersToRemove).forEach(removeListener => removeListener());
173
160
  }
174
161
 
175
- return null;
176
- }
177
- function trackTableGrid(tableNode, tableElement, editor) {
178
- const cells = [];
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
- const calcSize = () => {
186
- let currentNode = tableElement.firstChild;
187
- let x = 0;
188
- let y = 0;
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
- currentNode._cell = cell;
172
+ if (nodeName === 'TABLE' || nodeName === 'TR') {
173
+ gridNeedsRedraw = true;
174
+ break;
175
+ }
176
+ }
205
177
 
206
- if (cells[y] === undefined) {
207
- cells[y] = [];
178
+ if (!gridNeedsRedraw) {
179
+ return;
208
180
  }
209
181
 
210
- cells[y][x] = cell;
211
- } else {
212
- const child = currentNode.firstChild;
182
+ const tableElement = this.editor.getElementByKey(this.tableNodeKey);
213
183
 
214
- if (child != null) {
215
- currentNode = child;
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
- const sibling = currentNode.nextSibling;
198
+ this.grid = getTableGrid(tableElement);
199
+ observer.observe(tableElement, {
200
+ childList: true,
201
+ subtree: true
202
+ });
203
+ });
204
+ }
221
205
 
222
- if (sibling != null) {
223
- x++;
224
- currentNode = sibling;
225
- continue;
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 parent = currentNode.parentNode;
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
- const parentSibling = parent.nextSibling;
233
+ parent.removeChild(removeHighlightStyle);
234
+ }
235
+ });
236
+ }
232
237
 
233
- if (parentSibling == null) {
234
- break;
235
- }
238
+ adjustFocusCellForSelection(cell, ignoreStart = false) {
239
+ this.editor.update(() => {
240
+ this.isMouseDown = true;
241
+ const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
236
242
 
237
- y++;
238
- x = 0;
239
- currentNode = parentSibling;
243
+ if (!$isTableNode(tableNode)) {
244
+ throw new Error('Expected TableNode.');
240
245
  }
241
- }
242
246
 
243
- grid.columns = x + 1;
244
- grid.rows = y + 1;
245
- tableNode.setGrid(grid);
246
- };
247
+ const tableElement = this.editor.getElementByKey(this.tableNodeKey);
247
248
 
248
- const observer = new MutationObserver(records => {
249
- editor.update(() => {
250
- let gridNeedsRedraw = false;
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
- for (let i = 0; i < records.length; i++) {
253
- const record = records[i];
254
- const target = record.target;
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 (nodeName === 'TABLE' || nodeName === 'TR') {
258
- gridNeedsRedraw = true;
259
- break;
260
+ if (anchorNode !== null) {
261
+ // Collapse the selection
262
+ domSelection.setBaseAndExtent(anchorNode, 0, anchorNode, 0);
260
263
  }
261
- }
262
264
 
263
- if (!gridNeedsRedraw) {
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
- calcSize();
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
- for (let y = 0; y < cells.length; y++) {
281
- const row = cells[y];
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
- for (let x = 0; x < row.length; x++) {
284
- const cell = row[x];
285
- const elemStyle = cell.elem.style;
314
+ formatCells(type) {
315
+ this.editor.update(() => {
316
+ const selection = lexical.$getSelection();
286
317
 
287
- if (x >= fromX && x <= toX && y >= fromY && y <= toY) {
288
- if (!cell.highlighted) {
289
- cell.highlighted = true;
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
- if (!cell.elem.getAttribute('style')) {
301
- cell.elem.removeAttribute('style');
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
- function $applyCustomTableHandlers(tableNode, tableElement, editor) {
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
- trackTableGrid(tableNode, tableElement, editor);
317
- const grid = tableNode.getGrid();
318
- let isSelected = false;
319
- let isHighlightingCells = false;
320
- let startX = -1;
321
- let startY = -1;
322
- let currentX = -1;
323
- let currentY = -1;
324
- let highlightedCells = [];
325
- const editorListeners = new Set();
326
- let deleteCharacterListener = null;
327
-
328
- if (grid == null) {
329
- throw new Error('Table grid not found.');
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 (isSelected) {
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 (!isHighlightingCells && (startX !== cellX || startY !== cellY)) {
438
+ if (tableSelection.isMouseDown && (tableSelection.startX !== cellX || tableSelection.startY !== cellY || tableSelection.isHighlightingCells)) {
342
439
  event.preventDefault();
343
- const domSelection = getDOMSelection();
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 clearHighlight = () => {
457
+ const mouseDownCallback = e => {
426
458
  editor.update(() => {
427
- isHighlightingCells = false;
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 (deleteCharacterListener !== null) {
439
- deleteCharacterListener();
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
- tableElement.addEventListener('mouseleave', event => {
453
- if (isSelected) {
454
- return;
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
- const formatCells = type => {
459
- let selection = lexical.$getSelection();
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
- if (!lexical.$isRangeSelection(selection)) {
462
- selection = lexical.$createRangeSelection();
463
- } // This is to make Flow play ball.
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
- const formatSelection = selection;
467
- const anchor = formatSelection.anchor;
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
- if (lexical.$isElementNode(cellNode) && cellNode.getTextContentSize() !== 0) {
473
- anchor.set(cellNode.getKey(), 0, 'element');
474
- focus.set(cellNode.getKey(), cellNode.getChildrenSize(), 'element');
475
- formatSelection.formatText(type);
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
- selection.anchor.set(selection.anchor.key, selection.anchor.offset, selection.anchor.type);
480
- selection.focus.set(selection.anchor.key, selection.anchor.offset, selection.anchor.type);
481
- lexical.$setSelection(selection);
482
- };
510
+ if (type === 'keyArrowDown' || type === 'keyArrowUp' || type === 'keyArrowLeft' || type === 'keyArrowRight') {
511
+ const event = payload;
483
512
 
484
- tableElement.addEventListener('mousedown', event => {
485
- if (isSelected) {
486
- if (isHighlightingCells) {
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
- return;
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
- setTimeout(() => {
494
- if (isHighlightingCells) {
495
- clearHighlight();
496
- } // $FlowFixMe: event.target is always a Node on the DOM
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
- const cell = getCellFromTarget(event.target);
563
+ if (nodeName === 'TD' || nodeName === 'TH') {
564
+ // $FlowFixMe: internal field
565
+ const cell = currentNode._cell;
500
566
 
501
- if (cell !== null) {
502
- isSelected = true;
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
- }, 0);
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
- const selectGridNodeInDirection = (x, y, direction) => {
523
- switch (direction) {
524
- case 'backward':
525
- case 'forward':
526
- {
527
- const isForward = direction === 'forward';
574
+ currentNode = currentNode.parentNode;
575
+ }
528
576
 
529
- if (x !== (isForward ? grid.columns - 1 : 0)) {
530
- tableNode.getCellNodeFromCordsOrThrow(x + (isForward ? 1 : -1), y).select();
531
- } else {
532
- if (y !== (isForward ? grid.rows - 1 : 0)) {
533
- tableNode.getCellNodeFromCordsOrThrow(isForward ? 0 : grid.columns - 1, y + (isForward ? 1 : -1)).select();
534
- } else if (!isForward) {
535
- tableNode.selectPrevious();
536
- } else {
537
- tableNode.selectNext();
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
- return true;
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
- case 'up':
545
- {
546
- if (y !== 0) {
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
- return true;
553
- }
614
+ if (child != null) {
615
+ currentNode = child;
616
+ continue;
617
+ }
618
+ }
554
619
 
555
- case 'down':
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
- return true;
564
- }
622
+ if (sibling != null) {
623
+ x++;
624
+ currentNode = sibling;
625
+ continue;
565
626
  }
566
627
 
567
- return false;
568
- };
628
+ const parent = currentNode.parentNode;
569
629
 
570
- const genericCommandListener = editor.addListener('command', (type, payload) => {
571
- const selection = lexical.$getSelection();
630
+ if (parent != null) {
631
+ const parentSibling = parent.nextSibling;
632
+
633
+ if (parentSibling == null) {
634
+ break;
635
+ }
572
636
 
573
- if (!lexical.$isRangeSelection(selection)) {
574
- return false;
637
+ y++;
638
+ x = 0;
639
+ currentNode = parentSibling;
575
640
  }
641
+ }
576
642
 
577
- const tableCellNode = $findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
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
- if (!$isTableCellNode(tableCellNode)) {
580
- return false;
581
- }
654
+ for (let y = 0; y < cells.length; y++) {
655
+ const row = cells[y];
582
656
 
583
- if (type === 'deleteCharacter') {
584
- if (highlightedCells.length === 0 && selection.isCollapsed() && selection.anchor.offset === 0 && selection.anchor.getNode().getPreviousSiblings().length === 0) {
585
- return true;
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
- if (type === 'keyTab') {
590
- const event = payload;
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
- if (type === 'keyArrowDown' || type === 'keyArrowUp') {
601
- const event = payload;
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
- if (selection.isCollapsed() && highlightedCells.length === 0) {
604
- const currentCords = tableNode.getCordsFromCellNode(tableCellNode);
605
- const elementParentNode = $findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
712
+ return true;
713
+ }
606
714
 
607
- if (type === 'keyArrowUp' && elementParentNode === tableCellNode.getFirstChild() || type === 'keyArrowDown' && elementParentNode === tableCellNode.getLastChild()) {
608
- event.preventDefault();
609
- event.stopImmediatePropagation();
610
- selectGridNodeInDirection(currentCords.x, currentCords.y, type === 'keyArrowUp' ? 'up' : 'down');
611
- return true;
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
- return false;
617
- }, CriticalPriority);
618
- editorListeners.add(genericCommandListener);
619
- return () => Array.from(editorListeners).forEach(removeListener => removeListener ? removeListener() : null);
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, selectionShape, grid) {
636
- // TODO: selectionShape and grid aren't being deeply cloned?
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(selectionShape, grid, key) {
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
- setSelectionState(selectionShape) {
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
- setGrid(grid) {
761
- const self = this.getWritable();
762
- self.__grid = grid;
763
- return self;
853
+ canSelectBefore() {
854
+ return true;
764
855
  }
765
856
 
766
- getGrid() {
767
- return this.getLatest().__grid;
768
- }
857
+ }
858
+ function $getElementGridForTableNode(editor, tableNode) {
859
+ const tableElement = editor.getElementByKey(tableNode.getKey());
769
860
 
770
- canSelectBefore() {
771
- return true;
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
- addClassNamesToElement(element, config.theme.tableRow);
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
- updateDOM() {
810
- return false;
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
- const headerStyles = new Set();
948
+ let headerState = TableCellHeaderStates.NO_STATUS;
841
949
 
842
950
  if (includeHeaders) {
843
- if (iRow === 0) headerStyles.add('row');
844
- if (iColumn === 0) headerStyles.add('column');
951
+ if (iRow === 0) headerState |= TableCellHeaderStates.ROW;
952
+ if (iColumn === 0) headerState |= TableCellHeaderStates.COLUMN;
845
953
  }
846
954
 
847
- const tableCellNode = $createTableCellNode(headerStyles);
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 = $findMatchingParent(startingNode, n => $isTableCellNode(n));
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 = $findMatchingParent(startingNode, n => $isTableRowNode(n));
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 = $findMatchingParent(startingNode, n => $isTableNode(n));
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
- const headerStyles = new Set();
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.getHeaderStyles().has('column') || below && below.getHeaderStyles().has('column')) {
948
- headerStyles.add('column');
1056
+ if (above && above.hasHeaderState(TableCellHeaderStates.COLUMN) || below && below.hasHeaderState(TableCellHeaderStates.COLUMN)) {
1057
+ headerState |= TableCellHeaderStates.COLUMN;
949
1058
  }
950
1059
 
951
- const tableCellNode = $createTableCellNode(headerStyles);
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
- const headerStyles = new Set();
1085
+ let headerState = TableCellHeaderStates.NO_STATUS;
977
1086
 
978
1087
  if (r === 0) {
979
- headerStyles.add('row');
1088
+ headerState |= TableCellHeaderStates.ROW;
980
1089
  }
981
1090
 
982
- const newTableCell = $createTableCellNode(headerStyles);
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;