@zuilib/text-editor 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,76 @@
1
1
  # Changelog — @zuilib/text-editor
2
2
 
3
+ ## 0.7.0
4
+
5
+ **Themed drawing canvas.** The canvas chrome now follows the host theme
6
+ instead of shipping its own look.
7
+
8
+ - Tool row and contextual property row are a flat header in the editor's
9
+ own toolbar idiom (in flow, no floating panels over the drawing)
10
+ - Every color, radius, shadow and font of the canvas is a
11
+ `--zui-drawing-*` custom property defaulting to the core theme tokens
12
+ (`--primary`, `--foreground`, `--border`, `--popover`, `--radius`,
13
+ `--shadow-medium`, …), so light and dark mode come from the tokens;
14
+ override them on `.zui-drawing-canvas` or an ancestor. See README,
15
+ "Theming the canvas"
16
+ - Selection frame, handles, marquee, bind highlight and connector label
17
+ plates are drawn in `currentColor`/theme variables; the table selection
18
+ tint uses `--primary` too, so the editor shares one accent
19
+ - `--zui-drawing-dark-filter` exposes the dark-mode inversion of the
20
+ drawing area (`none` opts out)
21
+
22
+ ## 0.6.0
23
+
24
+ **Text measure and `text` block width.** Additive: markdown, JSON, class
25
+ names and props keep their meaning; with no configuration the layout is
26
+ unchanged.
27
+
28
+ - **Measure** (opt in): `measure="48rem"` on `MarkdownEditor` /
29
+ `MarkdownEditor.Root`, or `--zui-text-editor-measure: 48rem` in a
30
+ stylesheet — the CSS custom property is the contract, the prop is sugar.
31
+ Text blocks (paragraphs, headings, lists, quotes, code, frontmatter) are
32
+ capped at the measure and centred in the content pane; the placeholder
33
+ and fold chevrons follow the column. The pane itself is never capped and
34
+ full-width blocks stop short of the outline sidebar
35
+ - **`BlockWidth` gains `'text'`**: `'full' | 'text' | 'content'`. `text`
36
+ aligns a table or drawing with the text column; without a measure it is
37
+ visually identical to `full` (resolved in CSS through the variable's
38
+ fallback). `full` (default, omitted) and `content` (shrink to fit) are
39
+ unchanged
40
+ - **Persistence**: tables `<!-- width: text -->` (combinable with
41
+ `density`); drawings and ` ```diagram ` skeletons `"width":"text"`.
42
+ `DRAWING_DATA_JSON_SCHEMA`, `DRAWING_SKELETON_JSON_SCHEMA` and
43
+ `DRAWING_FORMAT.md` updated. Unknown width values are ignored (treated as
44
+ `full`) instead of being rejected, so documents from newer versions still
45
+ open — `parseTableSettingsMarker` now returns `{}` (rather than `null`)
46
+ for a marker whose only known key carries an unknown value, and the
47
+ transformer consumes that line
48
+ - **Insertion defaults**: `defaultBlockWidth={{ table?, drawing? }}` on
49
+ Root applies when the toolbar / `useMarkdownEditor()` inserts a new table
50
+ or drawing. The chosen width is written to the markdown explicitly, even
51
+ `full`, so the document reads the same in an app with other defaults; a
52
+ width named in the source (`<!-- width: full -->`, `"width":"full"`) is
53
+ preserved on round trip
54
+ - **UI / headless**: the floating table toolbar and the drawing toolbar
55
+ offer all three widths with distinct icons (`BLOCK_WIDTH_OPTIONS`).
56
+ `useMarkdownEditor()` gains `blockWidth` / `setBlockWidth` for the block
57
+ containing the selection — the focused drawing or the table the caret is
58
+ in; `insertTable` / `insertDrawing` accept a `width` option. `tableWidth`
59
+ / `setTableWidth` keep working and are deprecated
60
+ - **CSS**: the new layout lives in zero-specificity `:where()` rules. The
61
+ content pane exposes `--zui-text-editor-gutter` and
62
+ `--zui-text-editor-bleed`; every top-level block reads
63
+ `--zui-text-editor-block-bleed`, so one class rule overrides any block
64
+ kind. New block classes (added next to the existing utility classes):
65
+ `.zui-paragraph`, `.zui-heading` / `.zui-heading-1`…`6`, `.zui-list` /
66
+ `.zui-list-ordered` / `.zui-list-unordered`, `.zui-quote`, `.zui-code`;
67
+ `.zui-drawing-canvas` gains `.is-text-width`. Nothing is renamed
68
+ - New exports: `BLOCK_WIDTHS`, `isBlockWidth`, `BlockWidthDefaults`,
69
+ `TableSettingsOptions`, `$isTableWidthExplicit`; `$setTableSettings` and
70
+ `formatTableSettingsMarker` take an optional `{ explicitWidth }`
71
+ - **Adopting**: set `measure` (or the CSS variable) and delete any external
72
+ `max-width` / `margin-inline` overrides on `.zui-text-editor-content > *`
73
+
3
74
  ## 0.5.0
4
75
 
5
76
  **Diagram builder rewrite.** The drawing canvas, its payload format and the
package/DRAWING_FORMAT.md CHANGED
@@ -41,9 +41,13 @@ skeleton, which is a separate block type.
41
41
  narrower layouts (SVG viewBox), so coordinates can assume that width.
42
42
  When omitted the canvas is fluid and as wide as the editor; keep shapes
43
43
  within roughly x in [0, 700] to be safe on typical layouts.
44
- - `"width":"content"` sizes the block to fit the rightmost shape (plus a
45
- margin), left-aligned with the text. Use it for small diagrams that
46
- should not stretch across the page. Default `"full"`, omit it.
44
+ - `width` is the block's horizontal sizing in the page, independent of the
45
+ coordinates: `"full"` (default, omit it) spans the editor pane;
46
+ `"text"` aligns the block with the text column (the same as `"full"`
47
+ unless the app sets a text measure); `"content"` sizes the block to fit
48
+ the rightmost shape (plus a margin), left-aligned with the text. Use
49
+ `"content"` for small diagrams that should not stretch across the page.
50
+ Unknown values are ignored (treated as `"full"`).
47
51
 
48
52
  ## Top-level object
49
53
 
@@ -52,7 +56,7 @@ skeleton, which is a separate block type.
52
56
  | `version` | `2` | Literal `2` |
53
57
  | `canvasHeight` | `number` | Canvas height in px (min 80) |
54
58
  | `canvasWidth` | `number` | Optional logical width in px (min 120); scales to fit when set |
55
- | `width` | `"full"` \| `"content"` | Optional; default `"full"`. `"content"` fits the shapes' extent |
59
+ | `width` | `"full"` \| `"text"` \| `"content"` | Optional; default `"full"`. `"text"` aligns with the text column, `"content"` fits the shapes' extent |
56
60
  | `shapes` | `Shape[]` | Render order: later shapes draw on top |
57
61
 
58
62
  ## Shape object
@@ -197,7 +201,7 @@ one-way: once opened, the document stores the concrete ```drawing block.
197
201
  ```
198
202
  {
199
203
  "direction"?: "right" | "down", // auto-layout flow, default right
200
- "canvasWidth"?: n, "canvasHeight"?: n, "width"?: "content",
204
+ "canvasWidth"?: n, "canvasHeight"?: n, "width"?: "full" | "text" | "content",
201
205
  "boxes": [ { "id", "type"?: <box type, default rect>, "label"?, "text"?, "footer"?,
202
206
  "x"?, "y"?, // omitted: auto layout by connector rank
203
207
  "w"?, "h"?, // omitted: sized to fit the text
@@ -224,6 +228,8 @@ Rules:
224
228
  them. Boxes without `w`/`h` are sized to fit their text. `canvasHeight`
225
229
  is computed when omitted.
226
230
  - `texts` are free annotations and need explicit coordinates.
231
+ - `width` is copied to the expanded drawing (see [Coordinate
232
+ system](#coordinate-system)); omit it for `"full"`.
227
233
 
228
234
  A three-box flow:
229
235
 
package/README.md CHANGED
@@ -13,8 +13,9 @@ document outline, and collapsible sections.
13
13
  blockquotes, links, fenced code (with syntax highlighting), tables
14
14
  - **Tables**: GFM pipe tables, edited in place (tab between cells, ranges,
15
15
  inline formatting), styled like Claude artifacts
16
- - **Table settings**: full/content width and row density per table;
17
- diagrams switch between full and content width too Slab-style
16
+ - **Text measure and block width**: an opt-in readable text column
17
+ (`measure="48rem"`); each table and diagram picks *full* / *text* /
18
+ *content* width, Slab-style; row density per table
18
19
  - **Diagrams**: a drawing canvas embedded in the document. Eight box
19
20
  shapes (rectangle, ellipse, diamond, note, database, cloud, queue, actor)
20
21
  with attached text slots, bound arrows that follow their boxes and attach
@@ -73,6 +74,8 @@ emits. The emitted string is always plain markdown.
73
74
  | `toolbar` | `boolean \| (items) => ReactNode` | `true` | Formatting/insert toolbar (`edit-md`); function form customises it |
74
75
  | `outline` | `boolean` | `false` | Table-of-contents sidebar |
75
76
  | `foldable` | `boolean` | `true` | Collapse sections under headings |
77
+ | `measure` | `string` | — | Max width of the text column, a CSS length (`'48rem'` recommended). Sugar for `--zui-text-editor-measure` |
78
+ | `defaultBlockWidth` | `{ table?, drawing? }` | — | `BlockWidth` written when the toolbar inserts a table / drawing |
76
79
 
77
80
  ### Modes
78
81
 
@@ -101,16 +104,12 @@ Editing is in place: Tab/arrows between cells, cell range selection, inline
101
104
  formatting inside cells. Cell content is single-line in markdown; newlines
102
105
  are escaped as `\n`.
103
106
 
104
- ### Table settings: width and density
107
+ ### Table density
105
108
 
106
109
  Place the caret in a table and a small toolbar floats at its top-right
107
- corner:
108
-
109
- - **Width** — *full* (default: columns share the editor width) or
110
- *content* (the table shrinks to fit its columns, left-aligned with the
111
- text, never wider than the editor).
112
- - **Density** — *compact*, *comfortable* (default), or *spacious* cell
113
- padding and font size.
110
+ corner with the table's width (see [Block width and text
111
+ measure](#block-width-and-text-measure)) and its **density** — *compact*,
112
+ *comfortable* (default), or *spacious* cell padding and font size.
114
113
 
115
114
  Non-default settings are persisted as one HTML comment on the line directly
116
115
  above the table — other markdown renderers hide it:
@@ -122,12 +121,70 @@ above the table — other markdown renderers hide it:
122
121
  | Region | eu-west-1 |
123
122
  ```
124
123
 
125
- Programmatic access: `useMarkdownEditor().tableWidth` / `setTableWidth` and
126
- `tableDensity` / `setTableDensity` (for custom toolbars), or
127
- `$getTableSettings(node)` / `$setTableSettings(node, { width, density })`
128
- inside `editor.update`. `parseTableSettingsMarker` /
129
- `formatTableSettingsMarker` convert between the comment line and a
130
- `TableSettings` object.
124
+ Programmatic access: `useMarkdownEditor().tableDensity` / `setTableDensity`
125
+ (for custom toolbars), or `$getTableSettings(node)` /
126
+ `$setTableSettings(node, { width, density })` inside `editor.update`.
127
+ `parseTableSettingsMarker` / `formatTableSettingsMarker` convert between
128
+ the comment line and a `TableSettings` object.
129
+
130
+ ## Block width and text measure
131
+
132
+ By default every block spans the content pane. Set a **measure** to get a
133
+ readable text column instead: paragraphs, headings, lists, quotes, code,
134
+ frontmatter are capped at that width and centred in the pane, while each
135
+ table and drawing chooses its own width.
136
+
137
+ ```tsx
138
+ <MarkdownEditor value={value} onChange={setValue} measure="48rem" />
139
+ ```
140
+
141
+ The prop is sugar for the CSS custom property `--zui-text-editor-measure`,
142
+ which is the actual contract — set it in a stylesheet on `.zui-text-editor`
143
+ (or any ancestor) and never touch the prop:
144
+
145
+ ```css
146
+ .zui-text-editor { --zui-text-editor-measure: 48rem; }
147
+ ```
148
+
149
+ **Adopting:** set `measure` (or the variable) and delete any external
150
+ `max-width` / `margin-inline` overrides on `.zui-text-editor-content > *`;
151
+ the library now owns that layout.
152
+
153
+ Every table and drawing has a `BlockWidth`, picked from the floating table
154
+ toolbar or the right end of the drawing toolbar:
155
+
156
+ | `BlockWidth` | Layout | Markdown |
157
+ |--------------|--------|----------|
158
+ | `full` | The content pane, edge to edge (never under the outline sidebar). The default | Omitted |
159
+ | `text` | The text column: edges align with the paragraphs. Identical to `full` until a measure is set | `<!-- width: text -->` / `"width":"text"` |
160
+ | `content` | Shrinks to its columns / shapes, left-aligned with the text, never wider than the column | `<!-- width: content -->` / `"width":"content"` |
161
+
162
+ Absence of a marker always means `full`, in every app. `defaultBlockWidth`
163
+ only changes what the toolbar / `insertTable` / `insertDrawing` write into
164
+ *new* blocks — and that value is written explicitly, even when it is
165
+ `full`, so the document reads the same elsewhere:
166
+
167
+ ```tsx
168
+ <MarkdownEditor measure="48rem" defaultBlockWidth={{ table: 'text', drawing: 'text' }} … />
169
+ ```
170
+
171
+ Headless: `useMarkdownEditor().blockWidth` / `setBlockWidth` act on the
172
+ block containing the selection — the focused drawing, or else the table
173
+ the caret is in. (`tableWidth` / `setTableWidth` still work and are
174
+ deprecated in favour of these.)
175
+
176
+ Styling: the layout is driven by low-specificity `:where()` rules and two
177
+ derived custom properties on `.zui-text-editor-main` —
178
+ `--zui-text-editor-gutter` (the pane padding, `2rem` without a measure)
179
+ and `--zui-text-editor-bleed` (how far a full-width block extends past the
180
+ column, `0` without a measure). Each top-level block reads
181
+ `--zui-text-editor-block-bleed`, so a single class rule overrides any block
182
+ kind: `.zui-code { --zui-text-editor-block-bleed: var(--zui-text-editor-bleed) }`
183
+ makes code blocks full width; `.zui-table { --zui-text-editor-block-bleed: 0px }`
184
+ keeps every table inside the column. Block classes: `.zui-paragraph`,
185
+ `.zui-heading` (+ `.zui-heading-1`…`6`), `.zui-list` (+ `-ordered` /
186
+ `-unordered`, `.zui-checklist`), `.zui-quote`, `.zui-code`,
187
+ `.zui-frontmatter`, `.zui-table`, `.zui-drawing`.
131
188
 
132
189
  ## Toolbar & custom toolbars
133
190
 
@@ -212,10 +269,11 @@ function BoldButton() {
212
269
  ```
213
270
 
214
271
  It returns `editor` (the Lexical instance), `activeFormats`,
215
- `toggleFormat`, `insertTable`, `insertDrawing`, `tableWidth` /
216
- `setTableWidth` and `tableDensity` / `setTableDensity` (settings of the
217
- table containing the selection, `null` outside tables), `canUndo`,
218
- `canRedo`, `undo`, `redo`.
272
+ `toggleFormat`, `insertTable`, `insertDrawing`, `blockWidth` /
273
+ `setBlockWidth` (width of the table or drawing containing the selection,
274
+ `null` outside both), `tableDensity` / `setTableDensity` (`null` outside
275
+ tables), `canUndo`, `canRedo`, `undo`, `redo`. `tableWidth` /
276
+ `setTableWidth` remain as deprecated aliases limited to tables.
219
277
 
220
278
  ## Diagrams (drawing canvas)
221
279
 
@@ -251,10 +309,12 @@ fully specified in **[DRAWING_FORMAT.md](./DRAWING_FORMAT.md)**.
251
309
  - **Canvas**: resizable height, dot grid, white surface that inverts
252
310
  Excalidraw-style in dark mode (`.dark` ancestor class). An optional
253
311
  `canvasWidth` scales the drawing to fit narrower layouts.
254
- - **Width**: the toggle at the right end of the canvas toolbar switches
255
- between **full width** (spans the editor) and **content width** (the
256
- canvas fits the rightmost shape and grows as shapes move). Stored as
257
- `"width":"content"` in the payload; omitted when full.
312
+ - **Width**: the buttons at the right end of the canvas toolbar switch
313
+ between **full** (spans the pane), **text** (aligns with the text column,
314
+ see [Block width and text measure](#block-width-and-text-measure)) and
315
+ **content** (the canvas fits the rightmost shape and grows as shapes
316
+ move). Stored as `"width":"text"` / `"width":"content"` in the payload;
317
+ omitted when full.
258
318
 
259
319
  A stored drawing looks like this:
260
320
 
@@ -293,6 +353,41 @@ The full skeleton spec (attach sides, explicit positions, free texts) is
293
353
  in [DRAWING_FORMAT.md](./DRAWING_FORMAT.md). Programmatic access:
294
354
  `parseDrawingSkeleton`, `expandSkeleton`, `DRAWING_SKELETON_JSON_SCHEMA`.
295
355
 
356
+ ### Theming the canvas
357
+
358
+ The canvas chrome (header, property row, popover, selection handles) is
359
+ styled entirely through `--zui-drawing-*` custom properties. They default
360
+ to the ZUI core tokens (`--primary`, `--foreground`, `--border`,
361
+ `--popover`, `--radius`, `--shadow-medium`, …), so the canvas follows the
362
+ host theme in light and dark mode. Override any of them on
363
+ `.zui-drawing-canvas` or an ancestor:
364
+
365
+ ```css
366
+ .my-app .zui-drawing-canvas {
367
+ --zui-drawing-accent: #0f766e; /* selection, active tool, handles */
368
+ --zui-drawing-surface: #fbfbf7; /* drawing area (pre dark-mode filter) */
369
+ --zui-drawing-grid: rgba(0, 0, 0, 0.12);
370
+ --zui-drawing-grid-size: 16px;
371
+ --zui-drawing-font: 'Inter', sans-serif;
372
+ }
373
+ ```
374
+
375
+ | Variable | Default | Used for |
376
+ |----------|---------|----------|
377
+ | `--zui-drawing-accent` | `var(--primary)` | Selection frame and handles, active tool, focus ring, bind highlight |
378
+ | `--zui-drawing-foreground` | `var(--foreground)` | Header text and icons |
379
+ | `--zui-drawing-muted-foreground` | `var(--muted-foreground)` | Swatch labels, empty-state hint |
380
+ | `--zui-drawing-border` | `var(--border)` | Block border, header divider, popover border |
381
+ | `--zui-drawing-chrome` | `var(--background)` | Header and property row background |
382
+ | `--zui-drawing-popover` / `-foreground` | `var(--popover)` / `var(--popover-foreground)` | "More shapes" menu |
383
+ | `--zui-drawing-danger` / `--zui-drawing-success` | `var(--destructive)` / `var(--success)` | Delete button, "copied" state |
384
+ | `--zui-drawing-radius` / `--zui-drawing-control-radius` | `var(--radius-lg)` / `var(--radius)` | Block corners / buttons and menus |
385
+ | `--zui-drawing-shadow` | `var(--shadow-medium)` | Popover |
386
+ | `--zui-drawing-font` | system sans | Shape text and the inline editor |
387
+ | `--zui-drawing-surface` / `--zui-drawing-grid` / `--zui-drawing-grid-size` | white / 9% black / `20px` | Drawing area and its dot grid, before the dark filter |
388
+ | `--zui-drawing-dark-filter` | `invert(93%) hue-rotate(180deg)` | Applied to the drawing area under `.dark`; set to `none` to opt out |
389
+ | `--zui-drawing-hover` / `--zui-drawing-active` | `currentColor` 8% / 12% | Button hover and pressed backgrounds |
390
+
296
391
  ## Outline & section folding
297
392
 
298
393
  `outline` docks a collapsible table-of-contents sidebar: live heading list
@@ -335,8 +430,9 @@ diagrams:
335
430
  | `Toolbar`, `ToolbarButton`, `ToolbarDivider`, `FormatButtons`, `InsertButtons`, `HistoryButtons` | Toolbar primitives |
336
431
  | `@zuilib/text-editor/styles.css` | Editor chrome + theme styles (required) |
337
432
  | `TABLE` | GFM table markdown transformer |
338
- | `BlockWidth`, `TableDensity`, `TableSettings`, `DEFAULT_TABLE_SETTINGS` | Table setting types |
339
- | `$getTableSettings`, `$setTableSettings`, `$getTableWidth`, `$setTableWidth`, `$getTableDensity`, `$setTableDensity`, `$getSelectedTable` | Table setting helpers (inside `editor.update`/`read`) |
433
+ | `BlockWidth`, `BLOCK_WIDTHS`, `isBlockWidth`, `BlockWidthDefaults` | Block width (`full` / `text` / `content`) type, values, guard, insertion defaults |
434
+ | `TableDensity`, `TableSettings`, `TableSettingsOptions`, `DEFAULT_TABLE_SETTINGS` | Table setting types |
435
+ | `$getTableSettings`, `$setTableSettings`, `$isTableWidthExplicit`, `$getTableWidth`, `$setTableWidth`, `$getTableDensity`, `$setTableDensity`, `$getSelectedTable` | Table setting helpers (inside `editor.update`/`read`) |
340
436
  | `parseTableSettingsMarker`, `formatTableSettingsMarker` | Marker comment ⇄ `TableSettings` |
341
437
  | `DRAWING`, `DIAGRAM`, `DrawingNode`, `$createDrawingNode`, `$isDrawingNode` | Drawing node + markdown transformers (` ```drawing ` and ` ```diagram `) |
342
438
  | `FRONTMATTER`, `FrontmatterNode`, `$createFrontmatterNode`, `$isFrontmatterNode` | Frontmatter node + transformer |
package/dist/index.d.ts CHANGED
@@ -4,7 +4,33 @@ import { LexicalEditor, TextFormatType, ElementNode, NodeKey, EditorConfig, Seri
4
4
  import { TableNode } from '@lexical/table';
5
5
  import { MultilineElementTransformer, ElementTransformer } from '@lexical/markdown';
6
6
 
7
+ /**
8
+ * Horizontal sizing of a block that would otherwise span the editor:
9
+ *
10
+ * - `full` — the container width (the content pane, minus its gutters).
11
+ * The default; omitted when serialised.
12
+ * - `text` — the text column: the block's edges align with the paragraphs
13
+ * around it. Only differs from `full` when a measure is set
14
+ * (`--zui-text-editor-measure` / the `measure` prop); otherwise the two
15
+ * are visually identical.
16
+ * - `content` — shrinks to fit what is inside (table columns, drawing
17
+ * shapes), left-aligned with the text and never wider than the column.
18
+ */
19
+ type BlockWidth = 'full' | 'text' | 'content';
20
+ declare const BLOCK_WIDTHS: readonly BlockWidth[];
21
+ declare function isBlockWidth(value: unknown): value is BlockWidth;
22
+ /**
23
+ * Width written into the markdown when a new table / drawing is inserted
24
+ * (`MarkdownEditor.Root`'s `defaultBlockWidth`). Only affects insertion:
25
+ * existing markdown without a width marker always means `full`.
26
+ */
27
+ type BlockWidthDefaults = Readonly<{
28
+ table?: BlockWidth;
29
+ drawing?: BlockWidth;
30
+ }>;
31
+
7
32
  type EditorMode = 'edit-raw' | 'edit-md' | 'view';
33
+
8
34
  type EditorRootProps = Readonly<{
9
35
  value?: string;
10
36
  onChange?: (value: string) => void;
@@ -12,6 +38,22 @@ type EditorRootProps = Readonly<{
12
38
  className?: string;
13
39
  mode?: EditorMode;
14
40
  autoFocus?: boolean;
41
+ /**
42
+ * Text measure: the maximum width of the text column, as a CSS length
43
+ * (`'48rem'` recommended). Text blocks are capped at this width and
44
+ * centred; tables and drawings choose per block whether to align with
45
+ * the column (`text`), span the pane (`full`) or hug their content.
46
+ * Sugar for setting `--zui-text-editor-measure` on the root; the
47
+ * variable can equally be set from a stylesheet. Unset: no measure, every
48
+ * block spans the pane.
49
+ */
50
+ measure?: string;
51
+ /**
52
+ * Width written into the markdown when the toolbar or
53
+ * `useMarkdownEditor()` inserts a new table / drawing. Only affects
54
+ * insertion — markdown without a width marker always means `full`.
55
+ */
56
+ defaultBlockWidth?: BlockWidthDefaults;
15
57
  children: ReactNode;
16
58
  }>;
17
59
  /**
@@ -19,7 +61,7 @@ type EditorRootProps = Readonly<{
19
61
  * beneath it (`Content`, `Toolbar`, `Outline`, or your own components using
20
62
  * `useMarkdownEditor`) shares the same editor instance.
21
63
  */
22
- declare function EditorRoot({ value, onChange, readOnly, className, mode, autoFocus, children, }: EditorRootProps): ReactElement;
64
+ declare function EditorRoot({ value, onChange, readOnly, className, mode, autoFocus, measure, defaultBlockWidth, children, }: EditorRootProps): ReactElement;
23
65
 
24
66
  type EditorContentProps = Readonly<{
25
67
  placeholder?: string;
@@ -41,13 +83,6 @@ declare function EditorContent({ placeholder, foldable, children, }: EditorConte
41
83
  */
42
84
  declare function OutlinePlugin(): ReactElement;
43
85
 
44
- /**
45
- * Horizontal sizing of a block that would otherwise span the editor:
46
- * `full` stretches to the content column, `content` shrinks to fit what is
47
- * inside (table columns, drawing shapes) and left-aligns with the text.
48
- */
49
- type BlockWidth = 'full' | 'content';
50
-
51
86
  /** Cell padding / font size preset */
52
87
  type TableDensity = 'compact' | 'comfortable' | 'spacious';
53
88
  type TableSettings = Readonly<{
@@ -55,8 +90,14 @@ type TableSettings = Readonly<{
55
90
  density: TableDensity;
56
91
  }>;
57
92
  declare const DEFAULT_TABLE_SETTINGS: TableSettings;
93
+ type TableSettingsOptions = Readonly<{
94
+ /** Persist the width even when it is `full` */
95
+ explicitWidth?: boolean;
96
+ }>;
58
97
  declare function $getTableSettings(table: TableNode): TableSettings;
59
- declare function $setTableSettings(table: TableNode, settings: Partial<TableSettings>): void;
98
+ declare function $setTableSettings(table: TableNode, settings: Partial<TableSettings>, options?: TableSettingsOptions): void;
99
+ /** Whether the table's width should be persisted even when it is `full` */
100
+ declare function $isTableWidthExplicit(table: TableNode): boolean;
60
101
  declare function $getTableWidth(table: TableNode): BlockWidth;
61
102
  declare function $setTableWidth(table: TableNode, width: BlockWidth): void;
62
103
  declare function $getTableDensity(table: TableNode): TableDensity;
@@ -65,10 +106,17 @@ declare function $setTableDensity(table: TableNode, density: TableDensity): void
65
106
  declare function $getSelectedTable(): TableNode | null;
66
107
  /** @deprecated Use `formatTableSettingsMarker({ ...DEFAULT_TABLE_SETTINGS, width: 'content' })` */
67
108
  declare const TABLE_WIDTH_MARKER = "<!-- width: content -->";
68
- /** Settings encoded in a marker line, or null if the text is not a marker */
109
+ /**
110
+ * Settings encoded in a marker line, or null if the text is not a marker.
111
+ * A marker naming a known setting with an unknown value yields that setting
112
+ * omitted (possibly an empty object): the line is still a settings marker.
113
+ */
69
114
  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;
115
+ /**
116
+ * Marker line for the given settings, or null when everything is default.
117
+ * With `explicitWidth` the width is listed even when it is `full`.
118
+ */
119
+ declare function formatTableSettingsMarker(settings: TableSettings, options?: TableSettingsOptions): string | null;
72
120
 
73
121
  type MarkdownEditorApi = Readonly<{
74
122
  /** The underlying Lexical editor, for dispatching your own commands */
@@ -76,14 +124,40 @@ type MarkdownEditorApi = Readonly<{
76
124
  /** Text formats active at the current selection */
77
125
  activeFormats: ReadonlySet<TextFormatType>;
78
126
  toggleFormat: (format: TextFormatType) => void;
127
+ /**
128
+ * Insert a table at the selection. `width` defaults to
129
+ * `defaultBlockWidth.table` (Root prop); when given it is written to the
130
+ * markdown explicitly, even when `full`.
131
+ */
79
132
  insertTable: (options?: {
80
133
  rows?: number;
81
134
  columns?: number;
135
+ width?: BlockWidth;
82
136
  }) => void;
83
- insertDrawing: () => void;
84
- /** Width of the table containing the selection; `null` outside tables */
137
+ /**
138
+ * Insert an empty drawing at the selection. `width` defaults to
139
+ * `defaultBlockWidth.drawing` (Root prop); when given it is written to
140
+ * the markdown explicitly, even when `full`.
141
+ */
142
+ insertDrawing: (options?: {
143
+ width?: BlockWidth;
144
+ }) => void;
145
+ /**
146
+ * Width of the block containing the selection — the focused drawing, or
147
+ * else the table the caret is in; `null` outside both.
148
+ */
149
+ blockWidth: BlockWidth | null;
150
+ /** Resize that block; no-op when `blockWidth` is `null` */
151
+ setBlockWidth: (width: BlockWidth) => void;
152
+ /**
153
+ * Width of the table containing the selection; `null` outside tables.
154
+ * @deprecated Use `blockWidth`, which also covers drawings.
155
+ */
85
156
  tableWidth: BlockWidth | null;
86
- /** Resize the table containing the selection; no-op outside tables */
157
+ /**
158
+ * Resize the table containing the selection; no-op outside tables.
159
+ * @deprecated Use `setBlockWidth`, which also covers drawings.
160
+ */
87
161
  setTableWidth: (width: BlockWidth) => void;
88
162
  /** Density of the table containing the selection; `null` outside tables */
89
163
  tableDensity: TableDensity | null;
@@ -283,8 +357,10 @@ type DrawingData = Readonly<{
283
357
  canvasWidth?: number;
284
358
  canvasHeight: number;
285
359
  /**
286
- * Block width: `full` (default, omitted when serialized) spans the
287
- * editor; `content` fits the shapes' horizontal extent.
360
+ * Block width: `full` (default) spans the editor; `text` aligns with the
361
+ * text column; `content` fits the shapes' horizontal extent. The editor
362
+ * omits `full` unless it was written explicitly (an insertion default or
363
+ * the source payload); unknown values are dropped.
288
364
  */
289
365
  width?: BlockWidth;
290
366
  shapes: readonly DrawingShape[];
@@ -350,7 +426,7 @@ declare const DIAGRAM: MultilineElementTransformer;
350
426
  * Markdown transformer for GFM tables. Adapted from the Lexical playground.
351
427
  * Rows are matched line-by-line on import and stitched into a single
352
428
  * TableNode; the divider row promotes the row above it to a header row.
353
- * A `<!-- width: content; density: compact -->` settings line directly
429
+ * A `<!-- width: text; density: compact -->` settings line directly
354
430
  * above the table (see tableSettings.ts) is consumed on import and
355
431
  * re-emitted on export.
356
432
  */
@@ -392,8 +468,8 @@ declare const DRAWING_DATA_JSON_SCHEMA: {
392
468
  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.";
393
469
  };
394
470
  readonly width: {
395
- readonly enum: readonly ["full", "content"];
396
- readonly description: "Block width: \"full\" (default, omit it) spans the editor; \"content\" fits the shapes' horizontal extent and left-aligns with the text";
471
+ readonly enum: readonly ["full", "text", "content"];
472
+ readonly description: "Block width: \"full\" (default, omit it) spans the editor; \"text\" aligns the block with the text column (same as \"full\" unless the app sets a text measure); \"content\" fits the shapes' horizontal extent and left-aligns with the text";
397
473
  };
398
474
  readonly shapes: {
399
475
  readonly type: "array";
@@ -595,6 +671,13 @@ type BoxDefinition = Readonly<{
595
671
  }>;
596
672
  declare const BOX_DEFINITIONS: Record<BoxType, BoxDefinition>;
597
673
 
674
+ /**
675
+ * Skeleton (intent) layer: a compact, LLM-friendly description of a diagram
676
+ * — boxes, connectors between them and loose texts — that expands into a
677
+ * full `DrawingData` document. Sizes, positions and connector geometry are
678
+ * derived, so a generator only needs to say *what* is on the canvas.
679
+ */
680
+
598
681
  type ColorName = 'gray' | 'red' | 'green' | 'blue' | 'orange' | 'purple';
599
682
  declare const COLOR_PRESETS: Record<ColorName, {
600
683
  stroke: string;
@@ -648,7 +731,8 @@ type DrawingSkeleton = Readonly<{
648
731
  direction?: 'right' | 'down';
649
732
  canvasWidth?: number;
650
733
  canvasHeight?: number;
651
- width?: 'content';
734
+ /** Block width of the expanded drawing; omit for `full` */
735
+ width?: BlockWidth;
652
736
  boxes: readonly SkeletonBox[];
653
737
  connectors?: readonly SkeletonConnector[];
654
738
  texts?: readonly SkeletonText[];
@@ -685,8 +769,8 @@ declare const DRAWING_SKELETON_JSON_SCHEMA: {
685
769
  readonly description: "Canvas height in px. Omit to fit the content";
686
770
  };
687
771
  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";
772
+ readonly enum: readonly ["full", "text", "content"];
773
+ readonly description: "Block width: \"text\" aligns the drawing with the text column (same as \"full\" unless the app sets a text measure); \"content\" fits the drawing to its shapes and left-aligns it with the text; omit to span the editor";
690
774
  };
691
775
  readonly boxes: {
692
776
  readonly type: "array";
@@ -891,4 +975,4 @@ type MermaidOptions = Readonly<{
891
975
  */
892
976
  declare function drawingToMermaid(data: DrawingData, options?: MermaidOptions): string;
893
977
 
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 };
978
+ export { $createDrawingNode, $createFrontmatterNode, $getSelectedTable, $getTableDensity, $getTableSettings, $getTableWidth, $isDrawingNode, $isFrontmatterNode, $isTableWidthExplicit, $setTableDensity, $setTableSettings, $setTableWidth, BLOCK_WIDTHS, BOX_DEFINITIONS, BOX_TYPES, type Binding, type BindingSide, type BlockWidth, type BlockWidthDefaults, 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 TableSettingsOptions, type TextField, Toolbar, ToolbarButton, ToolbarDivider, type ToolbarItems, anchorPoint, bindEndpoints, boxOutline, connectorPoints, drawingToMermaid, expandSkeleton, findBoxAt, fixedPointFor, formatTableSettingsMarker, isBlockWidth, isDrawingSkeleton, makeBinding, normalizeDrawingData, parseDrawingData, parseDrawingSkeleton, parseTableSettingsMarker, resolveBindings, routeElbow, serializeDrawingData, useMarkdownEditor };