@zuilib/text-editor 0.8.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/CHANGELOG.md +29 -0
- package/README.md +33 -1
- package/dist/index.d.ts +213 -99
- package/dist/index.js +1270 -472
- package/dist/styles.css +126 -5
- package/package.json +1 -1
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
|
|
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
|
|
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,15 +1994,29 @@ import {
|
|
|
1696
1994
|
// src/drawing/canvas/DrawingCanvas.tsx
|
|
1697
1995
|
import {
|
|
1698
1996
|
useCallback,
|
|
1699
|
-
useEffect as
|
|
1997
|
+
useEffect as useEffect8,
|
|
1700
1998
|
useMemo,
|
|
1701
1999
|
useRef as useRef4,
|
|
1702
|
-
useState as useState3
|
|
2000
|
+
useState as useState3,
|
|
2001
|
+
useContext as useContext2
|
|
1703
2002
|
} from "react";
|
|
1704
|
-
import { $getNodeByKey as $
|
|
1705
|
-
import { useLexicalComposerContext as
|
|
2003
|
+
import { $getNodeByKey as $getNodeByKey4 } from "lexical";
|
|
2004
|
+
import { useLexicalComposerContext as useLexicalComposerContext6 } from "@lexical/react/LexicalComposerContext";
|
|
1706
2005
|
import { useLexicalEditable } from "@lexical/react/useLexicalEditable";
|
|
1707
2006
|
|
|
2007
|
+
// src/editorContext.ts
|
|
2008
|
+
import { createContext, useContext } from "react";
|
|
2009
|
+
var EditorContext = createContext(null);
|
|
2010
|
+
function useEditorContext() {
|
|
2011
|
+
const ctx = useContext(EditorContext);
|
|
2012
|
+
if (!ctx) {
|
|
2013
|
+
throw new Error(
|
|
2014
|
+
"@zuilib/text-editor: this component must be rendered inside <MarkdownEditor> or <MarkdownEditor.Root>"
|
|
2015
|
+
);
|
|
2016
|
+
}
|
|
2017
|
+
return ctx;
|
|
2018
|
+
}
|
|
2019
|
+
|
|
1708
2020
|
// src/drawing/focusCommand.ts
|
|
1709
2021
|
import { createCommand } from "lexical";
|
|
1710
2022
|
var DRAWING_FOCUS_COMMAND = createCommand(
|
|
@@ -2138,23 +2450,23 @@ var BOX_DEFINITIONS = {
|
|
|
2138
2450
|
defaultFill: "#ffec99",
|
|
2139
2451
|
outline: (s) => {
|
|
2140
2452
|
const b = bbox(s);
|
|
2141
|
-
const
|
|
2453
|
+
const f3 = NOTE_FOLD(b);
|
|
2142
2454
|
return [
|
|
2143
2455
|
{ x: b.x, y: b.y },
|
|
2144
2456
|
{ x: b.x + b.w, y: b.y },
|
|
2145
|
-
{ x: b.x + b.w, y: b.y + b.h -
|
|
2146
|
-
{ x: b.x + b.w -
|
|
2457
|
+
{ x: b.x + b.w, y: b.y + b.h - f3 },
|
|
2458
|
+
{ x: b.x + b.w - f3, y: b.y + b.h },
|
|
2147
2459
|
{ x: b.x, y: b.y + b.h }
|
|
2148
2460
|
];
|
|
2149
2461
|
},
|
|
2150
2462
|
textArea: (s) => {
|
|
2151
2463
|
const b = bbox(s);
|
|
2152
|
-
const
|
|
2464
|
+
const f3 = NOTE_FOLD(b);
|
|
2153
2465
|
return {
|
|
2154
2466
|
x: b.x + BOX_TEXT_PADDING,
|
|
2155
2467
|
y: b.y + BOX_TEXT_PADDING,
|
|
2156
2468
|
w: Math.max(b.w - BOX_TEXT_PADDING * 2, 20),
|
|
2157
|
-
h: Math.max(b.h - BOX_TEXT_PADDING * 2 -
|
|
2469
|
+
h: Math.max(b.h - BOX_TEXT_PADDING * 2 - f3 / 2, 10)
|
|
2158
2470
|
};
|
|
2159
2471
|
}
|
|
2160
2472
|
},
|
|
@@ -2656,13 +2968,17 @@ function segmentAngleAt(points, index, backward) {
|
|
|
2656
2968
|
}
|
|
2657
2969
|
return 0;
|
|
2658
2970
|
}
|
|
2659
|
-
function
|
|
2971
|
+
function arrowHeadPoints(tip, angle, length) {
|
|
2660
2972
|
const spread = Math.PI / 7;
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2973
|
+
return [
|
|
2974
|
+
{ x: tip.x - length * Math.cos(angle - spread), y: tip.y - length * Math.sin(angle - spread) },
|
|
2975
|
+
tip,
|
|
2976
|
+
{ x: tip.x - length * Math.cos(angle + spread), y: tip.y - length * Math.sin(angle + spread) }
|
|
2977
|
+
];
|
|
2978
|
+
}
|
|
2979
|
+
function arrowHeadPath(tip, angle, length) {
|
|
2980
|
+
const [a, t, b] = arrowHeadPoints(tip, angle, length);
|
|
2981
|
+
return `M ${fmt(a.x)} ${fmt(a.y)} L ${fmt(t.x)} ${fmt(t.y)} L ${fmt(b.x)} ${fmt(b.y)}`;
|
|
2666
2982
|
}
|
|
2667
2983
|
function pathLength(points) {
|
|
2668
2984
|
let total = 0;
|
|
@@ -3774,7 +4090,7 @@ function BoxGeometry({
|
|
|
3774
4090
|
}
|
|
3775
4091
|
);
|
|
3776
4092
|
case "note": {
|
|
3777
|
-
const
|
|
4093
|
+
const f3 = NOTE_FOLD(b);
|
|
3778
4094
|
const r = b.x + b.w;
|
|
3779
4095
|
const btm = b.y + b.h;
|
|
3780
4096
|
return /* @__PURE__ */ jsxs4("g", { children: [
|
|
@@ -3782,7 +4098,7 @@ function BoxGeometry({
|
|
|
3782
4098
|
"path",
|
|
3783
4099
|
{
|
|
3784
4100
|
...stroke,
|
|
3785
|
-
d: `M ${n(b.x)} ${n(b.y)} H ${n(r)} V ${n(btm -
|
|
4101
|
+
d: `M ${n(b.x)} ${n(b.y)} H ${n(r)} V ${n(btm - f3)} L ${n(r - f3)} ${n(btm)} H ${n(b.x)} Z`,
|
|
3786
4102
|
fill
|
|
3787
4103
|
}
|
|
3788
4104
|
),
|
|
@@ -3790,7 +4106,7 @@ function BoxGeometry({
|
|
|
3790
4106
|
"path",
|
|
3791
4107
|
{
|
|
3792
4108
|
...stroke,
|
|
3793
|
-
d: `M ${n(r -
|
|
4109
|
+
d: `M ${n(r - f3)} ${n(btm)} V ${n(btm - f3)} H ${n(r)}`,
|
|
3794
4110
|
fill: "rgba(0,0,0,0.08)"
|
|
3795
4111
|
}
|
|
3796
4112
|
)
|
|
@@ -3873,41 +4189,418 @@ function BoxGeometry({
|
|
|
3873
4189
|
}
|
|
3874
4190
|
}
|
|
3875
4191
|
|
|
3876
|
-
// src/drawing/
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
4192
|
+
// src/drawing/ink.ts
|
|
4193
|
+
var SAMPLE_STEP = 5;
|
|
4194
|
+
var PRESSURE = 0.3;
|
|
4195
|
+
function seedFrom(text) {
|
|
4196
|
+
let h = 2166136261;
|
|
4197
|
+
for (let i = 0; i < text.length; i++) {
|
|
4198
|
+
h ^= text.charCodeAt(i);
|
|
4199
|
+
h = Math.imul(h, 16777619);
|
|
4200
|
+
}
|
|
4201
|
+
return h >>> 0;
|
|
4202
|
+
}
|
|
4203
|
+
function mulberry32(seed) {
|
|
4204
|
+
let a = seed >>> 0;
|
|
4205
|
+
return () => {
|
|
4206
|
+
a = a + 1831565813 | 0;
|
|
4207
|
+
let t = Math.imul(a ^ a >>> 15, 1 | a);
|
|
4208
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
4209
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
3886
4210
|
};
|
|
3887
4211
|
}
|
|
3888
|
-
function
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
4212
|
+
function inkAmplitude(size) {
|
|
4213
|
+
return Math.min(4, Math.max(1, size * 0.03));
|
|
4214
|
+
}
|
|
4215
|
+
function inkFillOffset(seed) {
|
|
4216
|
+
const rand = mulberry32(seed ^ 2654435769);
|
|
4217
|
+
const angle = rand() * Math.PI * 2;
|
|
4218
|
+
const d = 2 + rand();
|
|
4219
|
+
return { x: Math.cos(angle) * d, y: Math.sin(angle) * d };
|
|
4220
|
+
}
|
|
4221
|
+
function makeField(seed, amplitude, closed) {
|
|
4222
|
+
const rand = mulberry32(seed);
|
|
4223
|
+
const int = (lo, span) => lo + Math.floor(rand() * span);
|
|
4224
|
+
const f1 = closed ? int(2, 2) : 1.5 + rand();
|
|
4225
|
+
const f22 = closed ? int(5, 3) : 3 + rand() * 2;
|
|
4226
|
+
const g = closed ? int(2, 2) : 1 + rand();
|
|
4227
|
+
const p1 = rand() * Math.PI * 2;
|
|
4228
|
+
const p2 = rand() * Math.PI * 2;
|
|
4229
|
+
const pg = rand() * Math.PI * 2;
|
|
4230
|
+
const a1 = amplitude * (0.55 + rand() * 0.15);
|
|
4231
|
+
const a2 = amplitude * 0.3;
|
|
4232
|
+
const TAU = Math.PI * 2;
|
|
4233
|
+
return {
|
|
4234
|
+
offset: (t) => a1 * Math.sin(TAU * f1 * t + p1) + a2 * Math.sin(TAU * f22 * t + p2),
|
|
4235
|
+
pressure: (t) => 1 + PRESSURE * Math.sin(TAU * g * t + pg)
|
|
4236
|
+
};
|
|
3894
4237
|
}
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
const
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
4238
|
+
function resample(points, closed) {
|
|
4239
|
+
const src = closed ? [...points, points[0]] : [...points];
|
|
4240
|
+
const lengths = [];
|
|
4241
|
+
let total = 0;
|
|
4242
|
+
for (let i = 1; i < src.length; i++) {
|
|
4243
|
+
const l = Math.hypot(src[i].x - src[i - 1].x, src[i].y - src[i - 1].y);
|
|
4244
|
+
lengths.push(l);
|
|
4245
|
+
total += l;
|
|
4246
|
+
}
|
|
4247
|
+
if (total === 0) return { points: [src[0]], ts: [0] };
|
|
4248
|
+
const out = [];
|
|
4249
|
+
const ts = [];
|
|
4250
|
+
let walked = 0;
|
|
4251
|
+
for (let i = 1; i < src.length; i++) {
|
|
4252
|
+
const a = src[i - 1];
|
|
4253
|
+
const b = src[i];
|
|
4254
|
+
const l = lengths[i - 1];
|
|
4255
|
+
const n2 = Math.max(1, Math.round(l / SAMPLE_STEP));
|
|
4256
|
+
for (let k = 0; k < n2; k++) {
|
|
4257
|
+
const u = k / n2;
|
|
4258
|
+
out.push({ x: a.x + (b.x - a.x) * u, y: a.y + (b.y - a.y) * u });
|
|
4259
|
+
ts.push((walked + l * u) / total);
|
|
4260
|
+
}
|
|
4261
|
+
walked += l;
|
|
4262
|
+
}
|
|
4263
|
+
if (!closed) {
|
|
4264
|
+
out.push(src[src.length - 1]);
|
|
4265
|
+
ts.push(1);
|
|
4266
|
+
}
|
|
4267
|
+
return { points: out, ts };
|
|
4268
|
+
}
|
|
4269
|
+
function normalAt(points, i, closed) {
|
|
4270
|
+
const n2 = points.length;
|
|
4271
|
+
const prev = points[closed ? (i - 1 + n2) % n2 : Math.max(0, i - 1)];
|
|
4272
|
+
const next = points[closed ? (i + 1) % n2 : Math.min(n2 - 1, i + 1)];
|
|
4273
|
+
const tx = next.x - prev.x;
|
|
4274
|
+
const ty = next.y - prev.y;
|
|
4275
|
+
const len = Math.hypot(tx, ty) || 1;
|
|
4276
|
+
return { x: -ty / len, y: tx / len };
|
|
4277
|
+
}
|
|
4278
|
+
var f = (v) => Number.isInteger(v) ? String(v) : v.toFixed(2);
|
|
4279
|
+
var pathOf = (points) => points.map((p, i) => `${i === 0 ? "M" : "L"} ${f(p.x)} ${f(p.y)}`).join(" ");
|
|
4280
|
+
function inkStroke(points, options) {
|
|
4281
|
+
if (points.length < 2) return { ring: "", center: "" };
|
|
4282
|
+
const { closed, seed, width, amplitude } = options;
|
|
4283
|
+
const field = makeField(seed, amplitude, closed);
|
|
4284
|
+
const { points: pts, ts } = resample(points, closed);
|
|
4285
|
+
if (pts.length < 2) return { ring: "", center: "" };
|
|
4286
|
+
const center2 = [];
|
|
4287
|
+
const outer = [];
|
|
4288
|
+
const inner = [];
|
|
4289
|
+
for (let i = 0; i < pts.length; i++) {
|
|
4290
|
+
const t = ts[i];
|
|
4291
|
+
const nrm = normalAt(pts, i, closed);
|
|
4292
|
+
const off = field.offset(t);
|
|
4293
|
+
const c2 = { x: pts[i].x + nrm.x * off, y: pts[i].y + nrm.y * off };
|
|
4294
|
+
const taper = closed ? 1 : 0.55 + 0.45 * Math.min(1, t / 0.1, (1 - t) / 0.1);
|
|
4295
|
+
const half = width * field.pressure(t) * taper / 2;
|
|
4296
|
+
center2.push(c2);
|
|
4297
|
+
outer.push({ x: c2.x + nrm.x * half, y: c2.y + nrm.y * half });
|
|
4298
|
+
inner.push({ x: c2.x - nrm.x * half, y: c2.y - nrm.y * half });
|
|
4299
|
+
}
|
|
4300
|
+
if (closed) {
|
|
4301
|
+
return {
|
|
4302
|
+
ring: `${pathOf(outer)} Z ${pathOf([...inner].reverse())} Z`,
|
|
4303
|
+
center: `${pathOf(center2)} Z`
|
|
4304
|
+
};
|
|
4305
|
+
}
|
|
4306
|
+
return {
|
|
4307
|
+
ring: `${pathOf(outer)} ${pathOf([...inner].reverse()).replace(/^M/, "L")} Z`,
|
|
4308
|
+
center: pathOf(center2)
|
|
4309
|
+
};
|
|
3902
4310
|
}
|
|
3903
|
-
function
|
|
3904
|
-
|
|
3905
|
-
if (
|
|
3906
|
-
|
|
4311
|
+
function roundedRectPolygon(r, radius, segments = 4) {
|
|
4312
|
+
const rad = Math.min(radius, r.w / 2, r.h / 2);
|
|
4313
|
+
if (rad <= 0) {
|
|
4314
|
+
return [
|
|
4315
|
+
{ x: r.x, y: r.y },
|
|
4316
|
+
{ x: r.x + r.w, y: r.y },
|
|
4317
|
+
{ x: r.x + r.w, y: r.y + r.h },
|
|
4318
|
+
{ x: r.x, y: r.y + r.h }
|
|
4319
|
+
];
|
|
4320
|
+
}
|
|
4321
|
+
const corners = [
|
|
4322
|
+
[r.x + r.w - rad, r.y + rad, -Math.PI / 2],
|
|
4323
|
+
[r.x + r.w - rad, r.y + r.h - rad, 0],
|
|
4324
|
+
[r.x + rad, r.y + r.h - rad, Math.PI / 2],
|
|
4325
|
+
[r.x + rad, r.y + rad, Math.PI]
|
|
4326
|
+
];
|
|
4327
|
+
const out = [];
|
|
4328
|
+
for (const [cx, cy, start] of corners) {
|
|
4329
|
+
for (let i = 0; i <= segments; i++) {
|
|
4330
|
+
const a = start + Math.PI / 2 * (i / segments);
|
|
4331
|
+
out.push({ x: cx + rad * Math.cos(a), y: cy + rad * Math.sin(a) });
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4334
|
+
return out;
|
|
3907
4335
|
}
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
4336
|
+
function roundedPolyline(points, cornerRadius = 6, segments = 4) {
|
|
4337
|
+
if (points.length < 3) return [...points];
|
|
4338
|
+
const out = [points[0]];
|
|
4339
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
4340
|
+
const prev = points[i - 1];
|
|
4341
|
+
const p = points[i];
|
|
4342
|
+
const next = points[i + 1];
|
|
4343
|
+
const inLen = Math.hypot(p.x - prev.x, p.y - prev.y);
|
|
4344
|
+
const outLen = Math.hypot(next.x - p.x, next.y - p.y);
|
|
4345
|
+
const r = Math.min(cornerRadius, inLen / 2, outLen / 2);
|
|
4346
|
+
if (r < 0.5) {
|
|
4347
|
+
out.push(p);
|
|
4348
|
+
continue;
|
|
4349
|
+
}
|
|
4350
|
+
const a = { x: p.x - (p.x - prev.x) / inLen * r, y: p.y - (p.y - prev.y) / inLen * r };
|
|
4351
|
+
const b = { x: p.x + (next.x - p.x) / outLen * r, y: p.y + (next.y - p.y) / outLen * r };
|
|
4352
|
+
for (let k = 0; k <= segments; k++) {
|
|
4353
|
+
const u = k / segments;
|
|
4354
|
+
const v = 1 - u;
|
|
4355
|
+
out.push({
|
|
4356
|
+
x: v * v * a.x + 2 * v * u * p.x + u * u * b.x,
|
|
4357
|
+
y: v * v * a.y + 2 * v * u * p.y + u * u * b.y
|
|
4358
|
+
});
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
out.push(points[points.length - 1]);
|
|
4362
|
+
return out;
|
|
4363
|
+
}
|
|
4364
|
+
function sampleCubic(p0, p1, p2, p3, segments = 10) {
|
|
4365
|
+
const out = [];
|
|
4366
|
+
for (let k = 1; k <= segments; k++) {
|
|
4367
|
+
const u = k / segments;
|
|
4368
|
+
const v = 1 - u;
|
|
4369
|
+
out.push({
|
|
4370
|
+
x: v * v * v * p0.x + 3 * v * v * u * p1.x + 3 * v * u * u * p2.x + u * u * u * p3.x,
|
|
4371
|
+
y: v * v * v * p0.y + 3 * v * v * u * p1.y + 3 * v * u * u * p2.y + u * u * u * p3.y
|
|
4372
|
+
});
|
|
4373
|
+
}
|
|
4374
|
+
return out;
|
|
4375
|
+
}
|
|
4376
|
+
function arcPolygon(cx, cy, rx, ry, from, to, segments = 12) {
|
|
4377
|
+
return Array.from({ length: segments + 1 }, (_, i) => {
|
|
4378
|
+
const a = from + (to - from) * i / segments;
|
|
4379
|
+
return { x: cx + rx * Math.cos(a), y: cy + ry * Math.sin(a) };
|
|
4380
|
+
});
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
// src/drawing/shapes/inkRender.tsx
|
|
4384
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
4385
|
+
var f2 = (v) => Number.isInteger(v) ? String(v) : v.toFixed(2);
|
|
4386
|
+
function extent(points) {
|
|
4387
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
4388
|
+
for (const p of points) {
|
|
4389
|
+
if (p.x < minX) minX = p.x;
|
|
4390
|
+
if (p.x > maxX) maxX = p.x;
|
|
4391
|
+
if (p.y < minY) minY = p.y;
|
|
4392
|
+
if (p.y > maxY) maxY = p.y;
|
|
4393
|
+
}
|
|
4394
|
+
return { w: maxX - minX, h: maxY - minY };
|
|
4395
|
+
}
|
|
4396
|
+
function InkBoxGeometry({ shape }) {
|
|
4397
|
+
const b = bbox(shape);
|
|
4398
|
+
const seed = seedFrom(shape.id);
|
|
4399
|
+
const width = shape.strokeWidth;
|
|
4400
|
+
const off = inkFillOffset(seed);
|
|
4401
|
+
const fillTransform = `translate(${f2(off.x)} ${f2(off.y)})`;
|
|
4402
|
+
const amplitudeOf = (points) => inkAmplitude(Math.min(extent(points).w, extent(points).h));
|
|
4403
|
+
const closed = (points, part, fill = shape.fill) => {
|
|
4404
|
+
const s = inkStroke(points, { closed: true, seed: seed + part, width, amplitude: amplitudeOf(points) });
|
|
4405
|
+
return /* @__PURE__ */ jsxs5("g", { children: [
|
|
4406
|
+
/* @__PURE__ */ jsx5("path", { d: s.center, fill, stroke: "none", transform: fillTransform }),
|
|
4407
|
+
/* @__PURE__ */ jsx5("path", { d: s.ring, fill: shape.stroke, fillRule: "evenodd", stroke: "none" })
|
|
4408
|
+
] });
|
|
4409
|
+
};
|
|
4410
|
+
const open = (points, part, w = width) => /* @__PURE__ */ jsx5(
|
|
4411
|
+
"path",
|
|
4412
|
+
{
|
|
4413
|
+
d: inkStroke(points, { closed: false, seed: seed + part, width: w, amplitude: amplitudeOf(points) }).ring,
|
|
4414
|
+
fill: shape.stroke,
|
|
4415
|
+
stroke: "none"
|
|
4416
|
+
}
|
|
4417
|
+
);
|
|
4418
|
+
switch (shape.type) {
|
|
4419
|
+
case "rect":
|
|
4420
|
+
return closed(roundedRectPolygon(b, Math.min(8, b.w / 4, b.h / 4)), 0);
|
|
4421
|
+
case "ellipse":
|
|
4422
|
+
return closed(ellipsePolygon(b, 64), 0);
|
|
4423
|
+
case "diamond":
|
|
4424
|
+
return closed(
|
|
4425
|
+
[
|
|
4426
|
+
{ x: b.x + b.w / 2, y: b.y },
|
|
4427
|
+
{ x: b.x + b.w, y: b.y + b.h / 2 },
|
|
4428
|
+
{ x: b.x + b.w / 2, y: b.y + b.h },
|
|
4429
|
+
{ x: b.x, y: b.y + b.h / 2 }
|
|
4430
|
+
],
|
|
4431
|
+
0
|
|
4432
|
+
);
|
|
4433
|
+
case "note": {
|
|
4434
|
+
const fold = NOTE_FOLD(b);
|
|
4435
|
+
const r = b.x + b.w;
|
|
4436
|
+
const btm = b.y + b.h;
|
|
4437
|
+
const fillPts = [
|
|
4438
|
+
{ x: b.x, y: b.y },
|
|
4439
|
+
{ x: r, y: b.y },
|
|
4440
|
+
{ x: r, y: btm - fold },
|
|
4441
|
+
{ x: r - fold, y: btm },
|
|
4442
|
+
{ x: b.x, y: btm }
|
|
4443
|
+
];
|
|
4444
|
+
const foldPts = [
|
|
4445
|
+
{ x: r - fold, y: btm },
|
|
4446
|
+
{ x: r - fold, y: btm - fold },
|
|
4447
|
+
{ x: r, y: btm - fold }
|
|
4448
|
+
];
|
|
4449
|
+
return /* @__PURE__ */ jsxs5("g", { children: [
|
|
4450
|
+
closed(fillPts, 0),
|
|
4451
|
+
/* @__PURE__ */ jsx5(
|
|
4452
|
+
"path",
|
|
4453
|
+
{
|
|
4454
|
+
d: `M ${foldPts.map((p) => `${f2(p.x)} ${f2(p.y)}`).join(" L ")} Z`,
|
|
4455
|
+
fill: "rgba(0,0,0,0.08)",
|
|
4456
|
+
stroke: "none"
|
|
4457
|
+
}
|
|
4458
|
+
),
|
|
4459
|
+
open(foldPts, 1)
|
|
4460
|
+
] });
|
|
4461
|
+
}
|
|
4462
|
+
case "cylinder": {
|
|
4463
|
+
const ry = CYLINDER_RY(b);
|
|
4464
|
+
const rx = b.w / 2;
|
|
4465
|
+
const cx = b.x + rx;
|
|
4466
|
+
const body = [
|
|
4467
|
+
{ x: b.x, y: b.y + ry },
|
|
4468
|
+
{ x: b.x, y: b.y + b.h - ry },
|
|
4469
|
+
...arcPolygon(cx, b.y + b.h - ry, rx, ry, Math.PI, 0, 16),
|
|
4470
|
+
{ x: b.x + b.w, y: b.y + ry }
|
|
4471
|
+
];
|
|
4472
|
+
const s = inkStroke(body, { closed: false, seed: seed + 0, width, amplitude: amplitudeOf(body) });
|
|
4473
|
+
return /* @__PURE__ */ jsxs5("g", { children: [
|
|
4474
|
+
/* @__PURE__ */ jsx5("path", { d: `${s.center} Z`, fill: shape.fill, stroke: "none", transform: fillTransform }),
|
|
4475
|
+
/* @__PURE__ */ jsx5("path", { d: s.ring, fill: shape.stroke, stroke: "none" }),
|
|
4476
|
+
closed(ellipsePolygon({ x: b.x, y: b.y, w: b.w, h: ry * 2 }, 48), 1)
|
|
4477
|
+
] });
|
|
4478
|
+
}
|
|
4479
|
+
case "cloud": {
|
|
4480
|
+
const p = (u, v) => ({ x: b.x + u * b.w, y: b.y + v * b.h });
|
|
4481
|
+
const start = p(0.22, 0.86);
|
|
4482
|
+
const segs = [
|
|
4483
|
+
[p(0.04, 0.88), p(0, 0.58), p(0.16, 0.5)],
|
|
4484
|
+
[p(0.08, 0.26), p(0.3, 0.12), p(0.42, 0.28)],
|
|
4485
|
+
[p(0.5, 0.02), p(0.76, 0.04), p(0.78, 0.3)],
|
|
4486
|
+
[p(0.98, 0.26), p(1.04, 0.56), p(0.88, 0.64)],
|
|
4487
|
+
[p(1, 0.8), p(0.9, 0.9), p(0.76, 0.86)]
|
|
4488
|
+
];
|
|
4489
|
+
const pts = [start];
|
|
4490
|
+
let from = start;
|
|
4491
|
+
for (const [c1, c2, to] of segs) {
|
|
4492
|
+
pts.push(...sampleCubic(from, c1, c2, to, 8));
|
|
4493
|
+
from = to;
|
|
4494
|
+
}
|
|
4495
|
+
return closed(pts, 0);
|
|
4496
|
+
}
|
|
4497
|
+
case "queue": {
|
|
4498
|
+
const rx = QUEUE_RX(b);
|
|
4499
|
+
const ry = b.h / 2;
|
|
4500
|
+
const body = [
|
|
4501
|
+
{ x: b.x + rx, y: b.y },
|
|
4502
|
+
{ x: b.x + b.w - rx, y: b.y },
|
|
4503
|
+
{ x: b.x + b.w - rx, y: b.y + b.h },
|
|
4504
|
+
{ x: b.x + rx, y: b.y + b.h },
|
|
4505
|
+
...arcPolygon(b.x + rx, b.y + ry, rx, ry, Math.PI / 2, 3 * Math.PI / 2, 16).slice(1, -1)
|
|
4506
|
+
];
|
|
4507
|
+
return /* @__PURE__ */ jsxs5("g", { children: [
|
|
4508
|
+
closed(body, 0),
|
|
4509
|
+
closed(ellipsePolygon({ x: b.x + b.w - rx * 2, y: b.y, w: rx * 2, h: b.h }, 48), 1)
|
|
4510
|
+
] });
|
|
4511
|
+
}
|
|
4512
|
+
case "actor": {
|
|
4513
|
+
const figH = b.h * ACTOR_FIGURE_RATIO;
|
|
4514
|
+
const cx = b.x + b.w / 2;
|
|
4515
|
+
const r = Math.max(4, Math.min(figH * 0.16, b.w * 0.2));
|
|
4516
|
+
const neck = b.y + r * 2;
|
|
4517
|
+
const hip = b.y + figH * 0.62;
|
|
4518
|
+
const armY = neck + figH * 0.12;
|
|
4519
|
+
const reach = Math.min(b.w * 0.32, figH * 0.3);
|
|
4520
|
+
return /* @__PURE__ */ jsxs5("g", { children: [
|
|
4521
|
+
closed(ellipsePolygon({ x: cx - r, y: b.y, w: r * 2, h: r * 2 }, 32), 0),
|
|
4522
|
+
open([{ x: cx, y: neck }, { x: cx, y: hip }], 1),
|
|
4523
|
+
open([{ x: cx - reach, y: armY }, { x: cx + reach, y: armY }], 2),
|
|
4524
|
+
open(
|
|
4525
|
+
[
|
|
4526
|
+
{ x: cx - reach, y: b.y + figH },
|
|
4527
|
+
{ x: cx, y: hip },
|
|
4528
|
+
{ x: cx + reach, y: b.y + figH }
|
|
4529
|
+
],
|
|
4530
|
+
3
|
|
4531
|
+
)
|
|
4532
|
+
] });
|
|
4533
|
+
}
|
|
4534
|
+
default:
|
|
4535
|
+
return null;
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
function InkConnector({
|
|
4539
|
+
shape,
|
|
4540
|
+
points
|
|
4541
|
+
}) {
|
|
4542
|
+
if (points.length < 2) return null;
|
|
4543
|
+
const seed = seedFrom(shape.id);
|
|
4544
|
+
const length = pathLength(points);
|
|
4545
|
+
const amplitude = Math.min(3, Math.max(0.8, length * 0.015));
|
|
4546
|
+
const width = shape.strokeWidth;
|
|
4547
|
+
const line = inkStroke(roundedPolyline(points), { closed: false, seed, width, amplitude });
|
|
4548
|
+
const heads = [];
|
|
4549
|
+
if (shape.type === "arrow" && length >= 1) {
|
|
4550
|
+
const headLength = Math.min(14, 4 + length / 4);
|
|
4551
|
+
const last = points.length - 1;
|
|
4552
|
+
heads.push(arrowHeadPoints(points[last], segmentAngleAt(points, last, false), headLength));
|
|
4553
|
+
if (shape.bidirectional) {
|
|
4554
|
+
heads.push(arrowHeadPoints(points[0], segmentAngleAt(points, 0, true), headLength));
|
|
4555
|
+
}
|
|
4556
|
+
}
|
|
4557
|
+
return /* @__PURE__ */ jsxs5("g", { fill: shape.stroke, stroke: "none", children: [
|
|
4558
|
+
/* @__PURE__ */ jsx5("path", { d: line.ring }),
|
|
4559
|
+
heads.map((pts, i) => /* @__PURE__ */ jsx5(
|
|
4560
|
+
"path",
|
|
4561
|
+
{
|
|
4562
|
+
d: inkStroke(pts, { closed: false, seed: seed + 1 + i, width: width * 1.15, amplitude: 0.8 }).ring
|
|
4563
|
+
},
|
|
4564
|
+
i
|
|
4565
|
+
))
|
|
4566
|
+
] });
|
|
4567
|
+
}
|
|
4568
|
+
|
|
4569
|
+
// src/drawing/canvas/ShapeView.tsx
|
|
4570
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
4571
|
+
import { createElement } from "react";
|
|
4572
|
+
var CONNECTOR_FONT_SIZE = 12;
|
|
4573
|
+
var CONNECTOR_LABEL_MAX_WIDTH = 160;
|
|
4574
|
+
function slotLayout(shape) {
|
|
4575
|
+
const def = boxDefinition(shape);
|
|
4576
|
+
return {
|
|
4577
|
+
area: def ? def.textArea(shape) : bbox(shape),
|
|
4578
|
+
slots: def ? def.textSlots : ["label", "text", "footer"]
|
|
4579
|
+
};
|
|
4580
|
+
}
|
|
4581
|
+
function slotAt(shape, y) {
|
|
4582
|
+
const { area, slots } = slotLayout(shape);
|
|
4583
|
+
const rel = (y - area.y) / Math.max(area.h, 1);
|
|
4584
|
+
if (rel < 0.3 && slots.includes("label")) return "label";
|
|
4585
|
+
if (rel > 0.7 && slots.includes("footer")) return "footer";
|
|
4586
|
+
return slots.includes("text") ? "text" : slots[0];
|
|
4587
|
+
}
|
|
4588
|
+
var textStyle = { userSelect: "none" };
|
|
4589
|
+
function luminance(color) {
|
|
4590
|
+
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color);
|
|
4591
|
+
if (!m) return 1;
|
|
4592
|
+
const hex = m[1].length === 3 ? m[1].replace(/./g, (c2) => c2 + c2) : m[1];
|
|
4593
|
+
const [r, g, b] = [0, 2, 4].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);
|
|
4594
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
4595
|
+
}
|
|
4596
|
+
function textColorFor(shape) {
|
|
4597
|
+
if (shape.stroke === "transparent" || shape.stroke === "none") return "#1e1e1e";
|
|
4598
|
+
if (luminance(shape.fill) < 0.35) return "#ffffff";
|
|
4599
|
+
return shape.stroke;
|
|
4600
|
+
}
|
|
4601
|
+
var hintStyle = { userSelect: "none", pointerEvents: "none" };
|
|
4602
|
+
function BoxTexts({
|
|
4603
|
+
shape,
|
|
3911
4604
|
hideField,
|
|
3912
4605
|
showHints
|
|
3913
4606
|
}) {
|
|
@@ -3925,7 +4618,7 @@ function BoxTexts({
|
|
|
3925
4618
|
fill: textColorFor(shape),
|
|
3926
4619
|
textAnchor: "middle"
|
|
3927
4620
|
};
|
|
3928
|
-
return /* @__PURE__ */
|
|
4621
|
+
return /* @__PURE__ */ jsxs6("g", { children: [
|
|
3929
4622
|
slots.includes("label") && hideField !== "label" && (shape.label ? labelLines.map((line, i) => /* @__PURE__ */ createElement(
|
|
3930
4623
|
"text",
|
|
3931
4624
|
{
|
|
@@ -3940,7 +4633,7 @@ function BoxTexts({
|
|
|
3940
4633
|
style: textStyle
|
|
3941
4634
|
},
|
|
3942
4635
|
line
|
|
3943
|
-
)) : hints && /* @__PURE__ */
|
|
4636
|
+
)) : hints && /* @__PURE__ */ jsx6(
|
|
3944
4637
|
"text",
|
|
3945
4638
|
{
|
|
3946
4639
|
...common,
|
|
@@ -3963,7 +4656,7 @@ function BoxTexts({
|
|
|
3963
4656
|
style: textStyle
|
|
3964
4657
|
},
|
|
3965
4658
|
line
|
|
3966
|
-
)) : hints && /* @__PURE__ */
|
|
4659
|
+
)) : hints && /* @__PURE__ */ jsx6(
|
|
3967
4660
|
"text",
|
|
3968
4661
|
{
|
|
3969
4662
|
...common,
|
|
@@ -3987,7 +4680,7 @@ function BoxTexts({
|
|
|
3987
4680
|
style: textStyle
|
|
3988
4681
|
},
|
|
3989
4682
|
line
|
|
3990
|
-
)) : hints && /* @__PURE__ */
|
|
4683
|
+
)) : hints && /* @__PURE__ */ jsx6(
|
|
3991
4684
|
"text",
|
|
3992
4685
|
{
|
|
3993
4686
|
...common,
|
|
@@ -4011,8 +4704,8 @@ function ConnectorLabel({
|
|
|
4011
4704
|
const { x: midX, y: midY } = connectorMidpoint(points);
|
|
4012
4705
|
const lineH = CONNECTOR_FONT_SIZE * LINE_HEIGHT;
|
|
4013
4706
|
const startY = midY - (lines.length - 1) * lineH / 2 + CONNECTOR_FONT_SIZE * 0.35;
|
|
4014
|
-
return /* @__PURE__ */
|
|
4015
|
-
/* @__PURE__ */
|
|
4707
|
+
return /* @__PURE__ */ jsxs6("g", { children: [
|
|
4708
|
+
/* @__PURE__ */ jsx6(
|
|
4016
4709
|
"rect",
|
|
4017
4710
|
{
|
|
4018
4711
|
x: midX - size.w / 2 - 5,
|
|
@@ -4024,7 +4717,7 @@ function ConnectorLabel({
|
|
|
4024
4717
|
opacity: 0.94
|
|
4025
4718
|
}
|
|
4026
4719
|
),
|
|
4027
|
-
lines.map((line, i) => /* @__PURE__ */
|
|
4720
|
+
lines.map((line, i) => /* @__PURE__ */ jsx6(
|
|
4028
4721
|
"text",
|
|
4029
4722
|
{
|
|
4030
4723
|
x: midX,
|
|
@@ -4043,7 +4736,8 @@ function ShapeView({
|
|
|
4043
4736
|
shape,
|
|
4044
4737
|
points,
|
|
4045
4738
|
hideField,
|
|
4046
|
-
showHints
|
|
4739
|
+
showHints,
|
|
4740
|
+
ink = false
|
|
4047
4741
|
}) {
|
|
4048
4742
|
const stroke = {
|
|
4049
4743
|
stroke: shape.stroke,
|
|
@@ -4052,9 +4746,9 @@ function ShapeView({
|
|
|
4052
4746
|
strokeLinejoin: "round"
|
|
4053
4747
|
};
|
|
4054
4748
|
if (isBoxType(shape.type)) {
|
|
4055
|
-
return /* @__PURE__ */
|
|
4056
|
-
/* @__PURE__ */
|
|
4057
|
-
/* @__PURE__ */
|
|
4749
|
+
return /* @__PURE__ */ jsxs6("g", { children: [
|
|
4750
|
+
ink ? /* @__PURE__ */ jsx6(InkBoxGeometry, { shape }) : /* @__PURE__ */ jsx6(BoxGeometry, { shape, stroke }),
|
|
4751
|
+
/* @__PURE__ */ jsx6(BoxTexts, { shape, hideField, showHints })
|
|
4058
4752
|
] });
|
|
4059
4753
|
}
|
|
4060
4754
|
if (isConnectorType(shape.type)) {
|
|
@@ -4062,13 +4756,15 @@ function ShapeView({
|
|
|
4062
4756
|
{ x: shape.x, y: shape.y },
|
|
4063
4757
|
{ x: shape.x + shape.w, y: shape.y + shape.h }
|
|
4064
4758
|
];
|
|
4065
|
-
return /* @__PURE__ */
|
|
4066
|
-
/* @__PURE__ */
|
|
4067
|
-
|
|
4068
|
-
|
|
4759
|
+
return /* @__PURE__ */ jsxs6("g", { children: [
|
|
4760
|
+
ink ? /* @__PURE__ */ jsx6(InkConnector, { shape, points: pts }) : /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
4761
|
+
/* @__PURE__ */ jsx6("path", { ...stroke, d: polylinePath(pts), fill: "none" }),
|
|
4762
|
+
arrowHeads(shape, pts).map((d, i) => /* @__PURE__ */ jsx6("path", { ...stroke, d, fill: "none" }, i))
|
|
4763
|
+
] }),
|
|
4764
|
+
shape.text && hideField !== "text" && /* @__PURE__ */ jsx6(ConnectorLabel, { shape, points: pts })
|
|
4069
4765
|
] });
|
|
4070
4766
|
}
|
|
4071
|
-
return /* @__PURE__ */
|
|
4767
|
+
return /* @__PURE__ */ jsx6(
|
|
4072
4768
|
"text",
|
|
4073
4769
|
{
|
|
4074
4770
|
x: shape.x,
|
|
@@ -4076,7 +4772,7 @@ function ShapeView({
|
|
|
4076
4772
|
fill: shape.stroke,
|
|
4077
4773
|
fontSize: FONT_SIZE,
|
|
4078
4774
|
style: { userSelect: "none", whiteSpace: "pre" },
|
|
4079
|
-
children: (shape.text ?? "").split("\n").map((line, i) => /* @__PURE__ */
|
|
4775
|
+
children: (shape.text ?? "").split("\n").map((line, i) => /* @__PURE__ */ jsx6("tspan", { x: shape.x, dy: i === 0 ? 0 : FONT_SIZE * LINE_HEIGHT, children: line }, i))
|
|
4080
4776
|
}
|
|
4081
4777
|
);
|
|
4082
4778
|
}
|
|
@@ -4085,10 +4781,10 @@ function HitArea({
|
|
|
4085
4781
|
points
|
|
4086
4782
|
}) {
|
|
4087
4783
|
if (isConnectorType(shape.type) && points) {
|
|
4088
|
-
return /* @__PURE__ */
|
|
4784
|
+
return /* @__PURE__ */ jsx6("path", { d: polylinePath(points), fill: "none", stroke: "transparent", strokeWidth: 16 });
|
|
4089
4785
|
}
|
|
4090
4786
|
const b = bbox(shape);
|
|
4091
|
-
return /* @__PURE__ */
|
|
4787
|
+
return /* @__PURE__ */ jsx6(
|
|
4092
4788
|
"rect",
|
|
4093
4789
|
{
|
|
4094
4790
|
x: b.x - 2,
|
|
@@ -4103,11 +4799,11 @@ function HitArea({
|
|
|
4103
4799
|
|
|
4104
4800
|
// src/drawing/canvas/TextEditOverlay.tsx
|
|
4105
4801
|
import {
|
|
4106
|
-
useEffect as
|
|
4802
|
+
useEffect as useEffect6,
|
|
4107
4803
|
useRef as useRef2,
|
|
4108
4804
|
useState
|
|
4109
4805
|
} from "react";
|
|
4110
|
-
import { jsx as
|
|
4806
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
4111
4807
|
function TextEditOverlay({
|
|
4112
4808
|
shape,
|
|
4113
4809
|
field,
|
|
@@ -4119,7 +4815,7 @@ function TextEditOverlay({
|
|
|
4119
4815
|
const ref = useRef2(null);
|
|
4120
4816
|
const valueRef = useRef2(value);
|
|
4121
4817
|
valueRef.current = value;
|
|
4122
|
-
|
|
4818
|
+
useEffect6(() => {
|
|
4123
4819
|
const el = ref.current;
|
|
4124
4820
|
if (!el) return;
|
|
4125
4821
|
el.focus();
|
|
@@ -4210,7 +4906,7 @@ function TextEditOverlay({
|
|
|
4210
4906
|
});
|
|
4211
4907
|
}
|
|
4212
4908
|
const placeholder = field === "label" ? "Label" : field === "footer" ? "Footer" : "Text";
|
|
4213
|
-
return /* @__PURE__ */
|
|
4909
|
+
return /* @__PURE__ */ jsx7(
|
|
4214
4910
|
"textarea",
|
|
4215
4911
|
{
|
|
4216
4912
|
ref,
|
|
@@ -4227,19 +4923,19 @@ function TextEditOverlay({
|
|
|
4227
4923
|
}
|
|
4228
4924
|
|
|
4229
4925
|
// src/drawing/canvas/Toolbar.tsx
|
|
4230
|
-
import { useEffect as
|
|
4926
|
+
import { useEffect as useEffect7, useRef as useRef3, useState as useState2 } from "react";
|
|
4231
4927
|
|
|
4232
4928
|
// src/components/blockWidthOptions.tsx
|
|
4233
|
-
import { Fragment, jsx as
|
|
4929
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
4234
4930
|
var LAYOUT_OPTIONS = [
|
|
4235
4931
|
{
|
|
4236
4932
|
preset: "compact",
|
|
4237
4933
|
label: "Compact (shrink to content, tight rows)",
|
|
4238
4934
|
width: "content",
|
|
4239
4935
|
density: "compact",
|
|
4240
|
-
icon: /* @__PURE__ */
|
|
4241
|
-
/* @__PURE__ */
|
|
4242
|
-
/* @__PURE__ */
|
|
4936
|
+
icon: /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
4937
|
+
/* @__PURE__ */ jsx8("path", { d: "M3 4v12M17 4v12" }),
|
|
4938
|
+
/* @__PURE__ */ jsx8("path", { d: "M5.5 10h3M11.5 10h3M6.5 7.5L9 10l-2.5 2.5M13.5 7.5L11 10l2.5 2.5" })
|
|
4243
4939
|
] })
|
|
4244
4940
|
},
|
|
4245
4941
|
{
|
|
@@ -4247,9 +4943,9 @@ var LAYOUT_OPTIONS = [
|
|
|
4247
4943
|
label: "Comfortable (text width)",
|
|
4248
4944
|
width: "text",
|
|
4249
4945
|
density: "comfortable",
|
|
4250
|
-
icon: /* @__PURE__ */
|
|
4251
|
-
/* @__PURE__ */
|
|
4252
|
-
/* @__PURE__ */
|
|
4946
|
+
icon: /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
4947
|
+
/* @__PURE__ */ jsx8("path", { d: "M3 4v12M17 4v12" }),
|
|
4948
|
+
/* @__PURE__ */ jsx8("path", { d: "M6.5 7h7M6.5 10h7M6.5 13h4.5" })
|
|
4253
4949
|
] })
|
|
4254
4950
|
},
|
|
4255
4951
|
{
|
|
@@ -4257,9 +4953,9 @@ var LAYOUT_OPTIONS = [
|
|
|
4257
4953
|
label: "Full width",
|
|
4258
4954
|
width: "full",
|
|
4259
4955
|
density: "comfortable",
|
|
4260
|
-
icon: /* @__PURE__ */
|
|
4261
|
-
/* @__PURE__ */
|
|
4262
|
-
/* @__PURE__ */
|
|
4956
|
+
icon: /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
4957
|
+
/* @__PURE__ */ jsx8("path", { d: "M3 4v12M17 4v12" }),
|
|
4958
|
+
/* @__PURE__ */ jsx8("path", { d: "M6 10h8M8.5 7.5L6 10l2.5 2.5M11.5 7.5L14 10l-2.5 2.5" })
|
|
4263
4959
|
] })
|
|
4264
4960
|
}
|
|
4265
4961
|
];
|
|
@@ -4268,7 +4964,7 @@ function layoutPreset(width) {
|
|
|
4268
4964
|
}
|
|
4269
4965
|
|
|
4270
4966
|
// src/drawing/canvas/Toolbar.tsx
|
|
4271
|
-
import { Fragment as
|
|
4967
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
4272
4968
|
var PRIMARY_TOOLS = [
|
|
4273
4969
|
{ tool: "select", label: "Select" },
|
|
4274
4970
|
{ tool: "rect", label: "Rectangle" },
|
|
@@ -4287,7 +4983,7 @@ function ToolButton({
|
|
|
4287
4983
|
className,
|
|
4288
4984
|
pressed
|
|
4289
4985
|
}) {
|
|
4290
|
-
return /* @__PURE__ */
|
|
4986
|
+
return /* @__PURE__ */ jsx9(
|
|
4291
4987
|
"button",
|
|
4292
4988
|
{
|
|
4293
4989
|
type: "button",
|
|
@@ -4296,7 +4992,7 @@ function ToolButton({
|
|
|
4296
4992
|
"aria-pressed": pressed ?? active,
|
|
4297
4993
|
className: `zui-drawing-tool ${active ? "is-active" : ""} ${className ?? ""}`,
|
|
4298
4994
|
onClick,
|
|
4299
|
-
children: /* @__PURE__ */
|
|
4995
|
+
children: /* @__PURE__ */ jsx9(Icon, { children })
|
|
4300
4996
|
}
|
|
4301
4997
|
);
|
|
4302
4998
|
}
|
|
@@ -4312,7 +5008,7 @@ function DrawingToolbar({
|
|
|
4312
5008
|
const [lastMore, setLastMore] = useState2("note");
|
|
4313
5009
|
const [copied, setCopied] = useState2(false);
|
|
4314
5010
|
const moreRef = useRef3(null);
|
|
4315
|
-
|
|
5011
|
+
useEffect7(() => {
|
|
4316
5012
|
if (!moreOpen) return;
|
|
4317
5013
|
const close = (e) => {
|
|
4318
5014
|
if (!moreRef.current?.contains(e.target)) setMoreOpen(false);
|
|
@@ -4329,11 +5025,11 @@ function DrawingToolbar({
|
|
|
4329
5025
|
}, [moreOpen]);
|
|
4330
5026
|
const moreActive = MORE_SHAPES.includes(tool);
|
|
4331
5027
|
const moreIcon = moreActive ? SHAPE_ICONS[tool] : SHAPE_ICONS[lastMore];
|
|
4332
|
-
return /* @__PURE__ */
|
|
4333
|
-
/* @__PURE__ */
|
|
4334
|
-
PRIMARY_TOOLS.map(({ tool: t, label }) => /* @__PURE__ */
|
|
4335
|
-
/* @__PURE__ */
|
|
4336
|
-
/* @__PURE__ */
|
|
5028
|
+
return /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
5029
|
+
/* @__PURE__ */ jsxs8("div", { className: "zui-drawing-toolbar-group", role: "toolbar", "aria-label": "Drawing tools", children: [
|
|
5030
|
+
PRIMARY_TOOLS.map(({ tool: t, label }) => /* @__PURE__ */ jsx9(ToolButton, { label, active: tool === t, onClick: () => onToolChange(t), children: SHAPE_ICONS[t] }, t)),
|
|
5031
|
+
/* @__PURE__ */ jsxs8("div", { className: "zui-drawing-more", ref: moreRef, children: [
|
|
5032
|
+
/* @__PURE__ */ jsxs8(
|
|
4337
5033
|
"button",
|
|
4338
5034
|
{
|
|
4339
5035
|
type: "button",
|
|
@@ -4344,12 +5040,12 @@ function DrawingToolbar({
|
|
|
4344
5040
|
className: `zui-drawing-tool zui-drawing-tool-more ${moreActive ? "is-active" : ""}`,
|
|
4345
5041
|
onClick: () => setMoreOpen((open) => !open),
|
|
4346
5042
|
children: [
|
|
4347
|
-
/* @__PURE__ */
|
|
4348
|
-
/* @__PURE__ */
|
|
5043
|
+
/* @__PURE__ */ jsx9(Icon, { children: moreIcon }),
|
|
5044
|
+
/* @__PURE__ */ jsx9("span", { className: "zui-drawing-caret", "aria-hidden": "true" })
|
|
4349
5045
|
]
|
|
4350
5046
|
}
|
|
4351
5047
|
),
|
|
4352
|
-
moreOpen && /* @__PURE__ */
|
|
5048
|
+
moreOpen && /* @__PURE__ */ jsx9("div", { className: "zui-drawing-popover", role: "menu", children: MORE_SHAPES.map((type) => /* @__PURE__ */ jsxs8(
|
|
4353
5049
|
"button",
|
|
4354
5050
|
{
|
|
4355
5051
|
type: "button",
|
|
@@ -4362,8 +5058,8 @@ function DrawingToolbar({
|
|
|
4362
5058
|
setMoreOpen(false);
|
|
4363
5059
|
},
|
|
4364
5060
|
children: [
|
|
4365
|
-
/* @__PURE__ */
|
|
4366
|
-
/* @__PURE__ */
|
|
5061
|
+
/* @__PURE__ */ jsx9(Icon, { size: 18, children: SHAPE_ICONS[type] }),
|
|
5062
|
+
/* @__PURE__ */ jsx9("span", { children: BOX_DEFINITIONS[type].label })
|
|
4367
5063
|
]
|
|
4368
5064
|
},
|
|
4369
5065
|
type
|
|
@@ -4371,8 +5067,8 @@ function DrawingToolbar({
|
|
|
4371
5067
|
] })
|
|
4372
5068
|
] }),
|
|
4373
5069
|
properties,
|
|
4374
|
-
/* @__PURE__ */
|
|
4375
|
-
/* @__PURE__ */
|
|
5070
|
+
/* @__PURE__ */ jsxs8("div", { className: "zui-drawing-toolbar-group zui-drawing-toolbar-group-end", children: [
|
|
5071
|
+
/* @__PURE__ */ jsx9(
|
|
4376
5072
|
ToolButton,
|
|
4377
5073
|
{
|
|
4378
5074
|
label: copied ? "Copied Mermaid to clipboard" : "Copy as Mermaid",
|
|
@@ -4387,8 +5083,8 @@ function DrawingToolbar({
|
|
|
4387
5083
|
children: copied ? UI_ICONS.check : UI_ICONS.mermaid
|
|
4388
5084
|
}
|
|
4389
5085
|
),
|
|
4390
|
-
/* @__PURE__ */
|
|
4391
|
-
LAYOUT_OPTIONS.map(({ preset, label, icon, width: presetWidth }) => /* @__PURE__ */
|
|
5086
|
+
/* @__PURE__ */ jsx9("span", { className: "zui-drawing-toolbar-divider" }),
|
|
5087
|
+
LAYOUT_OPTIONS.map(({ preset, label, icon, width: presetWidth }) => /* @__PURE__ */ jsx9(
|
|
4392
5088
|
ToolButton,
|
|
4393
5089
|
{
|
|
4394
5090
|
label,
|
|
@@ -4403,7 +5099,7 @@ function DrawingToolbar({
|
|
|
4403
5099
|
}
|
|
4404
5100
|
|
|
4405
5101
|
// src/drawing/canvas/DrawingCanvas.tsx
|
|
4406
|
-
import { jsx as
|
|
5102
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
4407
5103
|
var MIN_HEIGHT = 120;
|
|
4408
5104
|
var MAX_HEIGHT = 1200;
|
|
4409
5105
|
var WIDTH_CLASS = {
|
|
@@ -4434,11 +5130,12 @@ function computePaths(shapes) {
|
|
|
4434
5130
|
return paths;
|
|
4435
5131
|
}
|
|
4436
5132
|
function DrawingCanvas({ nodeKey, data }) {
|
|
4437
|
-
const [editor] =
|
|
5133
|
+
const [editor] = useLexicalComposerContext6();
|
|
4438
5134
|
const isEditable = useLexicalEditable();
|
|
4439
5135
|
const [shapes, setShapes] = useState3(data.shapes);
|
|
4440
5136
|
const [canvasHeight, setCanvasHeight] = useState3(data.canvasHeight);
|
|
4441
5137
|
const [width, setWidth] = useState3(data.width ?? "full");
|
|
5138
|
+
const ink = useContext2(EditorContext)?.drawingStyle === "ink";
|
|
4442
5139
|
const [tool, setTool] = useState3("select");
|
|
4443
5140
|
const [selectedIds, setSelectedIds] = useState3(EMPTY_SET);
|
|
4444
5141
|
const [editingText, setEditingText] = useState3(null);
|
|
@@ -4465,7 +5162,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4465
5162
|
const paths = useMemo(() => computePaths(shapes), [shapes]);
|
|
4466
5163
|
const canvasWidth = data.canvasWidth;
|
|
4467
5164
|
const logicalWidth = canvasWidth ?? (width === "content" ? contentWidth(shapes, paths) : null);
|
|
4468
|
-
|
|
5165
|
+
useEffect8(() => {
|
|
4469
5166
|
const incoming = serializeDrawingData(data);
|
|
4470
5167
|
if (incoming !== lastCommittedRef.current) {
|
|
4471
5168
|
lastCommittedRef.current = incoming;
|
|
@@ -4476,7 +5173,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4476
5173
|
setEditingText(null);
|
|
4477
5174
|
}
|
|
4478
5175
|
}, [data]);
|
|
4479
|
-
|
|
5176
|
+
useEffect8(() => {
|
|
4480
5177
|
const svg = svgRef.current;
|
|
4481
5178
|
if (!logicalWidth || !svg || typeof ResizeObserver === "undefined") {
|
|
4482
5179
|
setScale(1);
|
|
@@ -4506,7 +5203,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4506
5203
|
if (json2 === lastCommittedRef.current) return;
|
|
4507
5204
|
lastCommittedRef.current = json2;
|
|
4508
5205
|
editor.update(() => {
|
|
4509
|
-
const node = $
|
|
5206
|
+
const node = $getNodeByKey4(nodeKey);
|
|
4510
5207
|
if ($isDrawingNode(node)) node.setData(payload);
|
|
4511
5208
|
});
|
|
4512
5209
|
},
|
|
@@ -4766,7 +5463,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4766
5463
|
}, [updateShapes]);
|
|
4767
5464
|
const editingRef = useRef4(editingText);
|
|
4768
5465
|
editingRef.current = editingText;
|
|
4769
|
-
|
|
5466
|
+
useEffect8(() => {
|
|
4770
5467
|
const root = rootRef.current;
|
|
4771
5468
|
if (!root || !isEditable) return;
|
|
4772
5469
|
const onKeyDown = (e) => {
|
|
@@ -4899,11 +5596,11 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4899
5596
|
const propStroke = single?.stroke ?? selection[0]?.stroke ?? stroke;
|
|
4900
5597
|
const propFill = single?.fill ?? selection[0]?.fill ?? fill;
|
|
4901
5598
|
const canvasCursor = tool === "select" ? "default" : tool === "text" ? "text" : "crosshair";
|
|
4902
|
-
return /* @__PURE__ */
|
|
5599
|
+
return /* @__PURE__ */ jsxs9(
|
|
4903
5600
|
"div",
|
|
4904
5601
|
{
|
|
4905
5602
|
ref: rootRef,
|
|
4906
|
-
className: `zui-drawing-canvas ${WIDTH_CLASS[width]} ${isEditable ? "is-editable" : ""}`,
|
|
5603
|
+
className: `zui-drawing-canvas ${WIDTH_CLASS[width]} ${isEditable ? "is-editable" : ""} ${ink ? "is-ink" : ""}`,
|
|
4907
5604
|
tabIndex: isEditable ? 0 : void 0,
|
|
4908
5605
|
onFocus: () => editor.dispatchCommand(DRAWING_FOCUS_COMMAND, nodeKey),
|
|
4909
5606
|
onBlur: (e) => {
|
|
@@ -4911,7 +5608,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4911
5608
|
editor.dispatchCommand(DRAWING_FOCUS_COMMAND, null);
|
|
4912
5609
|
},
|
|
4913
5610
|
children: [
|
|
4914
|
-
isEditable && /* @__PURE__ */
|
|
5611
|
+
isEditable && /* @__PURE__ */ jsx10("div", { className: "zui-drawing-toolbar", onPointerDown: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx10(
|
|
4915
5612
|
DrawingToolbar,
|
|
4916
5613
|
{
|
|
4917
5614
|
tool,
|
|
@@ -4925,7 +5622,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4925
5622
|
properties: (
|
|
4926
5623
|
// Inline in the same row (so the stage never shifts); shown
|
|
4927
5624
|
// only while the canvas has focus (see .zui-drawing-props-host)
|
|
4928
|
-
/* @__PURE__ */
|
|
5625
|
+
/* @__PURE__ */ jsx10("div", { className: "zui-drawing-props-host", children: /* @__PURE__ */ jsx10(
|
|
4929
5626
|
PropertyBar,
|
|
4930
5627
|
{
|
|
4931
5628
|
selection,
|
|
@@ -4940,8 +5637,8 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4940
5637
|
)
|
|
4941
5638
|
}
|
|
4942
5639
|
) }),
|
|
4943
|
-
/* @__PURE__ */
|
|
4944
|
-
/* @__PURE__ */
|
|
5640
|
+
/* @__PURE__ */ jsxs9("div", { className: "zui-drawing-stage", children: [
|
|
5641
|
+
/* @__PURE__ */ jsxs9(
|
|
4945
5642
|
"svg",
|
|
4946
5643
|
{
|
|
4947
5644
|
ref: svgRef,
|
|
@@ -4972,7 +5669,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4972
5669
|
}
|
|
4973
5670
|
},
|
|
4974
5671
|
children: [
|
|
4975
|
-
shapes.map((shape) => /* @__PURE__ */
|
|
5672
|
+
shapes.map((shape) => /* @__PURE__ */ jsxs9(
|
|
4976
5673
|
"g",
|
|
4977
5674
|
{
|
|
4978
5675
|
"data-shape-id": shape.id,
|
|
@@ -4980,11 +5677,12 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4980
5677
|
style: { cursor: isEditable && tool === "select" ? "move" : void 0 },
|
|
4981
5678
|
onPointerDown: (e) => handleShapePointerDown(e, shape),
|
|
4982
5679
|
children: [
|
|
4983
|
-
/* @__PURE__ */
|
|
4984
|
-
shape.id === editingText?.id && shape.type === "text" ? null : /* @__PURE__ */
|
|
5680
|
+
/* @__PURE__ */ jsx10(HitArea, { shape, points: paths.get(shape.id) }),
|
|
5681
|
+
shape.id === editingText?.id && shape.type === "text" ? null : /* @__PURE__ */ jsx10(
|
|
4985
5682
|
ShapeView,
|
|
4986
5683
|
{
|
|
4987
5684
|
shape,
|
|
5685
|
+
ink,
|
|
4988
5686
|
points: paths.get(shape.id),
|
|
4989
5687
|
hideField: shape.id === editingText?.id ? editingText.field : null,
|
|
4990
5688
|
showHints: isEditable && tool === "select" && single?.id === shape.id && shape.id !== editingText?.id
|
|
@@ -4994,7 +5692,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
4994
5692
|
},
|
|
4995
5693
|
shape.id
|
|
4996
5694
|
)),
|
|
4997
|
-
hoverBox && /* @__PURE__ */
|
|
5695
|
+
hoverBox && /* @__PURE__ */ jsx10(
|
|
4998
5696
|
"polygon",
|
|
4999
5697
|
{
|
|
5000
5698
|
className: "zui-drawing-selection zui-drawing-bind-target",
|
|
@@ -5007,7 +5705,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
5007
5705
|
pointerEvents: "none"
|
|
5008
5706
|
}
|
|
5009
5707
|
),
|
|
5010
|
-
single && isEditable && !editingText && /* @__PURE__ */
|
|
5708
|
+
single && isEditable && !editingText && /* @__PURE__ */ jsx10(
|
|
5011
5709
|
SelectionOverlay,
|
|
5012
5710
|
{
|
|
5013
5711
|
shape: single,
|
|
@@ -5017,13 +5715,13 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
5017
5715
|
onWaypointRemove: removeWaypoint
|
|
5018
5716
|
}
|
|
5019
5717
|
),
|
|
5020
|
-
selection.length > 1 && isEditable && /* @__PURE__ */
|
|
5021
|
-
marquee && /* @__PURE__ */
|
|
5718
|
+
selection.length > 1 && isEditable && /* @__PURE__ */ jsx10(GroupSelectionOverlay, { shapes: selection, paths }),
|
|
5719
|
+
marquee && /* @__PURE__ */ jsx10(MarqueeOverlay, { rect: marqueeRect(marquee.origin, marquee.current) })
|
|
5022
5720
|
]
|
|
5023
5721
|
}
|
|
5024
5722
|
),
|
|
5025
|
-
isEditable && shapes.length === 0 && /* @__PURE__ */
|
|
5026
|
-
editingShape && editingText && /* @__PURE__ */
|
|
5723
|
+
isEditable && shapes.length === 0 && /* @__PURE__ */ jsx10("div", { className: "zui-drawing-empty", "aria-hidden": "true", children: "Pick a shape above, then click or drag on the canvas" }),
|
|
5724
|
+
editingShape && editingText && /* @__PURE__ */ jsx10(
|
|
5027
5725
|
"div",
|
|
5028
5726
|
{
|
|
5029
5727
|
className: "zui-drawing-overlay",
|
|
@@ -5032,7 +5730,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
5032
5730
|
width: logicalWidth ?? void 0,
|
|
5033
5731
|
height: logicalWidth ? canvasHeight : void 0
|
|
5034
5732
|
},
|
|
5035
|
-
children: /* @__PURE__ */
|
|
5733
|
+
children: /* @__PURE__ */ jsx10(
|
|
5036
5734
|
TextEditOverlay,
|
|
5037
5735
|
{
|
|
5038
5736
|
shape: editingShape,
|
|
@@ -5044,7 +5742,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
5044
5742
|
)
|
|
5045
5743
|
}
|
|
5046
5744
|
),
|
|
5047
|
-
isEditable && /* @__PURE__ */
|
|
5745
|
+
isEditable && /* @__PURE__ */ jsx10(
|
|
5048
5746
|
HeightHandle,
|
|
5049
5747
|
{
|
|
5050
5748
|
height: canvasHeight,
|
|
@@ -5068,7 +5766,7 @@ function HeightHandle({
|
|
|
5068
5766
|
const latestRef = useRef4(height);
|
|
5069
5767
|
latestRef.current = height;
|
|
5070
5768
|
const clamp = (h) => Math.round(Math.min(MAX_HEIGHT, Math.max(MIN_HEIGHT, h)));
|
|
5071
|
-
return /* @__PURE__ */
|
|
5769
|
+
return /* @__PURE__ */ jsx10(
|
|
5072
5770
|
"div",
|
|
5073
5771
|
{
|
|
5074
5772
|
className: "zui-drawing-resize",
|
|
@@ -5091,13 +5789,13 @@ function HeightHandle({
|
|
|
5091
5789
|
dragRef.current = null;
|
|
5092
5790
|
onCommit(latestRef.current);
|
|
5093
5791
|
},
|
|
5094
|
-
children: /* @__PURE__ */
|
|
5792
|
+
children: /* @__PURE__ */ jsx10(Icon, { size: 14, children: UI_ICONS.grip })
|
|
5095
5793
|
}
|
|
5096
5794
|
);
|
|
5097
5795
|
}
|
|
5098
5796
|
|
|
5099
5797
|
// src/nodes/DrawingNode.tsx
|
|
5100
|
-
import { jsx as
|
|
5798
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
5101
5799
|
var DrawingNode = class _DrawingNode extends DecoratorNode {
|
|
5102
5800
|
static getType() {
|
|
5103
5801
|
return "drawing";
|
|
@@ -5161,7 +5859,7 @@ var DrawingNode = class _DrawingNode extends DecoratorNode {
|
|
|
5161
5859
|
return false;
|
|
5162
5860
|
}
|
|
5163
5861
|
decorate(_editor, _config) {
|
|
5164
|
-
return /* @__PURE__ */
|
|
5862
|
+
return /* @__PURE__ */ jsx11(DrawingCanvas, { nodeKey: this.getKey(), data: this.getData() });
|
|
5165
5863
|
}
|
|
5166
5864
|
};
|
|
5167
5865
|
function $createDrawingNode(data = serializeDrawingData(EMPTY_DRAWING)) {
|
|
@@ -5212,161 +5910,17 @@ import {
|
|
|
5212
5910
|
TRANSFORMERS
|
|
5213
5911
|
} from "@lexical/markdown";
|
|
5214
5912
|
import {
|
|
5215
|
-
$createTableCellNode,
|
|
5913
|
+
$createTableCellNode as $createTableCellNode2,
|
|
5216
5914
|
$createTableNode,
|
|
5217
|
-
$createTableRowNode,
|
|
5218
|
-
$isTableCellNode,
|
|
5219
|
-
$isTableNode as $
|
|
5220
|
-
$isTableRowNode,
|
|
5221
|
-
TableCellHeaderStates,
|
|
5915
|
+
$createTableRowNode as $createTableRowNode2,
|
|
5916
|
+
$isTableCellNode as $isTableCellNode2,
|
|
5917
|
+
$isTableNode as $isTableNode3,
|
|
5918
|
+
$isTableRowNode as $isTableRowNode3,
|
|
5919
|
+
TableCellHeaderStates as TableCellHeaderStates2,
|
|
5222
5920
|
TableCellNode,
|
|
5223
5921
|
TableNode,
|
|
5224
5922
|
TableRowNode
|
|
5225
5923
|
} from "@lexical/table";
|
|
5226
|
-
|
|
5227
|
-
// src/transformers/tableSettings.ts
|
|
5228
|
-
import {
|
|
5229
|
-
$getNodeByKey as $getNodeByKey3,
|
|
5230
|
-
$getSelection as $getSelection2,
|
|
5231
|
-
$isRangeSelection as $isRangeSelection2
|
|
5232
|
-
} from "lexical";
|
|
5233
|
-
import { $findMatchingParent } from "@lexical/utils";
|
|
5234
|
-
import { $isTableNode, $isTableSelection } from "@lexical/table";
|
|
5235
|
-
var DEFAULT_TABLE_SETTINGS = {
|
|
5236
|
-
width: "full",
|
|
5237
|
-
density: "comfortable"
|
|
5238
|
-
};
|
|
5239
|
-
var BLOCK_BLEED_PROPERTY = "--zui-text-editor-block-bleed";
|
|
5240
|
-
var OPTION_DECLARATIONS = {
|
|
5241
|
-
width: {
|
|
5242
|
-
full: {},
|
|
5243
|
-
content: { width: "auto", "table-layout": "auto", [BLOCK_BLEED_PROPERTY]: "0px" },
|
|
5244
|
-
text: { [BLOCK_BLEED_PROPERTY]: "0px" }
|
|
5245
|
-
},
|
|
5246
|
-
density: {
|
|
5247
|
-
comfortable: {},
|
|
5248
|
-
compact: {
|
|
5249
|
-
"--zui-table-cell-padding": "0.25rem 0.5rem",
|
|
5250
|
-
"--zui-table-font-size": "0.8125rem"
|
|
5251
|
-
},
|
|
5252
|
-
spacious: {
|
|
5253
|
-
"--zui-table-cell-padding": "0.875rem 1rem",
|
|
5254
|
-
"--zui-table-font-size": "0.9375rem"
|
|
5255
|
-
}
|
|
5256
|
-
}
|
|
5257
|
-
};
|
|
5258
|
-
var SETTING_KEYS = Object.keys(OPTION_DECLARATIONS);
|
|
5259
|
-
var EXPLICIT_WIDTH_PROPERTY = "--zui-table-width";
|
|
5260
|
-
function parseStyle(style) {
|
|
5261
|
-
const declarations = /* @__PURE__ */ new Map();
|
|
5262
|
-
for (const part of style.split(";")) {
|
|
5263
|
-
const index = part.indexOf(":");
|
|
5264
|
-
if (index === -1) continue;
|
|
5265
|
-
const key = part.slice(0, index).trim();
|
|
5266
|
-
const value = part.slice(index + 1).trim();
|
|
5267
|
-
if (key && value) declarations.set(key, value);
|
|
5268
|
-
}
|
|
5269
|
-
return declarations;
|
|
5270
|
-
}
|
|
5271
|
-
function serializeStyle(declarations) {
|
|
5272
|
-
return [...declarations].map(([key, value]) => `${key}: ${value}`).join("; ");
|
|
5273
|
-
}
|
|
5274
|
-
function optionsOf(setting) {
|
|
5275
|
-
return Object.entries(OPTION_DECLARATIONS[setting]);
|
|
5276
|
-
}
|
|
5277
|
-
function readSetting(declarations, setting) {
|
|
5278
|
-
for (const [option, decls] of optionsOf(setting)) {
|
|
5279
|
-
const entries = Object.entries(decls);
|
|
5280
|
-
if (entries.length === 0) continue;
|
|
5281
|
-
if (entries.every(([key, value]) => declarations.get(key) === value)) {
|
|
5282
|
-
return option;
|
|
5283
|
-
}
|
|
5284
|
-
}
|
|
5285
|
-
return DEFAULT_TABLE_SETTINGS[setting];
|
|
5286
|
-
}
|
|
5287
|
-
function writeSetting(declarations, setting, option) {
|
|
5288
|
-
for (const [, decls] of optionsOf(setting)) {
|
|
5289
|
-
for (const key of Object.keys(decls)) declarations.delete(key);
|
|
5290
|
-
}
|
|
5291
|
-
for (const [key, value] of Object.entries(OPTION_DECLARATIONS[setting][option])) {
|
|
5292
|
-
declarations.set(key, value);
|
|
5293
|
-
}
|
|
5294
|
-
}
|
|
5295
|
-
function $getTableSettings(table) {
|
|
5296
|
-
const declarations = parseStyle(table.getStyle());
|
|
5297
|
-
return {
|
|
5298
|
-
width: readSetting(declarations, "width"),
|
|
5299
|
-
density: readSetting(declarations, "density")
|
|
5300
|
-
};
|
|
5301
|
-
}
|
|
5302
|
-
function $setTableSettings(table, settings, options = {}) {
|
|
5303
|
-
const declarations = parseStyle(table.getStyle());
|
|
5304
|
-
for (const key of SETTING_KEYS) {
|
|
5305
|
-
const option = settings[key];
|
|
5306
|
-
if (option !== void 0) writeSetting(declarations, key, option);
|
|
5307
|
-
}
|
|
5308
|
-
if (settings.width !== void 0) {
|
|
5309
|
-
if (options.explicitWidth) declarations.set(EXPLICIT_WIDTH_PROPERTY, settings.width);
|
|
5310
|
-
else declarations.delete(EXPLICIT_WIDTH_PROPERTY);
|
|
5311
|
-
}
|
|
5312
|
-
table.setStyle(serializeStyle(declarations));
|
|
5313
|
-
}
|
|
5314
|
-
function $isTableWidthExplicit(table) {
|
|
5315
|
-
const declarations = parseStyle(table.getStyle());
|
|
5316
|
-
return declarations.get(EXPLICIT_WIDTH_PROPERTY) === readSetting(declarations, "width");
|
|
5317
|
-
}
|
|
5318
|
-
function $getTableWidth(table) {
|
|
5319
|
-
return $getTableSettings(table).width;
|
|
5320
|
-
}
|
|
5321
|
-
function $setTableWidth(table, width) {
|
|
5322
|
-
$setTableSettings(table, { width });
|
|
5323
|
-
}
|
|
5324
|
-
function $getTableDensity(table) {
|
|
5325
|
-
return $getTableSettings(table).density;
|
|
5326
|
-
}
|
|
5327
|
-
function $setTableDensity(table, density) {
|
|
5328
|
-
$setTableSettings(table, { density });
|
|
5329
|
-
}
|
|
5330
|
-
function $getSelectedTable() {
|
|
5331
|
-
const selection = $getSelection2();
|
|
5332
|
-
if ($isTableSelection(selection)) {
|
|
5333
|
-
const node = $getNodeByKey3(selection.tableKey);
|
|
5334
|
-
return $isTableNode(node) ? node : null;
|
|
5335
|
-
}
|
|
5336
|
-
if (!$isRangeSelection2(selection)) return null;
|
|
5337
|
-
const table = $findMatchingParent(
|
|
5338
|
-
selection.anchor.getNode(),
|
|
5339
|
-
(node) => $isTableNode(node)
|
|
5340
|
-
);
|
|
5341
|
-
return $isTableNode(table) ? table : null;
|
|
5342
|
-
}
|
|
5343
|
-
var MARKER_REG_EXP = /^<!--\s*([a-z]+\s*:\s*[a-z]+(?:\s*;\s*[a-z]+\s*:\s*[a-z]+)*)\s*;?\s*-->\s*$/;
|
|
5344
|
-
function isOption(setting, value) {
|
|
5345
|
-
return value in OPTION_DECLARATIONS[setting];
|
|
5346
|
-
}
|
|
5347
|
-
var TABLE_WIDTH_MARKER = "<!-- width: content -->";
|
|
5348
|
-
function parseTableSettingsMarker(text) {
|
|
5349
|
-
const match = MARKER_REG_EXP.exec(text);
|
|
5350
|
-
if (!match) return null;
|
|
5351
|
-
const settings = {};
|
|
5352
|
-
let recognised = false;
|
|
5353
|
-
for (const pair of match[1].split(";")) {
|
|
5354
|
-
const [key, value] = pair.split(":").map((s) => s.trim());
|
|
5355
|
-
if (key !== "width" && key !== "density") continue;
|
|
5356
|
-
recognised = true;
|
|
5357
|
-
if (key === "width" && isOption("width", value)) settings.width = value;
|
|
5358
|
-
if (key === "density" && isOption("density", value)) settings.density = value;
|
|
5359
|
-
}
|
|
5360
|
-
return recognised ? settings : null;
|
|
5361
|
-
}
|
|
5362
|
-
function formatTableSettingsMarker(settings, options = {}) {
|
|
5363
|
-
const pairs = SETTING_KEYS.filter(
|
|
5364
|
-
(key) => settings[key] !== DEFAULT_TABLE_SETTINGS[key] || key === "width" && options.explicitWidth
|
|
5365
|
-
).map((key) => `${key}: ${settings[key]}`);
|
|
5366
|
-
return pairs.length > 0 ? `<!-- ${pairs.join("; ")} -->` : null;
|
|
5367
|
-
}
|
|
5368
|
-
|
|
5369
|
-
// src/transformers/tableTransformer.ts
|
|
5370
5924
|
var TABLE_ROW_REG_EXP = /^\|(.+)\|\s?$/;
|
|
5371
5925
|
var TABLE_ROW_DIVIDER_REG_EXP = /^(\| ?:?-*:? ?)+\|\s?$/;
|
|
5372
5926
|
function $getMarkerSettings(node) {
|
|
@@ -5376,11 +5930,11 @@ function $getMarkerSettings(node) {
|
|
|
5376
5930
|
}
|
|
5377
5931
|
function getTableColumnsSize(table) {
|
|
5378
5932
|
const row = table.getFirstChild();
|
|
5379
|
-
return $
|
|
5933
|
+
return $isTableRowNode3(row) ? row.getChildrenSize() : 0;
|
|
5380
5934
|
}
|
|
5381
5935
|
function createTableCell(textContent) {
|
|
5382
5936
|
const unescaped = textContent.replace(/\\n/g, "\n");
|
|
5383
|
-
const cell = $
|
|
5937
|
+
const cell = $createTableCellNode2(TableCellHeaderStates2.NO_STATUS);
|
|
5384
5938
|
$convertFromMarkdownString2(unescaped, TRANSFORMERS, cell);
|
|
5385
5939
|
return cell;
|
|
5386
5940
|
}
|
|
@@ -5392,22 +5946,22 @@ function mapToTableCells(textContent) {
|
|
|
5392
5946
|
var TABLE = {
|
|
5393
5947
|
dependencies: [TableNode, TableRowNode, TableCellNode],
|
|
5394
5948
|
export: (node) => {
|
|
5395
|
-
if (!$
|
|
5949
|
+
if (!$isTableNode3(node)) return null;
|
|
5396
5950
|
const output = [];
|
|
5397
5951
|
const marker = formatTableSettingsMarker($getTableSettings(node), {
|
|
5398
5952
|
explicitWidth: $isTableWidthExplicit(node)
|
|
5399
5953
|
});
|
|
5400
5954
|
if (marker) output.push(marker);
|
|
5401
5955
|
for (const row of node.getChildren()) {
|
|
5402
|
-
if (!$
|
|
5956
|
+
if (!$isTableRowNode3(row)) continue;
|
|
5403
5957
|
const rowOutput = [];
|
|
5404
5958
|
let isHeaderRow = false;
|
|
5405
5959
|
for (const cell of row.getChildren()) {
|
|
5406
|
-
if (!$
|
|
5960
|
+
if (!$isTableCellNode2(cell)) continue;
|
|
5407
5961
|
rowOutput.push(
|
|
5408
5962
|
$convertToMarkdownString2(TRANSFORMERS, cell).replace(/\n/g, "\\n")
|
|
5409
5963
|
);
|
|
5410
|
-
if (cell.__headerState ===
|
|
5964
|
+
if (cell.__headerState === TableCellHeaderStates2.ROW) {
|
|
5411
5965
|
isHeaderRow = true;
|
|
5412
5966
|
}
|
|
5413
5967
|
}
|
|
@@ -5422,12 +5976,12 @@ var TABLE = {
|
|
|
5422
5976
|
replace: (parentNode, _children, match) => {
|
|
5423
5977
|
if (TABLE_ROW_DIVIDER_REG_EXP.test(match[0])) {
|
|
5424
5978
|
const table2 = parentNode.getPreviousSibling();
|
|
5425
|
-
if (!table2 || !$
|
|
5979
|
+
if (!table2 || !$isTableNode3(table2)) return;
|
|
5426
5980
|
const lastRow = table2.getLastChild();
|
|
5427
|
-
if (!lastRow || !$
|
|
5981
|
+
if (!lastRow || !$isTableRowNode3(lastRow)) return;
|
|
5428
5982
|
lastRow.getChildren().forEach((cell) => {
|
|
5429
|
-
if ($
|
|
5430
|
-
cell.setHeaderStyles(
|
|
5983
|
+
if ($isTableCellNode2(cell)) {
|
|
5984
|
+
cell.setHeaderStyles(TableCellHeaderStates2.ROW, TableCellHeaderStates2.ROW);
|
|
5431
5985
|
}
|
|
5432
5986
|
});
|
|
5433
5987
|
parentNode.remove();
|
|
@@ -5452,14 +6006,14 @@ var TABLE = {
|
|
|
5452
6006
|
}
|
|
5453
6007
|
const table = $createTableNode();
|
|
5454
6008
|
for (const cells of rows) {
|
|
5455
|
-
const tableRow = $
|
|
6009
|
+
const tableRow = $createTableRowNode2();
|
|
5456
6010
|
table.append(tableRow);
|
|
5457
6011
|
for (let i = 0; i < maxCells; i++) {
|
|
5458
6012
|
tableRow.append(i < cells.length ? cells[i] : createTableCell(""));
|
|
5459
6013
|
}
|
|
5460
6014
|
}
|
|
5461
6015
|
const previousSibling = parentNode.getPreviousSibling();
|
|
5462
|
-
if ($
|
|
6016
|
+
if ($isTableNode3(previousSibling) && getTableColumnsSize(previousSibling) === maxCells) {
|
|
5463
6017
|
previousSibling.append(...table.getChildren());
|
|
5464
6018
|
parentNode.remove();
|
|
5465
6019
|
} else {
|
|
@@ -5538,21 +6092,8 @@ var editorTheme = {
|
|
|
5538
6092
|
drawing: "zui-drawing"
|
|
5539
6093
|
};
|
|
5540
6094
|
|
|
5541
|
-
// src/editorContext.ts
|
|
5542
|
-
import { createContext, useContext } from "react";
|
|
5543
|
-
var EditorContext = createContext(null);
|
|
5544
|
-
function useEditorContext() {
|
|
5545
|
-
const ctx = useContext(EditorContext);
|
|
5546
|
-
if (!ctx) {
|
|
5547
|
-
throw new Error(
|
|
5548
|
-
"@zuilib/text-editor: this component must be rendered inside <MarkdownEditor> or <MarkdownEditor.Root>"
|
|
5549
|
-
);
|
|
5550
|
-
}
|
|
5551
|
-
return ctx;
|
|
5552
|
-
}
|
|
5553
|
-
|
|
5554
6095
|
// src/EditorRoot.tsx
|
|
5555
|
-
import { Fragment as
|
|
6096
|
+
import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
5556
6097
|
var SYNC_TRANSFORMERS = [
|
|
5557
6098
|
FRONTMATTER,
|
|
5558
6099
|
DRAWING,
|
|
@@ -5583,8 +6124,8 @@ var editorNodes = [
|
|
|
5583
6124
|
DrawingNode
|
|
5584
6125
|
];
|
|
5585
6126
|
function ReadOnlyPlugin({ readOnly }) {
|
|
5586
|
-
const [editor] =
|
|
5587
|
-
|
|
6127
|
+
const [editor] = useLexicalComposerContext7();
|
|
6128
|
+
useEffect9(() => {
|
|
5588
6129
|
editor.setEditable(!readOnly);
|
|
5589
6130
|
}, [editor, readOnly]);
|
|
5590
6131
|
return null;
|
|
@@ -5596,14 +6137,15 @@ function EditorRoot({
|
|
|
5596
6137
|
className,
|
|
5597
6138
|
mode = "edit-md",
|
|
5598
6139
|
autoFocus = false,
|
|
5599
|
-
measure,
|
|
6140
|
+
measure: measure2,
|
|
5600
6141
|
defaultBlockWidth = NO_DEFAULT_BLOCK_WIDTH,
|
|
6142
|
+
drawingStyle = "clean",
|
|
5601
6143
|
children
|
|
5602
6144
|
}) {
|
|
5603
6145
|
const latestValueRef = useRef5(value ?? "");
|
|
5604
6146
|
const [mountKey, setMountKey] = useState4(0);
|
|
5605
6147
|
const [capturedMarkdown, setCapturedMarkdown] = useState4(value ?? "");
|
|
5606
|
-
|
|
6148
|
+
useEffect9(() => {
|
|
5607
6149
|
if (value !== void 0) {
|
|
5608
6150
|
latestValueRef.current = value;
|
|
5609
6151
|
}
|
|
@@ -5616,7 +6158,7 @@ function EditorRoot({
|
|
|
5616
6158
|
[onChange]
|
|
5617
6159
|
);
|
|
5618
6160
|
const prevModeRef = useRef5(mode);
|
|
5619
|
-
|
|
6161
|
+
useEffect9(() => {
|
|
5620
6162
|
if (prevModeRef.current === "edit-raw" && mode !== "edit-raw") {
|
|
5621
6163
|
setCapturedMarkdown(latestValueRef.current);
|
|
5622
6164
|
setMountKey((k) => k + 1);
|
|
@@ -5639,19 +6181,20 @@ function EditorRoot({
|
|
|
5639
6181
|
autoFocus,
|
|
5640
6182
|
rawValue: value ?? "",
|
|
5641
6183
|
onRawChange: handleChange,
|
|
5642
|
-
defaultBlockWidth
|
|
6184
|
+
defaultBlockWidth,
|
|
6185
|
+
drawingStyle
|
|
5643
6186
|
}),
|
|
5644
|
-
[mode, readOnly, autoFocus, value, handleChange, defaultBlockWidth]
|
|
6187
|
+
[mode, readOnly, autoFocus, value, handleChange, defaultBlockWidth, drawingStyle]
|
|
5645
6188
|
);
|
|
5646
6189
|
const isRaw = mode === "edit-raw";
|
|
5647
6190
|
const rootStyle = useMemo2(
|
|
5648
|
-
() =>
|
|
5649
|
-
[
|
|
6191
|
+
() => measure2 !== void 0 ? { "--zui-text-editor-measure": measure2 } : void 0,
|
|
6192
|
+
[measure2]
|
|
5650
6193
|
);
|
|
5651
|
-
return /* @__PURE__ */
|
|
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: [
|
|
5652
6195
|
children,
|
|
5653
|
-
!isRaw && /* @__PURE__ */
|
|
5654
|
-
/* @__PURE__ */
|
|
6196
|
+
!isRaw && /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
6197
|
+
/* @__PURE__ */ jsx12(
|
|
5655
6198
|
MarkdownSyncPlugin,
|
|
5656
6199
|
{
|
|
5657
6200
|
initialMarkdown: mode === "view" ? value ?? "" : capturedMarkdown,
|
|
@@ -5659,17 +6202,18 @@ function EditorRoot({
|
|
|
5659
6202
|
transformers: SYNC_TRANSFORMERS
|
|
5660
6203
|
}
|
|
5661
6204
|
),
|
|
5662
|
-
/* @__PURE__ */
|
|
5663
|
-
/* @__PURE__ */
|
|
5664
|
-
/* @__PURE__ */
|
|
5665
|
-
/* @__PURE__ */
|
|
5666
|
-
/* @__PURE__ */
|
|
5667
|
-
/* @__PURE__ */
|
|
5668
|
-
/* @__PURE__ */
|
|
5669
|
-
/* @__PURE__ */
|
|
5670
|
-
/* @__PURE__ */
|
|
5671
|
-
/* @__PURE__ */
|
|
5672
|
-
|
|
6205
|
+
/* @__PURE__ */ jsx12(HistoryPlugin, {}),
|
|
6206
|
+
/* @__PURE__ */ jsx12(ListPlugin, {}),
|
|
6207
|
+
/* @__PURE__ */ jsx12(CheckListPlugin, {}),
|
|
6208
|
+
/* @__PURE__ */ jsx12(ChecklistShortcutPlugin, {}),
|
|
6209
|
+
/* @__PURE__ */ jsx12(CodeBlockShortcutPlugin, {}),
|
|
6210
|
+
/* @__PURE__ */ jsx12(CodeHighlightPlugin, {}),
|
|
6211
|
+
/* @__PURE__ */ jsx12(TablePlugin, {}),
|
|
6212
|
+
/* @__PURE__ */ jsx12(TableRowShortcutsPlugin, {}),
|
|
6213
|
+
/* @__PURE__ */ jsx12(LinkPlugin, {}),
|
|
6214
|
+
/* @__PURE__ */ jsx12(MarkdownShortcutPlugin, { transformers: SHORTCUT_TRANSFORMERS }),
|
|
6215
|
+
/* @__PURE__ */ jsx12(ReadOnlyPlugin, { readOnly: readOnly || mode === "view" }),
|
|
6216
|
+
autoFocus && /* @__PURE__ */ jsx12(AutoFocusPlugin, {})
|
|
5673
6217
|
] })
|
|
5674
6218
|
] }) }) }, mountKey);
|
|
5675
6219
|
}
|
|
@@ -5682,14 +6226,14 @@ import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
|
5682
6226
|
// src/plugins/FoldingPlugin.tsx
|
|
5683
6227
|
import {
|
|
5684
6228
|
useCallback as useCallback3,
|
|
5685
|
-
useEffect as
|
|
6229
|
+
useEffect as useEffect10,
|
|
5686
6230
|
useRef as useRef6,
|
|
5687
6231
|
useState as useState5
|
|
5688
6232
|
} from "react";
|
|
5689
|
-
import { $getRoot, $getSelection as $
|
|
5690
|
-
import { useLexicalComposerContext as
|
|
6233
|
+
import { $getRoot, $getSelection as $getSelection5, $isRangeSelection as $isRangeSelection5 } from "lexical";
|
|
6234
|
+
import { useLexicalComposerContext as useLexicalComposerContext8 } from "@lexical/react/LexicalComposerContext";
|
|
5691
6235
|
import { $isHeadingNode } from "@lexical/rich-text";
|
|
5692
|
-
import { jsx as
|
|
6236
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
5693
6237
|
var HEADING_LEVELS = {
|
|
5694
6238
|
h1: 1,
|
|
5695
6239
|
h2: 2,
|
|
@@ -5699,7 +6243,7 @@ var HEADING_LEVELS = {
|
|
|
5699
6243
|
h6: 6
|
|
5700
6244
|
};
|
|
5701
6245
|
function FoldingPlugin() {
|
|
5702
|
-
const [editor] =
|
|
6246
|
+
const [editor] = useLexicalComposerContext8();
|
|
5703
6247
|
const [foldedKeys, setFoldedKeys] = useState5(/* @__PURE__ */ new Set());
|
|
5704
6248
|
const [buttons, setButtons] = useState5([]);
|
|
5705
6249
|
const foldedRef = useRef6(foldedKeys);
|
|
@@ -5725,8 +6269,8 @@ function FoldingPlugin() {
|
|
|
5725
6269
|
hidden.add(sibling.getKey());
|
|
5726
6270
|
}
|
|
5727
6271
|
}
|
|
5728
|
-
const selection = $
|
|
5729
|
-
if ($
|
|
6272
|
+
const selection = $getSelection5();
|
|
6273
|
+
if ($isRangeSelection5(selection)) {
|
|
5730
6274
|
const topLevel = selection.anchor.getNode().getTopLevelElement();
|
|
5731
6275
|
if (topLevel && hidden.has(topLevel.getKey())) {
|
|
5732
6276
|
let node = topLevel.getPreviousSibling();
|
|
@@ -5768,7 +6312,7 @@ function FoldingPlugin() {
|
|
|
5768
6312
|
);
|
|
5769
6313
|
});
|
|
5770
6314
|
}, [editor]);
|
|
5771
|
-
|
|
6315
|
+
useEffect10(() => {
|
|
5772
6316
|
sync();
|
|
5773
6317
|
const unregister = editor.registerUpdateListener(sync);
|
|
5774
6318
|
const rootElement = editor.getRootElement();
|
|
@@ -5787,7 +6331,7 @@ function FoldingPlugin() {
|
|
|
5787
6331
|
return next;
|
|
5788
6332
|
});
|
|
5789
6333
|
}, []);
|
|
5790
|
-
return /* @__PURE__ */
|
|
6334
|
+
return /* @__PURE__ */ jsx13("div", { className: "zui-text-editor-fold-gutter", children: buttons.map(({ key, folded, top, height }) => /* @__PURE__ */ jsx13(
|
|
5791
6335
|
"button",
|
|
5792
6336
|
{
|
|
5793
6337
|
type: "button",
|
|
@@ -5797,7 +6341,7 @@ function FoldingPlugin() {
|
|
|
5797
6341
|
"aria-label": folded ? "Expand section" : "Collapse section",
|
|
5798
6342
|
"aria-expanded": !folded,
|
|
5799
6343
|
onClick: () => toggle(key),
|
|
5800
|
-
children: /* @__PURE__ */
|
|
6344
|
+
children: /* @__PURE__ */ jsx13(
|
|
5801
6345
|
"svg",
|
|
5802
6346
|
{
|
|
5803
6347
|
viewBox: "0 0 20 20",
|
|
@@ -5808,7 +6352,7 @@ function FoldingPlugin() {
|
|
|
5808
6352
|
strokeWidth: "2",
|
|
5809
6353
|
strokeLinecap: "round",
|
|
5810
6354
|
strokeLinejoin: "round",
|
|
5811
|
-
children: /* @__PURE__ */
|
|
6355
|
+
children: /* @__PURE__ */ jsx13("path", { d: "M6 8l4 4 4-4" })
|
|
5812
6356
|
}
|
|
5813
6357
|
)
|
|
5814
6358
|
},
|
|
@@ -5816,17 +6360,150 @@ function FoldingPlugin() {
|
|
|
5816
6360
|
)) });
|
|
5817
6361
|
}
|
|
5818
6362
|
|
|
5819
|
-
// src/plugins/
|
|
5820
|
-
import { useCallback as
|
|
5821
|
-
import { useLexicalComposerContext as
|
|
6363
|
+
// src/plugins/TableControlsPlugin.tsx
|
|
6364
|
+
import { useCallback as useCallback7 } from "react";
|
|
6365
|
+
import { useLexicalComposerContext as useLexicalComposerContext11 } from "@lexical/react/LexicalComposerContext";
|
|
5822
6366
|
import { useLexicalEditable as useLexicalEditable2 } from "@lexical/react/useLexicalEditable";
|
|
5823
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
|
+
|
|
5824
6501
|
// src/useMarkdownEditor.ts
|
|
5825
|
-
import { useCallback as
|
|
6502
|
+
import { useCallback as useCallback5, useEffect as useEffect11, useRef as useRef8, useState as useState7 } from "react";
|
|
5826
6503
|
import {
|
|
5827
|
-
$getNodeByKey as $
|
|
5828
|
-
$getSelection as $
|
|
5829
|
-
$isRangeSelection as $
|
|
6504
|
+
$getNodeByKey as $getNodeByKey5,
|
|
6505
|
+
$getSelection as $getSelection6,
|
|
6506
|
+
$isRangeSelection as $isRangeSelection6,
|
|
5830
6507
|
CAN_REDO_COMMAND,
|
|
5831
6508
|
CAN_UNDO_COMMAND,
|
|
5832
6509
|
COMMAND_PRIORITY_LOW as COMMAND_PRIORITY_LOW2,
|
|
@@ -5834,7 +6511,7 @@ import {
|
|
|
5834
6511
|
REDO_COMMAND,
|
|
5835
6512
|
UNDO_COMMAND
|
|
5836
6513
|
} from "lexical";
|
|
5837
|
-
import { useLexicalComposerContext as
|
|
6514
|
+
import { useLexicalComposerContext as useLexicalComposerContext9 } from "@lexical/react/LexicalComposerContext";
|
|
5838
6515
|
import { INSERT_TABLE_COMMAND } from "@lexical/table";
|
|
5839
6516
|
import { $insertNodeToNearestRoot, mergeRegister as mergeRegister2 } from "@lexical/utils";
|
|
5840
6517
|
var TRACKED_FORMATS = [
|
|
@@ -5846,29 +6523,31 @@ var TRACKED_FORMATS = [
|
|
|
5846
6523
|
];
|
|
5847
6524
|
function $readDrawingWidth(key) {
|
|
5848
6525
|
if (key === null) return null;
|
|
5849
|
-
const node = $
|
|
6526
|
+
const node = $getNodeByKey5(key);
|
|
5850
6527
|
return $isDrawingNode(node) ? node.getData().width ?? "full" : null;
|
|
5851
6528
|
}
|
|
5852
6529
|
function useMarkdownEditor() {
|
|
5853
|
-
const [editor] =
|
|
6530
|
+
const [editor] = useLexicalComposerContext9();
|
|
5854
6531
|
const { defaultBlockWidth } = useEditorContext();
|
|
5855
|
-
const [activeFormats, setActiveFormats] =
|
|
6532
|
+
const [activeFormats, setActiveFormats] = useState7(
|
|
5856
6533
|
/* @__PURE__ */ new Set()
|
|
5857
6534
|
);
|
|
5858
|
-
const [canUndo, setCanUndo] =
|
|
5859
|
-
const [canRedo, setCanRedo] =
|
|
5860
|
-
const [tableSettings, setTableSettingsState] =
|
|
5861
|
-
const
|
|
5862
|
-
const
|
|
5863
|
-
|
|
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(
|
|
5864
6542
|
() => mergeRegister2(
|
|
5865
6543
|
editor.registerUpdateListener(({ editorState }) => {
|
|
5866
6544
|
editorState.read(() => {
|
|
5867
6545
|
const table = $getSelectedTable();
|
|
5868
6546
|
setTableSettingsState(table ? $getTableSettings(table) : null);
|
|
6547
|
+
setTableRow(table ? $getTableRowPosition() : null);
|
|
5869
6548
|
setDrawingWidth($readDrawingWidth(activeDrawingRef.current));
|
|
5870
|
-
const selection = $
|
|
5871
|
-
if (!$
|
|
6549
|
+
const selection = $getSelection6();
|
|
6550
|
+
if (!$isRangeSelection6(selection)) {
|
|
5872
6551
|
setActiveFormats(/* @__PURE__ */ new Set());
|
|
5873
6552
|
return;
|
|
5874
6553
|
}
|
|
@@ -5907,13 +6586,13 @@ function useMarkdownEditor() {
|
|
|
5907
6586
|
),
|
|
5908
6587
|
[editor]
|
|
5909
6588
|
);
|
|
5910
|
-
const toggleFormat =
|
|
6589
|
+
const toggleFormat = useCallback5(
|
|
5911
6590
|
(format) => {
|
|
5912
6591
|
editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
|
|
5913
6592
|
},
|
|
5914
6593
|
[editor]
|
|
5915
6594
|
);
|
|
5916
|
-
const insertTable =
|
|
6595
|
+
const insertTable = useCallback5(
|
|
5917
6596
|
({
|
|
5918
6597
|
rows = 3,
|
|
5919
6598
|
columns = 3,
|
|
@@ -5935,7 +6614,7 @@ function useMarkdownEditor() {
|
|
|
5935
6614
|
},
|
|
5936
6615
|
[editor, defaultBlockWidth.table]
|
|
5937
6616
|
);
|
|
5938
|
-
const insertDrawing =
|
|
6617
|
+
const insertDrawing = useCallback5(
|
|
5939
6618
|
({ width = defaultBlockWidth.drawing } = {}) => {
|
|
5940
6619
|
editor.update(() => {
|
|
5941
6620
|
const data = width === void 0 ? EMPTY_DRAWING : { version: 2, canvasHeight: EMPTY_DRAWING.canvasHeight, width, shapes: [] };
|
|
@@ -5944,7 +6623,7 @@ function useMarkdownEditor() {
|
|
|
5944
6623
|
},
|
|
5945
6624
|
[editor, defaultBlockWidth.drawing]
|
|
5946
6625
|
);
|
|
5947
|
-
const updateTableSettings =
|
|
6626
|
+
const updateTableSettings = useCallback5(
|
|
5948
6627
|
(settings) => {
|
|
5949
6628
|
editor.update(() => {
|
|
5950
6629
|
const table = $getSelectedTable();
|
|
@@ -5953,15 +6632,30 @@ function useMarkdownEditor() {
|
|
|
5953
6632
|
},
|
|
5954
6633
|
[editor]
|
|
5955
6634
|
);
|
|
5956
|
-
const setTableWidth =
|
|
6635
|
+
const setTableWidth = useCallback5(
|
|
5957
6636
|
(width) => updateTableSettings({ width }),
|
|
5958
6637
|
[updateTableSettings]
|
|
5959
6638
|
);
|
|
5960
|
-
const setTableDensity =
|
|
6639
|
+
const setTableDensity = useCallback5(
|
|
5961
6640
|
(density) => updateTableSettings({ density }),
|
|
5962
6641
|
[updateTableSettings]
|
|
5963
6642
|
);
|
|
5964
|
-
const
|
|
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(
|
|
5965
6659
|
(width) => {
|
|
5966
6660
|
const key = activeDrawingRef.current;
|
|
5967
6661
|
if (key === null) {
|
|
@@ -5969,7 +6663,7 @@ function useMarkdownEditor() {
|
|
|
5969
6663
|
return;
|
|
5970
6664
|
}
|
|
5971
6665
|
editor.update(() => {
|
|
5972
|
-
const node = $
|
|
6666
|
+
const node = $getNodeByKey5(key);
|
|
5973
6667
|
if (!$isDrawingNode(node)) return;
|
|
5974
6668
|
const { width: _previous, ...data } = node.getData();
|
|
5975
6669
|
node.setData(width === "full" ? data : { ...data, width });
|
|
@@ -5977,10 +6671,10 @@ function useMarkdownEditor() {
|
|
|
5977
6671
|
},
|
|
5978
6672
|
[editor, updateTableSettings]
|
|
5979
6673
|
);
|
|
5980
|
-
const undo =
|
|
6674
|
+
const undo = useCallback5(() => {
|
|
5981
6675
|
editor.dispatchCommand(UNDO_COMMAND, void 0);
|
|
5982
6676
|
}, [editor]);
|
|
5983
|
-
const redo =
|
|
6677
|
+
const redo = useCallback5(() => {
|
|
5984
6678
|
editor.dispatchCommand(REDO_COMMAND, void 0);
|
|
5985
6679
|
}, [editor]);
|
|
5986
6680
|
return {
|
|
@@ -5995,6 +6689,9 @@ function useMarkdownEditor() {
|
|
|
5995
6689
|
setTableWidth,
|
|
5996
6690
|
tableDensity: tableSettings?.density ?? null,
|
|
5997
6691
|
setTableDensity,
|
|
6692
|
+
tableRow,
|
|
6693
|
+
insertTableRow,
|
|
6694
|
+
deleteTableRow,
|
|
5998
6695
|
canUndo,
|
|
5999
6696
|
canRedo,
|
|
6000
6697
|
undo,
|
|
@@ -6003,23 +6700,23 @@ function useMarkdownEditor() {
|
|
|
6003
6700
|
}
|
|
6004
6701
|
|
|
6005
6702
|
// src/components/Toolbar.tsx
|
|
6006
|
-
import { Fragment as
|
|
6703
|
+
import { Fragment as Fragment6, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
6007
6704
|
function Toolbar({ children, className }) {
|
|
6008
|
-
return /* @__PURE__ */
|
|
6705
|
+
return /* @__PURE__ */ jsx16(
|
|
6009
6706
|
"div",
|
|
6010
6707
|
{
|
|
6011
6708
|
className: `zui-text-editor-toolbar ${className ?? ""}`,
|
|
6012
6709
|
role: "toolbar",
|
|
6013
|
-
children: children ?? /* @__PURE__ */
|
|
6014
|
-
/* @__PURE__ */
|
|
6015
|
-
/* @__PURE__ */
|
|
6016
|
-
/* @__PURE__ */
|
|
6710
|
+
children: children ?? /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
6711
|
+
/* @__PURE__ */ jsx16(FormatButtons, {}),
|
|
6712
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
6713
|
+
/* @__PURE__ */ jsx16(InsertButtons, {})
|
|
6017
6714
|
] })
|
|
6018
6715
|
}
|
|
6019
6716
|
);
|
|
6020
6717
|
}
|
|
6021
6718
|
function ToolbarDivider() {
|
|
6022
|
-
return /* @__PURE__ */
|
|
6719
|
+
return /* @__PURE__ */ jsx16("div", { className: "zui-text-editor-toolbar-divider" });
|
|
6023
6720
|
}
|
|
6024
6721
|
function ToolbarButton({
|
|
6025
6722
|
label,
|
|
@@ -6029,7 +6726,7 @@ function ToolbarButton({
|
|
|
6029
6726
|
disabled = false,
|
|
6030
6727
|
className
|
|
6031
6728
|
}) {
|
|
6032
|
-
return /* @__PURE__ */
|
|
6729
|
+
return /* @__PURE__ */ jsx16(
|
|
6033
6730
|
"button",
|
|
6034
6731
|
{
|
|
6035
6732
|
type: "button",
|
|
@@ -6045,7 +6742,7 @@ function ToolbarButton({
|
|
|
6045
6742
|
);
|
|
6046
6743
|
}
|
|
6047
6744
|
function Icon2({ children, strokeWidth = 1.5 }) {
|
|
6048
|
-
return /* @__PURE__ */
|
|
6745
|
+
return /* @__PURE__ */ jsx16(
|
|
6049
6746
|
"svg",
|
|
6050
6747
|
{
|
|
6051
6748
|
viewBox: "0 0 20 20",
|
|
@@ -6064,27 +6761,27 @@ var FORMAT_BUTTONS = [
|
|
|
6064
6761
|
{
|
|
6065
6762
|
format: "bold",
|
|
6066
6763
|
label: "Bold",
|
|
6067
|
-
icon: /* @__PURE__ */
|
|
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" }) })
|
|
6068
6765
|
},
|
|
6069
6766
|
{
|
|
6070
6767
|
format: "italic",
|
|
6071
6768
|
label: "Italic",
|
|
6072
|
-
icon: /* @__PURE__ */
|
|
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" }) })
|
|
6073
6770
|
},
|
|
6074
6771
|
{
|
|
6075
6772
|
format: "strikethrough",
|
|
6076
6773
|
label: "Strikethrough",
|
|
6077
|
-
icon: /* @__PURE__ */
|
|
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" }) })
|
|
6078
6775
|
},
|
|
6079
6776
|
{
|
|
6080
6777
|
format: "code",
|
|
6081
6778
|
label: "Inline code",
|
|
6082
|
-
icon: /* @__PURE__ */
|
|
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" }) })
|
|
6083
6780
|
}
|
|
6084
6781
|
];
|
|
6085
6782
|
function FormatButtons() {
|
|
6086
6783
|
const { activeFormats, toggleFormat } = useMarkdownEditor();
|
|
6087
|
-
return /* @__PURE__ */
|
|
6784
|
+
return /* @__PURE__ */ jsx16(Fragment6, { children: FORMAT_BUTTONS.map(({ format, label, icon }) => /* @__PURE__ */ jsx16(
|
|
6088
6785
|
ToolbarButton,
|
|
6089
6786
|
{
|
|
6090
6787
|
label,
|
|
@@ -6097,36 +6794,36 @@ function FormatButtons() {
|
|
|
6097
6794
|
}
|
|
6098
6795
|
function InsertButtons() {
|
|
6099
6796
|
const { insertTable, insertDrawing } = useMarkdownEditor();
|
|
6100
|
-
return /* @__PURE__ */
|
|
6101
|
-
/* @__PURE__ */
|
|
6102
|
-
/* @__PURE__ */
|
|
6103
|
-
/* @__PURE__ */
|
|
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" })
|
|
6104
6801
|
] }) }),
|
|
6105
|
-
/* @__PURE__ */
|
|
6106
|
-
/* @__PURE__ */
|
|
6107
|
-
/* @__PURE__ */
|
|
6108
|
-
/* @__PURE__ */
|
|
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" })
|
|
6109
6806
|
] }) })
|
|
6110
6807
|
] });
|
|
6111
6808
|
}
|
|
6112
6809
|
function HistoryButtons() {
|
|
6113
6810
|
const { canUndo, canRedo, undo, redo } = useMarkdownEditor();
|
|
6114
|
-
return /* @__PURE__ */
|
|
6115
|
-
/* @__PURE__ */
|
|
6116
|
-
/* @__PURE__ */
|
|
6117
|
-
/* @__PURE__ */
|
|
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" })
|
|
6118
6815
|
] }) }),
|
|
6119
|
-
/* @__PURE__ */
|
|
6120
|
-
/* @__PURE__ */
|
|
6121
|
-
/* @__PURE__ */
|
|
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" })
|
|
6122
6819
|
] }) })
|
|
6123
6820
|
] });
|
|
6124
6821
|
}
|
|
6125
6822
|
|
|
6126
|
-
// src/
|
|
6127
|
-
import { jsx as
|
|
6823
|
+
// src/components/TableSettingsToolbar.tsx
|
|
6824
|
+
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
6128
6825
|
function Icon3({ children }) {
|
|
6129
|
-
return /* @__PURE__ */
|
|
6826
|
+
return /* @__PURE__ */ jsx17(
|
|
6130
6827
|
"svg",
|
|
6131
6828
|
{
|
|
6132
6829
|
viewBox: "0 0 20 20",
|
|
@@ -6141,32 +6838,79 @@ function Icon3({ children }) {
|
|
|
6141
6838
|
}
|
|
6142
6839
|
);
|
|
6143
6840
|
}
|
|
6144
|
-
function
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
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(() => {
|
|
6150
6900
|
const table = editor.getEditorState().read(() => {
|
|
6151
6901
|
const node = $getSelectedTable();
|
|
6152
|
-
|
|
6902
|
+
const position = $getTableRowPosition();
|
|
6903
|
+
return node && position ? { key: node.getKey(), settings: $getTableSettings(node), position } : null;
|
|
6153
6904
|
});
|
|
6154
6905
|
const element = table ? editor.getElementByKey(table.key) : null;
|
|
6155
6906
|
const main = editor.getRootElement()?.parentElement;
|
|
6156
6907
|
if (!table || !element || !main) {
|
|
6157
|
-
|
|
6158
|
-
setSettings(null);
|
|
6908
|
+
setSelected(null);
|
|
6159
6909
|
return;
|
|
6160
6910
|
}
|
|
6161
|
-
|
|
6162
|
-
const mainRect = main.getBoundingClientRect();
|
|
6163
|
-
setAnchor({
|
|
6164
|
-
top: rect.top - mainRect.top,
|
|
6165
|
-
right: mainRect.right - rect.right + 8
|
|
6166
|
-
});
|
|
6167
|
-
setSettings(table.settings);
|
|
6911
|
+
setSelected({ ...table, ...measure(element, main) });
|
|
6168
6912
|
}, [editor]);
|
|
6169
|
-
|
|
6913
|
+
useEffect12(() => {
|
|
6170
6914
|
sync();
|
|
6171
6915
|
const unregister = editor.registerUpdateListener(sync);
|
|
6172
6916
|
const rootElement = editor.getRootElement();
|
|
@@ -6177,39 +6921,79 @@ function TableSettingsPlugin() {
|
|
|
6177
6921
|
observer?.disconnect();
|
|
6178
6922
|
};
|
|
6179
6923
|
}, [editor, sync]);
|
|
6180
|
-
const
|
|
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(
|
|
6181
6943
|
(next) => {
|
|
6182
6944
|
editor.update(() => {
|
|
6183
|
-
const
|
|
6184
|
-
if (
|
|
6945
|
+
const node = $getSelectedTable();
|
|
6946
|
+
if (node) $setTableSettings(node, next);
|
|
6185
6947
|
});
|
|
6186
6948
|
},
|
|
6187
6949
|
[editor]
|
|
6188
6950
|
);
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
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]
|
|
6961
|
+
);
|
|
6962
|
+
const insertAt = useCallback7(
|
|
6963
|
+
(index) => {
|
|
6964
|
+
editor.update(() => {
|
|
6965
|
+
const node = $getSelectedTable();
|
|
6966
|
+
if (node) $insertTableRowAt(node, index);
|
|
6967
|
+
});
|
|
6968
|
+
},
|
|
6969
|
+
[editor]
|
|
6208
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
|
+
] });
|
|
6209
6993
|
}
|
|
6210
6994
|
|
|
6211
6995
|
// src/EditorContent.tsx
|
|
6212
|
-
import { jsx as
|
|
6996
|
+
import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
6213
6997
|
function EditorContent({
|
|
6214
6998
|
placeholder = "Start writing...",
|
|
6215
6999
|
foldable = true,
|
|
@@ -6217,7 +7001,7 @@ function EditorContent({
|
|
|
6217
7001
|
}) {
|
|
6218
7002
|
const { mode, readOnly, autoFocus, rawValue, onRawChange } = useEditorContext();
|
|
6219
7003
|
if (mode === "edit-raw") {
|
|
6220
|
-
return /* @__PURE__ */
|
|
7004
|
+
return /* @__PURE__ */ jsx19(
|
|
6221
7005
|
"textarea",
|
|
6222
7006
|
{
|
|
6223
7007
|
className: "zui-text-editor-textarea",
|
|
@@ -6230,36 +7014,36 @@ function EditorContent({
|
|
|
6230
7014
|
}
|
|
6231
7015
|
);
|
|
6232
7016
|
}
|
|
6233
|
-
return /* @__PURE__ */
|
|
6234
|
-
/* @__PURE__ */
|
|
6235
|
-
/* @__PURE__ */
|
|
7017
|
+
return /* @__PURE__ */ jsxs16("div", { className: "zui-text-editor-body", children: [
|
|
7018
|
+
/* @__PURE__ */ jsxs16("div", { className: "zui-text-editor-main", children: [
|
|
7019
|
+
/* @__PURE__ */ jsx19(
|
|
6236
7020
|
RichTextPlugin,
|
|
6237
7021
|
{
|
|
6238
|
-
contentEditable: /* @__PURE__ */
|
|
7022
|
+
contentEditable: /* @__PURE__ */ jsx19(
|
|
6239
7023
|
ContentEditable,
|
|
6240
7024
|
{
|
|
6241
7025
|
className: "zui-text-editor-content",
|
|
6242
7026
|
"aria-placeholder": placeholder,
|
|
6243
|
-
placeholder: /* @__PURE__ */
|
|
7027
|
+
placeholder: /* @__PURE__ */ jsx19("div", { className: "zui-text-editor-placeholder", children: placeholder })
|
|
6244
7028
|
}
|
|
6245
7029
|
),
|
|
6246
7030
|
ErrorBoundary: LexicalErrorBoundary
|
|
6247
7031
|
}
|
|
6248
7032
|
),
|
|
6249
|
-
foldable && /* @__PURE__ */
|
|
6250
|
-
/* @__PURE__ */
|
|
7033
|
+
foldable && /* @__PURE__ */ jsx19(FoldingPlugin, {}),
|
|
7034
|
+
/* @__PURE__ */ jsx19(TableControlsPlugin, {})
|
|
6251
7035
|
] }),
|
|
6252
7036
|
children
|
|
6253
7037
|
] });
|
|
6254
7038
|
}
|
|
6255
7039
|
|
|
6256
7040
|
// src/plugins/OutlinePlugin.tsx
|
|
6257
|
-
import { useCallback as
|
|
6258
|
-
import { useLexicalComposerContext as
|
|
7041
|
+
import { useCallback as useCallback8, useEffect as useEffect13, useState as useState9 } from "react";
|
|
7042
|
+
import { useLexicalComposerContext as useLexicalComposerContext12 } from "@lexical/react/LexicalComposerContext";
|
|
6259
7043
|
import {
|
|
6260
7044
|
TableOfContentsPlugin
|
|
6261
7045
|
} from "@lexical/react/LexicalTableOfContentsPlugin";
|
|
6262
|
-
import { jsx as
|
|
7046
|
+
import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
6263
7047
|
var INDENT_PER_LEVEL = {
|
|
6264
7048
|
h1: 0,
|
|
6265
7049
|
h2: 1,
|
|
@@ -6269,10 +7053,10 @@ var INDENT_PER_LEVEL = {
|
|
|
6269
7053
|
h6: 5
|
|
6270
7054
|
};
|
|
6271
7055
|
function OutlinePlugin() {
|
|
6272
|
-
const [editor] =
|
|
6273
|
-
const [collapsed, setCollapsed] =
|
|
6274
|
-
const [activeKey, setActiveKey] =
|
|
6275
|
-
|
|
7056
|
+
const [editor] = useLexicalComposerContext12();
|
|
7057
|
+
const [collapsed, setCollapsed] = useState9(false);
|
|
7058
|
+
const [activeKey, setActiveKey] = useState9(null);
|
|
7059
|
+
useEffect13(() => {
|
|
6276
7060
|
const rootElement = editor.getRootElement();
|
|
6277
7061
|
const scroller = rootElement?.closest(".zui-text-editor");
|
|
6278
7062
|
if (!rootElement || !(scroller instanceof HTMLElement)) return;
|
|
@@ -6302,7 +7086,7 @@ function OutlinePlugin() {
|
|
|
6302
7086
|
unregister();
|
|
6303
7087
|
};
|
|
6304
7088
|
}, [editor]);
|
|
6305
|
-
const scrollTo =
|
|
7089
|
+
const scrollTo = useCallback8(
|
|
6306
7090
|
(key) => {
|
|
6307
7091
|
editor.getEditorState().read(() => {
|
|
6308
7092
|
const element = editor.getElementByKey(key);
|
|
@@ -6311,16 +7095,16 @@ function OutlinePlugin() {
|
|
|
6311
7095
|
},
|
|
6312
7096
|
[editor]
|
|
6313
7097
|
);
|
|
6314
|
-
return /* @__PURE__ */
|
|
7098
|
+
return /* @__PURE__ */ jsx20(TableOfContentsPlugin, { children: (entries) => {
|
|
6315
7099
|
for (const [key] of entries) {
|
|
6316
7100
|
editor.getElementByKey(key)?.setAttribute("data-outline-key", key);
|
|
6317
7101
|
}
|
|
6318
|
-
return /* @__PURE__ */
|
|
7102
|
+
return /* @__PURE__ */ jsxs17(
|
|
6319
7103
|
"div",
|
|
6320
7104
|
{
|
|
6321
7105
|
className: `zui-text-editor-outline ${collapsed ? "is-collapsed" : ""}`,
|
|
6322
7106
|
children: [
|
|
6323
|
-
/* @__PURE__ */
|
|
7107
|
+
/* @__PURE__ */ jsx20(
|
|
6324
7108
|
"button",
|
|
6325
7109
|
{
|
|
6326
7110
|
type: "button",
|
|
@@ -6329,7 +7113,7 @@ function OutlinePlugin() {
|
|
|
6329
7113
|
"aria-label": collapsed ? "Show outline" : "Hide outline",
|
|
6330
7114
|
"aria-expanded": !collapsed,
|
|
6331
7115
|
onClick: () => setCollapsed((c2) => !c2),
|
|
6332
|
-
children: /* @__PURE__ */
|
|
7116
|
+
children: /* @__PURE__ */ jsx20(
|
|
6333
7117
|
"svg",
|
|
6334
7118
|
{
|
|
6335
7119
|
viewBox: "0 0 20 20",
|
|
@@ -6339,14 +7123,14 @@ function OutlinePlugin() {
|
|
|
6339
7123
|
stroke: "currentColor",
|
|
6340
7124
|
strokeWidth: "1.8",
|
|
6341
7125
|
strokeLinecap: "round",
|
|
6342
|
-
children: /* @__PURE__ */
|
|
7126
|
+
children: /* @__PURE__ */ jsx20("path", { d: "M4 5h12M4 10h8M4 15h10" })
|
|
6343
7127
|
}
|
|
6344
7128
|
)
|
|
6345
7129
|
}
|
|
6346
7130
|
),
|
|
6347
|
-
!collapsed && /* @__PURE__ */
|
|
6348
|
-
entries.length === 0 && /* @__PURE__ */
|
|
6349
|
-
entries.map(([key, text, tag]) => /* @__PURE__ */
|
|
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(
|
|
6350
7134
|
"button",
|
|
6351
7135
|
{
|
|
6352
7136
|
type: "button",
|
|
@@ -6367,11 +7151,11 @@ function OutlinePlugin() {
|
|
|
6367
7151
|
}
|
|
6368
7152
|
|
|
6369
7153
|
// src/MarkdownEditor.tsx
|
|
6370
|
-
import { jsx as
|
|
7154
|
+
import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
6371
7155
|
var DEFAULT_ITEMS = {
|
|
6372
|
-
format: /* @__PURE__ */
|
|
6373
|
-
insert: /* @__PURE__ */
|
|
6374
|
-
history: /* @__PURE__ */
|
|
7156
|
+
format: /* @__PURE__ */ jsx21(FormatButtons, {}),
|
|
7157
|
+
insert: /* @__PURE__ */ jsx21(InsertButtons, {}),
|
|
7158
|
+
history: /* @__PURE__ */ jsx21(HistoryButtons, {})
|
|
6375
7159
|
};
|
|
6376
7160
|
function EditorToolbar({
|
|
6377
7161
|
children,
|
|
@@ -6379,7 +7163,7 @@ function EditorToolbar({
|
|
|
6379
7163
|
}) {
|
|
6380
7164
|
const { mode, readOnly } = useEditorContext();
|
|
6381
7165
|
if (mode !== "edit-md" || readOnly) return null;
|
|
6382
|
-
return /* @__PURE__ */
|
|
7166
|
+
return /* @__PURE__ */ jsx21(Toolbar, { className, children });
|
|
6383
7167
|
}
|
|
6384
7168
|
function MarkdownEditor({
|
|
6385
7169
|
placeholder,
|
|
@@ -6388,10 +7172,10 @@ function MarkdownEditor({
|
|
|
6388
7172
|
foldable = true,
|
|
6389
7173
|
...rootProps
|
|
6390
7174
|
}) {
|
|
6391
|
-
return /* @__PURE__ */
|
|
6392
|
-
toolbar === true && /* @__PURE__ */
|
|
7175
|
+
return /* @__PURE__ */ jsxs18(EditorRoot, { ...rootProps, children: [
|
|
7176
|
+
toolbar === true && /* @__PURE__ */ jsx21(EditorToolbar, {}),
|
|
6393
7177
|
typeof toolbar === "function" && toolbar(DEFAULT_ITEMS),
|
|
6394
|
-
/* @__PURE__ */
|
|
7178
|
+
/* @__PURE__ */ jsx21(EditorContent, { placeholder, foldable, children: outline && /* @__PURE__ */ jsx21(OutlinePlugin, {}) })
|
|
6395
7179
|
] });
|
|
6396
7180
|
}
|
|
6397
7181
|
MarkdownEditor.Root = EditorRoot;
|
|
@@ -6565,10 +7349,16 @@ var DRAWING_DATA_JSON_SCHEMA = {
|
|
|
6565
7349
|
export {
|
|
6566
7350
|
$createDrawingNode,
|
|
6567
7351
|
$createFrontmatterNode,
|
|
7352
|
+
$deleteSelectedTableRow,
|
|
7353
|
+
$deleteTableRowAt,
|
|
6568
7354
|
$getSelectedTable,
|
|
7355
|
+
$getSelectedTableCell,
|
|
6569
7356
|
$getTableDensity,
|
|
7357
|
+
$getTableRowPosition,
|
|
6570
7358
|
$getTableSettings,
|
|
6571
7359
|
$getTableWidth,
|
|
7360
|
+
$insertTableRowAt,
|
|
7361
|
+
$insertTableRowNear,
|
|
6572
7362
|
$isDrawingNode,
|
|
6573
7363
|
$isFrontmatterNode,
|
|
6574
7364
|
$isTableWidthExplicit,
|
|
@@ -6609,6 +7399,7 @@ export {
|
|
|
6609
7399
|
anchorPoint,
|
|
6610
7400
|
bindEndpoints,
|
|
6611
7401
|
boxOutline,
|
|
7402
|
+
canDeleteRow,
|
|
6612
7403
|
codeTokenizer,
|
|
6613
7404
|
connectorPoints,
|
|
6614
7405
|
drawingToMermaid,
|
|
@@ -6618,6 +7409,10 @@ export {
|
|
|
6618
7409
|
formatTableSettingsMarker,
|
|
6619
7410
|
getCodeLanguages,
|
|
6620
7411
|
hasCodeLanguage,
|
|
7412
|
+
inkAmplitude,
|
|
7413
|
+
inkFillOffset,
|
|
7414
|
+
inkStroke,
|
|
7415
|
+
insertableRowIndices,
|
|
6621
7416
|
isBlockWidth,
|
|
6622
7417
|
isDrawingSkeleton,
|
|
6623
7418
|
makeBinding,
|
|
@@ -6629,7 +7424,10 @@ export {
|
|
|
6629
7424
|
registerCodeLanguage,
|
|
6630
7425
|
resolveBindings,
|
|
6631
7426
|
resolveCodeLanguage,
|
|
7427
|
+
roundedPolyline,
|
|
7428
|
+
roundedRectPolygon,
|
|
6632
7429
|
routeElbow,
|
|
7430
|
+
seedFrom,
|
|
6633
7431
|
serializeDrawingData,
|
|
6634
7432
|
tokenizeCode,
|
|
6635
7433
|
useMarkdownEditor
|