@zuilib/text-editor 0.3.1 → 0.5.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.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, ReactElement } from 'react';
3
3
  import { LexicalEditor, TextFormatType, ElementNode, NodeKey, EditorConfig, SerializedElementNode, LexicalNode, DecoratorNode, Spread, SerializedLexicalNode, DOMExportOutput, DOMConversionMap } from 'lexical';
4
- import { MultilineElementTransformer, ElementTransformer } from '@lexical/markdown';
5
4
  import { TableNode } from '@lexical/table';
5
+ import { MultilineElementTransformer, ElementTransformer } from '@lexical/markdown';
6
6
 
7
7
  type EditorMode = 'edit-raw' | 'edit-md' | 'view';
8
8
  type EditorRootProps = Readonly<{
@@ -48,6 +48,28 @@ declare function OutlinePlugin(): ReactElement;
48
48
  */
49
49
  type BlockWidth = 'full' | 'content';
50
50
 
51
+ /** Cell padding / font size preset */
52
+ type TableDensity = 'compact' | 'comfortable' | 'spacious';
53
+ type TableSettings = Readonly<{
54
+ width: BlockWidth;
55
+ density: TableDensity;
56
+ }>;
57
+ declare const DEFAULT_TABLE_SETTINGS: TableSettings;
58
+ declare function $getTableSettings(table: TableNode): TableSettings;
59
+ declare function $setTableSettings(table: TableNode, settings: Partial<TableSettings>): void;
60
+ declare function $getTableWidth(table: TableNode): BlockWidth;
61
+ declare function $setTableWidth(table: TableNode, width: BlockWidth): void;
62
+ declare function $getTableDensity(table: TableNode): TableDensity;
63
+ declare function $setTableDensity(table: TableNode, density: TableDensity): void;
64
+ /** The table containing the current selection (caret or cell range), if any */
65
+ declare function $getSelectedTable(): TableNode | null;
66
+ /** @deprecated Use `formatTableSettingsMarker({ ...DEFAULT_TABLE_SETTINGS, width: 'content' })` */
67
+ declare const TABLE_WIDTH_MARKER = "<!-- width: content -->";
68
+ /** Settings encoded in a marker line, or null if the text is not a marker */
69
+ declare function parseTableSettingsMarker(text: string): Partial<TableSettings> | null;
70
+ /** Marker line for the given settings, or null when everything is default */
71
+ declare function formatTableSettingsMarker(settings: TableSettings): string | null;
72
+
51
73
  type MarkdownEditorApi = Readonly<{
52
74
  /** The underlying Lexical editor, for dispatching your own commands */
53
75
  editor: LexicalEditor;
@@ -63,6 +85,10 @@ type MarkdownEditorApi = Readonly<{
63
85
  tableWidth: BlockWidth | null;
64
86
  /** Resize the table containing the selection; no-op outside tables */
65
87
  setTableWidth: (width: BlockWidth) => void;
88
+ /** Density of the table containing the selection; `null` outside tables */
89
+ tableDensity: TableDensity | null;
90
+ /** Change the density of the table containing the selection; no-op outside tables */
91
+ setTableDensity: (density: TableDensity) => void;
66
92
  canUndo: boolean;
67
93
  canRedo: boolean;
68
94
  undo: () => void;
@@ -184,14 +210,39 @@ declare function $isFrontmatterNode(node: LexicalNode | null | undefined): node
184
210
  */
185
211
  declare const FRONTMATTER: MultilineElementTransformer;
186
212
 
187
- type DrawingShapeType = 'rect' | 'ellipse' | 'triangle' | 'pentagon' | 'arrow' | 'line' | 'text';
213
+ /** Card-like shapes: fillable, bindable, carrying the three text slots */
214
+ type BoxType = 'rect' | 'ellipse' | 'diamond' | 'note' | 'cylinder' | 'cloud' | 'queue' | 'actor';
215
+ type ConnectorType = 'arrow' | 'line';
216
+ type DrawingShapeType = BoxType | ConnectorType | 'text';
217
+ declare const BOX_TYPES: readonly BoxType[];
218
+ declare const CONNECTOR_TYPES: readonly ConnectorType[];
219
+ declare const SHAPE_TYPES: readonly DrawingShapeType[];
220
+ type Point = Readonly<{
221
+ x: number;
222
+ y: number;
223
+ }>;
224
+ type BindingSide = 'top' | 'right' | 'bottom' | 'left';
225
+ /**
226
+ * Where a connector endpoint attaches to a box.
227
+ *
228
+ * `fixedPoint` is a ratio inside the box's bounding box (`[0,0]` top-left,
229
+ * `[1,1]` bottom-right). Omitted = the box center, which makes the endpoint
230
+ * auto-aim at the other end. `mode: 'inside'` pins the endpoint exactly on
231
+ * the fixed point; the default (`'orbit'`) projects it onto the outline with
232
+ * a small gap.
233
+ */
234
+ type Binding = Readonly<{
235
+ id: string;
236
+ fixedPoint?: readonly [number, number];
237
+ mode?: 'orbit' | 'inside';
238
+ }>;
188
239
  type DrawingShape = Readonly<{
189
240
  id: string;
190
241
  type: DrawingShapeType;
191
- /** Top-left corner (rect/ellipse/text) or start point (arrow/line) */
242
+ /** Top-left corner (boxes/text) or start point (connectors) */
192
243
  x: number;
193
244
  y: number;
194
- /** Size (rect/ellipse) or delta to the end point (arrow/line) */
245
+ /** Size (boxes/text) or delta to the end point (connectors) */
195
246
  w: number;
196
247
  h: number;
197
248
  stroke: string;
@@ -203,44 +254,62 @@ type DrawingShape = Readonly<{
203
254
  label?: string;
204
255
  /** Small line rendered at the bottom of a box */
205
256
  footer?: string;
206
- /** Arrow/line: id of the box the start point is attached to */
207
- startBinding?: string;
208
- /** Arrow/line: id of the box the end point is attached to */
209
- endBinding?: string;
210
- /** Arrow: render arrowheads on both ends */
257
+ /** Connector: box the start point is attached to */
258
+ startBinding?: Binding;
259
+ /** Connector: box the end point is attached to */
260
+ endBinding?: Binding;
261
+ /** Arrow: arrowheads on both ends */
211
262
  bidirectional?: boolean;
212
- /** Connector routing: right-angled elbow path instead of a straight line */
263
+ /** Connector routing: right-angled auto-routed path instead of a straight line */
213
264
  routing?: 'elbow';
214
- /** Elbow middle-segment position as a fraction of the span (default 0.5) */
265
+ /**
266
+ * Elbow override: position of the middle segment as a fraction of the
267
+ * span, applied only when the routed path is a simple three-segment Z.
268
+ */
215
269
  elbow?: number;
216
270
  /**
217
271
  * Connector: intermediate path points between start and end (absolute
218
272
  * canvas coordinates). Takes precedence over `routing`.
219
273
  */
220
- waypoints?: ReadonlyArray<{
221
- x: number;
222
- y: number;
223
- }>;
274
+ waypoints?: readonly Point[];
224
275
  }>;
225
276
  type DrawingData = Readonly<{
226
- version: 1;
227
- height: number;
277
+ version: 2;
228
278
  /**
229
- * Canvas width: `full` (default, omitted when serialized) spans the editor;
230
- * `content` fits the shapes' horizontal extent.
279
+ * Logical canvas width. When set the drawing is scaled to fit narrower
280
+ * layouts (SVG viewBox); when omitted the canvas is fluid and shapes are
281
+ * in CSS pixels.
282
+ */
283
+ canvasWidth?: number;
284
+ canvasHeight: number;
285
+ /**
286
+ * Block width: `full` (default, omitted when serialized) spans the
287
+ * editor; `content` fits the shapes' horizontal extent.
231
288
  */
232
289
  width?: BlockWidth;
233
290
  shapes: readonly DrawingShape[];
234
291
  }>;
292
+ declare const EMPTY_DRAWING: DrawingData;
293
+ declare const STROKE_COLORS: readonly ["#1e1e1e", "#e03131", "#2f9e44", "#1971c2", "#f08c00", "#7048e8"];
294
+ declare const FILL_COLORS: readonly ["transparent", "#ffc9c9", "#b2f2bb", "#a5d8ff", "#ffec99", "#d0bfff"];
295
+ /** Edge midpoints, used by the ```diagram skeleton's `side` option */
296
+ declare const SIDE_FIXED_POINTS: Record<BindingSide, readonly [number, number]>;
235
297
  declare function serializeDrawingData(data: DrawingData): string;
298
+ /**
299
+ * Parse a ```drawing payload. Exactly one format is accepted: version 2 as
300
+ * written by the editor (the ```diagram skeleton is a separate block type,
301
+ * see skeleton.ts). Shapes that fail validation are dropped and a malformed
302
+ * document yields an empty canvas. Never throws.
303
+ */
236
304
  declare function parseDrawingData(json: string): DrawingData;
305
+ declare function normalizeDrawingData(parsed: unknown): DrawingData;
237
306
 
238
307
  type SerializedDrawingNode = Spread<{
239
308
  data: string;
240
309
  }, SerializedLexicalNode>;
241
310
  /**
242
- * A block-level decorator node embedding a vector drawing (rectangles,
243
- * ellipses, arrows, lines, text) edited on an Excalidraw-style canvas.
311
+ * A block-level decorator node embedding a vector diagram (cards, connectors,
312
+ * text) edited on a canvas.
244
313
  *
245
314
  * The drawing is stored as a JSON string and round-trips through markdown as
246
315
  * a ```drawing fenced code block, so documents remain plain markdown.
@@ -269,55 +338,62 @@ declare function $isDrawingNode(node: LexicalNode | null | undefined): node is D
269
338
  * claims the fence first on import.
270
339
  */
271
340
  declare const DRAWING: MultilineElementTransformer;
341
+ /**
342
+ * Import-only transformer for ```diagram blocks: a compact skeleton
343
+ * (boxes, connectors by id, auto layout) that expands into a full drawing.
344
+ * Once in the editor the node is a regular drawing and exports as
345
+ * ```drawing, so the expansion is one-way.
346
+ */
347
+ declare const DIAGRAM: MultilineElementTransformer;
272
348
 
273
349
  /**
274
350
  * Markdown transformer for GFM tables. Adapted from the Lexical playground.
275
351
  * Rows are matched line-by-line on import and stitched into a single
276
352
  * TableNode; the divider row promotes the row above it to a header row.
277
- * A `<!-- width: content -->` line directly above the table marks it as
278
- * content-width (see tableWidth.ts); it is consumed on import and re-emitted
279
- * on export.
353
+ * A `<!-- width: content; density: compact -->` settings line directly
354
+ * above the table (see tableSettings.ts) is consumed on import and
355
+ * re-emitted on export.
280
356
  */
281
357
  declare const TABLE: ElementTransformer;
282
358
 
283
359
  /**
284
- * A content-width table is persisted in markdown as a GFM table preceded by
285
- * this HTML comment on its own line. Renderers that don't know the marker
286
- * simply hide the comment.
287
- */
288
- declare const TABLE_WIDTH_MARKER = "<!-- width: content -->";
289
- declare function $getTableWidth(table: TableNode): BlockWidth;
290
- declare function $setTableWidth(table: TableNode, width: BlockWidth): void;
291
- /** The table containing the current selection (caret or cell range), if any */
292
- declare function $getSelectedTable(): TableNode | null;
293
-
294
- /**
295
- * JSON Schema (draft-07) for the payload of a ```drawing fenced block.
360
+ * JSON Schema (draft-07) for the payload of a ```drawing fenced block
361
+ * (format version 2).
296
362
  *
297
363
  * Use it to validate LLM- or tool-generated drawings before embedding them,
298
364
  * or pass it as a structured-output / tool schema so a model is forced to
299
- * emit valid payloads. Kept in sync with `parseDrawingData` / `isValidShape`
300
- * in drawingTypes.ts update both together.
365
+ * emit valid payloads. Kept in sync with `parseDrawingData` /
366
+ * `normalizeShape` in types.ts; update both together.
367
+ *
368
+ * For generation prefer the ```diagram skeleton
369
+ * (`DRAWING_SKELETON_JSON_SCHEMA`): it needs no coordinates and expands into
370
+ * this format on import.
301
371
  */
302
372
  declare const DRAWING_DATA_JSON_SCHEMA: {
303
373
  readonly $schema: "http://json-schema.org/draft-07/schema#";
304
374
  readonly title: "DrawingData";
305
- readonly description: "Vector drawing embedded in markdown as a ```drawing fenced code block";
375
+ readonly description: "Vector drawing embedded in markdown as a ```drawing fenced code block (format version 2)";
306
376
  readonly type: "object";
307
- readonly required: readonly ["version", "height", "shapes"];
377
+ readonly required: readonly ["version", "canvasHeight", "shapes"];
308
378
  readonly additionalProperties: false;
309
379
  readonly properties: {
310
380
  readonly version: {
311
- readonly const: 1;
381
+ readonly const: 2;
382
+ readonly description: "Format version; always 2";
312
383
  };
313
- readonly height: {
384
+ readonly canvasHeight: {
314
385
  readonly type: "number";
315
386
  readonly minimum: 80;
316
- readonly description: "Canvas height in pixels";
387
+ readonly description: "Canvas height in pixels. Make it large enough to contain every shape plus ~20px margin.";
388
+ };
389
+ readonly canvasWidth: {
390
+ readonly type: "number";
391
+ readonly minimum: 120;
392
+ readonly description: "Optional logical canvas width in pixels. When set, the drawing is scaled down to fit narrower layouts (SVG viewBox) so coordinates can assume this width. When omitted the canvas is fluid and coordinates are CSS pixels.";
317
393
  };
318
394
  readonly width: {
319
395
  readonly enum: readonly ["full", "content"];
320
- readonly description: "Canvas width: \"full\" (default) spans the editor; \"content\" fits the shapes' horizontal extent and left-aligns with the text";
396
+ readonly description: "Block width: \"full\" (default, omit it) spans the editor; \"content\" fits the shapes' horizontal extent and left-aligns with the text";
321
397
  };
322
398
  readonly shapes: {
323
399
  readonly type: "array";
@@ -335,9 +411,38 @@ declare const DRAWING_DATA_JSON_SCHEMA: {
335
411
  readonly properties: {
336
412
  readonly x: {
337
413
  readonly type: "number";
414
+ readonly description: "Absolute canvas x";
338
415
  };
339
416
  readonly y: {
340
417
  readonly type: "number";
418
+ readonly description: "Absolute canvas y";
419
+ };
420
+ };
421
+ };
422
+ readonly binding: {
423
+ readonly type: "object";
424
+ readonly description: "Where a connector endpoint attaches to a box. Omit fixedPoint to let the endpoint auto-aim from the box center at the other end.";
425
+ readonly required: readonly ["id"];
426
+ readonly additionalProperties: false;
427
+ readonly properties: {
428
+ readonly id: {
429
+ readonly type: "string";
430
+ readonly description: "Id of the box this endpoint is attached to";
431
+ };
432
+ readonly fixedPoint: {
433
+ readonly type: "array";
434
+ readonly items: {
435
+ readonly type: "number";
436
+ readonly minimum: 0;
437
+ readonly maximum: 1;
438
+ };
439
+ readonly minItems: 2;
440
+ readonly maxItems: 2;
441
+ readonly description: "Attach point as a ratio of the box's bounding box: [0,0] top-left, [1,1] bottom-right, [0.5,0] top edge midpoint, [1,0.5] right edge midpoint. Omitted: the endpoint auto-aims from the box center at the other end.";
442
+ };
443
+ readonly mode: {
444
+ readonly enum: readonly ["orbit", "inside"];
445
+ readonly description: "\"orbit\" (default): the endpoint is projected onto the box outline with a 6px gap. \"inside\": the endpoint sits exactly on the fixed point.";
341
446
  };
342
447
  };
343
448
  };
@@ -351,7 +456,8 @@ declare const DRAWING_DATA_JSON_SCHEMA: {
351
456
  readonly description: "Unique within the drawing; connector bindings reference it";
352
457
  };
353
458
  readonly type: {
354
- readonly enum: readonly ["rect", "ellipse", "triangle", "pentagon", "arrow", "line", "text"];
459
+ readonly enum: readonly ["rect", "ellipse", "diamond", "note", "cylinder", "cloud", "queue", "actor", "arrow", "line", "text"];
460
+ readonly description: "Boxes (cards with label/text/footer slots): rect, ellipse, diamond, note (sticky note with a folded corner), cylinder (database), cloud, queue (horizontal cylinder), actor (stick figure; only the text slot, rendered as a name under the figure). Connectors: arrow (head at the end), line. Free-floating annotation: text.";
355
461
  };
356
462
  readonly x: {
357
463
  readonly type: "number";
@@ -371,11 +477,11 @@ declare const DRAWING_DATA_JSON_SCHEMA: {
371
477
  };
372
478
  readonly stroke: {
373
479
  readonly type: "string";
374
- readonly description: "CSS color of the outline (and of any text)";
480
+ readonly description: "CSS color of the outline (and of any text). Palette: #1e1e1e (default), #e03131 red, #2f9e44 green, #1971c2 blue, #f08c00 orange, #7048e8 purple.";
375
481
  };
376
482
  readonly fill: {
377
483
  readonly type: "string";
378
- readonly description: "CSS color of the interior; \"transparent\" for none";
484
+ readonly description: "CSS color of the interior; \"transparent\" for none. Palette: #ffc9c9 red, #b2f2bb green, #a5d8ff blue, #ffec99 yellow, #d0bfff purple.";
379
485
  };
380
486
  readonly strokeWidth: {
381
487
  readonly type: "number";
@@ -383,23 +489,23 @@ declare const DRAWING_DATA_JSON_SCHEMA: {
383
489
  };
384
490
  readonly text: {
385
491
  readonly type: "string";
386
- readonly description: "Standalone text content; center content of a box; midpoint label of a connector";
492
+ readonly description: "Standalone text content; center content of a box (the name under an actor); midpoint label of a connector";
387
493
  };
388
494
  readonly label: {
389
495
  readonly type: "string";
390
- readonly description: "Boxes only: small bold heading at the top";
496
+ readonly description: "Boxes only (not actor): small bold heading at the top";
391
497
  };
392
498
  readonly footer: {
393
499
  readonly type: "string";
394
- readonly description: "Boxes only: small dim line at the bottom";
500
+ readonly description: "Boxes only (not actor): small dim line at the bottom";
395
501
  };
396
502
  readonly startBinding: {
397
- readonly type: "string";
398
- readonly description: "Connectors only: id of the box the start attaches to. The editor re-anchors the endpoint onto that box’s border.";
503
+ readonly $ref: "#/definitions/binding";
504
+ readonly description: "Connectors only: box the start point attaches to. The editor re-anchors the endpoint onto that box and keeps it attached as the box moves.";
399
505
  };
400
506
  readonly endBinding: {
401
- readonly type: "string";
402
- readonly description: "Connectors only: id of the box the end attaches to";
507
+ readonly $ref: "#/definitions/binding";
508
+ readonly description: "Connectors only: box the end point attaches to";
403
509
  };
404
510
  readonly bidirectional: {
405
511
  readonly type: "boolean";
@@ -407,24 +513,382 @@ declare const DRAWING_DATA_JSON_SCHEMA: {
407
513
  };
408
514
  readonly routing: {
409
515
  readonly const: "elbow";
410
- readonly description: "Connectors only: orthogonal (right-angled) auto-routing. Ignored when waypoints are present.";
516
+ readonly description: "Connectors only: right-angled auto-routed path. It leaves the box perpendicular to the attach side, avoids every box on the canvas and minimises bends. Ignored when waypoints are present.";
411
517
  };
412
518
  readonly elbow: {
413
519
  readonly type: "number";
414
520
  readonly minimum: 0;
415
521
  readonly maximum: 1;
416
- readonly description: "Elbow middle-segment position as a fraction of the span (default 0.5)";
522
+ readonly description: "Elbow override: position of the middle segment as a fraction of the span. Applied only when the routed path is a simple three-segment Z.";
417
523
  };
418
524
  readonly waypoints: {
419
525
  readonly type: "array";
420
526
  readonly items: {
421
527
  readonly $ref: "#/definitions/point";
422
528
  };
423
- readonly description: "Connectors only: intermediate path points in canvas coordinates, ordered startend. Takes precedence over routing.";
529
+ readonly description: "Connectors only: intermediate path points in canvas coordinates, ordered start to end. Takes precedence over routing.";
530
+ };
531
+ };
532
+ };
533
+ };
534
+ };
535
+
536
+ type Rect = Readonly<{
537
+ x: number;
538
+ y: number;
539
+ w: number;
540
+ h: number;
541
+ }>;
542
+
543
+ declare function boxOutline(box: DrawingShape): Point[];
544
+ /** Topmost box under a point, if any; smaller boxes win over enclosing ones */
545
+ declare function findBoxAt(shapes: readonly DrawingShape[], point: Point, excludeId?: string, tolerance?: number): DrawingShape | null;
546
+ /** The point a binding refers to: its fixed point, or the box center */
547
+ declare function anchorPoint(box: DrawingShape, binding?: Binding): Point;
548
+ /**
549
+ * Fixed point for a drop at `point`: undefined (auto-aim) for drops near
550
+ * the center, otherwise a ratio snapped onto the nearest bounding-box edge.
551
+ */
552
+ declare function fixedPointFor(box: DrawingShape, point: Point): [number, number] | undefined;
553
+ /**
554
+ * Recompute the endpoints of every bound connector from the current
555
+ * positions of the boxes they're attached to, and drop bindings whose box
556
+ * no longer exists. Idempotent, so it can run after every shape update.
557
+ */
558
+ declare function resolveBindings(shapes: readonly DrawingShape[]): readonly DrawingShape[];
559
+ /** Attach a freshly drawn connector to the boxes under its endpoints */
560
+ declare function bindEndpoints(shape: DrawingShape, shapes: readonly DrawingShape[]): DrawingShape;
561
+ declare function makeBinding(box: DrawingShape, point: Point): Binding;
562
+
563
+ /** Vertices of a connector's path, start to end */
564
+ declare function connectorPoints(shape: DrawingShape, shapes?: readonly DrawingShape[]): Point[];
565
+
566
+ /**
567
+ * Orthogonal route for an elbow connector: leaves each bound box
568
+ * perpendicular to its attach side, avoids every box on the canvas, and
569
+ * takes the path with the fewest bends (then the shortest). Falls back to
570
+ * a plain L when the grid search fails.
571
+ */
572
+ declare function routeElbow(shape: DrawingShape, shapes: readonly DrawingShape[]): Point[];
573
+
574
+ type TextField = 'text' | 'label' | 'footer';
575
+ /**
576
+ * Geometry of a box type, kept free of React so the router, bindings,
577
+ * skeleton expansion and exporters can use it without a DOM.
578
+ */
579
+ type BoxDefinition = Readonly<{
580
+ type: BoxType;
581
+ label: string;
582
+ /** Size used when a shape is created without explicit dimensions */
583
+ defaultSize: Readonly<{
584
+ w: number;
585
+ h: number;
586
+ }>;
587
+ /** Text slots the shape renders (and offers for editing) */
588
+ textSlots: readonly TextField[];
589
+ /** Fill applied when the tool is picked with the default (transparent) fill */
590
+ defaultFill?: string;
591
+ /** Closed outline used for hit-testing and binding endpoints */
592
+ outline: (shape: DrawingShape) => Point[];
593
+ /** Area the text slots lay out in */
594
+ textArea: (shape: DrawingShape) => Rect;
595
+ }>;
596
+ declare const BOX_DEFINITIONS: Record<BoxType, BoxDefinition>;
597
+
598
+ type ColorName = 'gray' | 'red' | 'green' | 'blue' | 'orange' | 'purple';
599
+ declare const COLOR_PRESETS: Record<ColorName, {
600
+ stroke: string;
601
+ fill: string;
602
+ }>;
603
+ type SkeletonBox = Readonly<{
604
+ id: string;
605
+ /** Default `'rect'` */
606
+ type?: BoxType;
607
+ label?: string;
608
+ text?: string;
609
+ footer?: string;
610
+ /** Omitted → auto layout */
611
+ x?: number;
612
+ y?: number;
613
+ /** Omitted → measured from the text, never smaller than the type's default size */
614
+ w?: number;
615
+ h?: number;
616
+ /** Preset → stroke + fill (fill only when `fill` isn't given) */
617
+ color?: ColorName;
618
+ stroke?: string;
619
+ fill?: string;
620
+ }>;
621
+ type SkeletonEnd = string | Readonly<{
622
+ id: string;
623
+ side?: BindingSide;
624
+ }>;
625
+ type SkeletonConnector = Readonly<{
626
+ id?: string;
627
+ /** Default `'arrow'` */
628
+ type?: ConnectorType;
629
+ from: SkeletonEnd;
630
+ to: SkeletonEnd;
631
+ text?: string;
632
+ bidirectional?: boolean;
633
+ /** Default `'straight'` */
634
+ routing?: 'elbow' | 'straight';
635
+ color?: ColorName;
636
+ stroke?: string;
637
+ }>;
638
+ type SkeletonText = Readonly<{
639
+ id?: string;
640
+ x: number;
641
+ y: number;
642
+ text: string;
643
+ color?: ColorName;
644
+ stroke?: string;
645
+ }>;
646
+ type DrawingSkeleton = Readonly<{
647
+ /** Auto-layout flow direction, default `'right'` */
648
+ direction?: 'right' | 'down';
649
+ canvasWidth?: number;
650
+ canvasHeight?: number;
651
+ width?: 'content';
652
+ boxes: readonly SkeletonBox[];
653
+ connectors?: readonly SkeletonConnector[];
654
+ texts?: readonly SkeletonText[];
655
+ }>;
656
+ /** Structural check: an object with a `boxes` array */
657
+ declare function isDrawingSkeleton(value: unknown): value is DrawingSkeleton;
658
+ /**
659
+ * Parse a skeleton JSON payload into drawing data. Lenient: invalid boxes,
660
+ * connectors and texts are dropped individually, and a malformed document
661
+ * yields an empty canvas. Never throws.
662
+ */
663
+ declare function parseDrawingSkeleton(json: string): DrawingData;
664
+ declare function expandSkeleton(skeleton: DrawingSkeleton): DrawingData;
665
+ declare const DRAWING_SKELETON_JSON_SCHEMA: {
666
+ readonly $schema: "http://json-schema.org/draft-07/schema#";
667
+ readonly title: "DrawingSkeleton";
668
+ readonly description: "Compact intent description of a diagram. Boxes are sized from their text and laid out automatically along the connector flow; connectors are drawn between box outlines. Only say what is on the canvas — geometry is derived";
669
+ readonly type: "object";
670
+ readonly required: readonly ["boxes"];
671
+ readonly additionalProperties: false;
672
+ readonly properties: {
673
+ readonly direction: {
674
+ readonly enum: readonly ["right", "down"];
675
+ readonly description: "Auto-layout flow direction. Boxes connected a→b are placed in successive ranks along this axis (\"right\" = columns left to right, \"down\" = rows top to bottom). Default \"right\"";
676
+ };
677
+ readonly canvasWidth: {
678
+ readonly type: "number";
679
+ readonly minimum: 120;
680
+ readonly description: "Logical canvas width in px. Omit for a fluid canvas in CSS pixels";
681
+ };
682
+ readonly canvasHeight: {
683
+ readonly type: "number";
684
+ readonly minimum: 80;
685
+ readonly description: "Canvas height in px. Omit to fit the content";
686
+ };
687
+ readonly width: {
688
+ readonly enum: readonly ["content"];
689
+ readonly description: "Block width: \"content\" fits the drawing to its shapes and left-aligns it with the text; omit to span the editor";
690
+ };
691
+ readonly boxes: {
692
+ readonly type: "array";
693
+ readonly items: {
694
+ readonly $ref: "#/definitions/box";
695
+ };
696
+ readonly description: "Card-like shapes carrying up to three text slots. Order is the render order and the stacking order within a layout rank";
697
+ };
698
+ readonly connectors: {
699
+ readonly type: "array";
700
+ readonly items: {
701
+ readonly $ref: "#/definitions/connector";
702
+ };
703
+ readonly description: "Arrows and lines between boxes. Connectors whose from/to id does not match a box are dropped";
704
+ };
705
+ readonly texts: {
706
+ readonly type: "array";
707
+ readonly items: {
708
+ readonly $ref: "#/definitions/text";
709
+ };
710
+ readonly description: "Free-floating annotations not attached to any box. Prefer box slots (label/text/footer) when the text belongs to a box";
711
+ };
712
+ };
713
+ readonly definitions: {
714
+ readonly box: {
715
+ readonly type: "object";
716
+ readonly required: readonly ["id"];
717
+ readonly additionalProperties: false;
718
+ readonly properties: {
719
+ readonly id: {
720
+ readonly type: "string";
721
+ readonly description: "Unique within the drawing; connectors reference it";
722
+ };
723
+ readonly type: {
724
+ readonly enum: readonly BoxType[];
725
+ readonly description: "Shape: rect (default), ellipse, diamond (decision), note (sticky note, yellow by default), cylinder (database), cloud (external system), queue (message queue), actor (stick figure; only the \"text\" slot renders, below the figure)";
726
+ };
727
+ readonly label: {
728
+ readonly type: "string";
729
+ readonly description: "Small bold heading at the top of the box";
730
+ };
731
+ readonly text: {
732
+ readonly type: "string";
733
+ readonly description: "Main content, centered. Wraps automatically; \"\\n\" forces a line break";
734
+ };
735
+ readonly footer: {
736
+ readonly type: "string";
737
+ readonly description: "Small dim line at the bottom of the box";
738
+ };
739
+ readonly x: {
740
+ readonly type: "number";
741
+ readonly description: "Top-left x in px. Omit (with y) to let the layout place the box";
742
+ };
743
+ readonly y: {
744
+ readonly type: "number";
745
+ readonly description: "Top-left y in px. Omit (with x) to let the layout place the box";
746
+ };
747
+ readonly w: {
748
+ readonly type: "number";
749
+ readonly exclusiveMinimum: 0;
750
+ readonly description: "Width in px. Omit to size from the text (never smaller than the type default)";
751
+ };
752
+ readonly h: {
753
+ readonly type: "number";
754
+ readonly exclusiveMinimum: 0;
755
+ readonly description: "Height in px. Omit to size from the text (never smaller than the type default)";
756
+ };
757
+ readonly color: {
758
+ readonly enum: readonly ColorName[];
759
+ readonly description: "Named color preset. Sets the stroke (outline + text) and, for boxes, a matching pastel fill. Omit for the default gray on transparent";
760
+ };
761
+ readonly stroke: {
762
+ readonly type: "string";
763
+ readonly description: "CSS color of the outline and text; overrides the preset";
764
+ };
765
+ readonly fill: {
766
+ readonly type: "string";
767
+ readonly description: "CSS color of the interior (\"transparent\" for none); overrides the preset";
768
+ };
769
+ };
770
+ };
771
+ readonly connector: {
772
+ readonly type: "object";
773
+ readonly required: readonly ["from", "to"];
774
+ readonly additionalProperties: false;
775
+ readonly properties: {
776
+ readonly id: {
777
+ readonly type: "string";
778
+ readonly description: "Optional; generated when omitted";
779
+ };
780
+ readonly type: {
781
+ readonly enum: readonly ConnectorType[];
782
+ readonly description: "arrow (default; arrowhead at \"to\") or line (no arrowheads)";
783
+ };
784
+ readonly from: {
785
+ readonly oneOf: readonly [{
786
+ readonly type: "string";
787
+ readonly description: "Id of a box. The connector attaches to its outline, aimed at the other end";
788
+ }, {
789
+ readonly type: "object";
790
+ readonly required: readonly ["id"];
791
+ readonly additionalProperties: false;
792
+ readonly properties: {
793
+ readonly id: {
794
+ readonly type: "string";
795
+ readonly description: "Id of a box";
796
+ };
797
+ readonly side: {
798
+ readonly enum: readonly ["top", "right", "bottom", "left"];
799
+ readonly description: "Pin the endpoint to the middle of this side of the box instead of auto-aiming";
800
+ };
801
+ };
802
+ }];
803
+ readonly description: "Box a connector end attaches to: a bare box id, or {id, side} to pick the attach edge";
804
+ };
805
+ readonly to: {
806
+ readonly oneOf: readonly [{
807
+ readonly type: "string";
808
+ readonly description: "Id of a box. The connector attaches to its outline, aimed at the other end";
809
+ }, {
810
+ readonly type: "object";
811
+ readonly required: readonly ["id"];
812
+ readonly additionalProperties: false;
813
+ readonly properties: {
814
+ readonly id: {
815
+ readonly type: "string";
816
+ readonly description: "Id of a box";
817
+ };
818
+ readonly side: {
819
+ readonly enum: readonly ["top", "right", "bottom", "left"];
820
+ readonly description: "Pin the endpoint to the middle of this side of the box instead of auto-aiming";
821
+ };
822
+ };
823
+ }];
824
+ readonly description: "Box a connector end attaches to: a bare box id, or {id, side} to pick the attach edge";
825
+ };
826
+ readonly text: {
827
+ readonly type: "string";
828
+ readonly description: "Label rendered at the middle of the connector";
829
+ };
830
+ readonly bidirectional: {
831
+ readonly type: "boolean";
832
+ readonly description: "Arrow only: arrowheads on both ends";
833
+ };
834
+ readonly routing: {
835
+ readonly enum: readonly ["straight", "elbow"];
836
+ readonly description: "straight (default) draws a direct line; elbow draws a right-angled path routed around the boxes";
837
+ };
838
+ readonly color: {
839
+ readonly enum: readonly ColorName[];
840
+ readonly description: "Named color preset. Sets the stroke (outline + text) and, for boxes, a matching pastel fill. Omit for the default gray on transparent";
841
+ };
842
+ readonly stroke: {
843
+ readonly type: "string";
844
+ readonly description: "CSS color of the line and label; overrides the preset";
845
+ };
846
+ };
847
+ };
848
+ readonly text: {
849
+ readonly type: "object";
850
+ readonly required: readonly ["x", "y", "text"];
851
+ readonly additionalProperties: false;
852
+ readonly properties: {
853
+ readonly id: {
854
+ readonly type: "string";
855
+ readonly description: "Optional; generated when omitted";
856
+ };
857
+ readonly x: {
858
+ readonly type: "number";
859
+ readonly description: "Top-left x of the first line, in px";
860
+ };
861
+ readonly y: {
862
+ readonly type: "number";
863
+ readonly description: "Top-left y of the first line, in px";
864
+ };
865
+ readonly text: {
866
+ readonly type: "string";
867
+ readonly description: "Content; \"\\n\" forces a line break";
868
+ };
869
+ readonly color: {
870
+ readonly enum: readonly ColorName[];
871
+ readonly description: "Named color preset. Sets the stroke (outline + text) and, for boxes, a matching pastel fill. Omit for the default gray on transparent";
872
+ };
873
+ readonly stroke: {
874
+ readonly type: "string";
875
+ readonly description: "CSS color of the text; overrides the preset";
424
876
  };
425
877
  };
426
878
  };
427
879
  };
428
880
  };
429
881
 
430
- export { $createDrawingNode, $createFrontmatterNode, $getSelectedTable, $getTableWidth, $isDrawingNode, $isFrontmatterNode, $setTableWidth, type BlockWidth, DRAWING, DRAWING_DATA_JSON_SCHEMA, type DrawingData, DrawingNode, type DrawingShape, type DrawingShapeType, type EditorContentProps, type EditorMode, type EditorRootProps, FRONTMATTER, FormatButtons, FrontmatterNode, HistoryButtons, InsertButtons, MarkdownEditor, type MarkdownEditorApi, type Props as MarkdownEditorProps, type SerializedDrawingNode, type SerializedFrontmatterNode, TABLE, TABLE_WIDTH_MARKER, Toolbar, ToolbarButton, ToolbarDivider, type ToolbarItems, parseDrawingData, serializeDrawingData, useMarkdownEditor };
882
+ type MermaidDirection = 'LR' | 'TD';
883
+ type MermaidOptions = Readonly<{
884
+ direction?: MermaidDirection;
885
+ }>;
886
+ /**
887
+ * Export a drawing as a Mermaid `flowchart`. Boxes become nodes (in shape
888
+ * order), connectors bound at both ends become edges; unbound connectors
889
+ * are dropped and free text shapes are kept as `%% note:` comments so
890
+ * nothing is silently lost.
891
+ */
892
+ declare function drawingToMermaid(data: DrawingData, options?: MermaidOptions): string;
893
+
894
+ export { $createDrawingNode, $createFrontmatterNode, $getSelectedTable, $getTableDensity, $getTableSettings, $getTableWidth, $isDrawingNode, $isFrontmatterNode, $setTableDensity, $setTableSettings, $setTableWidth, BOX_DEFINITIONS, BOX_TYPES, type Binding, type BindingSide, type BlockWidth, type BoxDefinition, type BoxType, COLOR_PRESETS, CONNECTOR_TYPES, type ColorName, type ConnectorType, DEFAULT_TABLE_SETTINGS, DIAGRAM, DRAWING, DRAWING_DATA_JSON_SCHEMA, DRAWING_SKELETON_JSON_SCHEMA, type DrawingData, DrawingNode, type DrawingShape, type DrawingShapeType, type DrawingSkeleton, EMPTY_DRAWING, type EditorContentProps, type EditorMode, type EditorRootProps, FILL_COLORS, FRONTMATTER, FormatButtons, FrontmatterNode, HistoryButtons, InsertButtons, MarkdownEditor, type MarkdownEditorApi, type Props as MarkdownEditorProps, type MermaidDirection, type MermaidOptions, type Point, SHAPE_TYPES, SIDE_FIXED_POINTS, STROKE_COLORS, type SerializedDrawingNode, type SerializedFrontmatterNode, type SkeletonBox, type SkeletonConnector, type SkeletonEnd, type SkeletonText, TABLE, TABLE_WIDTH_MARKER, type TableDensity, type TableSettings, type TextField, Toolbar, ToolbarButton, ToolbarDivider, type ToolbarItems, anchorPoint, bindEndpoints, boxOutline, connectorPoints, drawingToMermaid, expandSkeleton, findBoxAt, fixedPointFor, formatTableSettingsMarker, isDrawingSkeleton, makeBinding, normalizeDrawingData, parseDrawingData, parseDrawingSkeleton, parseTableSettingsMarker, resolveBindings, routeElbow, serializeDrawingData, useMarkdownEditor };