@lexical/table 0.44.1-nightly.20260519.0 → 0.45.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.
Files changed (37) hide show
  1. package/{LexicalTable.dev.js → dist/LexicalTable.dev.js} +243 -33
  2. package/{LexicalTable.dev.mjs → dist/LexicalTable.dev.mjs} +239 -33
  3. package/{LexicalTable.mjs → dist/LexicalTable.mjs} +4 -0
  4. package/{LexicalTable.node.mjs → dist/LexicalTable.node.mjs} +4 -0
  5. package/dist/LexicalTable.prod.js +9 -0
  6. package/dist/LexicalTable.prod.mjs +9 -0
  7. package/dist/TableImportExtension.d.ts +38 -0
  8. package/{index.d.ts → dist/index.d.ts} +1 -0
  9. package/package.json +34 -18
  10. package/src/LexicalTableCellNode.ts +479 -0
  11. package/src/LexicalTableCommands.ts +27 -0
  12. package/src/LexicalTableExtension.ts +104 -0
  13. package/src/LexicalTableNode.ts +678 -0
  14. package/src/LexicalTableObserver.ts +575 -0
  15. package/src/LexicalTablePluginHelpers.ts +694 -0
  16. package/src/LexicalTableRowNode.ts +154 -0
  17. package/src/LexicalTableSelection.ts +460 -0
  18. package/src/LexicalTableSelectionHelpers.ts +2409 -0
  19. package/src/LexicalTableUtils.ts +1386 -0
  20. package/src/TableImportExtension.ts +302 -0
  21. package/src/constants.ts +13 -0
  22. package/src/index.ts +97 -0
  23. package/LexicalTable.prod.js +0 -9
  24. package/LexicalTable.prod.mjs +0 -9
  25. /package/{LexicalTable.js → dist/LexicalTable.js} +0 -0
  26. /package/{LexicalTable.js.flow → dist/LexicalTable.js.flow} +0 -0
  27. /package/{LexicalTableCellNode.d.ts → dist/LexicalTableCellNode.d.ts} +0 -0
  28. /package/{LexicalTableCommands.d.ts → dist/LexicalTableCommands.d.ts} +0 -0
  29. /package/{LexicalTableExtension.d.ts → dist/LexicalTableExtension.d.ts} +0 -0
  30. /package/{LexicalTableNode.d.ts → dist/LexicalTableNode.d.ts} +0 -0
  31. /package/{LexicalTableObserver.d.ts → dist/LexicalTableObserver.d.ts} +0 -0
  32. /package/{LexicalTablePluginHelpers.d.ts → dist/LexicalTablePluginHelpers.d.ts} +0 -0
  33. /package/{LexicalTableRowNode.d.ts → dist/LexicalTableRowNode.d.ts} +0 -0
  34. /package/{LexicalTableSelection.d.ts → dist/LexicalTableSelection.d.ts} +0 -0
  35. /package/{LexicalTableSelectionHelpers.d.ts → dist/LexicalTableSelectionHelpers.d.ts} +0 -0
  36. /package/{LexicalTableUtils.d.ts → dist/LexicalTableUtils.d.ts} +0 -0
  37. /package/{constants.d.ts → dist/constants.d.ts} +0 -0
@@ -12,6 +12,7 @@ var utils = require('@lexical/utils');
12
12
  var lexical = require('lexical');
13
13
  var extension = require('@lexical/extension');
14
14
  var clipboard = require('@lexical/clipboard');
15
+ var html = require('@lexical/html');
15
16
 
16
17
  /**
17
18
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -111,7 +112,7 @@ class TableCellNode extends lexical.ElementNode {
111
112
  if (this.__backgroundColor !== null) {
112
113
  element.style.backgroundColor = this.__backgroundColor;
113
114
  }
114
- if (isValidVerticalAlign(this.__verticalAlign)) {
115
+ if (isValidVerticalAlign$1(this.__verticalAlign)) {
115
116
  element.style.verticalAlign = this.__verticalAlign;
116
117
  }
117
118
  utils.addClassNamesToElement(element, config.theme.tableCell, this.hasHeader() && config.theme.tableCellHeader);
@@ -141,7 +142,7 @@ class TableCellNode extends lexical.ElementNode {
141
142
  exportJSON() {
142
143
  return {
143
144
  ...super.exportJSON(),
144
- ...(isValidVerticalAlign(this.__verticalAlign) && {
145
+ ...(isValidVerticalAlign$1(this.__verticalAlign) && {
145
146
  verticalAlign: this.__verticalAlign
146
147
  }),
147
148
  backgroundColor: this.getBackgroundColor(),
@@ -233,7 +234,7 @@ class TableCellNode extends lexical.ElementNode {
233
234
  return false;
234
235
  }
235
236
  }
236
- function isValidVerticalAlign(verticalAlign) {
237
+ function isValidVerticalAlign$1(verticalAlign) {
237
238
  return verticalAlign === 'middle' || verticalAlign === 'bottom';
238
239
  }
239
240
  function $convertTableCellNodeElement(domNode) {
@@ -274,7 +275,7 @@ function $convertTableCellNodeElement(domNode) {
274
275
  tableCellNode.__backgroundColor = backgroundColor;
275
276
  }
276
277
  const verticalAlign = domNode_.style.verticalAlign;
277
- if (isValidVerticalAlign(verticalAlign)) {
278
+ if (isValidVerticalAlign$1(verticalAlign)) {
278
279
  tableCellNode.__verticalAlign = verticalAlign;
279
280
  }
280
281
  const style = domNode_.style;
@@ -469,28 +470,6 @@ function $isTableRowNode(node) {
469
470
  return node instanceof TableRowNode;
470
471
  }
471
472
 
472
- /**
473
- * Copyright (c) Meta Platforms, Inc. and affiliates.
474
- *
475
- * This source code is licensed under the MIT license found in the
476
- * LICENSE file in the root directory of this source tree.
477
- *
478
- */
479
-
480
- const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
481
-
482
- /**
483
- * Copyright (c) Meta Platforms, Inc. and affiliates.
484
- *
485
- * This source code is licensed under the MIT license found in the
486
- * LICENSE file in the root directory of this source tree.
487
- *
488
- */
489
-
490
- const documentMode = CAN_USE_DOM && 'documentMode' in document ? document.documentMode : null;
491
- const IS_FIREFOX = CAN_USE_DOM && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
492
- CAN_USE_DOM && 'InputEvent' in window && !documentMode ? 'getTargetRanges' in new window.InputEvent('input') : false;
493
-
494
473
  function $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders = true) {
495
474
  const tableNode = $createTableNode();
496
475
  for (let iRow = 0; iRow < rowCount; iRow++) {
@@ -1823,7 +1802,7 @@ function $isTableSelection(x) {
1823
1802
  function $createTableSelection() {
1824
1803
  // TODO this is a suboptimal design, it doesn't make sense to have
1825
1804
  // a table selection that isn't associated with a table. This
1826
- // constructor should have required arguments and in true we
1805
+ // constructor should have required arguments and in __DEV__ we
1827
1806
  // should check that they point to a table and are element points to
1828
1807
  // cell nodes of that table.
1829
1808
  const anchor = lexical.$createPoint('root', 0, 'element');
@@ -2390,7 +2369,7 @@ function $handleTableClick(editor, event, selectedDOMCell, tableElement, tableOb
2390
2369
  let focusCell = null;
2391
2370
  // In firefox the moveEvent.target may be captured so we must always
2392
2371
  // consult the coordinates #7245
2393
- const override = !(IS_FIREFOX || tableElement.contains(moveEvent.target));
2372
+ const override = !(lexical.IS_FIREFOX || tableElement.contains(moveEvent.target));
2394
2373
  if (override) {
2395
2374
  focusCell = getDOMCellInTableFromTarget(tableElement, moveEvent.target);
2396
2375
  } else {
@@ -2428,7 +2407,7 @@ function $handleTableClick(editor, event, selectedDOMCell, tableElement, tableOb
2428
2407
  // We can't trust Firefox to do the right thing with the selection and
2429
2408
  // we don't have a proper state machine to do this "correctly" but
2430
2409
  // if we go ahead and make the table selection now it will work
2431
- if (IS_FIREFOX && event.shiftKey && $isSelectionInTable(prevSelection, tableNode) && (lexical.$isRangeSelection(prevSelection) || $isTableSelection(prevSelection))) {
2410
+ if (lexical.IS_FIREFOX && event.shiftKey && $isSelectionInTable(prevSelection, tableNode) && (lexical.$isRangeSelection(prevSelection) || $isTableSelection(prevSelection))) {
2432
2411
  const prevAnchorNode = prevSelection.anchor.getNode();
2433
2412
  const prevAnchorCell = $findParentTableCellNodeInTable(tableNode, prevSelection.anchor.getNode());
2434
2413
  if (prevAnchorCell) {
@@ -3677,6 +3656,7 @@ function $getNearestTableCellInTableFromDOMNode(tableNode, startingDOM, editorSt
3677
3656
  return $findParentTableCellNodeInTable(tableNode, lexical.$getNearestNodeFromDOMNode(startingDOM, editorState));
3678
3657
  }
3679
3658
 
3659
+ const __DEV__ = "development" !== 'production';
3680
3660
  function isHTMLDivElement(element) {
3681
3661
  return utils.isHTMLElement(element) && element.nodeName === 'DIV';
3682
3662
  }
@@ -3771,7 +3751,7 @@ class TableNode extends lexical.ElementNode {
3771
3751
  setColWidths(colWidths) {
3772
3752
  const self = this.getWritable();
3773
3753
  // NOTE: Node properties should be immutable. Freeze to prevent accidental mutation.
3774
- self.__colWidths = colWidths !== undefined && true ? Object.freeze(colWidths) : colWidths;
3754
+ self.__colWidths = colWidths !== undefined && __DEV__ ? Object.freeze(colWidths) : colWidths;
3775
3755
  return self;
3776
3756
  }
3777
3757
  static clone(node) {
@@ -4601,9 +4581,11 @@ const TableExtension = lexical.defineExtension({
4601
4581
  const hadHorizontalScroll = $isScrollableTablesActive(editor);
4602
4582
  if (hadHorizontalScroll !== hasHorizontalScroll) {
4603
4583
  setScrollableTablesActive(editor, hasHorizontalScroll);
4604
- // Registering the transform has the side-effect of marking all existing
4605
- // TableNodes as dirty. The handler is immediately unregistered.
4606
- editor.registerNodeTransform(TableNode, () => {})();
4584
+ // Re-render existing tables through the new scroll-wrapper config
4585
+ // without cloning every TableNode the way marking them dirty would. A
4586
+ // full reconcile marks no nodes dirty, so it's deferred (no
4587
+ // synchronous render from this effect) and produces no history entry.
4588
+ editor.update(lexical.$fullReconcile);
4607
4589
  }
4608
4590
  }), registerTablePlugin(editor, stores), extension.effect(() => registerTableSelectionObserver(editor, stores.hasTabHandler.value)), extension.effect(() => stores.hasCellMerge.value ? undefined : registerTableCellUnmergeTransform(editor)), extension.effect(() => stores.hasCellBackgroundColor.value ? undefined : editor.registerNodeTransform(TableCellNode, node => {
4609
4591
  if (node.getBackgroundColor() !== null) {
@@ -4613,6 +4595,230 @@ const TableExtension = lexical.defineExtension({
4613
4595
  }
4614
4596
  });
4615
4597
 
4598
+ /**
4599
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4600
+ *
4601
+ * This source code is licensed under the MIT license found in the
4602
+ * LICENSE file in the root directory of this source tree.
4603
+ *
4604
+ */
4605
+
4606
+ function isValidVerticalAlign(verticalAlign) {
4607
+ return verticalAlign === 'middle' || verticalAlign === 'bottom';
4608
+ }
4609
+
4610
+ /**
4611
+ * Bitmask of TextNode format bits implied by a `<th>` / `<td>`'s
4612
+ * inline styles (`font-weight: bold`, `font-style: italic`, and
4613
+ * `underline` / `line-through` in `text-decoration`).
4614
+ */
4615
+ function cellTextFormatMask(style) {
4616
+ let mask = 0;
4617
+ const fontWeight = style.fontWeight;
4618
+ if (fontWeight === '700' || fontWeight === 'bold') {
4619
+ mask |= lexical.IS_BOLD;
4620
+ }
4621
+ if (style.fontStyle === 'italic') {
4622
+ mask |= lexical.IS_ITALIC;
4623
+ }
4624
+ const decoration = (style.textDecoration || '').split(' ');
4625
+ if (decoration.includes('underline')) {
4626
+ mask |= lexical.IS_UNDERLINE;
4627
+ }
4628
+ if (decoration.includes('line-through')) {
4629
+ mask |= lexical.IS_STRIKETHROUGH;
4630
+ }
4631
+ return mask;
4632
+ }
4633
+
4634
+ /**
4635
+ * Coalesce inline + line-break runs in a cell into paragraphs. Mirrors
4636
+ * the legacy `removeSingleLineBreakNode` cleanup so a sole `<br>` doesn't
4637
+ * survive as a paragraph's only child.
4638
+ */
4639
+ function $packageCellChildren(children) {
4640
+ const result = [];
4641
+ let paragraph = null;
4642
+ const flushSingleLineBreak = () => {
4643
+ if (paragraph !== null) {
4644
+ const first = paragraph.getFirstChild();
4645
+ if (lexical.$isLineBreakNode(first) && paragraph.getChildrenSize() === 1) {
4646
+ first.remove();
4647
+ }
4648
+ }
4649
+ };
4650
+ for (const child of children) {
4651
+ if (lexical.$isInlineElementOrDecoratorNode(child) || lexical.$isTextNode(child) || lexical.$isLineBreakNode(child)) {
4652
+ if (paragraph !== null) {
4653
+ paragraph.append(child);
4654
+ } else {
4655
+ paragraph = lexical.$createParagraphNode().append(child);
4656
+ result.push(paragraph);
4657
+ }
4658
+ } else {
4659
+ flushSingleLineBreak();
4660
+ result.push(child);
4661
+ paragraph = null;
4662
+ }
4663
+ }
4664
+ flushSingleLineBreak();
4665
+ if (result.length === 0) {
4666
+ result.push(lexical.$createParagraphNode());
4667
+ }
4668
+ return result;
4669
+ }
4670
+ const TableRule = html.defineImportRule({
4671
+ $import: (ctx, el) => {
4672
+ const node = $createTableNode();
4673
+ if (el.hasAttribute('data-lexical-row-striping')) {
4674
+ node.setRowStriping(true);
4675
+ }
4676
+ if (el.hasAttribute('data-lexical-frozen-column')) {
4677
+ node.setFrozenColumns(1);
4678
+ }
4679
+ if (el.hasAttribute('data-lexical-frozen-row')) {
4680
+ node.setFrozenRows(1);
4681
+ }
4682
+ const colGroup = el.querySelector(':scope > colgroup');
4683
+ if (colGroup) {
4684
+ let columns = [];
4685
+ for (const col of colGroup.querySelectorAll(':scope > col')) {
4686
+ let width = col.style.width || '';
4687
+ if (!PIXEL_VALUE_REG_EXP.test(width)) {
4688
+ width = col.getAttribute('width') || '';
4689
+ if (!/^\d+$/.test(width)) {
4690
+ columns = undefined;
4691
+ break;
4692
+ }
4693
+ }
4694
+ columns.push(parseFloat(width));
4695
+ }
4696
+ if (columns) {
4697
+ node.setColWidths(columns);
4698
+ }
4699
+ }
4700
+ return [node.splice(0, 0, utils.$descendantsMatching(ctx.$importChildren(el), $isTableRowNode))];
4701
+ },
4702
+ match: html.sel.tag('table'),
4703
+ name: '@lexical/table/table'
4704
+ });
4705
+ const TableRowRule = html.defineImportRule({
4706
+ $import: (ctx, el) => {
4707
+ const height = PIXEL_VALUE_REG_EXP.test(el.style.height) ? parseFloat(el.style.height) : undefined;
4708
+ return [$createTableRowNode(height).splice(0, 0, utils.$descendantsMatching(ctx.$importChildren(el), $isTableCellNode))];
4709
+ },
4710
+ match: html.sel.tag('tr'),
4711
+ name: '@lexical/table/tr'
4712
+ });
4713
+ const TableCellRule = html.defineImportRule({
4714
+ $import: (ctx, el) => {
4715
+ const isHeader = el.nodeName === 'TH';
4716
+ const width = PIXEL_VALUE_REG_EXP.test(el.style.width) ? parseFloat(el.style.width) : undefined;
4717
+ let headerState = TableCellHeaderStates.NO_STATUS;
4718
+ if (isHeader) {
4719
+ const scope = el.getAttribute('scope');
4720
+ if (scope === 'col') {
4721
+ headerState = TableCellHeaderStates.COLUMN;
4722
+ } else if (scope === 'row') {
4723
+ headerState = TableCellHeaderStates.ROW;
4724
+ } else {
4725
+ const parentRow = el.parentElement;
4726
+ const isInHeaderRow = lexical.isHTMLTableRowElement(parentRow) && (parentRow.parentElement && parentRow.parentElement.nodeName === 'THEAD' || parentRow.rowIndex === 0);
4727
+ const isFirstColumn = el.cellIndex === 0;
4728
+ if (isInHeaderRow) {
4729
+ headerState |= TableCellHeaderStates.ROW;
4730
+ }
4731
+ if (isFirstColumn) {
4732
+ headerState |= TableCellHeaderStates.COLUMN;
4733
+ }
4734
+ if (headerState === TableCellHeaderStates.NO_STATUS) {
4735
+ headerState = TableCellHeaderStates.ROW;
4736
+ }
4737
+ }
4738
+ }
4739
+ const cell = $createTableCellNode(headerState, el.colSpan, width);
4740
+ cell.__rowSpan = el.rowSpan;
4741
+ const backgroundColor = el.style.backgroundColor;
4742
+ if (backgroundColor !== '') {
4743
+ cell.__backgroundColor = backgroundColor;
4744
+ }
4745
+ const verticalAlign = el.style.verticalAlign;
4746
+ if (isValidVerticalAlign(verticalAlign)) {
4747
+ cell.__verticalAlign = verticalAlign;
4748
+ }
4749
+ // Propagate the cell's bold/italic/underline/strikethrough as
4750
+ // format bits, and the cell's `color` as a parsed-style record.
4751
+ // The core `#text` rule reads both at construction time and
4752
+ // applies them to each TextNode — no post-walk needed.
4753
+ const inheritedFormat = ctx.get(html.ImportTextFormat);
4754
+ const cellFormat = inheritedFormat | cellTextFormatMask(el.style);
4755
+ const inheritedStyle = ctx.get(html.ImportTextStyle);
4756
+ const color = el.style.color;
4757
+ const cellStyle = color ? {
4758
+ ...inheritedStyle,
4759
+ color
4760
+ } : inheritedStyle;
4761
+ const branchContext = [];
4762
+ if (cellFormat !== inheritedFormat) {
4763
+ branchContext.push(html.contextValue(html.ImportTextFormat, cellFormat));
4764
+ }
4765
+ if (cellStyle !== inheritedStyle) {
4766
+ branchContext.push(html.contextValue(html.ImportTextStyle, cellStyle));
4767
+ }
4768
+ return [cell.splice(0, 0, $packageCellChildren(ctx.$importChildren(el, {
4769
+ context: branchContext
4770
+ })))];
4771
+ },
4772
+ match: html.sel.tag('td', 'th'),
4773
+ name: '@lexical/table/cell'
4774
+ });
4775
+
4776
+ /**
4777
+ * A {@link ChildSchema} that enforces TableNode invariants: only
4778
+ * `TableRowNode` children are accepted; orphan `TableCellNode` runs are
4779
+ * wrapped in a synthesized row.
4780
+ *
4781
+ * @experimental
4782
+ */
4783
+ const TableSchema = {
4784
+ $accepts: $isTableRowNode,
4785
+ $packageRun: run => run.every($isTableCellNode) ? [$createTableRowNode().splice(0, 0, run)] : [],
4786
+ name: 'TableSchema'
4787
+ };
4788
+
4789
+ /**
4790
+ * A {@link ChildSchema} that enforces TableRowNode invariants: only
4791
+ * `TableCellNode` children are accepted; non-cell children are dropped
4792
+ * (the legacy converter does the same via `$descendantsMatching`).
4793
+ *
4794
+ * @experimental
4795
+ */
4796
+ const TableRowSchema = {
4797
+ $accepts: $isTableCellNode,
4798
+ name: 'TableRowSchema'
4799
+ };
4800
+
4801
+ /**
4802
+ * Import rules for {@link TableNode}, {@link TableRowNode}, and
4803
+ * {@link TableCellNode}.
4804
+ *
4805
+ * @experimental
4806
+ */
4807
+ const TableImportRules = [TableRule, TableRowRule, TableCellRule];
4808
+
4809
+ /**
4810
+ * Bundles {@link TableImportRules} (plus {@link CoreImportExtension})
4811
+ * into a single dependency.
4812
+ *
4813
+ * @experimental
4814
+ */
4815
+ const TableImportExtension = lexical.defineExtension({
4816
+ dependencies: [html.CoreImportExtension, TableExtension, lexical.configExtension(html.DOMImportExtension, {
4817
+ rules: TableImportRules
4818
+ })],
4819
+ name: '@lexical/table/Import'
4820
+ });
4821
+
4616
4822
  exports.$computeTableMap = $computeTableMap;
4617
4823
  exports.$computeTableMapSkipCellCheck = $computeTableMapSkipCellCheck;
4618
4824
  exports.$createTableCellNode = $createTableCellNode;
@@ -4657,9 +4863,13 @@ exports.INSERT_TABLE_COMMAND = INSERT_TABLE_COMMAND;
4657
4863
  exports.TableCellHeaderStates = TableCellHeaderStates;
4658
4864
  exports.TableCellNode = TableCellNode;
4659
4865
  exports.TableExtension = TableExtension;
4866
+ exports.TableImportExtension = TableImportExtension;
4867
+ exports.TableImportRules = TableImportRules;
4660
4868
  exports.TableNode = TableNode;
4661
4869
  exports.TableObserver = TableObserver;
4662
4870
  exports.TableRowNode = TableRowNode;
4871
+ exports.TableRowSchema = TableRowSchema;
4872
+ exports.TableSchema = TableSchema;
4663
4873
  exports.applyTableHandlers = applyTableHandlers;
4664
4874
  exports.getDOMCellFromTarget = getDOMCellFromTarget;
4665
4875
  exports.getTableElement = getTableElement;