@zuilib/text-editor 0.3.0 → 0.4.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 +35 -0
- package/DRAWING_FORMAT.md +7 -2
- package/README.md +41 -2
- package/dist/index.d.ts +52 -2
- package/dist/index.js +692 -324
- package/dist/styles.css +41 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -357,6 +357,9 @@ function parseDrawingData(json) {
|
|
|
357
357
|
return {
|
|
358
358
|
version: 1,
|
|
359
359
|
height: typeof raw.height === "number" && raw.height >= 80 ? raw.height : DEFAULT_DRAWING_HEIGHT,
|
|
360
|
+
// `full` is the default and stays implicit so existing payloads are
|
|
361
|
+
// serialized byte-for-byte unchanged
|
|
362
|
+
width: raw.width === "content" ? "content" : void 0,
|
|
360
363
|
shapes
|
|
361
364
|
};
|
|
362
365
|
} catch {
|
|
@@ -373,6 +376,27 @@ function isValidShape(value) {
|
|
|
373
376
|
));
|
|
374
377
|
}
|
|
375
378
|
|
|
379
|
+
// src/components/blockWidthOptions.tsx
|
|
380
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
381
|
+
var BLOCK_WIDTH_OPTIONS = [
|
|
382
|
+
{
|
|
383
|
+
width: "full",
|
|
384
|
+
label: "Full width",
|
|
385
|
+
icon: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
386
|
+
/* @__PURE__ */ jsx("path", { d: "M3 4v12M17 4v12" }),
|
|
387
|
+
/* @__PURE__ */ jsx("path", { d: "M6 10h8M8.5 7.5L6 10l2.5 2.5M11.5 7.5L14 10l-2.5 2.5" })
|
|
388
|
+
] })
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
width: "content",
|
|
392
|
+
label: "Content width",
|
|
393
|
+
icon: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
394
|
+
/* @__PURE__ */ jsx("path", { d: "M3 4v12M17 4v12" }),
|
|
395
|
+
/* @__PURE__ */ jsx("path", { d: "M5.5 10h3M11.5 10h3M6.5 7.5L9 10l-2.5 2.5M13.5 7.5L11 10l2.5 2.5" })
|
|
396
|
+
] })
|
|
397
|
+
}
|
|
398
|
+
];
|
|
399
|
+
|
|
376
400
|
// src/components/drawingGeometry.ts
|
|
377
401
|
var BINDING_GAP = 6;
|
|
378
402
|
var BINDING_TOLERANCE = 8;
|
|
@@ -615,10 +639,12 @@ function resolveBindings(shapes) {
|
|
|
615
639
|
}
|
|
616
640
|
|
|
617
641
|
// src/components/DrawingCanvas.tsx
|
|
618
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
642
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
619
643
|
import { createElement } from "react";
|
|
620
644
|
var MIN_HEIGHT = 120;
|
|
621
645
|
var MAX_HEIGHT = 900;
|
|
646
|
+
var MIN_CONTENT_WIDTH = 240;
|
|
647
|
+
var CONTENT_WIDTH_PADDING = 40;
|
|
622
648
|
var SELECTION_COLOR = "#6965db";
|
|
623
649
|
var CONNECTOR_FONT_SIZE = 12;
|
|
624
650
|
var CONNECTOR_LABEL_MAX_WIDTH = 160;
|
|
@@ -649,7 +675,7 @@ function BoxTexts({
|
|
|
649
675
|
opacity: 0.35,
|
|
650
676
|
style: { userSelect: "none", pointerEvents: "none" }
|
|
651
677
|
};
|
|
652
|
-
return /* @__PURE__ */
|
|
678
|
+
return /* @__PURE__ */ jsxs2("g", { children: [
|
|
653
679
|
hideField !== "label" && (shape.label ? labelLines.map((line, i) => /* @__PURE__ */ createElement(
|
|
654
680
|
"text",
|
|
655
681
|
{
|
|
@@ -662,7 +688,7 @@ function BoxTexts({
|
|
|
662
688
|
opacity: 0.85
|
|
663
689
|
},
|
|
664
690
|
line
|
|
665
|
-
)) : showHints && /* @__PURE__ */
|
|
691
|
+
)) : showHints && /* @__PURE__ */ jsx2("text", { ...hint, x: cx, y: b.y + SMALL_FONT_SIZE + 7, fontSize: SMALL_FONT_SIZE, children: "Label" })),
|
|
666
692
|
hideField !== "text" && (shape.text ? mainLines.map((line, i) => /* @__PURE__ */ createElement(
|
|
667
693
|
"text",
|
|
668
694
|
{
|
|
@@ -673,7 +699,7 @@ function BoxTexts({
|
|
|
673
699
|
fontSize: FONT_SIZE
|
|
674
700
|
},
|
|
675
701
|
line
|
|
676
|
-
)) : showHints && /* @__PURE__ */
|
|
702
|
+
)) : showHints && /* @__PURE__ */ jsx2("text", { ...hint, x: cx, y: mainStart, fontSize: FONT_SIZE, children: "Text" })),
|
|
677
703
|
hideField !== "footer" && (shape.footer ? footerLines.map((line, i) => /* @__PURE__ */ createElement(
|
|
678
704
|
"text",
|
|
679
705
|
{
|
|
@@ -685,7 +711,7 @@ function BoxTexts({
|
|
|
685
711
|
opacity: 0.65
|
|
686
712
|
},
|
|
687
713
|
line
|
|
688
|
-
)) : showHints && /* @__PURE__ */
|
|
714
|
+
)) : showHints && /* @__PURE__ */ jsx2("text", { ...hint, x: cx, y: b.y + b.h - 9, fontSize: SMALL_FONT_SIZE, children: "Footer" }))
|
|
689
715
|
] });
|
|
690
716
|
}
|
|
691
717
|
function ShapeView({
|
|
@@ -702,8 +728,8 @@ function ShapeView({
|
|
|
702
728
|
switch (shape.type) {
|
|
703
729
|
case "rect": {
|
|
704
730
|
const b = bbox(shape);
|
|
705
|
-
return /* @__PURE__ */
|
|
706
|
-
/* @__PURE__ */
|
|
731
|
+
return /* @__PURE__ */ jsxs2("g", { children: [
|
|
732
|
+
/* @__PURE__ */ jsx2(
|
|
707
733
|
"rect",
|
|
708
734
|
{
|
|
709
735
|
...common,
|
|
@@ -715,13 +741,13 @@ function ShapeView({
|
|
|
715
741
|
fill: shape.fill
|
|
716
742
|
}
|
|
717
743
|
),
|
|
718
|
-
/* @__PURE__ */
|
|
744
|
+
/* @__PURE__ */ jsx2(BoxTexts, { shape, hideField, showHints })
|
|
719
745
|
] });
|
|
720
746
|
}
|
|
721
747
|
case "ellipse": {
|
|
722
748
|
const b = bbox(shape);
|
|
723
|
-
return /* @__PURE__ */
|
|
724
|
-
/* @__PURE__ */
|
|
749
|
+
return /* @__PURE__ */ jsxs2("g", { children: [
|
|
750
|
+
/* @__PURE__ */ jsx2(
|
|
725
751
|
"ellipse",
|
|
726
752
|
{
|
|
727
753
|
...common,
|
|
@@ -732,13 +758,13 @@ function ShapeView({
|
|
|
732
758
|
fill: shape.fill
|
|
733
759
|
}
|
|
734
760
|
),
|
|
735
|
-
/* @__PURE__ */
|
|
761
|
+
/* @__PURE__ */ jsx2(BoxTexts, { shape, hideField, showHints })
|
|
736
762
|
] });
|
|
737
763
|
}
|
|
738
764
|
case "triangle":
|
|
739
765
|
case "pentagon":
|
|
740
|
-
return /* @__PURE__ */
|
|
741
|
-
/* @__PURE__ */
|
|
766
|
+
return /* @__PURE__ */ jsxs2("g", { children: [
|
|
767
|
+
/* @__PURE__ */ jsx2(
|
|
742
768
|
"polygon",
|
|
743
769
|
{
|
|
744
770
|
...common,
|
|
@@ -746,12 +772,12 @@ function ShapeView({
|
|
|
746
772
|
fill: shape.fill
|
|
747
773
|
}
|
|
748
774
|
),
|
|
749
|
-
/* @__PURE__ */
|
|
775
|
+
/* @__PURE__ */ jsx2(BoxTexts, { shape, hideField, showHints })
|
|
750
776
|
] });
|
|
751
777
|
case "line":
|
|
752
778
|
case "arrow":
|
|
753
|
-
return /* @__PURE__ */
|
|
754
|
-
/* @__PURE__ */
|
|
779
|
+
return /* @__PURE__ */ jsxs2("g", { children: [
|
|
780
|
+
/* @__PURE__ */ jsx2(
|
|
755
781
|
"path",
|
|
756
782
|
{
|
|
757
783
|
...common,
|
|
@@ -759,10 +785,10 @@ function ShapeView({
|
|
|
759
785
|
fill: "none"
|
|
760
786
|
}
|
|
761
787
|
),
|
|
762
|
-
shape.text && hideField !== "text" && /* @__PURE__ */
|
|
788
|
+
shape.text && hideField !== "text" && /* @__PURE__ */ jsx2(ConnectorLabel, { shape })
|
|
763
789
|
] });
|
|
764
790
|
case "text":
|
|
765
|
-
return /* @__PURE__ */
|
|
791
|
+
return /* @__PURE__ */ jsx2(
|
|
766
792
|
"text",
|
|
767
793
|
{
|
|
768
794
|
x: shape.x,
|
|
@@ -771,7 +797,7 @@ function ShapeView({
|
|
|
771
797
|
fontSize: FONT_SIZE,
|
|
772
798
|
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
773
799
|
style: { userSelect: "none", whiteSpace: "pre" },
|
|
774
|
-
children: (shape.text ?? "").split("\n").map((line, i) => /* @__PURE__ */
|
|
800
|
+
children: (shape.text ?? "").split("\n").map((line, i) => /* @__PURE__ */ jsx2("tspan", { x: shape.x, dy: i === 0 ? 0 : FONT_SIZE * 1.35, children: line }, i))
|
|
775
801
|
}
|
|
776
802
|
);
|
|
777
803
|
}
|
|
@@ -783,8 +809,8 @@ function ConnectorLabel({ shape }) {
|
|
|
783
809
|
const { x: midX, y: midY } = connectorMidpoint(shape);
|
|
784
810
|
const lineH = CONNECTOR_FONT_SIZE * LINE_HEIGHT;
|
|
785
811
|
const startY = midY - (lines.length - 1) * lineH / 2 + CONNECTOR_FONT_SIZE * 0.35;
|
|
786
|
-
return /* @__PURE__ */
|
|
787
|
-
/* @__PURE__ */
|
|
812
|
+
return /* @__PURE__ */ jsxs2("g", { children: [
|
|
813
|
+
/* @__PURE__ */ jsx2(
|
|
788
814
|
"rect",
|
|
789
815
|
{
|
|
790
816
|
x: midX - size.w / 2 - 5,
|
|
@@ -796,7 +822,7 @@ function ConnectorLabel({ shape }) {
|
|
|
796
822
|
opacity: 0.92
|
|
797
823
|
}
|
|
798
824
|
),
|
|
799
|
-
lines.map((line, i) => /* @__PURE__ */
|
|
825
|
+
lines.map((line, i) => /* @__PURE__ */ jsx2(
|
|
800
826
|
"text",
|
|
801
827
|
{
|
|
802
828
|
x: midX,
|
|
@@ -813,20 +839,20 @@ function ConnectorLabel({ shape }) {
|
|
|
813
839
|
] });
|
|
814
840
|
}
|
|
815
841
|
var TOOL_ICONS = {
|
|
816
|
-
select: /* @__PURE__ */
|
|
817
|
-
rect: /* @__PURE__ */
|
|
818
|
-
ellipse: /* @__PURE__ */
|
|
819
|
-
triangle: /* @__PURE__ */
|
|
820
|
-
pentagon: /* @__PURE__ */
|
|
821
|
-
arrow: /* @__PURE__ */
|
|
822
|
-
/* @__PURE__ */
|
|
823
|
-
/* @__PURE__ */
|
|
842
|
+
select: /* @__PURE__ */ jsx2("path", { d: "M4 2l12 6.5-5.2 1.6L8 16z", fill: "currentColor", stroke: "none" }),
|
|
843
|
+
rect: /* @__PURE__ */ jsx2("rect", { x: "3", y: "4.5", width: "14", height: "11", rx: "2" }),
|
|
844
|
+
ellipse: /* @__PURE__ */ jsx2("ellipse", { cx: "10", cy: "10", rx: "7", ry: "5.5" }),
|
|
845
|
+
triangle: /* @__PURE__ */ jsx2("path", { d: "M10 3.5L17 16.5H3z", strokeLinejoin: "round" }),
|
|
846
|
+
pentagon: /* @__PURE__ */ jsx2("path", { d: "M10 3L16.8 8.1L14.2 16.2H5.8L3.2 8.1z", strokeLinejoin: "round" }),
|
|
847
|
+
arrow: /* @__PURE__ */ jsxs2("g", { children: [
|
|
848
|
+
/* @__PURE__ */ jsx2("path", { d: "M4 16L16 4" }),
|
|
849
|
+
/* @__PURE__ */ jsx2("path", { d: "M9 4h7v7" })
|
|
824
850
|
] }),
|
|
825
|
-
line: /* @__PURE__ */
|
|
826
|
-
text: /* @__PURE__ */
|
|
827
|
-
/* @__PURE__ */
|
|
828
|
-
/* @__PURE__ */
|
|
829
|
-
/* @__PURE__ */
|
|
851
|
+
line: /* @__PURE__ */ jsx2("path", { d: "M4 16L16 4" }),
|
|
852
|
+
text: /* @__PURE__ */ jsxs2("g", { children: [
|
|
853
|
+
/* @__PURE__ */ jsx2("path", { d: "M4 5V3.5h12V5" }),
|
|
854
|
+
/* @__PURE__ */ jsx2("path", { d: "M10 3.5V16.5" }),
|
|
855
|
+
/* @__PURE__ */ jsx2("path", { d: "M7 16.5h6" })
|
|
830
856
|
] })
|
|
831
857
|
};
|
|
832
858
|
function bindEndpoints(shape, shapes) {
|
|
@@ -849,11 +875,24 @@ var TOOLS = [
|
|
|
849
875
|
{ tool: "line", label: "Line" },
|
|
850
876
|
{ tool: "text", label: "Text" }
|
|
851
877
|
];
|
|
878
|
+
function contentWidth(shapes) {
|
|
879
|
+
let right = 0;
|
|
880
|
+
for (const shape of shapes) {
|
|
881
|
+
if (isConnectorType(shape.type)) {
|
|
882
|
+
for (const p of connectorPoints(shape)) right = Math.max(right, p.x);
|
|
883
|
+
} else {
|
|
884
|
+
const b = bbox(shape);
|
|
885
|
+
right = Math.max(right, b.x + b.w);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
return Math.max(MIN_CONTENT_WIDTH, Math.ceil(right + CONTENT_WIDTH_PADDING));
|
|
889
|
+
}
|
|
852
890
|
function DrawingCanvas({ nodeKey, data }) {
|
|
853
891
|
const [editor] = useLexicalComposerContext5();
|
|
854
892
|
const isEditable = useLexicalEditable();
|
|
855
893
|
const [shapes, setShapes] = useState(data.shapes);
|
|
856
894
|
const [height, setHeight] = useState(data.height);
|
|
895
|
+
const [width, setWidth] = useState(data.width ?? "full");
|
|
857
896
|
const [tool, setTool] = useState("select");
|
|
858
897
|
const [selectedId, setSelectedId] = useState(null);
|
|
859
898
|
const [editingText, setEditingText] = useState(null);
|
|
@@ -866,21 +905,25 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
866
905
|
shapesRef.current = shapes;
|
|
867
906
|
const heightRef = useRef2(height);
|
|
868
907
|
heightRef.current = height;
|
|
908
|
+
const widthRef = useRef2(width);
|
|
909
|
+
widthRef.current = width;
|
|
869
910
|
useEffect5(() => {
|
|
870
911
|
const incoming = serializeDrawingData(data);
|
|
871
912
|
if (incoming !== lastCommittedRef.current) {
|
|
872
913
|
lastCommittedRef.current = incoming;
|
|
873
914
|
setShapes(data.shapes);
|
|
874
915
|
setHeight(data.height);
|
|
916
|
+
setWidth(data.width ?? "full");
|
|
875
917
|
setSelectedId(null);
|
|
876
918
|
setEditingText(null);
|
|
877
919
|
}
|
|
878
920
|
}, [data]);
|
|
879
921
|
const commit = useCallback(
|
|
880
|
-
(nextShapes, nextHeight) => {
|
|
922
|
+
(nextShapes, nextHeight, nextWidth) => {
|
|
881
923
|
const payload = {
|
|
882
924
|
version: 1,
|
|
883
925
|
height: nextHeight ?? heightRef.current,
|
|
926
|
+
width: (nextWidth ?? widthRef.current) === "content" ? "content" : void 0,
|
|
884
927
|
shapes: nextShapes
|
|
885
928
|
};
|
|
886
929
|
const json = serializeDrawingData(payload);
|
|
@@ -895,6 +938,13 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
895
938
|
},
|
|
896
939
|
[editor, nodeKey]
|
|
897
940
|
);
|
|
941
|
+
const applyWidth = useCallback(
|
|
942
|
+
(next) => {
|
|
943
|
+
setWidth(next);
|
|
944
|
+
commit(shapesRef.current, void 0, next);
|
|
945
|
+
},
|
|
946
|
+
[commit]
|
|
947
|
+
);
|
|
898
948
|
const updateShapes = useCallback(
|
|
899
949
|
(updater, options) => {
|
|
900
950
|
setShapes((prev) => {
|
|
@@ -1299,15 +1349,15 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1299
1349
|
const editingShape = shapes.find((s) => s.id === editingText?.id) ?? null;
|
|
1300
1350
|
const showFill = selectedShape != null ? isBoxType(selectedShape.type) : tool !== "select" && isBoxType(tool);
|
|
1301
1351
|
const canvasCursor = tool === "select" ? "default" : tool === "text" ? "text" : "crosshair";
|
|
1302
|
-
return /* @__PURE__ */
|
|
1352
|
+
return /* @__PURE__ */ jsxs2(
|
|
1303
1353
|
"div",
|
|
1304
1354
|
{
|
|
1305
|
-
className:
|
|
1355
|
+
className: `zui-drawing-canvas ${width === "content" ? "is-content-width" : ""}`,
|
|
1306
1356
|
tabIndex: isEditable ? 0 : void 0,
|
|
1307
1357
|
onKeyDown: handleKeyDown,
|
|
1308
1358
|
children: [
|
|
1309
|
-
isEditable && /* @__PURE__ */
|
|
1310
|
-
/* @__PURE__ */
|
|
1359
|
+
isEditable && /* @__PURE__ */ jsxs2("div", { className: "zui-drawing-toolbar", onPointerDown: (e) => e.stopPropagation(), children: [
|
|
1360
|
+
/* @__PURE__ */ jsx2("div", { className: "zui-drawing-toolbar-group", children: TOOLS.map(({ tool: t, label }) => /* @__PURE__ */ jsx2(
|
|
1311
1361
|
"button",
|
|
1312
1362
|
{
|
|
1313
1363
|
type: "button",
|
|
@@ -1318,7 +1368,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1318
1368
|
setTool(t);
|
|
1319
1369
|
if (t !== "select") setSelectedId(null);
|
|
1320
1370
|
},
|
|
1321
|
-
children: /* @__PURE__ */
|
|
1371
|
+
children: /* @__PURE__ */ jsx2(
|
|
1322
1372
|
"svg",
|
|
1323
1373
|
{
|
|
1324
1374
|
viewBox: "0 0 20 20",
|
|
@@ -1335,9 +1385,9 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1335
1385
|
},
|
|
1336
1386
|
t
|
|
1337
1387
|
)) }),
|
|
1338
|
-
/* @__PURE__ */
|
|
1339
|
-
/* @__PURE__ */
|
|
1340
|
-
STROKE_COLORS.map((color) => /* @__PURE__ */
|
|
1388
|
+
/* @__PURE__ */ jsxs2("div", { className: "zui-drawing-toolbar-group", children: [
|
|
1389
|
+
/* @__PURE__ */ jsx2("span", { className: "zui-drawing-swatch-label", children: "Stroke" }),
|
|
1390
|
+
STROKE_COLORS.map((color) => /* @__PURE__ */ jsx2(
|
|
1341
1391
|
"button",
|
|
1342
1392
|
{
|
|
1343
1393
|
type: "button",
|
|
@@ -1350,9 +1400,9 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1350
1400
|
color
|
|
1351
1401
|
))
|
|
1352
1402
|
] }),
|
|
1353
|
-
showFill && /* @__PURE__ */
|
|
1354
|
-
/* @__PURE__ */
|
|
1355
|
-
FILL_COLORS.map((color) => /* @__PURE__ */
|
|
1403
|
+
showFill && /* @__PURE__ */ jsxs2("div", { className: "zui-drawing-toolbar-group", children: [
|
|
1404
|
+
/* @__PURE__ */ jsx2("span", { className: "zui-drawing-swatch-label", children: "Fill" }),
|
|
1405
|
+
FILL_COLORS.map((color) => /* @__PURE__ */ jsx2(
|
|
1356
1406
|
"button",
|
|
1357
1407
|
{
|
|
1358
1408
|
type: "button",
|
|
@@ -1365,8 +1415,8 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1365
1415
|
color
|
|
1366
1416
|
))
|
|
1367
1417
|
] }),
|
|
1368
|
-
selectedShape && isConnectorType(selectedShape.type) && /* @__PURE__ */
|
|
1369
|
-
/* @__PURE__ */
|
|
1418
|
+
selectedShape && isConnectorType(selectedShape.type) && /* @__PURE__ */ jsxs2("div", { className: "zui-drawing-toolbar-group", children: [
|
|
1419
|
+
/* @__PURE__ */ jsx2(
|
|
1370
1420
|
"button",
|
|
1371
1421
|
{
|
|
1372
1422
|
type: "button",
|
|
@@ -1374,7 +1424,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1374
1424
|
"aria-label": "Straight connector",
|
|
1375
1425
|
className: `zui-drawing-tool ${selectedShape.routing !== "elbow" ? "is-active" : ""}`,
|
|
1376
1426
|
onClick: () => applyRouting(false),
|
|
1377
|
-
children: /* @__PURE__ */
|
|
1427
|
+
children: /* @__PURE__ */ jsx2(
|
|
1378
1428
|
"svg",
|
|
1379
1429
|
{
|
|
1380
1430
|
viewBox: "0 0 20 20",
|
|
@@ -1384,12 +1434,12 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1384
1434
|
stroke: "currentColor",
|
|
1385
1435
|
strokeWidth: "1.6",
|
|
1386
1436
|
strokeLinecap: "round",
|
|
1387
|
-
children: /* @__PURE__ */
|
|
1437
|
+
children: /* @__PURE__ */ jsx2("path", { d: "M4 16L16 4" })
|
|
1388
1438
|
}
|
|
1389
1439
|
)
|
|
1390
1440
|
}
|
|
1391
1441
|
),
|
|
1392
|
-
/* @__PURE__ */
|
|
1442
|
+
/* @__PURE__ */ jsx2(
|
|
1393
1443
|
"button",
|
|
1394
1444
|
{
|
|
1395
1445
|
type: "button",
|
|
@@ -1397,7 +1447,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1397
1447
|
"aria-label": "Elbow connector",
|
|
1398
1448
|
className: `zui-drawing-tool ${selectedShape.routing === "elbow" ? "is-active" : ""}`,
|
|
1399
1449
|
onClick: () => applyRouting(true),
|
|
1400
|
-
children: /* @__PURE__ */
|
|
1450
|
+
children: /* @__PURE__ */ jsx2(
|
|
1401
1451
|
"svg",
|
|
1402
1452
|
{
|
|
1403
1453
|
viewBox: "0 0 20 20",
|
|
@@ -1408,14 +1458,14 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1408
1458
|
strokeWidth: "1.6",
|
|
1409
1459
|
strokeLinecap: "round",
|
|
1410
1460
|
strokeLinejoin: "round",
|
|
1411
|
-
children: /* @__PURE__ */
|
|
1461
|
+
children: /* @__PURE__ */ jsx2("path", { d: "M4 16v-6h12V4" })
|
|
1412
1462
|
}
|
|
1413
1463
|
)
|
|
1414
1464
|
}
|
|
1415
1465
|
)
|
|
1416
1466
|
] }),
|
|
1417
|
-
selectedShape?.type === "arrow" && /* @__PURE__ */
|
|
1418
|
-
/* @__PURE__ */
|
|
1467
|
+
selectedShape?.type === "arrow" && /* @__PURE__ */ jsxs2("div", { className: "zui-drawing-toolbar-group", children: [
|
|
1468
|
+
/* @__PURE__ */ jsx2(
|
|
1419
1469
|
"button",
|
|
1420
1470
|
{
|
|
1421
1471
|
type: "button",
|
|
@@ -1423,7 +1473,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1423
1473
|
"aria-label": "One-way arrow",
|
|
1424
1474
|
className: `zui-drawing-tool ${!selectedShape.bidirectional ? "is-active" : ""}`,
|
|
1425
1475
|
onClick: () => applyDirection(false),
|
|
1426
|
-
children: /* @__PURE__ */
|
|
1476
|
+
children: /* @__PURE__ */ jsx2(
|
|
1427
1477
|
"svg",
|
|
1428
1478
|
{
|
|
1429
1479
|
viewBox: "0 0 20 20",
|
|
@@ -1434,12 +1484,12 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1434
1484
|
strokeWidth: "1.6",
|
|
1435
1485
|
strokeLinecap: "round",
|
|
1436
1486
|
strokeLinejoin: "round",
|
|
1437
|
-
children: /* @__PURE__ */
|
|
1487
|
+
children: /* @__PURE__ */ jsx2("path", { d: "M3 10h13M12 5.5L16.5 10L12 14.5" })
|
|
1438
1488
|
}
|
|
1439
1489
|
)
|
|
1440
1490
|
}
|
|
1441
1491
|
),
|
|
1442
|
-
/* @__PURE__ */
|
|
1492
|
+
/* @__PURE__ */ jsx2(
|
|
1443
1493
|
"button",
|
|
1444
1494
|
{
|
|
1445
1495
|
type: "button",
|
|
@@ -1447,7 +1497,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1447
1497
|
"aria-label": "Two-way arrow",
|
|
1448
1498
|
className: `zui-drawing-tool ${selectedShape.bidirectional ? "is-active" : ""}`,
|
|
1449
1499
|
onClick: () => applyDirection(true),
|
|
1450
|
-
children: /* @__PURE__ */
|
|
1500
|
+
children: /* @__PURE__ */ jsx2(
|
|
1451
1501
|
"svg",
|
|
1452
1502
|
{
|
|
1453
1503
|
viewBox: "0 0 20 20",
|
|
@@ -1458,13 +1508,13 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1458
1508
|
strokeWidth: "1.6",
|
|
1459
1509
|
strokeLinecap: "round",
|
|
1460
1510
|
strokeLinejoin: "round",
|
|
1461
|
-
children: /* @__PURE__ */
|
|
1511
|
+
children: /* @__PURE__ */ jsx2("path", { d: "M3.5 10h13M8 5.5L3.5 10L8 14.5M12 5.5L16.5 10L12 14.5" })
|
|
1462
1512
|
}
|
|
1463
1513
|
)
|
|
1464
1514
|
}
|
|
1465
1515
|
)
|
|
1466
1516
|
] }),
|
|
1467
|
-
selectedShape && /* @__PURE__ */
|
|
1517
|
+
selectedShape && /* @__PURE__ */ jsx2("div", { className: "zui-drawing-toolbar-group", children: /* @__PURE__ */ jsx2(
|
|
1468
1518
|
"button",
|
|
1469
1519
|
{
|
|
1470
1520
|
type: "button",
|
|
@@ -1472,7 +1522,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1472
1522
|
"aria-label": "Delete shape",
|
|
1473
1523
|
className: "zui-drawing-tool zui-drawing-tool-danger",
|
|
1474
1524
|
onClick: deleteSelected,
|
|
1475
|
-
children: /* @__PURE__ */
|
|
1525
|
+
children: /* @__PURE__ */ jsx2(
|
|
1476
1526
|
"svg",
|
|
1477
1527
|
{
|
|
1478
1528
|
viewBox: "0 0 20 20",
|
|
@@ -1482,18 +1532,48 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1482
1532
|
stroke: "currentColor",
|
|
1483
1533
|
strokeWidth: "1.6",
|
|
1484
1534
|
strokeLinecap: "round",
|
|
1485
|
-
children: /* @__PURE__ */
|
|
1535
|
+
children: /* @__PURE__ */ jsx2("path", { d: "M4 6h12M8 6V4h4v2M6 6l1 10h6l1-10M8.5 9v4M11.5 9v4" })
|
|
1486
1536
|
}
|
|
1487
1537
|
)
|
|
1488
1538
|
}
|
|
1489
|
-
) })
|
|
1539
|
+
) }),
|
|
1540
|
+
/* @__PURE__ */ jsx2("div", { className: "zui-drawing-toolbar-group zui-drawing-toolbar-group-end", children: BLOCK_WIDTH_OPTIONS.map(({ width: option, label, icon }) => /* @__PURE__ */ jsx2(
|
|
1541
|
+
"button",
|
|
1542
|
+
{
|
|
1543
|
+
type: "button",
|
|
1544
|
+
title: label,
|
|
1545
|
+
"aria-label": label,
|
|
1546
|
+
"aria-pressed": width === option,
|
|
1547
|
+
className: `zui-drawing-tool ${width === option ? "is-active" : ""}`,
|
|
1548
|
+
onClick: () => applyWidth(option),
|
|
1549
|
+
children: /* @__PURE__ */ jsx2(
|
|
1550
|
+
"svg",
|
|
1551
|
+
{
|
|
1552
|
+
viewBox: "0 0 20 20",
|
|
1553
|
+
width: "16",
|
|
1554
|
+
height: "16",
|
|
1555
|
+
fill: "none",
|
|
1556
|
+
stroke: "currentColor",
|
|
1557
|
+
strokeWidth: "1.6",
|
|
1558
|
+
strokeLinecap: "round",
|
|
1559
|
+
strokeLinejoin: "round",
|
|
1560
|
+
children: icon
|
|
1561
|
+
}
|
|
1562
|
+
)
|
|
1563
|
+
},
|
|
1564
|
+
option
|
|
1565
|
+
)) })
|
|
1490
1566
|
] }),
|
|
1491
|
-
/* @__PURE__ */
|
|
1567
|
+
/* @__PURE__ */ jsxs2(
|
|
1492
1568
|
"svg",
|
|
1493
1569
|
{
|
|
1494
1570
|
ref: svgRef,
|
|
1495
1571
|
className: "zui-drawing-surface",
|
|
1496
|
-
style: {
|
|
1572
|
+
style: {
|
|
1573
|
+
height,
|
|
1574
|
+
width: width === "content" ? contentWidth(shapes) : void 0,
|
|
1575
|
+
cursor: canvasCursor
|
|
1576
|
+
},
|
|
1497
1577
|
onPointerDown: handleBackgroundPointerDown,
|
|
1498
1578
|
onPointerMove: handlePointerMove,
|
|
1499
1579
|
onPointerUp: handlePointerUp,
|
|
@@ -1515,7 +1595,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1515
1595
|
}
|
|
1516
1596
|
},
|
|
1517
1597
|
children: [
|
|
1518
|
-
shapes.map((shape) => /* @__PURE__ */
|
|
1598
|
+
shapes.map((shape) => /* @__PURE__ */ jsxs2(
|
|
1519
1599
|
"g",
|
|
1520
1600
|
{
|
|
1521
1601
|
"data-shape-id": shape.id,
|
|
@@ -1524,7 +1604,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1524
1604
|
},
|
|
1525
1605
|
onPointerDown: (e) => handleShapePointerDown(e, shape),
|
|
1526
1606
|
children: [
|
|
1527
|
-
isConnectorType(shape.type) && /* @__PURE__ */
|
|
1607
|
+
isConnectorType(shape.type) && /* @__PURE__ */ jsx2(
|
|
1528
1608
|
"path",
|
|
1529
1609
|
{
|
|
1530
1610
|
d: connectorPath(shape),
|
|
@@ -1533,8 +1613,8 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1533
1613
|
strokeWidth: 14
|
|
1534
1614
|
}
|
|
1535
1615
|
),
|
|
1536
|
-
(isBoxType(shape.type) || shape.type === "text") && /* @__PURE__ */
|
|
1537
|
-
shape.id === editingText?.id && shape.type === "text" ? null : /* @__PURE__ */
|
|
1616
|
+
(isBoxType(shape.type) || shape.type === "text") && /* @__PURE__ */ jsx2(HitArea, { shape }),
|
|
1617
|
+
shape.id === editingText?.id && shape.type === "text" ? null : /* @__PURE__ */ jsx2(
|
|
1538
1618
|
ShapeView,
|
|
1539
1619
|
{
|
|
1540
1620
|
shape,
|
|
@@ -1546,7 +1626,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1546
1626
|
},
|
|
1547
1627
|
shape.id
|
|
1548
1628
|
)),
|
|
1549
|
-
selectedShape && isEditable && !editingText && /* @__PURE__ */
|
|
1629
|
+
selectedShape && isEditable && !editingText && /* @__PURE__ */ jsx2(
|
|
1550
1630
|
SelectionOverlay,
|
|
1551
1631
|
{
|
|
1552
1632
|
shape: selectedShape,
|
|
@@ -1558,7 +1638,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1558
1638
|
]
|
|
1559
1639
|
}
|
|
1560
1640
|
),
|
|
1561
|
-
editingShape && editingText && /* @__PURE__ */
|
|
1641
|
+
editingShape && editingText && /* @__PURE__ */ jsx2(
|
|
1562
1642
|
TextEditOverlay,
|
|
1563
1643
|
{
|
|
1564
1644
|
shape: editingShape,
|
|
@@ -1567,7 +1647,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1567
1647
|
},
|
|
1568
1648
|
`${editingShape.id}:${editingText.field}`
|
|
1569
1649
|
),
|
|
1570
|
-
isEditable && /* @__PURE__ */
|
|
1650
|
+
isEditable && /* @__PURE__ */ jsx2(
|
|
1571
1651
|
"div",
|
|
1572
1652
|
{
|
|
1573
1653
|
className: "zui-drawing-resize",
|
|
@@ -1606,7 +1686,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
1606
1686
|
}
|
|
1607
1687
|
function HitArea({ shape }) {
|
|
1608
1688
|
const b = bbox(shape);
|
|
1609
|
-
return /* @__PURE__ */
|
|
1689
|
+
return /* @__PURE__ */ jsx2(
|
|
1610
1690
|
"rect",
|
|
1611
1691
|
{
|
|
1612
1692
|
x: b.x,
|
|
@@ -1640,8 +1720,8 @@ function SelectionOverlay({
|
|
|
1640
1720
|
if (hasElbowHandle && i === 1) return [];
|
|
1641
1721
|
return [{ index: i, x: (p.x + q.x) / 2, y: (p.y + q.y) / 2 }];
|
|
1642
1722
|
});
|
|
1643
|
-
return /* @__PURE__ */
|
|
1644
|
-
ghosts.map(({ index, x, y }) => /* @__PURE__ */
|
|
1723
|
+
return /* @__PURE__ */ jsxs2("g", { children: [
|
|
1724
|
+
ghosts.map(({ index, x, y }) => /* @__PURE__ */ jsx2(
|
|
1645
1725
|
"circle",
|
|
1646
1726
|
{
|
|
1647
1727
|
cx: x,
|
|
@@ -1654,11 +1734,11 @@ function SelectionOverlay({
|
|
|
1654
1734
|
opacity: 0.6,
|
|
1655
1735
|
style: { cursor: "copy" },
|
|
1656
1736
|
onPointerDown: (e) => onWaypointAdd(e, shape.id, index, { x, y }),
|
|
1657
|
-
children: /* @__PURE__ */
|
|
1737
|
+
children: /* @__PURE__ */ jsx2("title", { children: "Drag to add a point" })
|
|
1658
1738
|
},
|
|
1659
1739
|
`ghost-${index}`
|
|
1660
1740
|
)),
|
|
1661
|
-
waypoints.map((p, i) => /* @__PURE__ */
|
|
1741
|
+
waypoints.map((p, i) => /* @__PURE__ */ jsx2(
|
|
1662
1742
|
"rect",
|
|
1663
1743
|
{
|
|
1664
1744
|
x: p.x - 4,
|
|
@@ -1679,11 +1759,11 @@ function SelectionOverlay({
|
|
|
1679
1759
|
e.stopPropagation();
|
|
1680
1760
|
onWaypointRemove(shape.id, i);
|
|
1681
1761
|
},
|
|
1682
|
-
children: /* @__PURE__ */
|
|
1762
|
+
children: /* @__PURE__ */ jsx2("title", { children: "Drag to move, double-click to remove" })
|
|
1683
1763
|
},
|
|
1684
1764
|
`wp-${i}`
|
|
1685
1765
|
)),
|
|
1686
|
-
ends.map(({ end, x, y }) => /* @__PURE__ */
|
|
1766
|
+
ends.map(({ end, x, y }) => /* @__PURE__ */ jsx2(
|
|
1687
1767
|
"circle",
|
|
1688
1768
|
{
|
|
1689
1769
|
cx: x,
|
|
@@ -1702,7 +1782,7 @@ function SelectionOverlay({
|
|
|
1702
1782
|
},
|
|
1703
1783
|
end
|
|
1704
1784
|
)),
|
|
1705
|
-
elbowMid && /* @__PURE__ */
|
|
1785
|
+
elbowMid && /* @__PURE__ */ jsx2(
|
|
1706
1786
|
"rect",
|
|
1707
1787
|
{
|
|
1708
1788
|
x: elbowMid.x - 4,
|
|
@@ -1732,8 +1812,8 @@ function SelectionOverlay({
|
|
|
1732
1812
|
{ corner: "se", x: b.x + b.w + pad, y: b.y + b.h + pad }
|
|
1733
1813
|
];
|
|
1734
1814
|
const resizable = shape.type !== "text";
|
|
1735
|
-
return /* @__PURE__ */
|
|
1736
|
-
/* @__PURE__ */
|
|
1815
|
+
return /* @__PURE__ */ jsxs2("g", { children: [
|
|
1816
|
+
/* @__PURE__ */ jsx2(
|
|
1737
1817
|
"rect",
|
|
1738
1818
|
{
|
|
1739
1819
|
x: b.x - pad,
|
|
@@ -1747,7 +1827,7 @@ function SelectionOverlay({
|
|
|
1747
1827
|
pointerEvents: "none"
|
|
1748
1828
|
}
|
|
1749
1829
|
),
|
|
1750
|
-
resizable && corners.map(({ corner, x, y }) => /* @__PURE__ */
|
|
1830
|
+
resizable && corners.map(({ corner, x, y }) => /* @__PURE__ */ jsx2(
|
|
1751
1831
|
"rect",
|
|
1752
1832
|
{
|
|
1753
1833
|
x: x - 4,
|
|
@@ -1823,7 +1903,7 @@ function TextEditOverlay({
|
|
|
1823
1903
|
});
|
|
1824
1904
|
}
|
|
1825
1905
|
const placeholder = field === "label" ? "Label" : field === "footer" ? "Footer" : "Text";
|
|
1826
|
-
return /* @__PURE__ */
|
|
1906
|
+
return /* @__PURE__ */ jsx2(
|
|
1827
1907
|
"textarea",
|
|
1828
1908
|
{
|
|
1829
1909
|
ref,
|
|
@@ -1849,7 +1929,7 @@ function TextEditOverlay({
|
|
|
1849
1929
|
}
|
|
1850
1930
|
|
|
1851
1931
|
// src/nodes/DrawingNode.tsx
|
|
1852
|
-
import { jsx as
|
|
1932
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1853
1933
|
var DrawingNode = class _DrawingNode extends DecoratorNode {
|
|
1854
1934
|
static getType() {
|
|
1855
1935
|
return "drawing";
|
|
@@ -1913,7 +1993,7 @@ var DrawingNode = class _DrawingNode extends DecoratorNode {
|
|
|
1913
1993
|
return false;
|
|
1914
1994
|
}
|
|
1915
1995
|
decorate(_editor, _config) {
|
|
1916
|
-
return /* @__PURE__ */
|
|
1996
|
+
return /* @__PURE__ */ jsx3(DrawingCanvas, { nodeKey: this.getKey(), data: this.getData() });
|
|
1917
1997
|
}
|
|
1918
1998
|
};
|
|
1919
1999
|
function $createDrawingNode(data = serializeDrawingData(EMPTY_DRAWING)) {
|
|
@@ -1958,15 +2038,150 @@ import {
|
|
|
1958
2038
|
$createTableNode,
|
|
1959
2039
|
$createTableRowNode,
|
|
1960
2040
|
$isTableCellNode,
|
|
1961
|
-
$isTableNode,
|
|
2041
|
+
$isTableNode as $isTableNode2,
|
|
1962
2042
|
$isTableRowNode,
|
|
1963
2043
|
TableCellHeaderStates,
|
|
1964
2044
|
TableCellNode,
|
|
1965
2045
|
TableNode,
|
|
1966
2046
|
TableRowNode
|
|
1967
2047
|
} from "@lexical/table";
|
|
2048
|
+
|
|
2049
|
+
// src/transformers/tableSettings.ts
|
|
2050
|
+
import {
|
|
2051
|
+
$getNodeByKey as $getNodeByKey3,
|
|
2052
|
+
$getSelection as $getSelection2,
|
|
2053
|
+
$isRangeSelection as $isRangeSelection2
|
|
2054
|
+
} from "lexical";
|
|
2055
|
+
import { $findMatchingParent } from "@lexical/utils";
|
|
2056
|
+
import { $isTableNode, $isTableSelection } from "@lexical/table";
|
|
2057
|
+
var DEFAULT_TABLE_SETTINGS = {
|
|
2058
|
+
width: "full",
|
|
2059
|
+
density: "comfortable"
|
|
2060
|
+
};
|
|
2061
|
+
var OPTION_DECLARATIONS = {
|
|
2062
|
+
width: {
|
|
2063
|
+
full: {},
|
|
2064
|
+
content: { width: "auto", "table-layout": "auto" }
|
|
2065
|
+
},
|
|
2066
|
+
density: {
|
|
2067
|
+
comfortable: {},
|
|
2068
|
+
compact: {
|
|
2069
|
+
"--zui-table-cell-padding": "0.25rem 0.5rem",
|
|
2070
|
+
"--zui-table-font-size": "0.8125rem"
|
|
2071
|
+
},
|
|
2072
|
+
spacious: {
|
|
2073
|
+
"--zui-table-cell-padding": "0.875rem 1rem",
|
|
2074
|
+
"--zui-table-font-size": "0.9375rem"
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
};
|
|
2078
|
+
var SETTING_KEYS = Object.keys(OPTION_DECLARATIONS);
|
|
2079
|
+
function parseStyle(style) {
|
|
2080
|
+
const declarations = /* @__PURE__ */ new Map();
|
|
2081
|
+
for (const part of style.split(";")) {
|
|
2082
|
+
const index = part.indexOf(":");
|
|
2083
|
+
if (index === -1) continue;
|
|
2084
|
+
const key = part.slice(0, index).trim();
|
|
2085
|
+
const value = part.slice(index + 1).trim();
|
|
2086
|
+
if (key && value) declarations.set(key, value);
|
|
2087
|
+
}
|
|
2088
|
+
return declarations;
|
|
2089
|
+
}
|
|
2090
|
+
function serializeStyle(declarations) {
|
|
2091
|
+
return [...declarations].map(([key, value]) => `${key}: ${value}`).join("; ");
|
|
2092
|
+
}
|
|
2093
|
+
function optionsOf(setting) {
|
|
2094
|
+
return Object.entries(OPTION_DECLARATIONS[setting]);
|
|
2095
|
+
}
|
|
2096
|
+
function readSetting(declarations, setting) {
|
|
2097
|
+
for (const [option, decls] of optionsOf(setting)) {
|
|
2098
|
+
const entries = Object.entries(decls);
|
|
2099
|
+
if (entries.length === 0) continue;
|
|
2100
|
+
if (entries.every(([key, value]) => declarations.get(key) === value)) {
|
|
2101
|
+
return option;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
return DEFAULT_TABLE_SETTINGS[setting];
|
|
2105
|
+
}
|
|
2106
|
+
function writeSetting(declarations, setting, option) {
|
|
2107
|
+
for (const [, decls] of optionsOf(setting)) {
|
|
2108
|
+
for (const key of Object.keys(decls)) declarations.delete(key);
|
|
2109
|
+
}
|
|
2110
|
+
for (const [key, value] of Object.entries(OPTION_DECLARATIONS[setting][option])) {
|
|
2111
|
+
declarations.set(key, value);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
function $getTableSettings(table) {
|
|
2115
|
+
const declarations = parseStyle(table.getStyle());
|
|
2116
|
+
return {
|
|
2117
|
+
width: readSetting(declarations, "width"),
|
|
2118
|
+
density: readSetting(declarations, "density")
|
|
2119
|
+
};
|
|
2120
|
+
}
|
|
2121
|
+
function $setTableSettings(table, settings) {
|
|
2122
|
+
const declarations = parseStyle(table.getStyle());
|
|
2123
|
+
for (const key of SETTING_KEYS) {
|
|
2124
|
+
const option = settings[key];
|
|
2125
|
+
if (option !== void 0) writeSetting(declarations, key, option);
|
|
2126
|
+
}
|
|
2127
|
+
table.setStyle(serializeStyle(declarations));
|
|
2128
|
+
}
|
|
2129
|
+
function $getTableWidth(table) {
|
|
2130
|
+
return $getTableSettings(table).width;
|
|
2131
|
+
}
|
|
2132
|
+
function $setTableWidth(table, width) {
|
|
2133
|
+
$setTableSettings(table, { width });
|
|
2134
|
+
}
|
|
2135
|
+
function $getTableDensity(table) {
|
|
2136
|
+
return $getTableSettings(table).density;
|
|
2137
|
+
}
|
|
2138
|
+
function $setTableDensity(table, density) {
|
|
2139
|
+
$setTableSettings(table, { density });
|
|
2140
|
+
}
|
|
2141
|
+
function $getSelectedTable() {
|
|
2142
|
+
const selection = $getSelection2();
|
|
2143
|
+
if ($isTableSelection(selection)) {
|
|
2144
|
+
const node = $getNodeByKey3(selection.tableKey);
|
|
2145
|
+
return $isTableNode(node) ? node : null;
|
|
2146
|
+
}
|
|
2147
|
+
if (!$isRangeSelection2(selection)) return null;
|
|
2148
|
+
const table = $findMatchingParent(
|
|
2149
|
+
selection.anchor.getNode(),
|
|
2150
|
+
(node) => $isTableNode(node)
|
|
2151
|
+
);
|
|
2152
|
+
return $isTableNode(table) ? table : null;
|
|
2153
|
+
}
|
|
2154
|
+
var MARKER_REG_EXP = /^<!--\s*([a-z]+\s*:\s*[a-z]+(?:\s*;\s*[a-z]+\s*:\s*[a-z]+)*)\s*;?\s*-->\s*$/;
|
|
2155
|
+
function isOption(setting, value) {
|
|
2156
|
+
return value in OPTION_DECLARATIONS[setting];
|
|
2157
|
+
}
|
|
2158
|
+
var TABLE_WIDTH_MARKER = "<!-- width: content -->";
|
|
2159
|
+
function parseTableSettingsMarker(text) {
|
|
2160
|
+
const match = MARKER_REG_EXP.exec(text);
|
|
2161
|
+
if (!match) return null;
|
|
2162
|
+
const settings = {};
|
|
2163
|
+
for (const pair of match[1].split(";")) {
|
|
2164
|
+
const [key, value] = pair.split(":").map((s) => s.trim());
|
|
2165
|
+
if (key === "width" && isOption("width", value)) settings.width = value;
|
|
2166
|
+
if (key === "density" && isOption("density", value)) settings.density = value;
|
|
2167
|
+
}
|
|
2168
|
+
return Object.keys(settings).length > 0 ? settings : null;
|
|
2169
|
+
}
|
|
2170
|
+
function formatTableSettingsMarker(settings) {
|
|
2171
|
+
const pairs = SETTING_KEYS.filter(
|
|
2172
|
+
(key) => settings[key] !== DEFAULT_TABLE_SETTINGS[key]
|
|
2173
|
+
).map((key) => `${key}: ${settings[key]}`);
|
|
2174
|
+
return pairs.length > 0 ? `<!-- ${pairs.join("; ")} -->` : null;
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
// src/transformers/tableTransformer.ts
|
|
1968
2178
|
var TABLE_ROW_REG_EXP = /^\|(.+)\|\s?$/;
|
|
1969
2179
|
var TABLE_ROW_DIVIDER_REG_EXP = /^(\| ?:?-*:? ?)+\|\s?$/;
|
|
2180
|
+
function $getMarkerSettings(node) {
|
|
2181
|
+
if (!$isParagraphNode2(node) || node.getChildrenSize() !== 1) return null;
|
|
2182
|
+
const child = node.getFirstChild();
|
|
2183
|
+
return $isTextNode(child) ? parseTableSettingsMarker(child.getTextContent()) : null;
|
|
2184
|
+
}
|
|
1970
2185
|
function getTableColumnsSize(table) {
|
|
1971
2186
|
const row = table.getFirstChild();
|
|
1972
2187
|
return $isTableRowNode(row) ? row.getChildrenSize() : 0;
|
|
@@ -1985,8 +2200,10 @@ function mapToTableCells(textContent) {
|
|
|
1985
2200
|
var TABLE = {
|
|
1986
2201
|
dependencies: [TableNode, TableRowNode, TableCellNode],
|
|
1987
2202
|
export: (node) => {
|
|
1988
|
-
if (!$
|
|
2203
|
+
if (!$isTableNode2(node)) return null;
|
|
1989
2204
|
const output = [];
|
|
2205
|
+
const marker = formatTableSettingsMarker($getTableSettings(node));
|
|
2206
|
+
if (marker) output.push(marker);
|
|
1990
2207
|
for (const row of node.getChildren()) {
|
|
1991
2208
|
if (!$isTableRowNode(row)) continue;
|
|
1992
2209
|
const rowOutput = [];
|
|
@@ -2011,7 +2228,7 @@ var TABLE = {
|
|
|
2011
2228
|
replace: (parentNode, _children, match) => {
|
|
2012
2229
|
if (TABLE_ROW_DIVIDER_REG_EXP.test(match[0])) {
|
|
2013
2230
|
const table2 = parentNode.getPreviousSibling();
|
|
2014
|
-
if (!table2 || !$
|
|
2231
|
+
if (!table2 || !$isTableNode2(table2)) return;
|
|
2015
2232
|
const lastRow = table2.getLastChild();
|
|
2016
2233
|
if (!lastRow || !$isTableRowNode(lastRow)) return;
|
|
2017
2234
|
lastRow.getChildren().forEach((cell) => {
|
|
@@ -2048,10 +2265,15 @@ var TABLE = {
|
|
|
2048
2265
|
}
|
|
2049
2266
|
}
|
|
2050
2267
|
const previousSibling = parentNode.getPreviousSibling();
|
|
2051
|
-
if ($
|
|
2268
|
+
if ($isTableNode2(previousSibling) && getTableColumnsSize(previousSibling) === maxCells) {
|
|
2052
2269
|
previousSibling.append(...table.getChildren());
|
|
2053
2270
|
parentNode.remove();
|
|
2054
2271
|
} else {
|
|
2272
|
+
const markerSettings = $getMarkerSettings(previousSibling);
|
|
2273
|
+
if (markerSettings) {
|
|
2274
|
+
$setTableSettings(table, markerSettings);
|
|
2275
|
+
previousSibling?.remove();
|
|
2276
|
+
}
|
|
2055
2277
|
parentNode.replace(table);
|
|
2056
2278
|
}
|
|
2057
2279
|
table.selectEnd();
|
|
@@ -2139,7 +2361,7 @@ var editorTheme = {
|
|
|
2139
2361
|
};
|
|
2140
2362
|
|
|
2141
2363
|
// src/EditorRoot.tsx
|
|
2142
|
-
import { Fragment, jsx as
|
|
2364
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2143
2365
|
var SYNC_TRANSFORMERS = [FRONTMATTER, DRAWING, CHECK_LIST, TABLE, ...TRANSFORMERS2];
|
|
2144
2366
|
var SHORTCUT_TRANSFORMERS = [TABLE, ...TRANSFORMERS2.filter((t) => t !== CODE)];
|
|
2145
2367
|
var EditorContext = createContext(null);
|
|
@@ -2229,10 +2451,10 @@ function EditorRoot({
|
|
|
2229
2451
|
[mode, readOnly, autoFocus, value, handleChange]
|
|
2230
2452
|
);
|
|
2231
2453
|
const isRaw = mode === "edit-raw";
|
|
2232
|
-
return /* @__PURE__ */
|
|
2454
|
+
return /* @__PURE__ */ jsx4(LexicalComposer, { initialConfig, children: /* @__PURE__ */ jsx4(EditorContext.Provider, { value: context, children: /* @__PURE__ */ jsxs3("div", { className: `zui-text-editor ${className ?? ""}`, children: [
|
|
2233
2455
|
children,
|
|
2234
|
-
!isRaw && /* @__PURE__ */
|
|
2235
|
-
/* @__PURE__ */
|
|
2456
|
+
!isRaw && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
2457
|
+
/* @__PURE__ */ jsx4(
|
|
2236
2458
|
MarkdownSyncPlugin,
|
|
2237
2459
|
{
|
|
2238
2460
|
initialMarkdown: mode === "view" ? value ?? "" : capturedMarkdown,
|
|
@@ -2240,17 +2462,17 @@ function EditorRoot({
|
|
|
2240
2462
|
transformers: SYNC_TRANSFORMERS
|
|
2241
2463
|
}
|
|
2242
2464
|
),
|
|
2243
|
-
/* @__PURE__ */
|
|
2244
|
-
/* @__PURE__ */
|
|
2245
|
-
/* @__PURE__ */
|
|
2246
|
-
/* @__PURE__ */
|
|
2247
|
-
/* @__PURE__ */
|
|
2248
|
-
/* @__PURE__ */
|
|
2249
|
-
/* @__PURE__ */
|
|
2250
|
-
/* @__PURE__ */
|
|
2251
|
-
/* @__PURE__ */
|
|
2252
|
-
/* @__PURE__ */
|
|
2253
|
-
autoFocus && /* @__PURE__ */
|
|
2465
|
+
/* @__PURE__ */ jsx4(HistoryPlugin, {}),
|
|
2466
|
+
/* @__PURE__ */ jsx4(ListPlugin, {}),
|
|
2467
|
+
/* @__PURE__ */ jsx4(CheckListPlugin, {}),
|
|
2468
|
+
/* @__PURE__ */ jsx4(ChecklistShortcutPlugin, {}),
|
|
2469
|
+
/* @__PURE__ */ jsx4(CodeBlockShortcutPlugin, {}),
|
|
2470
|
+
/* @__PURE__ */ jsx4(CodeHighlightPlugin, {}),
|
|
2471
|
+
/* @__PURE__ */ jsx4(TablePlugin, {}),
|
|
2472
|
+
/* @__PURE__ */ jsx4(LinkPlugin, {}),
|
|
2473
|
+
/* @__PURE__ */ jsx4(MarkdownShortcutPlugin, { transformers: SHORTCUT_TRANSFORMERS }),
|
|
2474
|
+
/* @__PURE__ */ jsx4(ReadOnlyPlugin, { readOnly: readOnly || mode === "view" }),
|
|
2475
|
+
autoFocus && /* @__PURE__ */ jsx4(AutoFocusPlugin, {})
|
|
2254
2476
|
] })
|
|
2255
2477
|
] }) }) }, mountKey);
|
|
2256
2478
|
}
|
|
@@ -2267,10 +2489,10 @@ import {
|
|
|
2267
2489
|
useRef as useRef4,
|
|
2268
2490
|
useState as useState3
|
|
2269
2491
|
} from "react";
|
|
2270
|
-
import { $getRoot, $getSelection as $
|
|
2492
|
+
import { $getRoot, $getSelection as $getSelection3, $isRangeSelection as $isRangeSelection3 } from "lexical";
|
|
2271
2493
|
import { useLexicalComposerContext as useLexicalComposerContext7 } from "@lexical/react/LexicalComposerContext";
|
|
2272
2494
|
import { $isHeadingNode } from "@lexical/rich-text";
|
|
2273
|
-
import { jsx as
|
|
2495
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
2274
2496
|
var HEADING_LEVELS = {
|
|
2275
2497
|
h1: 1,
|
|
2276
2498
|
h2: 2,
|
|
@@ -2306,8 +2528,8 @@ function FoldingPlugin() {
|
|
|
2306
2528
|
hidden.add(sibling.getKey());
|
|
2307
2529
|
}
|
|
2308
2530
|
}
|
|
2309
|
-
const selection = $
|
|
2310
|
-
if ($
|
|
2531
|
+
const selection = $getSelection3();
|
|
2532
|
+
if ($isRangeSelection3(selection)) {
|
|
2311
2533
|
const topLevel = selection.anchor.getNode().getTopLevelElement();
|
|
2312
2534
|
if (topLevel && hidden.has(topLevel.getKey())) {
|
|
2313
2535
|
let node = topLevel.getPreviousSibling();
|
|
@@ -2368,7 +2590,7 @@ function FoldingPlugin() {
|
|
|
2368
2590
|
return next;
|
|
2369
2591
|
});
|
|
2370
2592
|
}, []);
|
|
2371
|
-
return /* @__PURE__ */
|
|
2593
|
+
return /* @__PURE__ */ jsx5("div", { className: "zui-text-editor-fold-gutter", children: buttons.map(({ key, folded, top, height }) => /* @__PURE__ */ jsx5(
|
|
2372
2594
|
"button",
|
|
2373
2595
|
{
|
|
2374
2596
|
type: "button",
|
|
@@ -2378,7 +2600,7 @@ function FoldingPlugin() {
|
|
|
2378
2600
|
"aria-label": folded ? "Expand section" : "Collapse section",
|
|
2379
2601
|
"aria-expanded": !folded,
|
|
2380
2602
|
onClick: () => toggle(key),
|
|
2381
|
-
children: /* @__PURE__ */
|
|
2603
|
+
children: /* @__PURE__ */ jsx5(
|
|
2382
2604
|
"svg",
|
|
2383
2605
|
{
|
|
2384
2606
|
viewBox: "0 0 20 20",
|
|
@@ -2389,7 +2611,7 @@ function FoldingPlugin() {
|
|
|
2389
2611
|
strokeWidth: "2",
|
|
2390
2612
|
strokeLinecap: "round",
|
|
2391
2613
|
strokeLinejoin: "round",
|
|
2392
|
-
children: /* @__PURE__ */
|
|
2614
|
+
children: /* @__PURE__ */ jsx5("path", { d: "M6 8l4 4 4-4" })
|
|
2393
2615
|
}
|
|
2394
2616
|
)
|
|
2395
2617
|
},
|
|
@@ -2397,168 +2619,16 @@ function FoldingPlugin() {
|
|
|
2397
2619
|
)) });
|
|
2398
2620
|
}
|
|
2399
2621
|
|
|
2400
|
-
// src/
|
|
2401
|
-
import {
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
foldable = true,
|
|
2405
|
-
children
|
|
2406
|
-
}) {
|
|
2407
|
-
const { mode, readOnly, autoFocus, rawValue, onRawChange } = useEditorContext();
|
|
2408
|
-
if (mode === "edit-raw") {
|
|
2409
|
-
return /* @__PURE__ */ jsx5(
|
|
2410
|
-
"textarea",
|
|
2411
|
-
{
|
|
2412
|
-
className: "zui-text-editor-textarea",
|
|
2413
|
-
value: rawValue,
|
|
2414
|
-
onChange: (e) => onRawChange(e.target.value),
|
|
2415
|
-
placeholder,
|
|
2416
|
-
readOnly,
|
|
2417
|
-
autoFocus,
|
|
2418
|
-
spellCheck: false
|
|
2419
|
-
}
|
|
2420
|
-
);
|
|
2421
|
-
}
|
|
2422
|
-
return /* @__PURE__ */ jsxs3("div", { className: "zui-text-editor-body", children: [
|
|
2423
|
-
/* @__PURE__ */ jsxs3("div", { className: "zui-text-editor-main", children: [
|
|
2424
|
-
/* @__PURE__ */ jsx5(
|
|
2425
|
-
RichTextPlugin,
|
|
2426
|
-
{
|
|
2427
|
-
contentEditable: /* @__PURE__ */ jsx5(
|
|
2428
|
-
ContentEditable,
|
|
2429
|
-
{
|
|
2430
|
-
className: "zui-text-editor-content",
|
|
2431
|
-
"aria-placeholder": placeholder,
|
|
2432
|
-
placeholder: /* @__PURE__ */ jsx5("div", { className: "zui-text-editor-placeholder", children: placeholder })
|
|
2433
|
-
}
|
|
2434
|
-
),
|
|
2435
|
-
ErrorBoundary: LexicalErrorBoundary
|
|
2436
|
-
}
|
|
2437
|
-
),
|
|
2438
|
-
foldable && /* @__PURE__ */ jsx5(FoldingPlugin, {})
|
|
2439
|
-
] }),
|
|
2440
|
-
children
|
|
2441
|
-
] });
|
|
2442
|
-
}
|
|
2443
|
-
|
|
2444
|
-
// src/plugins/OutlinePlugin.tsx
|
|
2445
|
-
import { useCallback as useCallback4, useEffect as useEffect8, useState as useState4 } from "react";
|
|
2446
|
-
import { useLexicalComposerContext as useLexicalComposerContext8 } from "@lexical/react/LexicalComposerContext";
|
|
2447
|
-
import {
|
|
2448
|
-
TableOfContentsPlugin
|
|
2449
|
-
} from "@lexical/react/LexicalTableOfContentsPlugin";
|
|
2450
|
-
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2451
|
-
var INDENT_PER_LEVEL = {
|
|
2452
|
-
h1: 0,
|
|
2453
|
-
h2: 1,
|
|
2454
|
-
h3: 2,
|
|
2455
|
-
h4: 3,
|
|
2456
|
-
h5: 4,
|
|
2457
|
-
h6: 5
|
|
2458
|
-
};
|
|
2459
|
-
function OutlinePlugin() {
|
|
2460
|
-
const [editor] = useLexicalComposerContext8();
|
|
2461
|
-
const [collapsed, setCollapsed] = useState4(false);
|
|
2462
|
-
const [activeKey, setActiveKey] = useState4(null);
|
|
2463
|
-
useEffect8(() => {
|
|
2464
|
-
const rootElement = editor.getRootElement();
|
|
2465
|
-
const scroller = rootElement?.closest(".zui-text-editor");
|
|
2466
|
-
if (!rootElement || !(scroller instanceof HTMLElement)) return;
|
|
2467
|
-
let frame = 0;
|
|
2468
|
-
const updateActive = () => {
|
|
2469
|
-
cancelAnimationFrame(frame);
|
|
2470
|
-
frame = requestAnimationFrame(() => {
|
|
2471
|
-
const headings = rootElement.querySelectorAll(
|
|
2472
|
-
"h1, h2, h3, h4, h5, h6"
|
|
2473
|
-
);
|
|
2474
|
-
const threshold = scroller.scrollTop + 80;
|
|
2475
|
-
let current = null;
|
|
2476
|
-
for (const el of headings) {
|
|
2477
|
-
if (el.offsetTop <= threshold) {
|
|
2478
|
-
current = el.getAttribute("data-outline-key");
|
|
2479
|
-
}
|
|
2480
|
-
}
|
|
2481
|
-
setActiveKey(current);
|
|
2482
|
-
});
|
|
2483
|
-
};
|
|
2484
|
-
updateActive();
|
|
2485
|
-
scroller.addEventListener("scroll", updateActive, { passive: true });
|
|
2486
|
-
const unregister = editor.registerUpdateListener(updateActive);
|
|
2487
|
-
return () => {
|
|
2488
|
-
cancelAnimationFrame(frame);
|
|
2489
|
-
scroller.removeEventListener("scroll", updateActive);
|
|
2490
|
-
unregister();
|
|
2491
|
-
};
|
|
2492
|
-
}, [editor]);
|
|
2493
|
-
const scrollTo = useCallback4(
|
|
2494
|
-
(key) => {
|
|
2495
|
-
editor.getEditorState().read(() => {
|
|
2496
|
-
const element = editor.getElementByKey(key);
|
|
2497
|
-
element?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
2498
|
-
});
|
|
2499
|
-
},
|
|
2500
|
-
[editor]
|
|
2501
|
-
);
|
|
2502
|
-
return /* @__PURE__ */ jsx6(TableOfContentsPlugin, { children: (entries) => {
|
|
2503
|
-
for (const [key] of entries) {
|
|
2504
|
-
editor.getElementByKey(key)?.setAttribute("data-outline-key", key);
|
|
2505
|
-
}
|
|
2506
|
-
return /* @__PURE__ */ jsxs4(
|
|
2507
|
-
"div",
|
|
2508
|
-
{
|
|
2509
|
-
className: `zui-text-editor-outline ${collapsed ? "is-collapsed" : ""}`,
|
|
2510
|
-
children: [
|
|
2511
|
-
/* @__PURE__ */ jsx6(
|
|
2512
|
-
"button",
|
|
2513
|
-
{
|
|
2514
|
-
type: "button",
|
|
2515
|
-
className: "zui-text-editor-outline-toggle",
|
|
2516
|
-
title: collapsed ? "Show outline" : "Hide outline",
|
|
2517
|
-
"aria-label": collapsed ? "Show outline" : "Hide outline",
|
|
2518
|
-
"aria-expanded": !collapsed,
|
|
2519
|
-
onClick: () => setCollapsed((c) => !c),
|
|
2520
|
-
children: /* @__PURE__ */ jsx6(
|
|
2521
|
-
"svg",
|
|
2522
|
-
{
|
|
2523
|
-
viewBox: "0 0 20 20",
|
|
2524
|
-
width: "14",
|
|
2525
|
-
height: "14",
|
|
2526
|
-
fill: "none",
|
|
2527
|
-
stroke: "currentColor",
|
|
2528
|
-
strokeWidth: "1.8",
|
|
2529
|
-
strokeLinecap: "round",
|
|
2530
|
-
children: /* @__PURE__ */ jsx6("path", { d: "M4 5h12M4 10h8M4 15h10" })
|
|
2531
|
-
}
|
|
2532
|
-
)
|
|
2533
|
-
}
|
|
2534
|
-
),
|
|
2535
|
-
!collapsed && /* @__PURE__ */ jsxs4("nav", { className: "zui-text-editor-outline-list", "aria-label": "Table of contents", children: [
|
|
2536
|
-
entries.length === 0 && /* @__PURE__ */ jsx6("div", { className: "zui-text-editor-outline-empty", children: "No headings" }),
|
|
2537
|
-
entries.map(([key, text, tag]) => /* @__PURE__ */ jsx6(
|
|
2538
|
-
"button",
|
|
2539
|
-
{
|
|
2540
|
-
type: "button",
|
|
2541
|
-
className: `zui-text-editor-outline-item ${key === activeKey ? "is-active" : ""}`,
|
|
2542
|
-
style: {
|
|
2543
|
-
paddingLeft: `${0.5 + INDENT_PER_LEVEL[tag] * 0.75}rem`
|
|
2544
|
-
},
|
|
2545
|
-
onClick: () => scrollTo(key),
|
|
2546
|
-
children: text || "Untitled"
|
|
2547
|
-
},
|
|
2548
|
-
key
|
|
2549
|
-
))
|
|
2550
|
-
] })
|
|
2551
|
-
]
|
|
2552
|
-
}
|
|
2553
|
-
);
|
|
2554
|
-
} });
|
|
2555
|
-
}
|
|
2622
|
+
// src/plugins/TableSettingsPlugin.tsx
|
|
2623
|
+
import { useCallback as useCallback5, useEffect as useEffect9, useState as useState5 } from "react";
|
|
2624
|
+
import { useLexicalComposerContext as useLexicalComposerContext9 } from "@lexical/react/LexicalComposerContext";
|
|
2625
|
+
import { useLexicalEditable as useLexicalEditable2 } from "@lexical/react/useLexicalEditable";
|
|
2556
2626
|
|
|
2557
2627
|
// src/useMarkdownEditor.ts
|
|
2558
|
-
import { useCallback as
|
|
2628
|
+
import { useCallback as useCallback4, useEffect as useEffect8, useState as useState4 } from "react";
|
|
2559
2629
|
import {
|
|
2560
|
-
$getSelection as $
|
|
2561
|
-
$isRangeSelection as $
|
|
2630
|
+
$getSelection as $getSelection4,
|
|
2631
|
+
$isRangeSelection as $isRangeSelection4,
|
|
2562
2632
|
CAN_REDO_COMMAND,
|
|
2563
2633
|
CAN_UNDO_COMMAND,
|
|
2564
2634
|
COMMAND_PRIORITY_LOW as COMMAND_PRIORITY_LOW2,
|
|
@@ -2566,7 +2636,7 @@ import {
|
|
|
2566
2636
|
REDO_COMMAND,
|
|
2567
2637
|
UNDO_COMMAND
|
|
2568
2638
|
} from "lexical";
|
|
2569
|
-
import { useLexicalComposerContext as
|
|
2639
|
+
import { useLexicalComposerContext as useLexicalComposerContext8 } from "@lexical/react/LexicalComposerContext";
|
|
2570
2640
|
import { INSERT_TABLE_COMMAND } from "@lexical/table";
|
|
2571
2641
|
import { $insertNodeToNearestRoot, mergeRegister } from "@lexical/utils";
|
|
2572
2642
|
var TRACKED_FORMATS = [
|
|
@@ -2577,18 +2647,21 @@ var TRACKED_FORMATS = [
|
|
|
2577
2647
|
"code"
|
|
2578
2648
|
];
|
|
2579
2649
|
function useMarkdownEditor() {
|
|
2580
|
-
const [editor] =
|
|
2581
|
-
const [activeFormats, setActiveFormats] =
|
|
2650
|
+
const [editor] = useLexicalComposerContext8();
|
|
2651
|
+
const [activeFormats, setActiveFormats] = useState4(
|
|
2582
2652
|
/* @__PURE__ */ new Set()
|
|
2583
2653
|
);
|
|
2584
|
-
const [canUndo, setCanUndo] =
|
|
2585
|
-
const [canRedo, setCanRedo] =
|
|
2586
|
-
|
|
2654
|
+
const [canUndo, setCanUndo] = useState4(false);
|
|
2655
|
+
const [canRedo, setCanRedo] = useState4(false);
|
|
2656
|
+
const [tableSettings, setTableSettingsState] = useState4(null);
|
|
2657
|
+
useEffect8(
|
|
2587
2658
|
() => mergeRegister(
|
|
2588
2659
|
editor.registerUpdateListener(({ editorState }) => {
|
|
2589
2660
|
editorState.read(() => {
|
|
2590
|
-
const
|
|
2591
|
-
|
|
2661
|
+
const table = $getSelectedTable();
|
|
2662
|
+
setTableSettingsState(table ? $getTableSettings(table) : null);
|
|
2663
|
+
const selection = $getSelection4();
|
|
2664
|
+
if (!$isRangeSelection4(selection)) {
|
|
2592
2665
|
setActiveFormats(/* @__PURE__ */ new Set());
|
|
2593
2666
|
return;
|
|
2594
2667
|
}
|
|
@@ -2618,13 +2691,13 @@ function useMarkdownEditor() {
|
|
|
2618
2691
|
),
|
|
2619
2692
|
[editor]
|
|
2620
2693
|
);
|
|
2621
|
-
const toggleFormat =
|
|
2694
|
+
const toggleFormat = useCallback4(
|
|
2622
2695
|
(format) => {
|
|
2623
2696
|
editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
|
|
2624
2697
|
},
|
|
2625
2698
|
[editor]
|
|
2626
2699
|
);
|
|
2627
|
-
const insertTable =
|
|
2700
|
+
const insertTable = useCallback4(
|
|
2628
2701
|
({ rows = 3, columns = 3 } = {}) => {
|
|
2629
2702
|
editor.dispatchCommand(INSERT_TABLE_COMMAND, {
|
|
2630
2703
|
columns: String(columns),
|
|
@@ -2634,15 +2707,32 @@ function useMarkdownEditor() {
|
|
|
2634
2707
|
},
|
|
2635
2708
|
[editor]
|
|
2636
2709
|
);
|
|
2637
|
-
const insertDrawing =
|
|
2710
|
+
const insertDrawing = useCallback4(() => {
|
|
2638
2711
|
editor.update(() => {
|
|
2639
2712
|
$insertNodeToNearestRoot($createDrawingNode());
|
|
2640
2713
|
});
|
|
2641
2714
|
}, [editor]);
|
|
2642
|
-
const
|
|
2715
|
+
const updateTableSettings = useCallback4(
|
|
2716
|
+
(settings) => {
|
|
2717
|
+
editor.update(() => {
|
|
2718
|
+
const table = $getSelectedTable();
|
|
2719
|
+
if (table) $setTableSettings(table, settings);
|
|
2720
|
+
});
|
|
2721
|
+
},
|
|
2722
|
+
[editor]
|
|
2723
|
+
);
|
|
2724
|
+
const setTableWidth = useCallback4(
|
|
2725
|
+
(width) => updateTableSettings({ width }),
|
|
2726
|
+
[updateTableSettings]
|
|
2727
|
+
);
|
|
2728
|
+
const setTableDensity = useCallback4(
|
|
2729
|
+
(density) => updateTableSettings({ density }),
|
|
2730
|
+
[updateTableSettings]
|
|
2731
|
+
);
|
|
2732
|
+
const undo = useCallback4(() => {
|
|
2643
2733
|
editor.dispatchCommand(UNDO_COMMAND, void 0);
|
|
2644
2734
|
}, [editor]);
|
|
2645
|
-
const redo =
|
|
2735
|
+
const redo = useCallback4(() => {
|
|
2646
2736
|
editor.dispatchCommand(REDO_COMMAND, void 0);
|
|
2647
2737
|
}, [editor]);
|
|
2648
2738
|
return {
|
|
@@ -2651,6 +2741,10 @@ function useMarkdownEditor() {
|
|
|
2651
2741
|
toggleFormat,
|
|
2652
2742
|
insertTable,
|
|
2653
2743
|
insertDrawing,
|
|
2744
|
+
tableWidth: tableSettings?.width ?? null,
|
|
2745
|
+
setTableWidth,
|
|
2746
|
+
tableDensity: tableSettings?.density ?? null,
|
|
2747
|
+
setTableDensity,
|
|
2654
2748
|
canUndo,
|
|
2655
2749
|
canRedo,
|
|
2656
2750
|
undo,
|
|
@@ -2659,23 +2753,23 @@ function useMarkdownEditor() {
|
|
|
2659
2753
|
}
|
|
2660
2754
|
|
|
2661
2755
|
// src/components/Toolbar.tsx
|
|
2662
|
-
import { Fragment as
|
|
2756
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2663
2757
|
function Toolbar({ children, className }) {
|
|
2664
|
-
return /* @__PURE__ */
|
|
2758
|
+
return /* @__PURE__ */ jsx6(
|
|
2665
2759
|
"div",
|
|
2666
2760
|
{
|
|
2667
2761
|
className: `zui-text-editor-toolbar ${className ?? ""}`,
|
|
2668
2762
|
role: "toolbar",
|
|
2669
|
-
children: children ?? /* @__PURE__ */
|
|
2670
|
-
/* @__PURE__ */
|
|
2671
|
-
/* @__PURE__ */
|
|
2672
|
-
/* @__PURE__ */
|
|
2763
|
+
children: children ?? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
2764
|
+
/* @__PURE__ */ jsx6(FormatButtons, {}),
|
|
2765
|
+
/* @__PURE__ */ jsx6(ToolbarDivider, {}),
|
|
2766
|
+
/* @__PURE__ */ jsx6(InsertButtons, {})
|
|
2673
2767
|
] })
|
|
2674
2768
|
}
|
|
2675
2769
|
);
|
|
2676
2770
|
}
|
|
2677
2771
|
function ToolbarDivider() {
|
|
2678
|
-
return /* @__PURE__ */
|
|
2772
|
+
return /* @__PURE__ */ jsx6("div", { className: "zui-text-editor-toolbar-divider" });
|
|
2679
2773
|
}
|
|
2680
2774
|
function ToolbarButton({
|
|
2681
2775
|
label,
|
|
@@ -2685,7 +2779,7 @@ function ToolbarButton({
|
|
|
2685
2779
|
disabled = false,
|
|
2686
2780
|
className
|
|
2687
2781
|
}) {
|
|
2688
|
-
return /* @__PURE__ */
|
|
2782
|
+
return /* @__PURE__ */ jsx6(
|
|
2689
2783
|
"button",
|
|
2690
2784
|
{
|
|
2691
2785
|
type: "button",
|
|
@@ -2701,7 +2795,7 @@ function ToolbarButton({
|
|
|
2701
2795
|
);
|
|
2702
2796
|
}
|
|
2703
2797
|
function Icon({ children, strokeWidth = 1.5 }) {
|
|
2704
|
-
return /* @__PURE__ */
|
|
2798
|
+
return /* @__PURE__ */ jsx6(
|
|
2705
2799
|
"svg",
|
|
2706
2800
|
{
|
|
2707
2801
|
viewBox: "0 0 20 20",
|
|
@@ -2720,27 +2814,27 @@ var FORMAT_BUTTONS = [
|
|
|
2720
2814
|
{
|
|
2721
2815
|
format: "bold",
|
|
2722
2816
|
label: "Bold",
|
|
2723
|
-
icon: /* @__PURE__ */
|
|
2817
|
+
icon: /* @__PURE__ */ jsx6(Icon, { strokeWidth: 1.8, children: /* @__PURE__ */ jsx6("path", { d: "M6 3.5h5a3 3 0 0 1 0 6H6zm0 6h6a3 3 0 0 1 0 6H6z" }) })
|
|
2724
2818
|
},
|
|
2725
2819
|
{
|
|
2726
2820
|
format: "italic",
|
|
2727
2821
|
label: "Italic",
|
|
2728
|
-
icon: /* @__PURE__ */
|
|
2822
|
+
icon: /* @__PURE__ */ jsx6(Icon, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx6("path", { d: "M8.5 3.5h6M5.5 16.5h6M11.5 3.5l-3 13" }) })
|
|
2729
2823
|
},
|
|
2730
2824
|
{
|
|
2731
2825
|
format: "strikethrough",
|
|
2732
2826
|
label: "Strikethrough",
|
|
2733
|
-
icon: /* @__PURE__ */
|
|
2827
|
+
icon: /* @__PURE__ */ jsx6(Icon, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx6("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" }) })
|
|
2734
2828
|
},
|
|
2735
2829
|
{
|
|
2736
2830
|
format: "code",
|
|
2737
2831
|
label: "Inline code",
|
|
2738
|
-
icon: /* @__PURE__ */
|
|
2832
|
+
icon: /* @__PURE__ */ jsx6(Icon, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx6("path", { d: "M7.5 6L4 10l3.5 4M12.5 6L16 10l-3.5 4" }) })
|
|
2739
2833
|
}
|
|
2740
2834
|
];
|
|
2741
2835
|
function FormatButtons() {
|
|
2742
2836
|
const { activeFormats, toggleFormat } = useMarkdownEditor();
|
|
2743
|
-
return /* @__PURE__ */
|
|
2837
|
+
return /* @__PURE__ */ jsx6(Fragment3, { children: FORMAT_BUTTONS.map(({ format, label, icon }) => /* @__PURE__ */ jsx6(
|
|
2744
2838
|
ToolbarButton,
|
|
2745
2839
|
{
|
|
2746
2840
|
label,
|
|
@@ -2753,38 +2847,297 @@ function FormatButtons() {
|
|
|
2753
2847
|
}
|
|
2754
2848
|
function InsertButtons() {
|
|
2755
2849
|
const { insertTable, insertDrawing } = useMarkdownEditor();
|
|
2756
|
-
return /* @__PURE__ */
|
|
2757
|
-
/* @__PURE__ */
|
|
2758
|
-
/* @__PURE__ */
|
|
2759
|
-
/* @__PURE__ */
|
|
2850
|
+
return /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
2851
|
+
/* @__PURE__ */ jsx6(ToolbarButton, { label: "Insert table", onClick: () => insertTable(), children: /* @__PURE__ */ jsxs4(Icon, { children: [
|
|
2852
|
+
/* @__PURE__ */ jsx6("rect", { x: "3", y: "3.5", width: "14", height: "13", rx: "1.5" }),
|
|
2853
|
+
/* @__PURE__ */ jsx6("path", { d: "M3 8h14M8 8v8.5M13 8v8.5" })
|
|
2760
2854
|
] }) }),
|
|
2761
|
-
/* @__PURE__ */
|
|
2762
|
-
/* @__PURE__ */
|
|
2763
|
-
/* @__PURE__ */
|
|
2764
|
-
/* @__PURE__ */
|
|
2855
|
+
/* @__PURE__ */ jsx6(ToolbarButton, { label: "Insert drawing", onClick: insertDrawing, children: /* @__PURE__ */ jsxs4(Icon, { children: [
|
|
2856
|
+
/* @__PURE__ */ jsx6("rect", { x: "3", y: "5", width: "8", height: "6", rx: "1.5" }),
|
|
2857
|
+
/* @__PURE__ */ jsx6("path", { d: "M13.5 8h3M14.5 6.5L17.5 8l-3 1.5" }),
|
|
2858
|
+
/* @__PURE__ */ jsx6("ellipse", { cx: "13", cy: "14.5", rx: "4", ry: "2.8" })
|
|
2765
2859
|
] }) })
|
|
2766
2860
|
] });
|
|
2767
2861
|
}
|
|
2768
2862
|
function HistoryButtons() {
|
|
2769
2863
|
const { canUndo, canRedo, undo, redo } = useMarkdownEditor();
|
|
2770
|
-
return /* @__PURE__ */
|
|
2771
|
-
/* @__PURE__ */
|
|
2772
|
-
/* @__PURE__ */
|
|
2773
|
-
/* @__PURE__ */
|
|
2864
|
+
return /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
2865
|
+
/* @__PURE__ */ jsx6(ToolbarButton, { label: "Undo", onClick: undo, disabled: !canUndo, children: /* @__PURE__ */ jsxs4(Icon, { children: [
|
|
2866
|
+
/* @__PURE__ */ jsx6("path", { d: "M7 6L3.5 9.5 7 13" }),
|
|
2867
|
+
/* @__PURE__ */ jsx6("path", { d: "M3.5 9.5H12a4 4 0 0 1 0 8h-1" })
|
|
2774
2868
|
] }) }),
|
|
2775
|
-
/* @__PURE__ */
|
|
2776
|
-
/* @__PURE__ */
|
|
2777
|
-
/* @__PURE__ */
|
|
2869
|
+
/* @__PURE__ */ jsx6(ToolbarButton, { label: "Redo", onClick: redo, disabled: !canRedo, children: /* @__PURE__ */ jsxs4(Icon, { children: [
|
|
2870
|
+
/* @__PURE__ */ jsx6("path", { d: "M13 6l3.5 3.5L13 13" }),
|
|
2871
|
+
/* @__PURE__ */ jsx6("path", { d: "M16.5 9.5H8a4 4 0 0 0 0 8h1" })
|
|
2778
2872
|
] }) })
|
|
2779
2873
|
] });
|
|
2780
2874
|
}
|
|
2781
2875
|
|
|
2782
|
-
// src/
|
|
2876
|
+
// src/plugins/TableSettingsPlugin.tsx
|
|
2877
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2878
|
+
var DENSITY_OPTIONS = [
|
|
2879
|
+
{
|
|
2880
|
+
density: "compact",
|
|
2881
|
+
label: "Compact rows",
|
|
2882
|
+
icon: /* @__PURE__ */ jsx7("path", { d: "M3 4.5h14M3 8.17h14M3 11.83h14M3 15.5h14" })
|
|
2883
|
+
},
|
|
2884
|
+
{
|
|
2885
|
+
density: "comfortable",
|
|
2886
|
+
label: "Comfortable rows",
|
|
2887
|
+
icon: /* @__PURE__ */ jsx7("path", { d: "M3 4.5h14M3 10h14M3 15.5h14" })
|
|
2888
|
+
},
|
|
2889
|
+
{
|
|
2890
|
+
density: "spacious",
|
|
2891
|
+
label: "Spacious rows",
|
|
2892
|
+
icon: /* @__PURE__ */ jsx7("path", { d: "M3 5h14M3 15h14" })
|
|
2893
|
+
}
|
|
2894
|
+
];
|
|
2895
|
+
function Icon2({ children }) {
|
|
2896
|
+
return /* @__PURE__ */ jsx7(
|
|
2897
|
+
"svg",
|
|
2898
|
+
{
|
|
2899
|
+
viewBox: "0 0 20 20",
|
|
2900
|
+
width: "16",
|
|
2901
|
+
height: "16",
|
|
2902
|
+
fill: "none",
|
|
2903
|
+
stroke: "currentColor",
|
|
2904
|
+
strokeWidth: "1.6",
|
|
2905
|
+
strokeLinecap: "round",
|
|
2906
|
+
strokeLinejoin: "round",
|
|
2907
|
+
children
|
|
2908
|
+
}
|
|
2909
|
+
);
|
|
2910
|
+
}
|
|
2911
|
+
function TableSettingsPlugin() {
|
|
2912
|
+
const [editor] = useLexicalComposerContext9();
|
|
2913
|
+
const isEditable = useLexicalEditable2();
|
|
2914
|
+
const { tableWidth, setTableWidth, tableDensity, setTableDensity } = useMarkdownEditor();
|
|
2915
|
+
const [anchor, setAnchor] = useState5(null);
|
|
2916
|
+
const sync = useCallback5(() => {
|
|
2917
|
+
const tableKey = editor.getEditorState().read(() => $getSelectedTable()?.getKey());
|
|
2918
|
+
const element = tableKey ? editor.getElementByKey(tableKey) : null;
|
|
2919
|
+
const main = editor.getRootElement()?.parentElement;
|
|
2920
|
+
if (!element || !main) {
|
|
2921
|
+
setAnchor(null);
|
|
2922
|
+
return;
|
|
2923
|
+
}
|
|
2924
|
+
const rect = element.getBoundingClientRect();
|
|
2925
|
+
const mainRect = main.getBoundingClientRect();
|
|
2926
|
+
setAnchor({
|
|
2927
|
+
top: rect.top - mainRect.top,
|
|
2928
|
+
right: mainRect.right - rect.right + 8
|
|
2929
|
+
});
|
|
2930
|
+
}, [editor]);
|
|
2931
|
+
useEffect9(() => {
|
|
2932
|
+
sync();
|
|
2933
|
+
const unregister = editor.registerUpdateListener(sync);
|
|
2934
|
+
const rootElement = editor.getRootElement();
|
|
2935
|
+
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(sync) : null;
|
|
2936
|
+
if (rootElement && observer) observer.observe(rootElement);
|
|
2937
|
+
return () => {
|
|
2938
|
+
unregister();
|
|
2939
|
+
observer?.disconnect();
|
|
2940
|
+
};
|
|
2941
|
+
}, [editor, sync]);
|
|
2942
|
+
if (!isEditable || !anchor || !tableWidth || !tableDensity) return null;
|
|
2943
|
+
return /* @__PURE__ */ jsxs5(
|
|
2944
|
+
"div",
|
|
2945
|
+
{
|
|
2946
|
+
className: "zui-table-settings",
|
|
2947
|
+
role: "toolbar",
|
|
2948
|
+
"aria-label": "Table settings",
|
|
2949
|
+
style: { top: anchor.top, right: anchor.right },
|
|
2950
|
+
children: [
|
|
2951
|
+
BLOCK_WIDTH_OPTIONS.map(({ width, label, icon }) => /* @__PURE__ */ jsx7(
|
|
2952
|
+
ToolbarButton,
|
|
2953
|
+
{
|
|
2954
|
+
label,
|
|
2955
|
+
active: tableWidth === width,
|
|
2956
|
+
onClick: () => setTableWidth(width),
|
|
2957
|
+
children: /* @__PURE__ */ jsx7(Icon2, { children: icon })
|
|
2958
|
+
},
|
|
2959
|
+
width
|
|
2960
|
+
)),
|
|
2961
|
+
/* @__PURE__ */ jsx7(ToolbarDivider, {}),
|
|
2962
|
+
DENSITY_OPTIONS.map(({ density, label, icon }) => /* @__PURE__ */ jsx7(
|
|
2963
|
+
ToolbarButton,
|
|
2964
|
+
{
|
|
2965
|
+
label,
|
|
2966
|
+
active: tableDensity === density,
|
|
2967
|
+
onClick: () => setTableDensity(density),
|
|
2968
|
+
children: /* @__PURE__ */ jsx7(Icon2, { children: icon })
|
|
2969
|
+
},
|
|
2970
|
+
density
|
|
2971
|
+
))
|
|
2972
|
+
]
|
|
2973
|
+
}
|
|
2974
|
+
);
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
// src/EditorContent.tsx
|
|
2783
2978
|
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2979
|
+
function EditorContent({
|
|
2980
|
+
placeholder = "Start writing...",
|
|
2981
|
+
foldable = true,
|
|
2982
|
+
children
|
|
2983
|
+
}) {
|
|
2984
|
+
const { mode, readOnly, autoFocus, rawValue, onRawChange } = useEditorContext();
|
|
2985
|
+
if (mode === "edit-raw") {
|
|
2986
|
+
return /* @__PURE__ */ jsx8(
|
|
2987
|
+
"textarea",
|
|
2988
|
+
{
|
|
2989
|
+
className: "zui-text-editor-textarea",
|
|
2990
|
+
value: rawValue,
|
|
2991
|
+
onChange: (e) => onRawChange(e.target.value),
|
|
2992
|
+
placeholder,
|
|
2993
|
+
readOnly,
|
|
2994
|
+
autoFocus,
|
|
2995
|
+
spellCheck: false
|
|
2996
|
+
}
|
|
2997
|
+
);
|
|
2998
|
+
}
|
|
2999
|
+
return /* @__PURE__ */ jsxs6("div", { className: "zui-text-editor-body", children: [
|
|
3000
|
+
/* @__PURE__ */ jsxs6("div", { className: "zui-text-editor-main", children: [
|
|
3001
|
+
/* @__PURE__ */ jsx8(
|
|
3002
|
+
RichTextPlugin,
|
|
3003
|
+
{
|
|
3004
|
+
contentEditable: /* @__PURE__ */ jsx8(
|
|
3005
|
+
ContentEditable,
|
|
3006
|
+
{
|
|
3007
|
+
className: "zui-text-editor-content",
|
|
3008
|
+
"aria-placeholder": placeholder,
|
|
3009
|
+
placeholder: /* @__PURE__ */ jsx8("div", { className: "zui-text-editor-placeholder", children: placeholder })
|
|
3010
|
+
}
|
|
3011
|
+
),
|
|
3012
|
+
ErrorBoundary: LexicalErrorBoundary
|
|
3013
|
+
}
|
|
3014
|
+
),
|
|
3015
|
+
foldable && /* @__PURE__ */ jsx8(FoldingPlugin, {}),
|
|
3016
|
+
/* @__PURE__ */ jsx8(TableSettingsPlugin, {})
|
|
3017
|
+
] }),
|
|
3018
|
+
children
|
|
3019
|
+
] });
|
|
3020
|
+
}
|
|
3021
|
+
|
|
3022
|
+
// src/plugins/OutlinePlugin.tsx
|
|
3023
|
+
import { useCallback as useCallback6, useEffect as useEffect10, useState as useState6 } from "react";
|
|
3024
|
+
import { useLexicalComposerContext as useLexicalComposerContext10 } from "@lexical/react/LexicalComposerContext";
|
|
3025
|
+
import {
|
|
3026
|
+
TableOfContentsPlugin
|
|
3027
|
+
} from "@lexical/react/LexicalTableOfContentsPlugin";
|
|
3028
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3029
|
+
var INDENT_PER_LEVEL = {
|
|
3030
|
+
h1: 0,
|
|
3031
|
+
h2: 1,
|
|
3032
|
+
h3: 2,
|
|
3033
|
+
h4: 3,
|
|
3034
|
+
h5: 4,
|
|
3035
|
+
h6: 5
|
|
3036
|
+
};
|
|
3037
|
+
function OutlinePlugin() {
|
|
3038
|
+
const [editor] = useLexicalComposerContext10();
|
|
3039
|
+
const [collapsed, setCollapsed] = useState6(false);
|
|
3040
|
+
const [activeKey, setActiveKey] = useState6(null);
|
|
3041
|
+
useEffect10(() => {
|
|
3042
|
+
const rootElement = editor.getRootElement();
|
|
3043
|
+
const scroller = rootElement?.closest(".zui-text-editor");
|
|
3044
|
+
if (!rootElement || !(scroller instanceof HTMLElement)) return;
|
|
3045
|
+
let frame = 0;
|
|
3046
|
+
const updateActive = () => {
|
|
3047
|
+
cancelAnimationFrame(frame);
|
|
3048
|
+
frame = requestAnimationFrame(() => {
|
|
3049
|
+
const headings = rootElement.querySelectorAll(
|
|
3050
|
+
"h1, h2, h3, h4, h5, h6"
|
|
3051
|
+
);
|
|
3052
|
+
const threshold = scroller.scrollTop + 80;
|
|
3053
|
+
let current = null;
|
|
3054
|
+
for (const el of headings) {
|
|
3055
|
+
if (el.offsetTop <= threshold) {
|
|
3056
|
+
current = el.getAttribute("data-outline-key");
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
setActiveKey(current);
|
|
3060
|
+
});
|
|
3061
|
+
};
|
|
3062
|
+
updateActive();
|
|
3063
|
+
scroller.addEventListener("scroll", updateActive, { passive: true });
|
|
3064
|
+
const unregister = editor.registerUpdateListener(updateActive);
|
|
3065
|
+
return () => {
|
|
3066
|
+
cancelAnimationFrame(frame);
|
|
3067
|
+
scroller.removeEventListener("scroll", updateActive);
|
|
3068
|
+
unregister();
|
|
3069
|
+
};
|
|
3070
|
+
}, [editor]);
|
|
3071
|
+
const scrollTo = useCallback6(
|
|
3072
|
+
(key) => {
|
|
3073
|
+
editor.getEditorState().read(() => {
|
|
3074
|
+
const element = editor.getElementByKey(key);
|
|
3075
|
+
element?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
3076
|
+
});
|
|
3077
|
+
},
|
|
3078
|
+
[editor]
|
|
3079
|
+
);
|
|
3080
|
+
return /* @__PURE__ */ jsx9(TableOfContentsPlugin, { children: (entries) => {
|
|
3081
|
+
for (const [key] of entries) {
|
|
3082
|
+
editor.getElementByKey(key)?.setAttribute("data-outline-key", key);
|
|
3083
|
+
}
|
|
3084
|
+
return /* @__PURE__ */ jsxs7(
|
|
3085
|
+
"div",
|
|
3086
|
+
{
|
|
3087
|
+
className: `zui-text-editor-outline ${collapsed ? "is-collapsed" : ""}`,
|
|
3088
|
+
children: [
|
|
3089
|
+
/* @__PURE__ */ jsx9(
|
|
3090
|
+
"button",
|
|
3091
|
+
{
|
|
3092
|
+
type: "button",
|
|
3093
|
+
className: "zui-text-editor-outline-toggle",
|
|
3094
|
+
title: collapsed ? "Show outline" : "Hide outline",
|
|
3095
|
+
"aria-label": collapsed ? "Show outline" : "Hide outline",
|
|
3096
|
+
"aria-expanded": !collapsed,
|
|
3097
|
+
onClick: () => setCollapsed((c) => !c),
|
|
3098
|
+
children: /* @__PURE__ */ jsx9(
|
|
3099
|
+
"svg",
|
|
3100
|
+
{
|
|
3101
|
+
viewBox: "0 0 20 20",
|
|
3102
|
+
width: "14",
|
|
3103
|
+
height: "14",
|
|
3104
|
+
fill: "none",
|
|
3105
|
+
stroke: "currentColor",
|
|
3106
|
+
strokeWidth: "1.8",
|
|
3107
|
+
strokeLinecap: "round",
|
|
3108
|
+
children: /* @__PURE__ */ jsx9("path", { d: "M4 5h12M4 10h8M4 15h10" })
|
|
3109
|
+
}
|
|
3110
|
+
)
|
|
3111
|
+
}
|
|
3112
|
+
),
|
|
3113
|
+
!collapsed && /* @__PURE__ */ jsxs7("nav", { className: "zui-text-editor-outline-list", "aria-label": "Table of contents", children: [
|
|
3114
|
+
entries.length === 0 && /* @__PURE__ */ jsx9("div", { className: "zui-text-editor-outline-empty", children: "No headings" }),
|
|
3115
|
+
entries.map(([key, text, tag]) => /* @__PURE__ */ jsx9(
|
|
3116
|
+
"button",
|
|
3117
|
+
{
|
|
3118
|
+
type: "button",
|
|
3119
|
+
className: `zui-text-editor-outline-item ${key === activeKey ? "is-active" : ""}`,
|
|
3120
|
+
style: {
|
|
3121
|
+
paddingLeft: `${0.5 + INDENT_PER_LEVEL[tag] * 0.75}rem`
|
|
3122
|
+
},
|
|
3123
|
+
onClick: () => scrollTo(key),
|
|
3124
|
+
children: text || "Untitled"
|
|
3125
|
+
},
|
|
3126
|
+
key
|
|
3127
|
+
))
|
|
3128
|
+
] })
|
|
3129
|
+
]
|
|
3130
|
+
}
|
|
3131
|
+
);
|
|
3132
|
+
} });
|
|
3133
|
+
}
|
|
3134
|
+
|
|
3135
|
+
// src/MarkdownEditor.tsx
|
|
3136
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2784
3137
|
var DEFAULT_ITEMS = {
|
|
2785
|
-
format: /* @__PURE__ */
|
|
2786
|
-
insert: /* @__PURE__ */
|
|
2787
|
-
history: /* @__PURE__ */
|
|
3138
|
+
format: /* @__PURE__ */ jsx10(FormatButtons, {}),
|
|
3139
|
+
insert: /* @__PURE__ */ jsx10(InsertButtons, {}),
|
|
3140
|
+
history: /* @__PURE__ */ jsx10(HistoryButtons, {})
|
|
2788
3141
|
};
|
|
2789
3142
|
function EditorToolbar({
|
|
2790
3143
|
children,
|
|
@@ -2792,7 +3145,7 @@ function EditorToolbar({
|
|
|
2792
3145
|
}) {
|
|
2793
3146
|
const { mode, readOnly } = useEditorContext();
|
|
2794
3147
|
if (mode !== "edit-md" || readOnly) return null;
|
|
2795
|
-
return /* @__PURE__ */
|
|
3148
|
+
return /* @__PURE__ */ jsx10(Toolbar, { className, children });
|
|
2796
3149
|
}
|
|
2797
3150
|
function MarkdownEditor({
|
|
2798
3151
|
placeholder,
|
|
@@ -2801,10 +3154,10 @@ function MarkdownEditor({
|
|
|
2801
3154
|
foldable = true,
|
|
2802
3155
|
...rootProps
|
|
2803
3156
|
}) {
|
|
2804
|
-
return /* @__PURE__ */
|
|
2805
|
-
toolbar === true && /* @__PURE__ */
|
|
3157
|
+
return /* @__PURE__ */ jsxs8(EditorRoot, { ...rootProps, children: [
|
|
3158
|
+
toolbar === true && /* @__PURE__ */ jsx10(EditorToolbar, {}),
|
|
2806
3159
|
typeof toolbar === "function" && toolbar(DEFAULT_ITEMS),
|
|
2807
|
-
/* @__PURE__ */
|
|
3160
|
+
/* @__PURE__ */ jsx10(EditorContent, { placeholder, foldable, children: outline && /* @__PURE__ */ jsx10(OutlinePlugin, {}) })
|
|
2808
3161
|
] });
|
|
2809
3162
|
}
|
|
2810
3163
|
MarkdownEditor.Root = EditorRoot;
|
|
@@ -2832,7 +3185,11 @@ var DRAWING_DATA_JSON_SCHEMA = {
|
|
|
2832
3185
|
height: {
|
|
2833
3186
|
type: "number",
|
|
2834
3187
|
minimum: 80,
|
|
2835
|
-
description: "Canvas height in pixels
|
|
3188
|
+
description: "Canvas height in pixels"
|
|
3189
|
+
},
|
|
3190
|
+
width: {
|
|
3191
|
+
enum: ["full", "content"],
|
|
3192
|
+
description: `Canvas width: "full" (default) spans the editor; "content" fits the shapes' horizontal extent and left-aligns with the text`
|
|
2836
3193
|
},
|
|
2837
3194
|
shapes: {
|
|
2838
3195
|
type: "array",
|
|
@@ -2930,8 +3287,16 @@ var DRAWING_DATA_JSON_SCHEMA = {
|
|
|
2930
3287
|
export {
|
|
2931
3288
|
$createDrawingNode,
|
|
2932
3289
|
$createFrontmatterNode,
|
|
3290
|
+
$getSelectedTable,
|
|
3291
|
+
$getTableDensity,
|
|
3292
|
+
$getTableSettings,
|
|
3293
|
+
$getTableWidth,
|
|
2933
3294
|
$isDrawingNode,
|
|
2934
3295
|
$isFrontmatterNode,
|
|
3296
|
+
$setTableDensity,
|
|
3297
|
+
$setTableSettings,
|
|
3298
|
+
$setTableWidth,
|
|
3299
|
+
DEFAULT_TABLE_SETTINGS,
|
|
2935
3300
|
DRAWING,
|
|
2936
3301
|
DRAWING_DATA_JSON_SCHEMA,
|
|
2937
3302
|
DrawingNode,
|
|
@@ -2942,10 +3307,13 @@ export {
|
|
|
2942
3307
|
InsertButtons,
|
|
2943
3308
|
MarkdownEditor_default as MarkdownEditor,
|
|
2944
3309
|
TABLE,
|
|
3310
|
+
TABLE_WIDTH_MARKER,
|
|
2945
3311
|
Toolbar,
|
|
2946
3312
|
ToolbarButton,
|
|
2947
3313
|
ToolbarDivider,
|
|
3314
|
+
formatTableSettingsMarker,
|
|
2948
3315
|
parseDrawingData,
|
|
3316
|
+
parseTableSettingsMarker,
|
|
2949
3317
|
serializeDrawingData,
|
|
2950
3318
|
useMarkdownEditor
|
|
2951
3319
|
};
|