@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/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__ */ jsxs("g", { children: [
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__ */ jsx("text", { ...hint, x: cx, y: b.y + SMALL_FONT_SIZE + 7, fontSize: SMALL_FONT_SIZE, children: "Label" })),
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__ */ jsx("text", { ...hint, x: cx, y: mainStart, fontSize: FONT_SIZE, children: "Text" })),
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__ */ jsx("text", { ...hint, x: cx, y: b.y + b.h - 9, fontSize: SMALL_FONT_SIZE, children: "Footer" }))
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__ */ jsxs("g", { children: [
706
- /* @__PURE__ */ jsx(
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__ */ jsx(BoxTexts, { shape, hideField, showHints })
744
+ /* @__PURE__ */ jsx2(BoxTexts, { shape, hideField, showHints })
719
745
  ] });
720
746
  }
721
747
  case "ellipse": {
722
748
  const b = bbox(shape);
723
- return /* @__PURE__ */ jsxs("g", { children: [
724
- /* @__PURE__ */ jsx(
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__ */ jsx(BoxTexts, { shape, hideField, showHints })
761
+ /* @__PURE__ */ jsx2(BoxTexts, { shape, hideField, showHints })
736
762
  ] });
737
763
  }
738
764
  case "triangle":
739
765
  case "pentagon":
740
- return /* @__PURE__ */ jsxs("g", { children: [
741
- /* @__PURE__ */ jsx(
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__ */ jsx(BoxTexts, { shape, hideField, showHints })
775
+ /* @__PURE__ */ jsx2(BoxTexts, { shape, hideField, showHints })
750
776
  ] });
751
777
  case "line":
752
778
  case "arrow":
753
- return /* @__PURE__ */ jsxs("g", { children: [
754
- /* @__PURE__ */ jsx(
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__ */ jsx(ConnectorLabel, { shape })
788
+ shape.text && hideField !== "text" && /* @__PURE__ */ jsx2(ConnectorLabel, { shape })
763
789
  ] });
764
790
  case "text":
765
- return /* @__PURE__ */ jsx(
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__ */ jsx("tspan", { x: shape.x, dy: i === 0 ? 0 : FONT_SIZE * 1.35, children: line }, i))
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__ */ jsxs("g", { children: [
787
- /* @__PURE__ */ jsx(
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__ */ jsx(
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__ */ jsx("path", { d: "M4 2l12 6.5-5.2 1.6L8 16z", fill: "currentColor", stroke: "none" }),
817
- rect: /* @__PURE__ */ jsx("rect", { x: "3", y: "4.5", width: "14", height: "11", rx: "2" }),
818
- ellipse: /* @__PURE__ */ jsx("ellipse", { cx: "10", cy: "10", rx: "7", ry: "5.5" }),
819
- triangle: /* @__PURE__ */ jsx("path", { d: "M10 3.5L17 16.5H3z", strokeLinejoin: "round" }),
820
- pentagon: /* @__PURE__ */ jsx("path", { d: "M10 3L16.8 8.1L14.2 16.2H5.8L3.2 8.1z", strokeLinejoin: "round" }),
821
- arrow: /* @__PURE__ */ jsxs("g", { children: [
822
- /* @__PURE__ */ jsx("path", { d: "M4 16L16 4" }),
823
- /* @__PURE__ */ jsx("path", { d: "M9 4h7v7" })
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__ */ jsx("path", { d: "M4 16L16 4" }),
826
- text: /* @__PURE__ */ jsxs("g", { children: [
827
- /* @__PURE__ */ jsx("path", { d: "M4 5V3.5h12V5" }),
828
- /* @__PURE__ */ jsx("path", { d: "M10 3.5V16.5" }),
829
- /* @__PURE__ */ jsx("path", { d: "M7 16.5h6" })
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__ */ jsxs(
1352
+ return /* @__PURE__ */ jsxs2(
1303
1353
  "div",
1304
1354
  {
1305
- className: "zui-drawing-canvas",
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__ */ jsxs("div", { className: "zui-drawing-toolbar", onPointerDown: (e) => e.stopPropagation(), children: [
1310
- /* @__PURE__ */ jsx("div", { className: "zui-drawing-toolbar-group", children: TOOLS.map(({ tool: t, label }) => /* @__PURE__ */ jsx(
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__ */ jsx(
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__ */ jsxs("div", { className: "zui-drawing-toolbar-group", children: [
1339
- /* @__PURE__ */ jsx("span", { className: "zui-drawing-swatch-label", children: "Stroke" }),
1340
- STROKE_COLORS.map((color) => /* @__PURE__ */ jsx(
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__ */ jsxs("div", { className: "zui-drawing-toolbar-group", children: [
1354
- /* @__PURE__ */ jsx("span", { className: "zui-drawing-swatch-label", children: "Fill" }),
1355
- FILL_COLORS.map((color) => /* @__PURE__ */ jsx(
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__ */ jsxs("div", { className: "zui-drawing-toolbar-group", children: [
1369
- /* @__PURE__ */ jsx(
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__ */ jsx(
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__ */ jsx("path", { d: "M4 16L16 4" })
1437
+ children: /* @__PURE__ */ jsx2("path", { d: "M4 16L16 4" })
1388
1438
  }
1389
1439
  )
1390
1440
  }
1391
1441
  ),
1392
- /* @__PURE__ */ jsx(
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__ */ jsx(
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__ */ jsx("path", { d: "M4 16v-6h12V4" })
1461
+ children: /* @__PURE__ */ jsx2("path", { d: "M4 16v-6h12V4" })
1412
1462
  }
1413
1463
  )
1414
1464
  }
1415
1465
  )
1416
1466
  ] }),
1417
- selectedShape?.type === "arrow" && /* @__PURE__ */ jsxs("div", { className: "zui-drawing-toolbar-group", children: [
1418
- /* @__PURE__ */ jsx(
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__ */ jsx(
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__ */ jsx("path", { d: "M3 10h13M12 5.5L16.5 10L12 14.5" })
1487
+ children: /* @__PURE__ */ jsx2("path", { d: "M3 10h13M12 5.5L16.5 10L12 14.5" })
1438
1488
  }
1439
1489
  )
1440
1490
  }
1441
1491
  ),
1442
- /* @__PURE__ */ jsx(
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__ */ jsx(
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__ */ jsx("path", { d: "M3.5 10h13M8 5.5L3.5 10L8 14.5M12 5.5L16.5 10L12 14.5" })
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__ */ jsx("div", { className: "zui-drawing-toolbar-group", children: /* @__PURE__ */ jsx(
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__ */ jsx(
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__ */ jsx("path", { d: "M4 6h12M8 6V4h4v2M6 6l1 10h6l1-10M8.5 9v4M11.5 9v4" })
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__ */ jsxs(
1567
+ /* @__PURE__ */ jsxs2(
1492
1568
  "svg",
1493
1569
  {
1494
1570
  ref: svgRef,
1495
1571
  className: "zui-drawing-surface",
1496
- style: { height, cursor: canvasCursor },
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__ */ jsxs(
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__ */ jsx(
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__ */ jsx(HitArea, { shape }),
1537
- shape.id === editingText?.id && shape.type === "text" ? null : /* @__PURE__ */ jsx(
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__ */ jsx(
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__ */ jsx(
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__ */ jsx(
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__ */ jsx(
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__ */ jsxs("g", { children: [
1644
- ghosts.map(({ index, x, y }) => /* @__PURE__ */ jsx(
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__ */ jsx("title", { children: "Drag to add a point" })
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__ */ jsx(
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__ */ jsx("title", { children: "Drag to move, double-click to remove" })
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__ */ jsx(
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__ */ jsx(
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__ */ jsxs("g", { children: [
1736
- /* @__PURE__ */ jsx(
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__ */ jsx(
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__ */ jsx(
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 jsx2 } from "react/jsx-runtime";
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__ */ jsx2(DrawingCanvas, { nodeKey: this.getKey(), data: this.getData() });
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 (!$isTableNode(node)) return null;
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 || !$isTableNode(table2)) return;
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 ($isTableNode(previousSibling) && getTableColumnsSize(previousSibling) === maxCells) {
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 jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
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__ */ jsx3(LexicalComposer, { initialConfig, children: /* @__PURE__ */ jsx3(EditorContext.Provider, { value: context, children: /* @__PURE__ */ jsxs2("div", { className: `zui-text-editor ${className ?? ""}`, children: [
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__ */ jsxs2(Fragment, { children: [
2235
- /* @__PURE__ */ jsx3(
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__ */ jsx3(HistoryPlugin, {}),
2244
- /* @__PURE__ */ jsx3(ListPlugin, {}),
2245
- /* @__PURE__ */ jsx3(CheckListPlugin, {}),
2246
- /* @__PURE__ */ jsx3(ChecklistShortcutPlugin, {}),
2247
- /* @__PURE__ */ jsx3(CodeBlockShortcutPlugin, {}),
2248
- /* @__PURE__ */ jsx3(CodeHighlightPlugin, {}),
2249
- /* @__PURE__ */ jsx3(TablePlugin, {}),
2250
- /* @__PURE__ */ jsx3(LinkPlugin, {}),
2251
- /* @__PURE__ */ jsx3(MarkdownShortcutPlugin, { transformers: SHORTCUT_TRANSFORMERS }),
2252
- /* @__PURE__ */ jsx3(ReadOnlyPlugin, { readOnly: readOnly || mode === "view" }),
2253
- autoFocus && /* @__PURE__ */ jsx3(AutoFocusPlugin, {})
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 $getSelection2, $isRangeSelection as $isRangeSelection2 } from "lexical";
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 jsx4 } from "react/jsx-runtime";
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 = $getSelection2();
2310
- if ($isRangeSelection2(selection)) {
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__ */ jsx4("div", { className: "zui-text-editor-fold-gutter", children: buttons.map(({ key, folded, top, height }) => /* @__PURE__ */ jsx4(
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__ */ jsx4(
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__ */ jsx4("path", { d: "M6 8l4 4 4-4" })
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/EditorContent.tsx
2401
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
2402
- function EditorContent({
2403
- placeholder = "Start writing...",
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 useCallback5, useEffect as useEffect9, useState as useState5 } from "react";
2628
+ import { useCallback as useCallback4, useEffect as useEffect8, useState as useState4 } from "react";
2559
2629
  import {
2560
- $getSelection as $getSelection3,
2561
- $isRangeSelection as $isRangeSelection3,
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 useLexicalComposerContext9 } from "@lexical/react/LexicalComposerContext";
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] = useLexicalComposerContext9();
2581
- const [activeFormats, setActiveFormats] = useState5(
2650
+ const [editor] = useLexicalComposerContext8();
2651
+ const [activeFormats, setActiveFormats] = useState4(
2582
2652
  /* @__PURE__ */ new Set()
2583
2653
  );
2584
- const [canUndo, setCanUndo] = useState5(false);
2585
- const [canRedo, setCanRedo] = useState5(false);
2586
- useEffect9(
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 selection = $getSelection3();
2591
- if (!$isRangeSelection3(selection)) {
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 = useCallback5(
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 = useCallback5(
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 = useCallback5(() => {
2710
+ const insertDrawing = useCallback4(() => {
2638
2711
  editor.update(() => {
2639
2712
  $insertNodeToNearestRoot($createDrawingNode());
2640
2713
  });
2641
2714
  }, [editor]);
2642
- const undo = useCallback5(() => {
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 = useCallback5(() => {
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 Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
2756
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
2663
2757
  function Toolbar({ children, className }) {
2664
- return /* @__PURE__ */ jsx7(
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__ */ jsxs5(Fragment2, { children: [
2670
- /* @__PURE__ */ jsx7(FormatButtons, {}),
2671
- /* @__PURE__ */ jsx7(ToolbarDivider, {}),
2672
- /* @__PURE__ */ jsx7(InsertButtons, {})
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__ */ jsx7("div", { className: "zui-text-editor-toolbar-divider" });
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__ */ jsx7(
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__ */ jsx7(
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__ */ jsx7(Icon, { strokeWidth: 1.8, children: /* @__PURE__ */ jsx7("path", { d: "M6 3.5h5a3 3 0 0 1 0 6H6zm0 6h6a3 3 0 0 1 0 6H6z" }) })
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__ */ jsx7(Icon, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx7("path", { d: "M8.5 3.5h6M5.5 16.5h6M11.5 3.5l-3 13" }) })
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__ */ jsx7(Icon, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx7("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" }) })
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__ */ jsx7(Icon, { strokeWidth: 1.6, children: /* @__PURE__ */ jsx7("path", { d: "M7.5 6L4 10l3.5 4M12.5 6L16 10l-3.5 4" }) })
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__ */ jsx7(Fragment2, { children: FORMAT_BUTTONS.map(({ format, label, icon }) => /* @__PURE__ */ jsx7(
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__ */ jsxs5(Fragment2, { children: [
2757
- /* @__PURE__ */ jsx7(ToolbarButton, { label: "Insert table", onClick: () => insertTable(), children: /* @__PURE__ */ jsxs5(Icon, { children: [
2758
- /* @__PURE__ */ jsx7("rect", { x: "3", y: "3.5", width: "14", height: "13", rx: "1.5" }),
2759
- /* @__PURE__ */ jsx7("path", { d: "M3 8h14M8 8v8.5M13 8v8.5" })
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__ */ jsx7(ToolbarButton, { label: "Insert drawing", onClick: insertDrawing, children: /* @__PURE__ */ jsxs5(Icon, { children: [
2762
- /* @__PURE__ */ jsx7("rect", { x: "3", y: "5", width: "8", height: "6", rx: "1.5" }),
2763
- /* @__PURE__ */ jsx7("path", { d: "M13.5 8h3M14.5 6.5L17.5 8l-3 1.5" }),
2764
- /* @__PURE__ */ jsx7("ellipse", { cx: "13", cy: "14.5", rx: "4", ry: "2.8" })
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__ */ jsxs5(Fragment2, { children: [
2771
- /* @__PURE__ */ jsx7(ToolbarButton, { label: "Undo", onClick: undo, disabled: !canUndo, children: /* @__PURE__ */ jsxs5(Icon, { children: [
2772
- /* @__PURE__ */ jsx7("path", { d: "M7 6L3.5 9.5 7 13" }),
2773
- /* @__PURE__ */ jsx7("path", { d: "M3.5 9.5H12a4 4 0 0 1 0 8h-1" })
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__ */ jsx7(ToolbarButton, { label: "Redo", onClick: redo, disabled: !canRedo, children: /* @__PURE__ */ jsxs5(Icon, { children: [
2776
- /* @__PURE__ */ jsx7("path", { d: "M13 6l3.5 3.5L13 13" }),
2777
- /* @__PURE__ */ jsx7("path", { d: "M16.5 9.5H8a4 4 0 0 0 0 8h1" })
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/MarkdownEditor.tsx
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__ */ jsx8(FormatButtons, {}),
2786
- insert: /* @__PURE__ */ jsx8(InsertButtons, {}),
2787
- history: /* @__PURE__ */ jsx8(HistoryButtons, {})
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__ */ jsx8(Toolbar, { className, children });
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__ */ jsxs6(EditorRoot, { ...rootProps, children: [
2805
- toolbar === true && /* @__PURE__ */ jsx8(EditorToolbar, {}),
3157
+ return /* @__PURE__ */ jsxs8(EditorRoot, { ...rootProps, children: [
3158
+ toolbar === true && /* @__PURE__ */ jsx10(EditorToolbar, {}),
2806
3159
  typeof toolbar === "function" && toolbar(DEFAULT_ITEMS),
2807
- /* @__PURE__ */ jsx8(EditorContent, { placeholder, foldable, children: outline && /* @__PURE__ */ jsx8(OutlinePlugin, {}) })
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 (width is fluid)"
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
  };