@lexical/table 0.14.5 → 0.16.0
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.dev.js +90 -35
- package/LexicalTable.dev.mjs +91 -37
- package/LexicalTable.js +2 -0
- package/LexicalTable.mjs +3 -0
- package/LexicalTable.node.mjs +3 -0
- package/LexicalTable.prod.js +78 -76
- package/LexicalTable.prod.mjs +3 -1
- package/LexicalTableCellNode.d.ts +1 -1
- package/LexicalTableNode.d.ts +1 -1
- package/LexicalTableRowNode.d.ts +1 -1
- package/LexicalTableUtils.d.ts +1 -0
- package/constants.d.ts +1 -0
- package/index.d.ts +2 -2
- package/package.json +3 -3
package/LexicalTable.dev.js
CHANGED
@@ -3,7 +3,9 @@
|
|
3
3
|
*
|
4
4
|
* This source code is licensed under the MIT license found in the
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
6
|
+
*
|
6
7
|
*/
|
8
|
+
|
7
9
|
'use strict';
|
8
10
|
|
9
11
|
var utils = require('@lexical/utils');
|
@@ -19,6 +21,10 @@ var lexical = require('lexical');
|
|
19
21
|
|
20
22
|
const PIXEL_VALUE_REG_EXP = /^(\d+(?:\.\d+)?)px$/;
|
21
23
|
|
24
|
+
// .PlaygroundEditorTheme__tableCell width value from
|
25
|
+
// packages/lexical-playground/src/themes/PlaygroundEditorTheme.css
|
26
|
+
const COLUMN_WIDTH = 75;
|
27
|
+
|
22
28
|
/**
|
23
29
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
24
30
|
*
|
@@ -26,6 +32,7 @@ const PIXEL_VALUE_REG_EXP = /^(\d+(?:\.\d+)?)px$/;
|
|
26
32
|
* LICENSE file in the root directory of this source tree.
|
27
33
|
*
|
28
34
|
*/
|
35
|
+
|
29
36
|
const TableCellHeaderStates = {
|
30
37
|
BOTH: 3,
|
31
38
|
COLUMN: 2,
|
@@ -56,11 +63,11 @@ class TableCellNode extends lexical.ElementNode {
|
|
56
63
|
static importDOM() {
|
57
64
|
return {
|
58
65
|
td: node => ({
|
59
|
-
conversion: convertTableCellNodeElement,
|
66
|
+
conversion: $convertTableCellNodeElement,
|
60
67
|
priority: 0
|
61
68
|
}),
|
62
69
|
th: node => ({
|
63
|
-
conversion: convertTableCellNodeElement,
|
70
|
+
conversion: $convertTableCellNodeElement,
|
64
71
|
priority: 0
|
65
72
|
})
|
66
73
|
};
|
@@ -104,8 +111,6 @@ class TableCellNode extends lexical.ElementNode {
|
|
104
111
|
} = super.exportDOM(editor);
|
105
112
|
if (element) {
|
106
113
|
const element_ = element;
|
107
|
-
const maxWidth = 700;
|
108
|
-
const colCount = this.getParentOrThrow().getChildrenSize();
|
109
114
|
element_.style.border = '1px solid black';
|
110
115
|
if (this.__colSpan > 1) {
|
111
116
|
element_.colSpan = this.__colSpan;
|
@@ -113,7 +118,7 @@ class TableCellNode extends lexical.ElementNode {
|
|
113
118
|
if (this.__rowSpan > 1) {
|
114
119
|
element_.rowSpan = this.__rowSpan;
|
115
120
|
}
|
116
|
-
element_.style.width = `${this.getWidth() ||
|
121
|
+
element_.style.width = `${this.getWidth() || COLUMN_WIDTH}px`;
|
117
122
|
element_.style.verticalAlign = 'top';
|
118
123
|
element_.style.textAlign = 'start';
|
119
124
|
const backgroundColor = this.getBackgroundColor();
|
@@ -208,7 +213,7 @@ class TableCellNode extends lexical.ElementNode {
|
|
208
213
|
return false;
|
209
214
|
}
|
210
215
|
}
|
211
|
-
function convertTableCellNodeElement(domNode) {
|
216
|
+
function $convertTableCellNodeElement(domNode) {
|
212
217
|
const domNode_ = domNode;
|
213
218
|
const nodeName = domNode.nodeName.toLowerCase();
|
214
219
|
let width = undefined;
|
@@ -222,10 +227,11 @@ function convertTableCellNodeElement(domNode) {
|
|
222
227
|
tableCellNode.__backgroundColor = backgroundColor;
|
223
228
|
}
|
224
229
|
const style = domNode_.style;
|
230
|
+
const textDecoration = style.textDecoration.split(' ');
|
225
231
|
const hasBoldFontWeight = style.fontWeight === '700' || style.fontWeight === 'bold';
|
226
|
-
const hasLinethroughTextDecoration =
|
232
|
+
const hasLinethroughTextDecoration = textDecoration.includes('line-through');
|
227
233
|
const hasItalicFontStyle = style.fontStyle === 'italic';
|
228
|
-
const hasUnderlineTextDecoration =
|
234
|
+
const hasUnderlineTextDecoration = textDecoration.includes('underline');
|
229
235
|
return {
|
230
236
|
after: childLexicalNodes => {
|
231
237
|
if (childLexicalNodes.length === 0) {
|
@@ -275,6 +281,7 @@ function $isTableCellNode(node) {
|
|
275
281
|
* LICENSE file in the root directory of this source tree.
|
276
282
|
*
|
277
283
|
*/
|
284
|
+
|
278
285
|
const INSERT_TABLE_COMMAND = lexical.createCommand('INSERT_TABLE_COMMAND');
|
279
286
|
|
280
287
|
/**
|
@@ -284,6 +291,7 @@ const INSERT_TABLE_COMMAND = lexical.createCommand('INSERT_TABLE_COMMAND');
|
|
284
291
|
* LICENSE file in the root directory of this source tree.
|
285
292
|
*
|
286
293
|
*/
|
294
|
+
|
287
295
|
/** @noInheritDoc */
|
288
296
|
class TableRowNode extends lexical.ElementNode {
|
289
297
|
/** @internal */
|
@@ -297,7 +305,7 @@ class TableRowNode extends lexical.ElementNode {
|
|
297
305
|
static importDOM() {
|
298
306
|
return {
|
299
307
|
tr: node => ({
|
300
|
-
conversion: convertTableRowElement,
|
308
|
+
conversion: $convertTableRowElement,
|
301
309
|
priority: 0
|
302
310
|
})
|
303
311
|
};
|
@@ -348,7 +356,7 @@ class TableRowNode extends lexical.ElementNode {
|
|
348
356
|
return false;
|
349
357
|
}
|
350
358
|
}
|
351
|
-
function convertTableRowElement(domNode) {
|
359
|
+
function $convertTableRowElement(domNode) {
|
352
360
|
const domNode_ = domNode;
|
353
361
|
let height = undefined;
|
354
362
|
if (PIXEL_VALUE_REG_EXP.test(domNode_.style.height)) {
|
@@ -382,6 +390,7 @@ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !==
|
|
382
390
|
* LICENSE file in the root directory of this source tree.
|
383
391
|
*
|
384
392
|
*/
|
393
|
+
|
385
394
|
function $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders = true) {
|
386
395
|
const tableNode = $createTableNode();
|
387
396
|
for (let iRow = 0; iRow < rowCount; iRow++) {
|
@@ -914,6 +923,16 @@ function $unmergeCell() {
|
|
914
923
|
}
|
915
924
|
}
|
916
925
|
function $computeTableMap(grid, cellA, cellB) {
|
926
|
+
const [tableMap, cellAValue, cellBValue] = $computeTableMapSkipCellCheck(grid, cellA, cellB);
|
927
|
+
if (!(cellAValue !== null)) {
|
928
|
+
throw Error(`Anchor not found in Grid`);
|
929
|
+
}
|
930
|
+
if (!(cellBValue !== null)) {
|
931
|
+
throw Error(`Focus not found in Grid`);
|
932
|
+
}
|
933
|
+
return [tableMap, cellAValue, cellBValue];
|
934
|
+
}
|
935
|
+
function $computeTableMapSkipCellCheck(grid, cellA, cellB) {
|
917
936
|
const tableMap = [];
|
918
937
|
let cellAValue = null;
|
919
938
|
let cellBValue = null;
|
@@ -933,10 +952,10 @@ function $computeTableMap(grid, cellA, cellB) {
|
|
933
952
|
tableMap[startRow + i][startColumn + j] = value;
|
934
953
|
}
|
935
954
|
}
|
936
|
-
if (cellA.is(cell)) {
|
955
|
+
if (cellA !== null && cellA.is(cell)) {
|
937
956
|
cellAValue = value;
|
938
957
|
}
|
939
|
-
if (cellB.is(cell)) {
|
958
|
+
if (cellB !== null && cellB.is(cell)) {
|
940
959
|
cellBValue = value;
|
941
960
|
}
|
942
961
|
}
|
@@ -962,12 +981,6 @@ function $computeTableMap(grid, cellA, cellB) {
|
|
962
981
|
j += cell.__colSpan;
|
963
982
|
}
|
964
983
|
}
|
965
|
-
if (!(cellAValue !== null)) {
|
966
|
-
throw Error(`Anchor not found in Grid`);
|
967
|
-
}
|
968
|
-
if (!(cellBValue !== null)) {
|
969
|
-
throw Error(`Focus not found in Grid`);
|
970
|
-
}
|
971
984
|
return [tableMap, cellAValue, cellBValue];
|
972
985
|
}
|
973
986
|
function $getNodeTriplet(source) {
|
@@ -1050,6 +1063,7 @@ function $getTableCellNodeRect(tableCellNode) {
|
|
1050
1063
|
* LICENSE file in the root directory of this source tree.
|
1051
1064
|
*
|
1052
1065
|
*/
|
1066
|
+
|
1053
1067
|
class TableSelection {
|
1054
1068
|
constructor(tableKey, anchor, focus) {
|
1055
1069
|
this.anchor = anchor;
|
@@ -1315,6 +1329,7 @@ function $getChildrenRecursively(node) {
|
|
1315
1329
|
* LICENSE file in the root directory of this source tree.
|
1316
1330
|
*
|
1317
1331
|
*/
|
1332
|
+
|
1318
1333
|
class TableObserver {
|
1319
1334
|
constructor(editor, tableNodeKey) {
|
1320
1335
|
this.isHighlightingCells = false;
|
@@ -1353,7 +1368,7 @@ class TableObserver {
|
|
1353
1368
|
const record = records[i];
|
1354
1369
|
const target = record.target;
|
1355
1370
|
const nodeName = target.nodeName;
|
1356
|
-
if (nodeName === 'TABLE' || nodeName === 'TR') {
|
1371
|
+
if (nodeName === 'TABLE' || nodeName === 'TBODY' || nodeName === 'THEAD' || nodeName === 'TR') {
|
1357
1372
|
gridNeedsRedraw = true;
|
1358
1373
|
break;
|
1359
1374
|
}
|
@@ -1574,8 +1589,12 @@ class TableObserver {
|
|
1574
1589
|
* LICENSE file in the root directory of this source tree.
|
1575
1590
|
*
|
1576
1591
|
*/
|
1592
|
+
|
1577
1593
|
const LEXICAL_ELEMENT_KEY = '__lexicalTableSelection';
|
1578
1594
|
const getDOMSelection = targetWindow => CAN_USE_DOM ? (targetWindow || window).getSelection() : null;
|
1595
|
+
const isMouseDownOnEvent = event => {
|
1596
|
+
return (event.buttons & 1) === 1;
|
1597
|
+
};
|
1579
1598
|
function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
1580
1599
|
const rootElement = editor.getRootElement();
|
1581
1600
|
if (rootElement === null) {
|
@@ -1591,11 +1610,20 @@ function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
|
1591
1610
|
editorWindow.removeEventListener('mousemove', onMouseMove);
|
1592
1611
|
};
|
1593
1612
|
const onMouseMove = moveEvent => {
|
1594
|
-
|
1595
|
-
|
1596
|
-
moveEvent.
|
1597
|
-
|
1598
|
-
|
1613
|
+
// delaying mousemove handler to allow selectionchange handler from LexicalEvents.ts to be executed first
|
1614
|
+
setTimeout(() => {
|
1615
|
+
if (!isMouseDownOnEvent(moveEvent) && tableObserver.isSelecting) {
|
1616
|
+
tableObserver.isSelecting = false;
|
1617
|
+
editorWindow.removeEventListener('mouseup', onMouseUp);
|
1618
|
+
editorWindow.removeEventListener('mousemove', onMouseMove);
|
1619
|
+
return;
|
1620
|
+
}
|
1621
|
+
const focusCell = getDOMCellFromTarget(moveEvent.target);
|
1622
|
+
if (focusCell !== null && (tableObserver.anchorX !== focusCell.x || tableObserver.anchorY !== focusCell.y)) {
|
1623
|
+
moveEvent.preventDefault();
|
1624
|
+
tableObserver.setFocusCellForSelection(focusCell);
|
1625
|
+
}
|
1626
|
+
}, 0);
|
1599
1627
|
};
|
1600
1628
|
return {
|
1601
1629
|
onMouseMove: onMouseMove,
|
@@ -1693,7 +1721,7 @@ function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
|
1693
1721
|
[lexical.DELETE_WORD_COMMAND, lexical.DELETE_LINE_COMMAND, lexical.DELETE_CHARACTER_COMMAND].forEach(command => {
|
1694
1722
|
tableObserver.listenersToRemove.add(editor.registerCommand(command, deleteTextHandler(command), lexical.COMMAND_PRIORITY_CRITICAL));
|
1695
1723
|
});
|
1696
|
-
const deleteCellHandler = event => {
|
1724
|
+
const $deleteCellHandler = event => {
|
1697
1725
|
const selection = lexical.$getSelection();
|
1698
1726
|
if (!$isSelectionInTable(selection, tableNode)) {
|
1699
1727
|
return false;
|
@@ -1711,8 +1739,8 @@ function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
|
1711
1739
|
}
|
1712
1740
|
return false;
|
1713
1741
|
};
|
1714
|
-
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_BACKSPACE_COMMAND, deleteCellHandler, lexical.COMMAND_PRIORITY_CRITICAL));
|
1715
|
-
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_DELETE_COMMAND, deleteCellHandler, lexical.COMMAND_PRIORITY_CRITICAL));
|
1742
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_BACKSPACE_COMMAND, $deleteCellHandler, lexical.COMMAND_PRIORITY_CRITICAL));
|
1743
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_DELETE_COMMAND, $deleteCellHandler, lexical.COMMAND_PRIORITY_CRITICAL));
|
1716
1744
|
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.FORMAT_TEXT_COMMAND, payload => {
|
1717
1745
|
const selection = lexical.$getSelection();
|
1718
1746
|
if (!$isSelectionInTable(selection, tableNode)) {
|
@@ -1910,7 +1938,7 @@ function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
|
1910
1938
|
if (isPartialyWithinTable) {
|
1911
1939
|
const newSelection = selection.clone();
|
1912
1940
|
if (isFocusInside) {
|
1913
|
-
newSelection.focus.set(tableNode.getParentOrThrow().getKey(),
|
1941
|
+
newSelection.focus.set(tableNode.getParentOrThrow().getKey(), tableNode.getIndexWithinParent(), 'element');
|
1914
1942
|
} else {
|
1915
1943
|
newSelection.anchor.set(tableNode.getParentOrThrow().getKey(), isBackward ? tableNode.getIndexWithinParent() + 1 : tableNode.getIndexWithinParent(), 'element');
|
1916
1944
|
}
|
@@ -2234,6 +2262,9 @@ function $findTableNode(node) {
|
|
2234
2262
|
return $isTableNode(tableNode) ? tableNode : null;
|
2235
2263
|
}
|
2236
2264
|
function $handleArrowKey(editor, event, direction, tableNode, tableObserver) {
|
2265
|
+
if ((direction === 'up' || direction === 'down') && isTypeaheadMenuInView(editor)) {
|
2266
|
+
return false;
|
2267
|
+
}
|
2237
2268
|
const selection = lexical.$getSelection();
|
2238
2269
|
if (!$isSelectionInTable(selection, tableNode)) {
|
2239
2270
|
if (direction === 'backward' && lexical.$isRangeSelection(selection) && selection.isCollapsed()) {
|
@@ -2285,6 +2316,10 @@ function $handleArrowKey(editor, event, direction, tableNode, tableObserver) {
|
|
2285
2316
|
if (!anchorNode) {
|
2286
2317
|
return false;
|
2287
2318
|
}
|
2319
|
+
const selectedNodes = selection.getNodes();
|
2320
|
+
if (selectedNodes.length === 1 && lexical.$isDecoratorNode(selectedNodes[0])) {
|
2321
|
+
return false;
|
2322
|
+
}
|
2288
2323
|
if (isExitingTableAnchor(anchorType, anchorOffset, anchorNode, direction)) {
|
2289
2324
|
return $handleTableExit(event, anchorNode, tableNode, direction);
|
2290
2325
|
}
|
@@ -2361,13 +2396,22 @@ function stopEvent(event) {
|
|
2361
2396
|
event.stopImmediatePropagation();
|
2362
2397
|
event.stopPropagation();
|
2363
2398
|
}
|
2399
|
+
function isTypeaheadMenuInView(editor) {
|
2400
|
+
// There is no inbuilt way to check if the component picker is in view
|
2401
|
+
// but we can check if the root DOM element has the aria-controls attribute "typeahead-menu".
|
2402
|
+
const root = editor.getRootElement();
|
2403
|
+
if (!root) {
|
2404
|
+
return false;
|
2405
|
+
}
|
2406
|
+
return root.hasAttribute('aria-controls') && root.getAttribute('aria-controls') === 'typeahead-menu';
|
2407
|
+
}
|
2364
2408
|
function isExitingTableAnchor(type, offset, anchorNode, direction) {
|
2365
|
-
return isExitingTableElementAnchor(type, anchorNode, direction) || isExitingTableTextAnchor(type, offset, anchorNode, direction);
|
2409
|
+
return isExitingTableElementAnchor(type, anchorNode, direction) || $isExitingTableTextAnchor(type, offset, anchorNode, direction);
|
2366
2410
|
}
|
2367
2411
|
function isExitingTableElementAnchor(type, anchorNode, direction) {
|
2368
2412
|
return type === 'element' && (direction === 'backward' ? anchorNode.getPreviousSibling() === null : anchorNode.getNextSibling() === null);
|
2369
2413
|
}
|
2370
|
-
function isExitingTableTextAnchor(type, offset, anchorNode, direction) {
|
2414
|
+
function $isExitingTableTextAnchor(type, offset, anchorNode, direction) {
|
2371
2415
|
const parentNode = utils.$findMatchingParent(anchorNode, n => lexical.$isElementNode(n) && !n.isInline());
|
2372
2416
|
if (!parentNode) {
|
2373
2417
|
return false;
|
@@ -2384,7 +2428,7 @@ function $handleTableExit(event, anchorNode, tableNode, direction) {
|
|
2384
2428
|
if (!isExitingCell(tableMap, cellValue, direction)) {
|
2385
2429
|
return false;
|
2386
2430
|
}
|
2387
|
-
const toNode = getExitingToNode(anchorNode, direction, tableNode);
|
2431
|
+
const toNode = $getExitingToNode(anchorNode, direction, tableNode);
|
2388
2432
|
if (!toNode || $isTableNode(toNode)) {
|
2389
2433
|
return false;
|
2390
2434
|
}
|
@@ -2405,7 +2449,7 @@ function isExitingCell(tableMap, cellValue, direction) {
|
|
2405
2449
|
} = cellValue;
|
2406
2450
|
return direction === 'backward' ? startColumn === firstCell.startColumn && startRow === firstCell.startRow : startColumn === lastCell.startColumn && startRow === lastCell.startRow;
|
2407
2451
|
}
|
2408
|
-
function getExitingToNode(anchorNode, direction, tableNode) {
|
2452
|
+
function $getExitingToNode(anchorNode, direction, tableNode) {
|
2409
2453
|
const parentNode = utils.$findMatchingParent(anchorNode, n => lexical.$isElementNode(n) && !n.isInline());
|
2410
2454
|
if (!parentNode) {
|
2411
2455
|
return undefined;
|
@@ -2424,9 +2468,18 @@ function $insertParagraphAtTableEdge(edgePosition, tableNode, children) {
|
|
2424
2468
|
paragraphNode.selectEnd();
|
2425
2469
|
}
|
2426
2470
|
function $getTableEdgeCursorPosition(editor, selection, tableNode) {
|
2471
|
+
const tableNodeParent = tableNode.getParent();
|
2472
|
+
if (!tableNodeParent) {
|
2473
|
+
return undefined;
|
2474
|
+
}
|
2475
|
+
const tableNodeParentDOM = editor.getElementByKey(tableNodeParent.getKey());
|
2476
|
+
if (!tableNodeParentDOM) {
|
2477
|
+
return undefined;
|
2478
|
+
}
|
2479
|
+
|
2427
2480
|
// TODO: Add support for nested tables
|
2428
2481
|
const domSelection = window.getSelection();
|
2429
|
-
if (!domSelection || domSelection.anchorNode !==
|
2482
|
+
if (!domSelection || domSelection.anchorNode !== tableNodeParentDOM) {
|
2430
2483
|
return undefined;
|
2431
2484
|
}
|
2432
2485
|
const anchorCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
@@ -2462,6 +2515,7 @@ function $getTableEdgeCursorPosition(editor, selection, tableNode) {
|
|
2462
2515
|
* LICENSE file in the root directory of this source tree.
|
2463
2516
|
*
|
2464
2517
|
*/
|
2518
|
+
|
2465
2519
|
/** @noInheritDoc */
|
2466
2520
|
class TableNode extends lexical.ElementNode {
|
2467
2521
|
static getType() {
|
@@ -2473,7 +2527,7 @@ class TableNode extends lexical.ElementNode {
|
|
2473
2527
|
static importDOM() {
|
2474
2528
|
return {
|
2475
2529
|
table: _node => ({
|
2476
|
-
conversion: convertTableElement,
|
2530
|
+
conversion: $convertTableElement,
|
2477
2531
|
priority: 1
|
2478
2532
|
})
|
2479
2533
|
};
|
@@ -2613,7 +2667,7 @@ function $getElementForTableNode(editor, tableNode) {
|
|
2613
2667
|
}
|
2614
2668
|
return getTable(tableElement);
|
2615
2669
|
}
|
2616
|
-
function convertTableElement(_domNode) {
|
2670
|
+
function $convertTableElement(_domNode) {
|
2617
2671
|
return {
|
2618
2672
|
node: $createTableNode()
|
2619
2673
|
};
|
@@ -2626,6 +2680,7 @@ function $isTableNode(node) {
|
|
2626
2680
|
}
|
2627
2681
|
|
2628
2682
|
exports.$computeTableMap = $computeTableMap;
|
2683
|
+
exports.$computeTableMapSkipCellCheck = $computeTableMapSkipCellCheck;
|
2629
2684
|
exports.$createTableCellNode = $createTableCellNode;
|
2630
2685
|
exports.$createTableNode = $createTableNode;
|
2631
2686
|
exports.$createTableNodeWithDimensions = $createTableNodeWithDimensions;
|