@zuilib/text-editor 0.9.0 → 0.10.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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/EditorRoot.tsx
2
2
  import {
3
3
  useCallback as useCallback2,
4
- useEffect as useEffect8,
4
+ useEffect as useEffect9,
5
5
  useMemo as useMemo2,
6
6
  useRef as useRef5,
7
7
  useState as useState4
@@ -15,7 +15,7 @@ import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPl
15
15
  import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
16
16
  import { TablePlugin } from "@lexical/react/LexicalTablePlugin";
17
17
  import { CHECK_LIST, CODE as CODE2, TRANSFORMERS as TRANSFORMERS2 } from "@lexical/markdown";
18
- import { useLexicalComposerContext as useLexicalComposerContext6 } from "@lexical/react/LexicalComposerContext";
18
+ import { useLexicalComposerContext as useLexicalComposerContext7 } from "@lexical/react/LexicalComposerContext";
19
19
  import { HeadingNode, QuoteNode } from "@lexical/rich-text";
20
20
  import { ListItemNode, ListNode as ListNode2 } from "@lexical/list";
21
21
  import { CodeHighlightNode, CodeNode as CodeNode2 } from "@lexical/code";
@@ -1607,6 +1607,304 @@ function MarkdownSyncPlugin({
1607
1607
  return null;
1608
1608
  }
1609
1609
 
1610
+ // src/plugins/TableRowShortcutsPlugin.tsx
1611
+ import { useEffect as useEffect5 } from "react";
1612
+ import { useLexicalComposerContext as useLexicalComposerContext5 } from "@lexical/react/LexicalComposerContext";
1613
+ import { $getSelection as $getSelection4, $isRangeSelection as $isRangeSelection4, COMMAND_PRIORITY_HIGH, KEY_DOWN_COMMAND } from "lexical";
1614
+ import { $isTableRowNode as $isTableRowNode2 } from "@lexical/table";
1615
+
1616
+ // src/transformers/tableSettings.ts
1617
+ import {
1618
+ $getNodeByKey as $getNodeByKey2,
1619
+ $getSelection as $getSelection2,
1620
+ $isRangeSelection as $isRangeSelection2
1621
+ } from "lexical";
1622
+ import { $findMatchingParent } from "@lexical/utils";
1623
+ import { $isTableNode, $isTableSelection } from "@lexical/table";
1624
+ var DEFAULT_TABLE_SETTINGS = {
1625
+ width: "full",
1626
+ density: "comfortable"
1627
+ };
1628
+ var BLOCK_BLEED_PROPERTY = "--zui-text-editor-block-bleed";
1629
+ var OPTION_DECLARATIONS = {
1630
+ width: {
1631
+ full: {},
1632
+ content: { width: "auto", "table-layout": "auto", [BLOCK_BLEED_PROPERTY]: "0px" },
1633
+ text: { [BLOCK_BLEED_PROPERTY]: "0px" }
1634
+ },
1635
+ density: {
1636
+ comfortable: {},
1637
+ compact: {
1638
+ "--zui-table-cell-padding": "0.25rem 0.5rem",
1639
+ "--zui-table-font-size": "0.8125rem"
1640
+ },
1641
+ spacious: {
1642
+ "--zui-table-cell-padding": "0.875rem 1rem",
1643
+ "--zui-table-font-size": "0.9375rem"
1644
+ }
1645
+ }
1646
+ };
1647
+ var SETTING_KEYS = Object.keys(OPTION_DECLARATIONS);
1648
+ var EXPLICIT_WIDTH_PROPERTY = "--zui-table-width";
1649
+ function parseStyle(style) {
1650
+ const declarations = /* @__PURE__ */ new Map();
1651
+ for (const part of style.split(";")) {
1652
+ const index = part.indexOf(":");
1653
+ if (index === -1) continue;
1654
+ const key = part.slice(0, index).trim();
1655
+ const value = part.slice(index + 1).trim();
1656
+ if (key && value) declarations.set(key, value);
1657
+ }
1658
+ return declarations;
1659
+ }
1660
+ function serializeStyle(declarations) {
1661
+ return [...declarations].map(([key, value]) => `${key}: ${value}`).join("; ");
1662
+ }
1663
+ function optionsOf(setting) {
1664
+ return Object.entries(OPTION_DECLARATIONS[setting]);
1665
+ }
1666
+ function readSetting(declarations, setting) {
1667
+ for (const [option, decls] of optionsOf(setting)) {
1668
+ const entries = Object.entries(decls);
1669
+ if (entries.length === 0) continue;
1670
+ if (entries.every(([key, value]) => declarations.get(key) === value)) {
1671
+ return option;
1672
+ }
1673
+ }
1674
+ return DEFAULT_TABLE_SETTINGS[setting];
1675
+ }
1676
+ function writeSetting(declarations, setting, option) {
1677
+ for (const [, decls] of optionsOf(setting)) {
1678
+ for (const key of Object.keys(decls)) declarations.delete(key);
1679
+ }
1680
+ for (const [key, value] of Object.entries(OPTION_DECLARATIONS[setting][option])) {
1681
+ declarations.set(key, value);
1682
+ }
1683
+ }
1684
+ function $getTableSettings(table) {
1685
+ const declarations = parseStyle(table.getStyle());
1686
+ return {
1687
+ width: readSetting(declarations, "width"),
1688
+ density: readSetting(declarations, "density")
1689
+ };
1690
+ }
1691
+ function $setTableSettings(table, settings, options = {}) {
1692
+ const declarations = parseStyle(table.getStyle());
1693
+ for (const key of SETTING_KEYS) {
1694
+ const option = settings[key];
1695
+ if (option !== void 0) writeSetting(declarations, key, option);
1696
+ }
1697
+ if (settings.width !== void 0) {
1698
+ if (options.explicitWidth) declarations.set(EXPLICIT_WIDTH_PROPERTY, settings.width);
1699
+ else declarations.delete(EXPLICIT_WIDTH_PROPERTY);
1700
+ }
1701
+ table.setStyle(serializeStyle(declarations));
1702
+ }
1703
+ function $isTableWidthExplicit(table) {
1704
+ const declarations = parseStyle(table.getStyle());
1705
+ return declarations.get(EXPLICIT_WIDTH_PROPERTY) === readSetting(declarations, "width");
1706
+ }
1707
+ function $getTableWidth(table) {
1708
+ return $getTableSettings(table).width;
1709
+ }
1710
+ function $setTableWidth(table, width) {
1711
+ $setTableSettings(table, { width });
1712
+ }
1713
+ function $getTableDensity(table) {
1714
+ return $getTableSettings(table).density;
1715
+ }
1716
+ function $setTableDensity(table, density) {
1717
+ $setTableSettings(table, { density });
1718
+ }
1719
+ function $getSelectedTable() {
1720
+ const selection = $getSelection2();
1721
+ if ($isTableSelection(selection)) {
1722
+ const node = $getNodeByKey2(selection.tableKey);
1723
+ return $isTableNode(node) ? node : null;
1724
+ }
1725
+ if (!$isRangeSelection2(selection)) return null;
1726
+ const table = $findMatchingParent(
1727
+ selection.anchor.getNode(),
1728
+ (node) => $isTableNode(node)
1729
+ );
1730
+ return $isTableNode(table) ? table : null;
1731
+ }
1732
+ var MARKER_REG_EXP = /^<!--\s*([a-z]+\s*:\s*[a-z]+(?:\s*;\s*[a-z]+\s*:\s*[a-z]+)*)\s*;?\s*-->\s*$/;
1733
+ function isOption(setting, value) {
1734
+ return value in OPTION_DECLARATIONS[setting];
1735
+ }
1736
+ var TABLE_WIDTH_MARKER = "<!-- width: content -->";
1737
+ function parseTableSettingsMarker(text) {
1738
+ const match = MARKER_REG_EXP.exec(text);
1739
+ if (!match) return null;
1740
+ const settings = {};
1741
+ let recognised = false;
1742
+ for (const pair of match[1].split(";")) {
1743
+ const [key, value] = pair.split(":").map((s) => s.trim());
1744
+ if (key !== "width" && key !== "density") continue;
1745
+ recognised = true;
1746
+ if (key === "width" && isOption("width", value)) settings.width = value;
1747
+ if (key === "density" && isOption("density", value)) settings.density = value;
1748
+ }
1749
+ return recognised ? settings : null;
1750
+ }
1751
+ function formatTableSettingsMarker(settings, options = {}) {
1752
+ const pairs = SETTING_KEYS.filter(
1753
+ (key) => settings[key] !== DEFAULT_TABLE_SETTINGS[key] || key === "width" && options.explicitWidth
1754
+ ).map((key) => `${key}: ${settings[key]}`);
1755
+ return pairs.length > 0 ? `<!-- ${pairs.join("; ")} -->` : null;
1756
+ }
1757
+
1758
+ // src/transformers/tableRows.ts
1759
+ import {
1760
+ $createParagraphNode as $createParagraphNode2,
1761
+ $getNodeByKey as $getNodeByKey3,
1762
+ $getSelection as $getSelection3,
1763
+ $isRangeSelection as $isRangeSelection3
1764
+ } from "lexical";
1765
+ import { $findMatchingParent as $findMatchingParent2 } from "@lexical/utils";
1766
+ import {
1767
+ $createTableCellNode,
1768
+ $createTableRowNode,
1769
+ $isTableCellNode,
1770
+ $isTableNode as $isTableNode2,
1771
+ $isTableRowNode,
1772
+ $isTableSelection as $isTableSelection2,
1773
+ TableCellHeaderStates
1774
+ } from "@lexical/table";
1775
+ function $rows(table) {
1776
+ return table.getChildren().filter($isTableRowNode);
1777
+ }
1778
+ function $cells(row) {
1779
+ return row.getChildren().filter($isTableCellNode);
1780
+ }
1781
+ function $isHeaderRow(row) {
1782
+ const cells = row ? $cells(row) : [];
1783
+ return cells.length > 0 && cells.every((cell) => cell.hasHeaderState(TableCellHeaderStates.ROW));
1784
+ }
1785
+ function $getSelectedTableCell() {
1786
+ const selection = $getSelection3();
1787
+ let node = null;
1788
+ if ($isTableSelection2(selection)) node = $getNodeByKey3(selection.anchor.key);
1789
+ else if ($isRangeSelection3(selection)) node = selection.anchor.getNode();
1790
+ if (!node) return null;
1791
+ const cell = $findMatchingParent2(node, (n2) => $isTableCellNode(n2));
1792
+ return $isTableCellNode(cell) ? cell : null;
1793
+ }
1794
+ function $getTableRowPosition() {
1795
+ const cell = $getSelectedTableCell();
1796
+ const row = cell?.getParent();
1797
+ const table = row?.getParent();
1798
+ if (!cell || !$isTableRowNode(row) || !$isTableNode2(table)) return null;
1799
+ const rows = $rows(table);
1800
+ return {
1801
+ index: rows.indexOf(row),
1802
+ column: $cells(row).indexOf(cell),
1803
+ count: rows.length,
1804
+ hasHeader: $isHeaderRow(rows[0])
1805
+ };
1806
+ }
1807
+ function insertableRowIndices(position) {
1808
+ const indices = [];
1809
+ for (let i = position.hasHeader ? 1 : 0; i <= position.count; i++) indices.push(i);
1810
+ return indices;
1811
+ }
1812
+ function canDeleteRow(position) {
1813
+ return position.count > 1;
1814
+ }
1815
+ function $selectCell(cell) {
1816
+ cell?.selectStart();
1817
+ }
1818
+ function $insertTableRowAt(table, index, column = 0) {
1819
+ const rows = $rows(table);
1820
+ const minIndex = $isHeaderRow(rows[0]) ? 1 : 0;
1821
+ const at = Math.max(minIndex, Math.min(index, rows.length));
1822
+ const reference = rows[Math.max(0, at - 1)] ?? rows[0];
1823
+ const referenceCells = reference ? $cells(reference) : [];
1824
+ const row = $createTableRowNode();
1825
+ for (const cell of referenceCells) {
1826
+ const columnHeader = cell.hasHeaderState(TableCellHeaderStates.COLUMN) ? TableCellHeaderStates.COLUMN : TableCellHeaderStates.NO_STATUS;
1827
+ row.append($createTableCellNode(columnHeader).append($createParagraphNode2()));
1828
+ }
1829
+ if (referenceCells.length === 0) {
1830
+ row.append($createTableCellNode(TableCellHeaderStates.NO_STATUS).append($createParagraphNode2()));
1831
+ }
1832
+ if (at >= rows.length) table.append(row);
1833
+ else rows[at].insertBefore(row);
1834
+ const cells = $cells(row);
1835
+ $selectCell(cells[Math.min(column, cells.length - 1)]);
1836
+ return row;
1837
+ }
1838
+ function $deleteTableRowAt(table, index, column = 0) {
1839
+ const rows = $rows(table);
1840
+ const row = rows[index];
1841
+ if (!row || rows.length < 2) return false;
1842
+ const wasHeader = index === 0 && $isHeaderRow(row);
1843
+ row.remove();
1844
+ const remaining = $rows(table);
1845
+ if (wasHeader) {
1846
+ for (const cell of $cells(remaining[0])) {
1847
+ cell.setHeaderStyles(TableCellHeaderStates.ROW, TableCellHeaderStates.ROW);
1848
+ }
1849
+ }
1850
+ const target = remaining[Math.min(index, remaining.length - 1)];
1851
+ const cells = $cells(target);
1852
+ $selectCell(cells[Math.min(column, cells.length - 1)]);
1853
+ return true;
1854
+ }
1855
+ function $insertTableRowNear(table, position) {
1856
+ const at = $getTableRowPosition();
1857
+ if (!at) return null;
1858
+ return $insertTableRowAt(table, position === "below" ? at.index + 1 : at.index, at.column);
1859
+ }
1860
+ function $deleteSelectedTableRow(table) {
1861
+ const at = $getTableRowPosition();
1862
+ if (!at || !canDeleteRow(at)) return false;
1863
+ return $deleteTableRowAt(table, at.index, at.column);
1864
+ }
1865
+
1866
+ // src/plugins/TableRowShortcutsPlugin.tsx
1867
+ function shortcutFor(event) {
1868
+ const mod = event.metaKey || event.ctrlKey;
1869
+ if (event.altKey) return null;
1870
+ if (event.key === "Enter" && mod) return event.shiftKey ? "insert-above" : "insert-below";
1871
+ if (event.key === "Backspace" && mod && event.shiftKey) return "delete";
1872
+ if (event.key === "Tab" && !mod && !event.shiftKey) return "tab";
1873
+ return null;
1874
+ }
1875
+ function TableRowShortcutsPlugin() {
1876
+ const [editor] = useLexicalComposerContext5();
1877
+ useEffect5(
1878
+ () => editor.registerCommand(
1879
+ KEY_DOWN_COMMAND,
1880
+ (event) => {
1881
+ const shortcut = shortcutFor(event);
1882
+ if (!shortcut) return false;
1883
+ const table = $getSelectedTable();
1884
+ const position = $getTableRowPosition();
1885
+ if (!table || !position) return false;
1886
+ if (shortcut === "tab") {
1887
+ const selection = $getSelection4();
1888
+ const firstRow = table.getFirstChild();
1889
+ const columns = $isTableRowNode2(firstRow) ? firstRow.getChildrenSize() : 0;
1890
+ const isLastCell = position.index === position.count - 1 && position.column === columns - 1;
1891
+ if (!isLastCell || !$isRangeSelection4(selection) || !selection.isCollapsed()) return false;
1892
+ event.preventDefault();
1893
+ $insertTableRowAt(table, position.count);
1894
+ return true;
1895
+ }
1896
+ event.preventDefault();
1897
+ if (shortcut === "delete") $deleteSelectedTableRow(table);
1898
+ else $insertTableRowNear(table, shortcut === "insert-above" ? "above" : "below");
1899
+ return true;
1900
+ },
1901
+ COMMAND_PRIORITY_HIGH
1902
+ ),
1903
+ [editor]
1904
+ );
1905
+ return null;
1906
+ }
1907
+
1610
1908
  // src/nodes/FrontmatterNode.ts
1611
1909
  import {
1612
1910
  $applyNodeReplacement,
@@ -1696,14 +1994,14 @@ import {
1696
1994
  // src/drawing/canvas/DrawingCanvas.tsx
1697
1995
  import {
1698
1996
  useCallback,
1699
- useEffect as useEffect7,
1997
+ useEffect as useEffect8,
1700
1998
  useMemo,
1701
1999
  useRef as useRef4,
1702
2000
  useState as useState3,
1703
2001
  useContext as useContext2
1704
2002
  } from "react";
1705
- import { $getNodeByKey as $getNodeByKey2 } from "lexical";
1706
- import { useLexicalComposerContext as useLexicalComposerContext5 } from "@lexical/react/LexicalComposerContext";
2003
+ import { $getNodeByKey as $getNodeByKey4 } from "lexical";
2004
+ import { useLexicalComposerContext as useLexicalComposerContext6 } from "@lexical/react/LexicalComposerContext";
1707
2005
  import { useLexicalEditable } from "@lexical/react/useLexicalEditable";
1708
2006
 
1709
2007
  // src/editorContext.ts
@@ -4501,7 +4799,7 @@ function HitArea({
4501
4799
 
4502
4800
  // src/drawing/canvas/TextEditOverlay.tsx
4503
4801
  import {
4504
- useEffect as useEffect5,
4802
+ useEffect as useEffect6,
4505
4803
  useRef as useRef2,
4506
4804
  useState
4507
4805
  } from "react";
@@ -4517,7 +4815,7 @@ function TextEditOverlay({
4517
4815
  const ref = useRef2(null);
4518
4816
  const valueRef = useRef2(value);
4519
4817
  valueRef.current = value;
4520
- useEffect5(() => {
4818
+ useEffect6(() => {
4521
4819
  const el = ref.current;
4522
4820
  if (!el) return;
4523
4821
  el.focus();
@@ -4625,7 +4923,7 @@ function TextEditOverlay({
4625
4923
  }
4626
4924
 
4627
4925
  // src/drawing/canvas/Toolbar.tsx
4628
- import { useEffect as useEffect6, useRef as useRef3, useState as useState2 } from "react";
4926
+ import { useEffect as useEffect7, useRef as useRef3, useState as useState2 } from "react";
4629
4927
 
4630
4928
  // src/components/blockWidthOptions.tsx
4631
4929
  import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
@@ -4710,7 +5008,7 @@ function DrawingToolbar({
4710
5008
  const [lastMore, setLastMore] = useState2("note");
4711
5009
  const [copied, setCopied] = useState2(false);
4712
5010
  const moreRef = useRef3(null);
4713
- useEffect6(() => {
5011
+ useEffect7(() => {
4714
5012
  if (!moreOpen) return;
4715
5013
  const close = (e) => {
4716
5014
  if (!moreRef.current?.contains(e.target)) setMoreOpen(false);
@@ -4832,7 +5130,7 @@ function computePaths(shapes) {
4832
5130
  return paths;
4833
5131
  }
4834
5132
  function DrawingCanvas({ nodeKey, data }) {
4835
- const [editor] = useLexicalComposerContext5();
5133
+ const [editor] = useLexicalComposerContext6();
4836
5134
  const isEditable = useLexicalEditable();
4837
5135
  const [shapes, setShapes] = useState3(data.shapes);
4838
5136
  const [canvasHeight, setCanvasHeight] = useState3(data.canvasHeight);
@@ -4864,7 +5162,7 @@ function DrawingCanvas({ nodeKey, data }) {
4864
5162
  const paths = useMemo(() => computePaths(shapes), [shapes]);
4865
5163
  const canvasWidth = data.canvasWidth;
4866
5164
  const logicalWidth = canvasWidth ?? (width === "content" ? contentWidth(shapes, paths) : null);
4867
- useEffect7(() => {
5165
+ useEffect8(() => {
4868
5166
  const incoming = serializeDrawingData(data);
4869
5167
  if (incoming !== lastCommittedRef.current) {
4870
5168
  lastCommittedRef.current = incoming;
@@ -4875,7 +5173,7 @@ function DrawingCanvas({ nodeKey, data }) {
4875
5173
  setEditingText(null);
4876
5174
  }
4877
5175
  }, [data]);
4878
- useEffect7(() => {
5176
+ useEffect8(() => {
4879
5177
  const svg = svgRef.current;
4880
5178
  if (!logicalWidth || !svg || typeof ResizeObserver === "undefined") {
4881
5179
  setScale(1);
@@ -4905,7 +5203,7 @@ function DrawingCanvas({ nodeKey, data }) {
4905
5203
  if (json2 === lastCommittedRef.current) return;
4906
5204
  lastCommittedRef.current = json2;
4907
5205
  editor.update(() => {
4908
- const node = $getNodeByKey2(nodeKey);
5206
+ const node = $getNodeByKey4(nodeKey);
4909
5207
  if ($isDrawingNode(node)) node.setData(payload);
4910
5208
  });
4911
5209
  },
@@ -5165,7 +5463,7 @@ function DrawingCanvas({ nodeKey, data }) {
5165
5463
  }, [updateShapes]);
5166
5464
  const editingRef = useRef4(editingText);
5167
5465
  editingRef.current = editingText;
5168
- useEffect7(() => {
5466
+ useEffect8(() => {
5169
5467
  const root = rootRef.current;
5170
5468
  if (!root || !isEditable) return;
5171
5469
  const onKeyDown = (e) => {
@@ -5612,161 +5910,17 @@ import {
5612
5910
  TRANSFORMERS
5613
5911
  } from "@lexical/markdown";
5614
5912
  import {
5615
- $createTableCellNode,
5913
+ $createTableCellNode as $createTableCellNode2,
5616
5914
  $createTableNode,
5617
- $createTableRowNode,
5618
- $isTableCellNode,
5619
- $isTableNode as $isTableNode2,
5620
- $isTableRowNode,
5621
- TableCellHeaderStates,
5915
+ $createTableRowNode as $createTableRowNode2,
5916
+ $isTableCellNode as $isTableCellNode2,
5917
+ $isTableNode as $isTableNode3,
5918
+ $isTableRowNode as $isTableRowNode3,
5919
+ TableCellHeaderStates as TableCellHeaderStates2,
5622
5920
  TableCellNode,
5623
5921
  TableNode,
5624
5922
  TableRowNode
5625
5923
  } from "@lexical/table";
5626
-
5627
- // src/transformers/tableSettings.ts
5628
- import {
5629
- $getNodeByKey as $getNodeByKey3,
5630
- $getSelection as $getSelection2,
5631
- $isRangeSelection as $isRangeSelection2
5632
- } from "lexical";
5633
- import { $findMatchingParent } from "@lexical/utils";
5634
- import { $isTableNode, $isTableSelection } from "@lexical/table";
5635
- var DEFAULT_TABLE_SETTINGS = {
5636
- width: "full",
5637
- density: "comfortable"
5638
- };
5639
- var BLOCK_BLEED_PROPERTY = "--zui-text-editor-block-bleed";
5640
- var OPTION_DECLARATIONS = {
5641
- width: {
5642
- full: {},
5643
- content: { width: "auto", "table-layout": "auto", [BLOCK_BLEED_PROPERTY]: "0px" },
5644
- text: { [BLOCK_BLEED_PROPERTY]: "0px" }
5645
- },
5646
- density: {
5647
- comfortable: {},
5648
- compact: {
5649
- "--zui-table-cell-padding": "0.25rem 0.5rem",
5650
- "--zui-table-font-size": "0.8125rem"
5651
- },
5652
- spacious: {
5653
- "--zui-table-cell-padding": "0.875rem 1rem",
5654
- "--zui-table-font-size": "0.9375rem"
5655
- }
5656
- }
5657
- };
5658
- var SETTING_KEYS = Object.keys(OPTION_DECLARATIONS);
5659
- var EXPLICIT_WIDTH_PROPERTY = "--zui-table-width";
5660
- function parseStyle(style) {
5661
- const declarations = /* @__PURE__ */ new Map();
5662
- for (const part of style.split(";")) {
5663
- const index = part.indexOf(":");
5664
- if (index === -1) continue;
5665
- const key = part.slice(0, index).trim();
5666
- const value = part.slice(index + 1).trim();
5667
- if (key && value) declarations.set(key, value);
5668
- }
5669
- return declarations;
5670
- }
5671
- function serializeStyle(declarations) {
5672
- return [...declarations].map(([key, value]) => `${key}: ${value}`).join("; ");
5673
- }
5674
- function optionsOf(setting) {
5675
- return Object.entries(OPTION_DECLARATIONS[setting]);
5676
- }
5677
- function readSetting(declarations, setting) {
5678
- for (const [option, decls] of optionsOf(setting)) {
5679
- const entries = Object.entries(decls);
5680
- if (entries.length === 0) continue;
5681
- if (entries.every(([key, value]) => declarations.get(key) === value)) {
5682
- return option;
5683
- }
5684
- }
5685
- return DEFAULT_TABLE_SETTINGS[setting];
5686
- }
5687
- function writeSetting(declarations, setting, option) {
5688
- for (const [, decls] of optionsOf(setting)) {
5689
- for (const key of Object.keys(decls)) declarations.delete(key);
5690
- }
5691
- for (const [key, value] of Object.entries(OPTION_DECLARATIONS[setting][option])) {
5692
- declarations.set(key, value);
5693
- }
5694
- }
5695
- function $getTableSettings(table) {
5696
- const declarations = parseStyle(table.getStyle());
5697
- return {
5698
- width: readSetting(declarations, "width"),
5699
- density: readSetting(declarations, "density")
5700
- };
5701
- }
5702
- function $setTableSettings(table, settings, options = {}) {
5703
- const declarations = parseStyle(table.getStyle());
5704
- for (const key of SETTING_KEYS) {
5705
- const option = settings[key];
5706
- if (option !== void 0) writeSetting(declarations, key, option);
5707
- }
5708
- if (settings.width !== void 0) {
5709
- if (options.explicitWidth) declarations.set(EXPLICIT_WIDTH_PROPERTY, settings.width);
5710
- else declarations.delete(EXPLICIT_WIDTH_PROPERTY);
5711
- }
5712
- table.setStyle(serializeStyle(declarations));
5713
- }
5714
- function $isTableWidthExplicit(table) {
5715
- const declarations = parseStyle(table.getStyle());
5716
- return declarations.get(EXPLICIT_WIDTH_PROPERTY) === readSetting(declarations, "width");
5717
- }
5718
- function $getTableWidth(table) {
5719
- return $getTableSettings(table).width;
5720
- }
5721
- function $setTableWidth(table, width) {
5722
- $setTableSettings(table, { width });
5723
- }
5724
- function $getTableDensity(table) {
5725
- return $getTableSettings(table).density;
5726
- }
5727
- function $setTableDensity(table, density) {
5728
- $setTableSettings(table, { density });
5729
- }
5730
- function $getSelectedTable() {
5731
- const selection = $getSelection2();
5732
- if ($isTableSelection(selection)) {
5733
- const node = $getNodeByKey3(selection.tableKey);
5734
- return $isTableNode(node) ? node : null;
5735
- }
5736
- if (!$isRangeSelection2(selection)) return null;
5737
- const table = $findMatchingParent(
5738
- selection.anchor.getNode(),
5739
- (node) => $isTableNode(node)
5740
- );
5741
- return $isTableNode(table) ? table : null;
5742
- }
5743
- var MARKER_REG_EXP = /^<!--\s*([a-z]+\s*:\s*[a-z]+(?:\s*;\s*[a-z]+\s*:\s*[a-z]+)*)\s*;?\s*-->\s*$/;
5744
- function isOption(setting, value) {
5745
- return value in OPTION_DECLARATIONS[setting];
5746
- }
5747
- var TABLE_WIDTH_MARKER = "<!-- width: content -->";
5748
- function parseTableSettingsMarker(text) {
5749
- const match = MARKER_REG_EXP.exec(text);
5750
- if (!match) return null;
5751
- const settings = {};
5752
- let recognised = false;
5753
- for (const pair of match[1].split(";")) {
5754
- const [key, value] = pair.split(":").map((s) => s.trim());
5755
- if (key !== "width" && key !== "density") continue;
5756
- recognised = true;
5757
- if (key === "width" && isOption("width", value)) settings.width = value;
5758
- if (key === "density" && isOption("density", value)) settings.density = value;
5759
- }
5760
- return recognised ? settings : null;
5761
- }
5762
- function formatTableSettingsMarker(settings, options = {}) {
5763
- const pairs = SETTING_KEYS.filter(
5764
- (key) => settings[key] !== DEFAULT_TABLE_SETTINGS[key] || key === "width" && options.explicitWidth
5765
- ).map((key) => `${key}: ${settings[key]}`);
5766
- return pairs.length > 0 ? `<!-- ${pairs.join("; ")} -->` : null;
5767
- }
5768
-
5769
- // src/transformers/tableTransformer.ts
5770
5924
  var TABLE_ROW_REG_EXP = /^\|(.+)\|\s?$/;
5771
5925
  var TABLE_ROW_DIVIDER_REG_EXP = /^(\| ?:?-*:? ?)+\|\s?$/;
5772
5926
  function $getMarkerSettings(node) {
@@ -5776,11 +5930,11 @@ function $getMarkerSettings(node) {
5776
5930
  }
5777
5931
  function getTableColumnsSize(table) {
5778
5932
  const row = table.getFirstChild();
5779
- return $isTableRowNode(row) ? row.getChildrenSize() : 0;
5933
+ return $isTableRowNode3(row) ? row.getChildrenSize() : 0;
5780
5934
  }
5781
5935
  function createTableCell(textContent) {
5782
5936
  const unescaped = textContent.replace(/\\n/g, "\n");
5783
- const cell = $createTableCellNode(TableCellHeaderStates.NO_STATUS);
5937
+ const cell = $createTableCellNode2(TableCellHeaderStates2.NO_STATUS);
5784
5938
  $convertFromMarkdownString2(unescaped, TRANSFORMERS, cell);
5785
5939
  return cell;
5786
5940
  }
@@ -5792,22 +5946,22 @@ function mapToTableCells(textContent) {
5792
5946
  var TABLE = {
5793
5947
  dependencies: [TableNode, TableRowNode, TableCellNode],
5794
5948
  export: (node) => {
5795
- if (!$isTableNode2(node)) return null;
5949
+ if (!$isTableNode3(node)) return null;
5796
5950
  const output = [];
5797
5951
  const marker = formatTableSettingsMarker($getTableSettings(node), {
5798
5952
  explicitWidth: $isTableWidthExplicit(node)
5799
5953
  });
5800
5954
  if (marker) output.push(marker);
5801
5955
  for (const row of node.getChildren()) {
5802
- if (!$isTableRowNode(row)) continue;
5956
+ if (!$isTableRowNode3(row)) continue;
5803
5957
  const rowOutput = [];
5804
5958
  let isHeaderRow = false;
5805
5959
  for (const cell of row.getChildren()) {
5806
- if (!$isTableCellNode(cell)) continue;
5960
+ if (!$isTableCellNode2(cell)) continue;
5807
5961
  rowOutput.push(
5808
5962
  $convertToMarkdownString2(TRANSFORMERS, cell).replace(/\n/g, "\\n")
5809
5963
  );
5810
- if (cell.__headerState === TableCellHeaderStates.ROW) {
5964
+ if (cell.__headerState === TableCellHeaderStates2.ROW) {
5811
5965
  isHeaderRow = true;
5812
5966
  }
5813
5967
  }
@@ -5822,12 +5976,12 @@ var TABLE = {
5822
5976
  replace: (parentNode, _children, match) => {
5823
5977
  if (TABLE_ROW_DIVIDER_REG_EXP.test(match[0])) {
5824
5978
  const table2 = parentNode.getPreviousSibling();
5825
- if (!table2 || !$isTableNode2(table2)) return;
5979
+ if (!table2 || !$isTableNode3(table2)) return;
5826
5980
  const lastRow = table2.getLastChild();
5827
- if (!lastRow || !$isTableRowNode(lastRow)) return;
5981
+ if (!lastRow || !$isTableRowNode3(lastRow)) return;
5828
5982
  lastRow.getChildren().forEach((cell) => {
5829
- if ($isTableCellNode(cell)) {
5830
- cell.setHeaderStyles(TableCellHeaderStates.ROW, TableCellHeaderStates.ROW);
5983
+ if ($isTableCellNode2(cell)) {
5984
+ cell.setHeaderStyles(TableCellHeaderStates2.ROW, TableCellHeaderStates2.ROW);
5831
5985
  }
5832
5986
  });
5833
5987
  parentNode.remove();
@@ -5852,14 +6006,14 @@ var TABLE = {
5852
6006
  }
5853
6007
  const table = $createTableNode();
5854
6008
  for (const cells of rows) {
5855
- const tableRow = $createTableRowNode();
6009
+ const tableRow = $createTableRowNode2();
5856
6010
  table.append(tableRow);
5857
6011
  for (let i = 0; i < maxCells; i++) {
5858
6012
  tableRow.append(i < cells.length ? cells[i] : createTableCell(""));
5859
6013
  }
5860
6014
  }
5861
6015
  const previousSibling = parentNode.getPreviousSibling();
5862
- if ($isTableNode2(previousSibling) && getTableColumnsSize(previousSibling) === maxCells) {
6016
+ if ($isTableNode3(previousSibling) && getTableColumnsSize(previousSibling) === maxCells) {
5863
6017
  previousSibling.append(...table.getChildren());
5864
6018
  parentNode.remove();
5865
6019
  } else {
@@ -5970,8 +6124,8 @@ var editorNodes = [
5970
6124
  DrawingNode
5971
6125
  ];
5972
6126
  function ReadOnlyPlugin({ readOnly }) {
5973
- const [editor] = useLexicalComposerContext6();
5974
- useEffect8(() => {
6127
+ const [editor] = useLexicalComposerContext7();
6128
+ useEffect9(() => {
5975
6129
  editor.setEditable(!readOnly);
5976
6130
  }, [editor, readOnly]);
5977
6131
  return null;
@@ -5983,7 +6137,7 @@ function EditorRoot({
5983
6137
  className,
5984
6138
  mode = "edit-md",
5985
6139
  autoFocus = false,
5986
- measure,
6140
+ measure: measure2,
5987
6141
  defaultBlockWidth = NO_DEFAULT_BLOCK_WIDTH,
5988
6142
  drawingStyle = "clean",
5989
6143
  children
@@ -5991,7 +6145,7 @@ function EditorRoot({
5991
6145
  const latestValueRef = useRef5(value ?? "");
5992
6146
  const [mountKey, setMountKey] = useState4(0);
5993
6147
  const [capturedMarkdown, setCapturedMarkdown] = useState4(value ?? "");
5994
- useEffect8(() => {
6148
+ useEffect9(() => {
5995
6149
  if (value !== void 0) {
5996
6150
  latestValueRef.current = value;
5997
6151
  }
@@ -6004,7 +6158,7 @@ function EditorRoot({
6004
6158
  [onChange]
6005
6159
  );
6006
6160
  const prevModeRef = useRef5(mode);
6007
- useEffect8(() => {
6161
+ useEffect9(() => {
6008
6162
  if (prevModeRef.current === "edit-raw" && mode !== "edit-raw") {
6009
6163
  setCapturedMarkdown(latestValueRef.current);
6010
6164
  setMountKey((k) => k + 1);
@@ -6034,8 +6188,8 @@ function EditorRoot({
6034
6188
  );
6035
6189
  const isRaw = mode === "edit-raw";
6036
6190
  const rootStyle = useMemo2(
6037
- () => measure !== void 0 ? { "--zui-text-editor-measure": measure } : void 0,
6038
- [measure]
6191
+ () => measure2 !== void 0 ? { "--zui-text-editor-measure": measure2 } : void 0,
6192
+ [measure2]
6039
6193
  );
6040
6194
  return /* @__PURE__ */ jsx12(LexicalComposer, { initialConfig, children: /* @__PURE__ */ jsx12(EditorContext.Provider, { value: context, children: /* @__PURE__ */ jsxs10("div", { className: `zui-text-editor ${className ?? ""}`, style: rootStyle, children: [
6041
6195
  children,
@@ -6055,6 +6209,7 @@ function EditorRoot({
6055
6209
  /* @__PURE__ */ jsx12(CodeBlockShortcutPlugin, {}),
6056
6210
  /* @__PURE__ */ jsx12(CodeHighlightPlugin, {}),
6057
6211
  /* @__PURE__ */ jsx12(TablePlugin, {}),
6212
+ /* @__PURE__ */ jsx12(TableRowShortcutsPlugin, {}),
6058
6213
  /* @__PURE__ */ jsx12(LinkPlugin, {}),
6059
6214
  /* @__PURE__ */ jsx12(MarkdownShortcutPlugin, { transformers: SHORTCUT_TRANSFORMERS }),
6060
6215
  /* @__PURE__ */ jsx12(ReadOnlyPlugin, { readOnly: readOnly || mode === "view" }),
@@ -6071,12 +6226,12 @@ import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
6071
6226
  // src/plugins/FoldingPlugin.tsx
6072
6227
  import {
6073
6228
  useCallback as useCallback3,
6074
- useEffect as useEffect9,
6229
+ useEffect as useEffect10,
6075
6230
  useRef as useRef6,
6076
6231
  useState as useState5
6077
6232
  } from "react";
6078
- import { $getRoot, $getSelection as $getSelection3, $isRangeSelection as $isRangeSelection3 } from "lexical";
6079
- import { useLexicalComposerContext as useLexicalComposerContext7 } from "@lexical/react/LexicalComposerContext";
6233
+ import { $getRoot, $getSelection as $getSelection5, $isRangeSelection as $isRangeSelection5 } from "lexical";
6234
+ import { useLexicalComposerContext as useLexicalComposerContext8 } from "@lexical/react/LexicalComposerContext";
6080
6235
  import { $isHeadingNode } from "@lexical/rich-text";
6081
6236
  import { jsx as jsx13 } from "react/jsx-runtime";
6082
6237
  var HEADING_LEVELS = {
@@ -6088,7 +6243,7 @@ var HEADING_LEVELS = {
6088
6243
  h6: 6
6089
6244
  };
6090
6245
  function FoldingPlugin() {
6091
- const [editor] = useLexicalComposerContext7();
6246
+ const [editor] = useLexicalComposerContext8();
6092
6247
  const [foldedKeys, setFoldedKeys] = useState5(/* @__PURE__ */ new Set());
6093
6248
  const [buttons, setButtons] = useState5([]);
6094
6249
  const foldedRef = useRef6(foldedKeys);
@@ -6114,8 +6269,8 @@ function FoldingPlugin() {
6114
6269
  hidden.add(sibling.getKey());
6115
6270
  }
6116
6271
  }
6117
- const selection = $getSelection3();
6118
- if ($isRangeSelection3(selection)) {
6272
+ const selection = $getSelection5();
6273
+ if ($isRangeSelection5(selection)) {
6119
6274
  const topLevel = selection.anchor.getNode().getTopLevelElement();
6120
6275
  if (topLevel && hidden.has(topLevel.getKey())) {
6121
6276
  let node = topLevel.getPreviousSibling();
@@ -6157,7 +6312,7 @@ function FoldingPlugin() {
6157
6312
  );
6158
6313
  });
6159
6314
  }, [editor]);
6160
- useEffect9(() => {
6315
+ useEffect10(() => {
6161
6316
  sync();
6162
6317
  const unregister = editor.registerUpdateListener(sync);
6163
6318
  const rootElement = editor.getRootElement();
@@ -6205,17 +6360,150 @@ function FoldingPlugin() {
6205
6360
  )) });
6206
6361
  }
6207
6362
 
6208
- // src/plugins/TableSettingsPlugin.tsx
6209
- import { useCallback as useCallback5, useEffect as useEffect11, useState as useState7 } from "react";
6210
- import { useLexicalComposerContext as useLexicalComposerContext9 } from "@lexical/react/LexicalComposerContext";
6363
+ // src/plugins/TableControlsPlugin.tsx
6364
+ import { useCallback as useCallback7 } from "react";
6365
+ import { useLexicalComposerContext as useLexicalComposerContext11 } from "@lexical/react/LexicalComposerContext";
6211
6366
  import { useLexicalEditable as useLexicalEditable2 } from "@lexical/react/useLexicalEditable";
6212
6367
 
6368
+ // src/components/TableRowRail.tsx
6369
+ import { useCallback as useCallback4, useRef as useRef7, useState as useState6 } from "react";
6370
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
6371
+ var TABLE_RAIL_WIDTH = 28;
6372
+ function TableRowRail({ box, rows, position, onInsert }) {
6373
+ const rail = useRef7(null);
6374
+ const [hovered, setHovered] = useState6(null);
6375
+ const boundaryTop = useCallback4(
6376
+ (index) => {
6377
+ if (index < rows.length) return rows[index].top;
6378
+ const last = rows[rows.length - 1];
6379
+ return last ? last.top + last.height : 0;
6380
+ },
6381
+ [rows]
6382
+ );
6383
+ const onPointerMove = useCallback4(
6384
+ (event) => {
6385
+ const element = rail.current;
6386
+ if (!element) return;
6387
+ const y = event.clientY - element.getBoundingClientRect().top;
6388
+ let nearest = null;
6389
+ let distance = Number.POSITIVE_INFINITY;
6390
+ for (const index of insertableRowIndices(position)) {
6391
+ const d = Math.abs(boundaryTop(index) - y);
6392
+ if (d < distance) {
6393
+ distance = d;
6394
+ nearest = index;
6395
+ }
6396
+ }
6397
+ setHovered(nearest);
6398
+ },
6399
+ [position, boundaryTop]
6400
+ );
6401
+ if (rows.length === 0) return null;
6402
+ const current = rows[Math.min(position.index, rows.length - 1)];
6403
+ const insertAt = hovered ?? position.count;
6404
+ const insertTop = boundaryTop(insertAt);
6405
+ return /* @__PURE__ */ jsxs11(
6406
+ "div",
6407
+ {
6408
+ ref: rail,
6409
+ className: "zui-table-rail",
6410
+ style: { top: box.top, left: box.left - TABLE_RAIL_WIDTH, width: TABLE_RAIL_WIDTH, height: box.height },
6411
+ onPointerMove,
6412
+ onPointerLeave: () => setHovered(null),
6413
+ children: [
6414
+ /* @__PURE__ */ jsx14(
6415
+ "div",
6416
+ {
6417
+ className: "zui-table-rail-marker",
6418
+ style: { top: current.top + 3, height: Math.max(4, current.height - 6) },
6419
+ "aria-hidden": true
6420
+ }
6421
+ ),
6422
+ /* @__PURE__ */ jsx14(
6423
+ "button",
6424
+ {
6425
+ type: "button",
6426
+ className: `zui-table-rail-add ${hovered === null ? "is-resting" : ""}`,
6427
+ style: { top: insertTop },
6428
+ title: insertAt === position.count ? "Add row" : `Insert row ${insertAt === 0 ? "at the top" : `after row ${insertAt}`}`,
6429
+ "aria-label": insertAt === position.count ? "Add row" : `Insert row before row ${insertAt + 1}`,
6430
+ onMouseDown: (e) => e.preventDefault(),
6431
+ onClick: () => onInsert(insertAt),
6432
+ children: /* @__PURE__ */ jsx14("svg", { viewBox: "0 0 12 12", width: "12", height: "12", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", children: /* @__PURE__ */ jsx14("path", { d: "M6 2.5v7M2.5 6h7" }) })
6433
+ }
6434
+ ),
6435
+ /* @__PURE__ */ jsx14(
6436
+ "div",
6437
+ {
6438
+ className: "zui-table-rail-line",
6439
+ style: { top: insertTop, left: TABLE_RAIL_WIDTH, width: box.width },
6440
+ "aria-hidden": true
6441
+ }
6442
+ )
6443
+ ]
6444
+ }
6445
+ );
6446
+ }
6447
+
6448
+ // src/components/shortcutLabel.ts
6449
+ var isApple = typeof navigator !== "undefined" && /Mac|iPhone|iPad|iPod/.test(navigator.platform ?? "");
6450
+ function shortcutLabel(keys) {
6451
+ const parts = keys.split("+");
6452
+ if (isApple) {
6453
+ const glyphs = {
6454
+ Mod: "\u2318",
6455
+ Shift: "\u21E7",
6456
+ Alt: "\u2325",
6457
+ Enter: "\u21A9",
6458
+ Backspace: "\u232B",
6459
+ Tab: "\u21E5"
6460
+ };
6461
+ return parts.map((part) => glyphs[part] ?? part).join("");
6462
+ }
6463
+ return parts.map((part) => part === "Mod" ? "Ctrl" : part).join("+");
6464
+ }
6465
+
6466
+ // src/components/tableRowActions.tsx
6467
+ import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
6468
+ var TABLE_ROW_ACTIONS = [
6469
+ {
6470
+ action: "insert-above",
6471
+ label: "Insert row above",
6472
+ shortcut: "Mod+Shift+Enter",
6473
+ icon: /* @__PURE__ */ jsxs12(Fragment5, { children: [
6474
+ /* @__PURE__ */ jsx15("path", { d: "M3 11.5h14M3 15.5h14" }),
6475
+ /* @__PURE__ */ jsx15("path", { d: "M10 3.5v5M7.5 6h5" })
6476
+ ] })
6477
+ },
6478
+ {
6479
+ action: "insert-below",
6480
+ label: "Insert row below",
6481
+ shortcut: "Mod+Enter",
6482
+ icon: /* @__PURE__ */ jsxs12(Fragment5, { children: [
6483
+ /* @__PURE__ */ jsx15("path", { d: "M3 4.5h14M3 8.5h14" }),
6484
+ /* @__PURE__ */ jsx15("path", { d: "M10 11.5v5M7.5 14h5" })
6485
+ ] })
6486
+ },
6487
+ {
6488
+ action: "delete",
6489
+ label: "Delete row",
6490
+ shortcut: "Mod+Shift+Backspace",
6491
+ icon: /* @__PURE__ */ jsxs12(Fragment5, { children: [
6492
+ /* @__PURE__ */ jsx15("path", { d: "M3 5.5h14M3 14.5h14" }),
6493
+ /* @__PURE__ */ jsx15("path", { d: "M7.5 10h5" })
6494
+ ] })
6495
+ }
6496
+ ];
6497
+ function tableRowActionTitle(action) {
6498
+ return `${action.label} (${shortcutLabel(action.shortcut)})`;
6499
+ }
6500
+
6213
6501
  // src/useMarkdownEditor.ts
6214
- import { useCallback as useCallback4, useEffect as useEffect10, useRef as useRef7, useState as useState6 } from "react";
6502
+ import { useCallback as useCallback5, useEffect as useEffect11, useRef as useRef8, useState as useState7 } from "react";
6215
6503
  import {
6216
- $getNodeByKey as $getNodeByKey4,
6217
- $getSelection as $getSelection4,
6218
- $isRangeSelection as $isRangeSelection4,
6504
+ $getNodeByKey as $getNodeByKey5,
6505
+ $getSelection as $getSelection6,
6506
+ $isRangeSelection as $isRangeSelection6,
6219
6507
  CAN_REDO_COMMAND,
6220
6508
  CAN_UNDO_COMMAND,
6221
6509
  COMMAND_PRIORITY_LOW as COMMAND_PRIORITY_LOW2,
@@ -6223,7 +6511,7 @@ import {
6223
6511
  REDO_COMMAND,
6224
6512
  UNDO_COMMAND
6225
6513
  } from "lexical";
6226
- import { useLexicalComposerContext as useLexicalComposerContext8 } from "@lexical/react/LexicalComposerContext";
6514
+ import { useLexicalComposerContext as useLexicalComposerContext9 } from "@lexical/react/LexicalComposerContext";
6227
6515
  import { INSERT_TABLE_COMMAND } from "@lexical/table";
6228
6516
  import { $insertNodeToNearestRoot, mergeRegister as mergeRegister2 } from "@lexical/utils";
6229
6517
  var TRACKED_FORMATS = [
@@ -6235,29 +6523,31 @@ var TRACKED_FORMATS = [
6235
6523
  ];
6236
6524
  function $readDrawingWidth(key) {
6237
6525
  if (key === null) return null;
6238
- const node = $getNodeByKey4(key);
6526
+ const node = $getNodeByKey5(key);
6239
6527
  return $isDrawingNode(node) ? node.getData().width ?? "full" : null;
6240
6528
  }
6241
6529
  function useMarkdownEditor() {
6242
- const [editor] = useLexicalComposerContext8();
6530
+ const [editor] = useLexicalComposerContext9();
6243
6531
  const { defaultBlockWidth } = useEditorContext();
6244
- const [activeFormats, setActiveFormats] = useState6(
6532
+ const [activeFormats, setActiveFormats] = useState7(
6245
6533
  /* @__PURE__ */ new Set()
6246
6534
  );
6247
- const [canUndo, setCanUndo] = useState6(false);
6248
- const [canRedo, setCanRedo] = useState6(false);
6249
- const [tableSettings, setTableSettingsState] = useState6(null);
6250
- const activeDrawingRef = useRef7(null);
6251
- const [drawingWidth, setDrawingWidth] = useState6(null);
6252
- useEffect10(
6535
+ const [canUndo, setCanUndo] = useState7(false);
6536
+ const [canRedo, setCanRedo] = useState7(false);
6537
+ const [tableSettings, setTableSettingsState] = useState7(null);
6538
+ const [tableRow, setTableRow] = useState7(null);
6539
+ const activeDrawingRef = useRef8(null);
6540
+ const [drawingWidth, setDrawingWidth] = useState7(null);
6541
+ useEffect11(
6253
6542
  () => mergeRegister2(
6254
6543
  editor.registerUpdateListener(({ editorState }) => {
6255
6544
  editorState.read(() => {
6256
6545
  const table = $getSelectedTable();
6257
6546
  setTableSettingsState(table ? $getTableSettings(table) : null);
6547
+ setTableRow(table ? $getTableRowPosition() : null);
6258
6548
  setDrawingWidth($readDrawingWidth(activeDrawingRef.current));
6259
- const selection = $getSelection4();
6260
- if (!$isRangeSelection4(selection)) {
6549
+ const selection = $getSelection6();
6550
+ if (!$isRangeSelection6(selection)) {
6261
6551
  setActiveFormats(/* @__PURE__ */ new Set());
6262
6552
  return;
6263
6553
  }
@@ -6296,13 +6586,13 @@ function useMarkdownEditor() {
6296
6586
  ),
6297
6587
  [editor]
6298
6588
  );
6299
- const toggleFormat = useCallback4(
6589
+ const toggleFormat = useCallback5(
6300
6590
  (format) => {
6301
6591
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
6302
6592
  },
6303
6593
  [editor]
6304
6594
  );
6305
- const insertTable = useCallback4(
6595
+ const insertTable = useCallback5(
6306
6596
  ({
6307
6597
  rows = 3,
6308
6598
  columns = 3,
@@ -6324,7 +6614,7 @@ function useMarkdownEditor() {
6324
6614
  },
6325
6615
  [editor, defaultBlockWidth.table]
6326
6616
  );
6327
- const insertDrawing = useCallback4(
6617
+ const insertDrawing = useCallback5(
6328
6618
  ({ width = defaultBlockWidth.drawing } = {}) => {
6329
6619
  editor.update(() => {
6330
6620
  const data = width === void 0 ? EMPTY_DRAWING : { version: 2, canvasHeight: EMPTY_DRAWING.canvasHeight, width, shapes: [] };
@@ -6333,7 +6623,7 @@ function useMarkdownEditor() {
6333
6623
  },
6334
6624
  [editor, defaultBlockWidth.drawing]
6335
6625
  );
6336
- const updateTableSettings = useCallback4(
6626
+ const updateTableSettings = useCallback5(
6337
6627
  (settings) => {
6338
6628
  editor.update(() => {
6339
6629
  const table = $getSelectedTable();
@@ -6342,15 +6632,30 @@ function useMarkdownEditor() {
6342
6632
  },
6343
6633
  [editor]
6344
6634
  );
6345
- const setTableWidth = useCallback4(
6635
+ const setTableWidth = useCallback5(
6346
6636
  (width) => updateTableSettings({ width }),
6347
6637
  [updateTableSettings]
6348
6638
  );
6349
- const setTableDensity = useCallback4(
6639
+ const setTableDensity = useCallback5(
6350
6640
  (density) => updateTableSettings({ density }),
6351
6641
  [updateTableSettings]
6352
6642
  );
6353
- const setBlockWidth = useCallback4(
6643
+ const insertTableRow = useCallback5(
6644
+ (position = "below") => {
6645
+ editor.update(() => {
6646
+ const table = $getSelectedTable();
6647
+ if (table) $insertTableRowNear(table, position);
6648
+ });
6649
+ },
6650
+ [editor]
6651
+ );
6652
+ const deleteTableRow = useCallback5(() => {
6653
+ editor.update(() => {
6654
+ const table = $getSelectedTable();
6655
+ if (table) $deleteSelectedTableRow(table);
6656
+ });
6657
+ }, [editor]);
6658
+ const setBlockWidth = useCallback5(
6354
6659
  (width) => {
6355
6660
  const key = activeDrawingRef.current;
6356
6661
  if (key === null) {
@@ -6358,7 +6663,7 @@ function useMarkdownEditor() {
6358
6663
  return;
6359
6664
  }
6360
6665
  editor.update(() => {
6361
- const node = $getNodeByKey4(key);
6666
+ const node = $getNodeByKey5(key);
6362
6667
  if (!$isDrawingNode(node)) return;
6363
6668
  const { width: _previous, ...data } = node.getData();
6364
6669
  node.setData(width === "full" ? data : { ...data, width });
@@ -6366,10 +6671,10 @@ function useMarkdownEditor() {
6366
6671
  },
6367
6672
  [editor, updateTableSettings]
6368
6673
  );
6369
- const undo = useCallback4(() => {
6674
+ const undo = useCallback5(() => {
6370
6675
  editor.dispatchCommand(UNDO_COMMAND, void 0);
6371
6676
  }, [editor]);
6372
- const redo = useCallback4(() => {
6677
+ const redo = useCallback5(() => {
6373
6678
  editor.dispatchCommand(REDO_COMMAND, void 0);
6374
6679
  }, [editor]);
6375
6680
  return {
@@ -6384,6 +6689,9 @@ function useMarkdownEditor() {
6384
6689
  setTableWidth,
6385
6690
  tableDensity: tableSettings?.density ?? null,
6386
6691
  setTableDensity,
6692
+ tableRow,
6693
+ insertTableRow,
6694
+ deleteTableRow,
6387
6695
  canUndo,
6388
6696
  canRedo,
6389
6697
  undo,
@@ -6392,23 +6700,23 @@ function useMarkdownEditor() {
6392
6700
  }
6393
6701
 
6394
6702
  // src/components/Toolbar.tsx
6395
- import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
6703
+ import { Fragment as Fragment6, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
6396
6704
  function Toolbar({ children, className }) {
6397
- return /* @__PURE__ */ jsx14(
6705
+ return /* @__PURE__ */ jsx16(
6398
6706
  "div",
6399
6707
  {
6400
6708
  className: `zui-text-editor-toolbar ${className ?? ""}`,
6401
6709
  role: "toolbar",
6402
- children: children ?? /* @__PURE__ */ jsxs11(Fragment5, { children: [
6403
- /* @__PURE__ */ jsx14(FormatButtons, {}),
6404
- /* @__PURE__ */ jsx14(ToolbarDivider, {}),
6405
- /* @__PURE__ */ jsx14(InsertButtons, {})
6710
+ children: children ?? /* @__PURE__ */ jsxs13(Fragment6, { children: [
6711
+ /* @__PURE__ */ jsx16(FormatButtons, {}),
6712
+ /* @__PURE__ */ jsx16(ToolbarDivider, {}),
6713
+ /* @__PURE__ */ jsx16(InsertButtons, {})
6406
6714
  ] })
6407
6715
  }
6408
6716
  );
6409
6717
  }
6410
6718
  function ToolbarDivider() {
6411
- return /* @__PURE__ */ jsx14("div", { className: "zui-text-editor-toolbar-divider" });
6719
+ return /* @__PURE__ */ jsx16("div", { className: "zui-text-editor-toolbar-divider" });
6412
6720
  }
6413
6721
  function ToolbarButton({
6414
6722
  label,
@@ -6418,7 +6726,7 @@ function ToolbarButton({
6418
6726
  disabled = false,
6419
6727
  className
6420
6728
  }) {
6421
- return /* @__PURE__ */ jsx14(
6729
+ return /* @__PURE__ */ jsx16(
6422
6730
  "button",
6423
6731
  {
6424
6732
  type: "button",
@@ -6434,7 +6742,7 @@ function ToolbarButton({
6434
6742
  );
6435
6743
  }
6436
6744
  function Icon2({ children, strokeWidth = 1.5 }) {
6437
- return /* @__PURE__ */ jsx14(
6745
+ return /* @__PURE__ */ jsx16(
6438
6746
  "svg",
6439
6747
  {
6440
6748
  viewBox: "0 0 20 20",
@@ -6453,27 +6761,27 @@ var FORMAT_BUTTONS = [
6453
6761
  {
6454
6762
  format: "bold",
6455
6763
  label: "Bold",
6456
- icon: /* @__PURE__ */ jsx14(Icon2, { strokeWidth: 1.8, children: /* @__PURE__ */ jsx14("path", { d: "M6 3.5h5a3 3 0 0 1 0 6H6zm0 6h6a3 3 0 0 1 0 6H6z" }) })
6764
+ icon: /* @__PURE__ */ jsx16(Icon2, { strokeWidth: 1.8, children: /* @__PURE__ */ jsx16("path", { d: "M6 3.5h5a3 3 0 0 1 0 6H6zm0 6h6a3 3 0 0 1 0 6H6z" }) })
6457
6765
  },
6458
6766
  {
6459
6767
  format: "italic",
6460
6768
  label: "Italic",
6461
- icon: /* @__PURE__ */ jsx14(Icon2, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx14("path", { d: "M8.5 3.5h6M5.5 16.5h6M11.5 3.5l-3 13" }) })
6769
+ icon: /* @__PURE__ */ jsx16(Icon2, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx16("path", { d: "M8.5 3.5h6M5.5 16.5h6M11.5 3.5l-3 13" }) })
6462
6770
  },
6463
6771
  {
6464
6772
  format: "strikethrough",
6465
6773
  label: "Strikethrough",
6466
- icon: /* @__PURE__ */ jsx14(Icon2, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx14("path", { d: "M4 10h12M13.5 5.5c-.6-1.2-2-2-3.5-2-2 0-3.5 1.2-3.5 2.8 0 .5.1.9.4 1.3m-.4 5c.5 1.6 2 2.9 3.9 2.9 2 0 3.6-1.2 3.6-2.9 0-.4-.1-.8-.2-1.1" }) })
6774
+ icon: /* @__PURE__ */ jsx16(Icon2, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx16("path", { d: "M4 10h12M13.5 5.5c-.6-1.2-2-2-3.5-2-2 0-3.5 1.2-3.5 2.8 0 .5.1.9.4 1.3m-.4 5c.5 1.6 2 2.9 3.9 2.9 2 0 3.6-1.2 3.6-2.9 0-.4-.1-.8-.2-1.1" }) })
6467
6775
  },
6468
6776
  {
6469
6777
  format: "code",
6470
6778
  label: "Inline code",
6471
- icon: /* @__PURE__ */ jsx14(Icon2, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx14("path", { d: "M7.5 6L4 10l3.5 4M12.5 6L16 10l-3.5 4" }) })
6779
+ icon: /* @__PURE__ */ jsx16(Icon2, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx16("path", { d: "M7.5 6L4 10l3.5 4M12.5 6L16 10l-3.5 4" }) })
6472
6780
  }
6473
6781
  ];
6474
6782
  function FormatButtons() {
6475
6783
  const { activeFormats, toggleFormat } = useMarkdownEditor();
6476
- return /* @__PURE__ */ jsx14(Fragment5, { children: FORMAT_BUTTONS.map(({ format, label, icon }) => /* @__PURE__ */ jsx14(
6784
+ return /* @__PURE__ */ jsx16(Fragment6, { children: FORMAT_BUTTONS.map(({ format, label, icon }) => /* @__PURE__ */ jsx16(
6477
6785
  ToolbarButton,
6478
6786
  {
6479
6787
  label,
@@ -6486,36 +6794,36 @@ function FormatButtons() {
6486
6794
  }
6487
6795
  function InsertButtons() {
6488
6796
  const { insertTable, insertDrawing } = useMarkdownEditor();
6489
- return /* @__PURE__ */ jsxs11(Fragment5, { children: [
6490
- /* @__PURE__ */ jsx14(ToolbarButton, { label: "Insert table", onClick: () => insertTable(), children: /* @__PURE__ */ jsxs11(Icon2, { children: [
6491
- /* @__PURE__ */ jsx14("rect", { x: "3", y: "3.5", width: "14", height: "13", rx: "1.5" }),
6492
- /* @__PURE__ */ jsx14("path", { d: "M3 8h14M8 8v8.5M13 8v8.5" })
6797
+ return /* @__PURE__ */ jsxs13(Fragment6, { children: [
6798
+ /* @__PURE__ */ jsx16(ToolbarButton, { label: "Insert table", onClick: () => insertTable(), children: /* @__PURE__ */ jsxs13(Icon2, { children: [
6799
+ /* @__PURE__ */ jsx16("rect", { x: "3", y: "3.5", width: "14", height: "13", rx: "1.5" }),
6800
+ /* @__PURE__ */ jsx16("path", { d: "M3 8h14M8 8v8.5M13 8v8.5" })
6493
6801
  ] }) }),
6494
- /* @__PURE__ */ jsx14(ToolbarButton, { label: "Insert drawing", onClick: insertDrawing, children: /* @__PURE__ */ jsxs11(Icon2, { children: [
6495
- /* @__PURE__ */ jsx14("rect", { x: "3", y: "5", width: "8", height: "6", rx: "1.5" }),
6496
- /* @__PURE__ */ jsx14("path", { d: "M13.5 8h3M14.5 6.5L17.5 8l-3 1.5" }),
6497
- /* @__PURE__ */ jsx14("ellipse", { cx: "13", cy: "14.5", rx: "4", ry: "2.8" })
6802
+ /* @__PURE__ */ jsx16(ToolbarButton, { label: "Insert drawing", onClick: insertDrawing, children: /* @__PURE__ */ jsxs13(Icon2, { children: [
6803
+ /* @__PURE__ */ jsx16("rect", { x: "3", y: "5", width: "8", height: "6", rx: "1.5" }),
6804
+ /* @__PURE__ */ jsx16("path", { d: "M13.5 8h3M14.5 6.5L17.5 8l-3 1.5" }),
6805
+ /* @__PURE__ */ jsx16("ellipse", { cx: "13", cy: "14.5", rx: "4", ry: "2.8" })
6498
6806
  ] }) })
6499
6807
  ] });
6500
6808
  }
6501
6809
  function HistoryButtons() {
6502
6810
  const { canUndo, canRedo, undo, redo } = useMarkdownEditor();
6503
- return /* @__PURE__ */ jsxs11(Fragment5, { children: [
6504
- /* @__PURE__ */ jsx14(ToolbarButton, { label: "Undo", onClick: undo, disabled: !canUndo, children: /* @__PURE__ */ jsxs11(Icon2, { children: [
6505
- /* @__PURE__ */ jsx14("path", { d: "M7 6L3.5 9.5 7 13" }),
6506
- /* @__PURE__ */ jsx14("path", { d: "M3.5 9.5H12a4 4 0 0 1 0 8h-1" })
6811
+ return /* @__PURE__ */ jsxs13(Fragment6, { children: [
6812
+ /* @__PURE__ */ jsx16(ToolbarButton, { label: "Undo", onClick: undo, disabled: !canUndo, children: /* @__PURE__ */ jsxs13(Icon2, { children: [
6813
+ /* @__PURE__ */ jsx16("path", { d: "M7 6L3.5 9.5 7 13" }),
6814
+ /* @__PURE__ */ jsx16("path", { d: "M3.5 9.5H12a4 4 0 0 1 0 8h-1" })
6507
6815
  ] }) }),
6508
- /* @__PURE__ */ jsx14(ToolbarButton, { label: "Redo", onClick: redo, disabled: !canRedo, children: /* @__PURE__ */ jsxs11(Icon2, { children: [
6509
- /* @__PURE__ */ jsx14("path", { d: "M13 6l3.5 3.5L13 13" }),
6510
- /* @__PURE__ */ jsx14("path", { d: "M16.5 9.5H8a4 4 0 0 0 0 8h1" })
6816
+ /* @__PURE__ */ jsx16(ToolbarButton, { label: "Redo", onClick: redo, disabled: !canRedo, children: /* @__PURE__ */ jsxs13(Icon2, { children: [
6817
+ /* @__PURE__ */ jsx16("path", { d: "M13 6l3.5 3.5L13 13" }),
6818
+ /* @__PURE__ */ jsx16("path", { d: "M16.5 9.5H8a4 4 0 0 0 0 8h1" })
6511
6819
  ] }) })
6512
6820
  ] });
6513
6821
  }
6514
6822
 
6515
- // src/plugins/TableSettingsPlugin.tsx
6516
- import { jsx as jsx15 } from "react/jsx-runtime";
6823
+ // src/components/TableSettingsToolbar.tsx
6824
+ import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
6517
6825
  function Icon3({ children }) {
6518
- return /* @__PURE__ */ jsx15(
6826
+ return /* @__PURE__ */ jsx17(
6519
6827
  "svg",
6520
6828
  {
6521
6829
  viewBox: "0 0 20 20",
@@ -6530,32 +6838,79 @@ function Icon3({ children }) {
6530
6838
  }
6531
6839
  );
6532
6840
  }
6533
- function TableSettingsPlugin() {
6534
- const [editor] = useLexicalComposerContext9();
6535
- const isEditable = useLexicalEditable2();
6536
- const [anchor, setAnchor] = useState7(null);
6537
- const [settings, setSettings] = useState7(null);
6538
- const sync = useCallback5(() => {
6841
+ function TableSettingsToolbar({
6842
+ settings,
6843
+ position,
6844
+ style,
6845
+ onSettings,
6846
+ onRowAction
6847
+ }) {
6848
+ return /* @__PURE__ */ jsxs14("div", { className: "zui-table-settings", role: "toolbar", "aria-label": "Table", style, children: [
6849
+ LAYOUT_OPTIONS.map(({ preset, label, icon, width, density }) => /* @__PURE__ */ jsx17(
6850
+ ToolbarButton,
6851
+ {
6852
+ label,
6853
+ active: layoutPreset(settings.width) === preset,
6854
+ onClick: () => onSettings({ width, density }),
6855
+ children: /* @__PURE__ */ jsx17(Icon3, { children: icon })
6856
+ },
6857
+ preset
6858
+ )),
6859
+ /* @__PURE__ */ jsx17(ToolbarDivider, {}),
6860
+ TABLE_ROW_ACTIONS.map((rowAction) => /* @__PURE__ */ jsx17(
6861
+ ToolbarButton,
6862
+ {
6863
+ label: tableRowActionTitle(rowAction),
6864
+ disabled: rowAction.action === "delete" && !canDeleteRow(position) || rowAction.action === "insert-above" && position.hasHeader && position.index === 0,
6865
+ onClick: () => onRowAction(rowAction.action),
6866
+ children: /* @__PURE__ */ jsx17(Icon3, { children: rowAction.icon })
6867
+ },
6868
+ rowAction.action
6869
+ ))
6870
+ ] });
6871
+ }
6872
+
6873
+ // src/plugins/useSelectedTable.ts
6874
+ import { useCallback as useCallback6, useEffect as useEffect12, useState as useState8 } from "react";
6875
+ import { useLexicalComposerContext as useLexicalComposerContext10 } from "@lexical/react/LexicalComposerContext";
6876
+ function measure(element, main) {
6877
+ const rect = element.getBoundingClientRect();
6878
+ const mainRect = main.getBoundingClientRect();
6879
+ const rows = Array.from(element.querySelectorAll(":scope > tbody > tr, :scope > tr")).map(
6880
+ (row) => {
6881
+ const r = row.getBoundingClientRect();
6882
+ return { top: r.top - rect.top, height: r.height };
6883
+ }
6884
+ );
6885
+ return {
6886
+ box: {
6887
+ top: rect.top - mainRect.top,
6888
+ left: rect.left - mainRect.left,
6889
+ right: mainRect.right - rect.right,
6890
+ width: rect.width,
6891
+ height: rect.height
6892
+ },
6893
+ rows
6894
+ };
6895
+ }
6896
+ function useSelectedTable() {
6897
+ const [editor] = useLexicalComposerContext10();
6898
+ const [selected, setSelected] = useState8(null);
6899
+ const sync = useCallback6(() => {
6539
6900
  const table = editor.getEditorState().read(() => {
6540
6901
  const node = $getSelectedTable();
6541
- return node ? { key: node.getKey(), settings: $getTableSettings(node) } : null;
6902
+ const position = $getTableRowPosition();
6903
+ return node && position ? { key: node.getKey(), settings: $getTableSettings(node), position } : null;
6542
6904
  });
6543
6905
  const element = table ? editor.getElementByKey(table.key) : null;
6544
6906
  const main = editor.getRootElement()?.parentElement;
6545
6907
  if (!table || !element || !main) {
6546
- setAnchor(null);
6547
- setSettings(null);
6908
+ setSelected(null);
6548
6909
  return;
6549
6910
  }
6550
- const rect = element.getBoundingClientRect();
6551
- const mainRect = main.getBoundingClientRect();
6552
- setAnchor({
6553
- top: rect.top - mainRect.top,
6554
- right: mainRect.right - rect.right + 8
6555
- });
6556
- setSettings(table.settings);
6911
+ setSelected({ ...table, ...measure(element, main) });
6557
6912
  }, [editor]);
6558
- useEffect11(() => {
6913
+ useEffect12(() => {
6559
6914
  sync();
6560
6915
  const unregister = editor.registerUpdateListener(sync);
6561
6916
  const rootElement = editor.getRootElement();
@@ -6566,39 +6921,79 @@ function TableSettingsPlugin() {
6566
6921
  observer?.disconnect();
6567
6922
  };
6568
6923
  }, [editor, sync]);
6569
- const update = useCallback5(
6924
+ const key = selected?.key ?? null;
6925
+ useEffect12(() => {
6926
+ if (key === null || typeof ResizeObserver === "undefined") return;
6927
+ const element = editor.getElementByKey(key);
6928
+ if (!element) return;
6929
+ const observer = new ResizeObserver(sync);
6930
+ observer.observe(element);
6931
+ return () => observer.disconnect();
6932
+ }, [editor, key, sync]);
6933
+ return selected;
6934
+ }
6935
+
6936
+ // src/plugins/TableControlsPlugin.tsx
6937
+ import { Fragment as Fragment7, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
6938
+ function TableControlsPlugin() {
6939
+ const [editor] = useLexicalComposerContext11();
6940
+ const isEditable = useLexicalEditable2();
6941
+ const table = useSelectedTable();
6942
+ const updateSettings = useCallback7(
6570
6943
  (next) => {
6571
6944
  editor.update(() => {
6572
- const table = $getSelectedTable();
6573
- if (table) $setTableSettings(table, next);
6945
+ const node = $getSelectedTable();
6946
+ if (node) $setTableSettings(node, next);
6574
6947
  });
6575
6948
  },
6576
6949
  [editor]
6577
6950
  );
6578
- if (!isEditable || !anchor || !settings) return null;
6579
- return /* @__PURE__ */ jsx15(
6580
- "div",
6581
- {
6582
- className: "zui-table-settings",
6583
- role: "toolbar",
6584
- "aria-label": "Table settings",
6585
- style: { top: anchor.top, right: anchor.right },
6586
- children: LAYOUT_OPTIONS.map(({ preset, label, icon, width, density }) => /* @__PURE__ */ jsx15(
6587
- ToolbarButton,
6588
- {
6589
- label,
6590
- active: layoutPreset(settings.width) === preset,
6591
- onClick: () => update({ width, density }),
6592
- children: /* @__PURE__ */ jsx15(Icon3, { children: icon })
6593
- },
6594
- preset
6595
- ))
6596
- }
6951
+ const rowAction = useCallback7(
6952
+ (action) => {
6953
+ editor.update(() => {
6954
+ const node = $getSelectedTable();
6955
+ if (!node) return;
6956
+ if (action === "delete") $deleteSelectedTableRow(node);
6957
+ else $insertTableRowNear(node, action === "insert-above" ? "above" : "below");
6958
+ });
6959
+ },
6960
+ [editor]
6597
6961
  );
6962
+ const insertAt = useCallback7(
6963
+ (index) => {
6964
+ editor.update(() => {
6965
+ const node = $getSelectedTable();
6966
+ if (node) $insertTableRowAt(node, index);
6967
+ });
6968
+ },
6969
+ [editor]
6970
+ );
6971
+ if (!isEditable || !table) return null;
6972
+ return /* @__PURE__ */ jsxs15(Fragment7, { children: [
6973
+ /* @__PURE__ */ jsx18(
6974
+ TableSettingsToolbar,
6975
+ {
6976
+ settings: table.settings,
6977
+ position: table.position,
6978
+ style: { top: table.box.top, right: table.box.right + 8 },
6979
+ onSettings: updateSettings,
6980
+ onRowAction: rowAction
6981
+ }
6982
+ ),
6983
+ /* @__PURE__ */ jsx18(
6984
+ TableRowRail,
6985
+ {
6986
+ box: table.box,
6987
+ rows: table.rows,
6988
+ position: table.position,
6989
+ onInsert: insertAt
6990
+ }
6991
+ )
6992
+ ] });
6598
6993
  }
6599
6994
 
6600
6995
  // src/EditorContent.tsx
6601
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
6996
+ import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
6602
6997
  function EditorContent({
6603
6998
  placeholder = "Start writing...",
6604
6999
  foldable = true,
@@ -6606,7 +7001,7 @@ function EditorContent({
6606
7001
  }) {
6607
7002
  const { mode, readOnly, autoFocus, rawValue, onRawChange } = useEditorContext();
6608
7003
  if (mode === "edit-raw") {
6609
- return /* @__PURE__ */ jsx16(
7004
+ return /* @__PURE__ */ jsx19(
6610
7005
  "textarea",
6611
7006
  {
6612
7007
  className: "zui-text-editor-textarea",
@@ -6619,36 +7014,36 @@ function EditorContent({
6619
7014
  }
6620
7015
  );
6621
7016
  }
6622
- return /* @__PURE__ */ jsxs12("div", { className: "zui-text-editor-body", children: [
6623
- /* @__PURE__ */ jsxs12("div", { className: "zui-text-editor-main", children: [
6624
- /* @__PURE__ */ jsx16(
7017
+ return /* @__PURE__ */ jsxs16("div", { className: "zui-text-editor-body", children: [
7018
+ /* @__PURE__ */ jsxs16("div", { className: "zui-text-editor-main", children: [
7019
+ /* @__PURE__ */ jsx19(
6625
7020
  RichTextPlugin,
6626
7021
  {
6627
- contentEditable: /* @__PURE__ */ jsx16(
7022
+ contentEditable: /* @__PURE__ */ jsx19(
6628
7023
  ContentEditable,
6629
7024
  {
6630
7025
  className: "zui-text-editor-content",
6631
7026
  "aria-placeholder": placeholder,
6632
- placeholder: /* @__PURE__ */ jsx16("div", { className: "zui-text-editor-placeholder", children: placeholder })
7027
+ placeholder: /* @__PURE__ */ jsx19("div", { className: "zui-text-editor-placeholder", children: placeholder })
6633
7028
  }
6634
7029
  ),
6635
7030
  ErrorBoundary: LexicalErrorBoundary
6636
7031
  }
6637
7032
  ),
6638
- foldable && /* @__PURE__ */ jsx16(FoldingPlugin, {}),
6639
- /* @__PURE__ */ jsx16(TableSettingsPlugin, {})
7033
+ foldable && /* @__PURE__ */ jsx19(FoldingPlugin, {}),
7034
+ /* @__PURE__ */ jsx19(TableControlsPlugin, {})
6640
7035
  ] }),
6641
7036
  children
6642
7037
  ] });
6643
7038
  }
6644
7039
 
6645
7040
  // src/plugins/OutlinePlugin.tsx
6646
- import { useCallback as useCallback6, useEffect as useEffect12, useState as useState8 } from "react";
6647
- import { useLexicalComposerContext as useLexicalComposerContext10 } from "@lexical/react/LexicalComposerContext";
7041
+ import { useCallback as useCallback8, useEffect as useEffect13, useState as useState9 } from "react";
7042
+ import { useLexicalComposerContext as useLexicalComposerContext12 } from "@lexical/react/LexicalComposerContext";
6648
7043
  import {
6649
7044
  TableOfContentsPlugin
6650
7045
  } from "@lexical/react/LexicalTableOfContentsPlugin";
6651
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
7046
+ import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
6652
7047
  var INDENT_PER_LEVEL = {
6653
7048
  h1: 0,
6654
7049
  h2: 1,
@@ -6658,10 +7053,10 @@ var INDENT_PER_LEVEL = {
6658
7053
  h6: 5
6659
7054
  };
6660
7055
  function OutlinePlugin() {
6661
- const [editor] = useLexicalComposerContext10();
6662
- const [collapsed, setCollapsed] = useState8(false);
6663
- const [activeKey, setActiveKey] = useState8(null);
6664
- useEffect12(() => {
7056
+ const [editor] = useLexicalComposerContext12();
7057
+ const [collapsed, setCollapsed] = useState9(false);
7058
+ const [activeKey, setActiveKey] = useState9(null);
7059
+ useEffect13(() => {
6665
7060
  const rootElement = editor.getRootElement();
6666
7061
  const scroller = rootElement?.closest(".zui-text-editor");
6667
7062
  if (!rootElement || !(scroller instanceof HTMLElement)) return;
@@ -6691,7 +7086,7 @@ function OutlinePlugin() {
6691
7086
  unregister();
6692
7087
  };
6693
7088
  }, [editor]);
6694
- const scrollTo = useCallback6(
7089
+ const scrollTo = useCallback8(
6695
7090
  (key) => {
6696
7091
  editor.getEditorState().read(() => {
6697
7092
  const element = editor.getElementByKey(key);
@@ -6700,16 +7095,16 @@ function OutlinePlugin() {
6700
7095
  },
6701
7096
  [editor]
6702
7097
  );
6703
- return /* @__PURE__ */ jsx17(TableOfContentsPlugin, { children: (entries) => {
7098
+ return /* @__PURE__ */ jsx20(TableOfContentsPlugin, { children: (entries) => {
6704
7099
  for (const [key] of entries) {
6705
7100
  editor.getElementByKey(key)?.setAttribute("data-outline-key", key);
6706
7101
  }
6707
- return /* @__PURE__ */ jsxs13(
7102
+ return /* @__PURE__ */ jsxs17(
6708
7103
  "div",
6709
7104
  {
6710
7105
  className: `zui-text-editor-outline ${collapsed ? "is-collapsed" : ""}`,
6711
7106
  children: [
6712
- /* @__PURE__ */ jsx17(
7107
+ /* @__PURE__ */ jsx20(
6713
7108
  "button",
6714
7109
  {
6715
7110
  type: "button",
@@ -6718,7 +7113,7 @@ function OutlinePlugin() {
6718
7113
  "aria-label": collapsed ? "Show outline" : "Hide outline",
6719
7114
  "aria-expanded": !collapsed,
6720
7115
  onClick: () => setCollapsed((c2) => !c2),
6721
- children: /* @__PURE__ */ jsx17(
7116
+ children: /* @__PURE__ */ jsx20(
6722
7117
  "svg",
6723
7118
  {
6724
7119
  viewBox: "0 0 20 20",
@@ -6728,14 +7123,14 @@ function OutlinePlugin() {
6728
7123
  stroke: "currentColor",
6729
7124
  strokeWidth: "1.8",
6730
7125
  strokeLinecap: "round",
6731
- children: /* @__PURE__ */ jsx17("path", { d: "M4 5h12M4 10h8M4 15h10" })
7126
+ children: /* @__PURE__ */ jsx20("path", { d: "M4 5h12M4 10h8M4 15h10" })
6732
7127
  }
6733
7128
  )
6734
7129
  }
6735
7130
  ),
6736
- !collapsed && /* @__PURE__ */ jsxs13("nav", { className: "zui-text-editor-outline-list", "aria-label": "Table of contents", children: [
6737
- entries.length === 0 && /* @__PURE__ */ jsx17("div", { className: "zui-text-editor-outline-empty", children: "No headings" }),
6738
- entries.map(([key, text, tag]) => /* @__PURE__ */ jsx17(
7131
+ !collapsed && /* @__PURE__ */ jsxs17("nav", { className: "zui-text-editor-outline-list", "aria-label": "Table of contents", children: [
7132
+ entries.length === 0 && /* @__PURE__ */ jsx20("div", { className: "zui-text-editor-outline-empty", children: "No headings" }),
7133
+ entries.map(([key, text, tag]) => /* @__PURE__ */ jsx20(
6739
7134
  "button",
6740
7135
  {
6741
7136
  type: "button",
@@ -6756,11 +7151,11 @@ function OutlinePlugin() {
6756
7151
  }
6757
7152
 
6758
7153
  // src/MarkdownEditor.tsx
6759
- import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
7154
+ import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
6760
7155
  var DEFAULT_ITEMS = {
6761
- format: /* @__PURE__ */ jsx18(FormatButtons, {}),
6762
- insert: /* @__PURE__ */ jsx18(InsertButtons, {}),
6763
- history: /* @__PURE__ */ jsx18(HistoryButtons, {})
7156
+ format: /* @__PURE__ */ jsx21(FormatButtons, {}),
7157
+ insert: /* @__PURE__ */ jsx21(InsertButtons, {}),
7158
+ history: /* @__PURE__ */ jsx21(HistoryButtons, {})
6764
7159
  };
6765
7160
  function EditorToolbar({
6766
7161
  children,
@@ -6768,7 +7163,7 @@ function EditorToolbar({
6768
7163
  }) {
6769
7164
  const { mode, readOnly } = useEditorContext();
6770
7165
  if (mode !== "edit-md" || readOnly) return null;
6771
- return /* @__PURE__ */ jsx18(Toolbar, { className, children });
7166
+ return /* @__PURE__ */ jsx21(Toolbar, { className, children });
6772
7167
  }
6773
7168
  function MarkdownEditor({
6774
7169
  placeholder,
@@ -6777,10 +7172,10 @@ function MarkdownEditor({
6777
7172
  foldable = true,
6778
7173
  ...rootProps
6779
7174
  }) {
6780
- return /* @__PURE__ */ jsxs14(EditorRoot, { ...rootProps, children: [
6781
- toolbar === true && /* @__PURE__ */ jsx18(EditorToolbar, {}),
7175
+ return /* @__PURE__ */ jsxs18(EditorRoot, { ...rootProps, children: [
7176
+ toolbar === true && /* @__PURE__ */ jsx21(EditorToolbar, {}),
6782
7177
  typeof toolbar === "function" && toolbar(DEFAULT_ITEMS),
6783
- /* @__PURE__ */ jsx18(EditorContent, { placeholder, foldable, children: outline && /* @__PURE__ */ jsx18(OutlinePlugin, {}) })
7178
+ /* @__PURE__ */ jsx21(EditorContent, { placeholder, foldable, children: outline && /* @__PURE__ */ jsx21(OutlinePlugin, {}) })
6784
7179
  ] });
6785
7180
  }
6786
7181
  MarkdownEditor.Root = EditorRoot;
@@ -6954,10 +7349,16 @@ var DRAWING_DATA_JSON_SCHEMA = {
6954
7349
  export {
6955
7350
  $createDrawingNode,
6956
7351
  $createFrontmatterNode,
7352
+ $deleteSelectedTableRow,
7353
+ $deleteTableRowAt,
6957
7354
  $getSelectedTable,
7355
+ $getSelectedTableCell,
6958
7356
  $getTableDensity,
7357
+ $getTableRowPosition,
6959
7358
  $getTableSettings,
6960
7359
  $getTableWidth,
7360
+ $insertTableRowAt,
7361
+ $insertTableRowNear,
6961
7362
  $isDrawingNode,
6962
7363
  $isFrontmatterNode,
6963
7364
  $isTableWidthExplicit,
@@ -6998,6 +7399,7 @@ export {
6998
7399
  anchorPoint,
6999
7400
  bindEndpoints,
7000
7401
  boxOutline,
7402
+ canDeleteRow,
7001
7403
  codeTokenizer,
7002
7404
  connectorPoints,
7003
7405
  drawingToMermaid,
@@ -7010,6 +7412,7 @@ export {
7010
7412
  inkAmplitude,
7011
7413
  inkFillOffset,
7012
7414
  inkStroke,
7415
+ insertableRowIndices,
7013
7416
  isBlockWidth,
7014
7417
  isDrawingSkeleton,
7015
7418
  makeBinding,