@zuilib/text-editor 0.2.1 → 0.3.1

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,41 @@
1
1
  # Changelog — @zuilib/text-editor
2
2
 
3
+ ## 0.4.0
4
+
5
+ - **Block width** for tables and drawings: switch any table or drawing
6
+ between *full width* (spans the editor, the previous behaviour) and
7
+ *content width* (shrinks to fit its columns / shapes, left-aligned with
8
+ the text), Slab-style
9
+ - Tables: a floating toggle docks to the top-right of the table the caret
10
+ is in; content width sizes columns by their content. Persisted as a
11
+ `<!-- width: content -->` line directly above the GFM table (hidden by
12
+ other markdown renderers)
13
+ - Drawings: toggle at the right end of the canvas toolbar; content width
14
+ fits the rightmost shape and grows as shapes move. Persisted as a
15
+ top-level `"width":"content"` field in the ```drawing payload
16
+ (`DrawingData.width`, `DRAWING_DATA_JSON_SCHEMA` updated; omitted when
17
+ full, so existing payloads are unchanged)
18
+ - `useMarkdownEditor()` gains `tableWidth` / `setTableWidth` for custom
19
+ toolbars
20
+ - New exports: `BlockWidth`, `$getTableWidth`, `$setTableWidth`,
21
+ `$getSelectedTable`, `TABLE_WIDTH_MARKER`
22
+
23
+ ## 0.3.0
24
+
25
+ - **Custom toolbars**
26
+ - `toolbar` prop accepts a render function receiving the default groups
27
+ (`format`, `insert`, `history`) so you can add your own buttons
28
+ - Compound components: `MarkdownEditor.Root` / `.Content` / `.Toolbar` /
29
+ `.Outline` plus `.FormatButtons` / `.InsertButtons` / `.HistoryButtons` /
30
+ `.ToolbarButton` / `.ToolbarDivider` — place the toolbar anywhere under
31
+ `Root`
32
+ - `useMarkdownEditor()` headless hook: `editor`, `activeFormats`,
33
+ `toggleFormat`, `insertTable`, `insertDrawing`, `undo`/`redo`
34
+ - Undo/redo buttons (`HistoryButtons`; in the default toolbar via the
35
+ function form only — default toolbar layout unchanged)
36
+ - Internal: `LexicalComposer` is now mounted in `edit-raw` mode too, so
37
+ hooks keep working across mode switches
38
+
3
39
  ## 0.2.1
4
40
 
5
41
  - `DRAWING_FORMAT.md`: authoritative spec of the ```drawing JSON payload,
package/DRAWING_FORMAT.md CHANGED
@@ -22,8 +22,12 @@ degrades to an empty canvas (invalid shapes are dropped individually).
22
22
 
23
23
  - Origin `(0,0)` is the canvas's top-left; x grows right, y grows down.
24
24
  - Units are CSS pixels.
25
- - The canvas is as wide as the editor (fluid). Keep shapes within roughly
26
- x ∈ [0, 700] to be safe on typical layouts.
25
+ - The canvas is as wide as the editor by default (`width` omitted or
26
+ `"full"`). Keep shapes within roughly x ∈ [0, 700] to be safe on typical
27
+ layouts.
28
+ - `"width":"content"` instead sizes the canvas to fit the rightmost shape
29
+ (plus a margin, never narrower than 240px), left-aligned with the text —
30
+ use it for small diagrams that shouldn't stretch across the page.
27
31
  - `height` is the canvas height in pixels (minimum 80; 300–400 is typical).
28
32
 
29
33
  ## Top-level object
@@ -32,6 +36,7 @@ degrades to an empty canvas (invalid shapes are dropped individually).
32
36
  |-----------|-----------|-----------------------------------------|
33
37
  | `version` | `1` | Literal `1` |
34
38
  | `height` | `number` | Canvas height in px |
39
+ | `width` | `"full"` \| `"content"` | Optional; default `"full"`. `"content"` fits the shapes' extent |
35
40
  | `shapes` | `Shape[]` | Render order: later shapes draw on top |
36
41
 
37
42
  ## Shape object
package/README.md CHANGED
@@ -13,6 +13,8 @@ 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
+ - **Block width**: tables and diagrams switch between full width and
17
+ content width, Slab-style
16
18
  - **Diagrams**: a drawing canvas embedded in the document — cards with
17
19
  attached text slots, bound arrows that follow their cards, elbow and
18
20
  multi-waypoint routing, labels, color palettes, dark mode
@@ -65,7 +67,7 @@ emits. The emitted string is always plain markdown.
65
67
  | `readOnly` | `boolean` | `false` | Disables editing in Lexical modes |
66
68
  | `autoFocus` | `boolean` | `false` | Focus on mount |
67
69
  | `className` | `string` | — | Root wrapper class |
68
- | `toolbar` | `boolean` | `true` | Formatting/insert toolbar (`edit-md`) |
70
+ | `toolbar` | `boolean \| (items) => ReactNode` | `true` | Formatting/insert toolbar (`edit-md`); function form customises it |
69
71
  | `outline` | `boolean` | `false` | Table-of-contents sidebar |
70
72
  | `foldable` | `boolean` | `true` | Collapse sections under headings |
71
73
 
@@ -96,6 +98,114 @@ Editing is in place: Tab/arrows between cells, cell range selection, inline
96
98
  formatting inside cells. Cell content is single-line in markdown; newlines
97
99
  are escaped as `\n`.
98
100
 
101
+ ### Full width vs content width
102
+
103
+ Tables span the editor by default. Place the caret in a table and a small
104
+ toggle floats at its top-right corner: **full width** (columns share the
105
+ editor width) or **content width** (the table shrinks to fit its columns,
106
+ left-aligned with the text, never wider than the editor). The setting is
107
+ persisted as an HTML comment on the line directly above the table — other
108
+ markdown renderers hide it:
109
+
110
+ ```md
111
+ <!-- width: content -->
112
+ | Key | Value |
113
+ | --- | --- |
114
+ | Region | eu-west-1 |
115
+ ```
116
+
117
+ Programmatic access: `useMarkdownEditor().tableWidth` / `setTableWidth`
118
+ (for custom toolbars), or `$getTableWidth(node)` / `$setTableWidth(node,
119
+ width)` inside `editor.update`. The marker string is exported as
120
+ `TABLE_WIDTH_MARKER`.
121
+
122
+ ## Toolbar & custom toolbars
123
+
124
+ In `edit-md` mode a toolbar offers inline formatting (bold, italic,
125
+ strikethrough, inline code) plus **Insert table** and **Insert drawing**.
126
+ Hide it with `toolbar={false}`.
127
+
128
+ ### Extending the toolbar
129
+
130
+ Pass a function as `toolbar`. It receives the default button groups and
131
+ returns the toolbar to render. Use `MarkdownEditor.ToolbarButton` for your
132
+ own buttons so they match the built-ins and keep the editor selection when
133
+ clicked.
134
+
135
+ ```tsx
136
+ <MarkdownEditor
137
+ value={value}
138
+ onChange={setValue}
139
+ toolbar={(items) => (
140
+ <MarkdownEditor.Toolbar>
141
+ {items.format}
142
+ <MarkdownEditor.ToolbarDivider />
143
+ {items.insert}
144
+ <MarkdownEditor.ToolbarDivider />
145
+ {items.history}
146
+ <MarkdownEditor.ToolbarButton label="Save" onClick={save}>
147
+ 💾
148
+ </MarkdownEditor.ToolbarButton>
149
+ </MarkdownEditor.Toolbar>
150
+ )}
151
+ />
152
+ ```
153
+
154
+ `MarkdownEditor.Toolbar` hides itself in `view` / `edit-raw` / `readOnly`.
155
+
156
+ ### Placing your own toolbar (compound components)
157
+
158
+ When the toolbar must live somewhere else in your layout (an app bar, a
159
+ panel header), compose the editor from its parts. Everything under
160
+ `MarkdownEditor.Root` shares one editor instance, so the toolbar can sit
161
+ anywhere in that subtree.
162
+
163
+ ```tsx
164
+ <MarkdownEditor.Root value={value} onChange={setValue}>
165
+ <header className="app-bar">
166
+ <MarkdownEditor.Toolbar>
167
+ <MarkdownEditor.FormatButtons />
168
+ <MarkdownEditor.ToolbarDivider />
169
+ <MarkdownEditor.InsertButtons />
170
+ </MarkdownEditor.Toolbar>
171
+ <MyAppButtons />
172
+ </header>
173
+ <MarkdownEditor.Content placeholder="Write…">
174
+ <MarkdownEditor.Outline />
175
+ </MarkdownEditor.Content>
176
+ </MarkdownEditor.Root>
177
+ ```
178
+
179
+ | Part | Role |
180
+ |------|------|
181
+ | `Root` | Lexical composer + plugins. Takes `value`, `onChange`, `mode`, `readOnly`, `autoFocus`, `className` |
182
+ | `Content` | The editable surface. Takes `placeholder`, `foldable`; children are docked sidebars |
183
+ | `Toolbar` | Container; renders the default groups when empty |
184
+ | `FormatButtons`, `InsertButtons`, `HistoryButtons` | Built-in groups |
185
+ | `ToolbarButton`, `ToolbarDivider` | Primitives for your own items |
186
+ | `Outline` | Table-of-contents sidebar |
187
+
188
+ ### Headless: `useMarkdownEditor()`
189
+
190
+ For fully custom UI (e.g. buttons in your own design system), call the hook
191
+ from any component rendered under `MarkdownEditor.Root`:
192
+
193
+ ```tsx
194
+ function BoldButton() {
195
+ const { activeFormats, toggleFormat } = useMarkdownEditor()
196
+ return (
197
+ <MyButton pressed={activeFormats.has('bold')} onClick={() => toggleFormat('bold')}>
198
+ B
199
+ </MyButton>
200
+ )
201
+ }
202
+ ```
203
+
204
+ It returns `editor` (the Lexical instance), `activeFormats`,
205
+ `toggleFormat`, `insertTable`, `insertDrawing`, `tableWidth` /
206
+ `setTableWidth` (width of the table containing the selection, `null`
207
+ outside tables), `canUndo`, `canRedo`, `undo`, `redo`.
208
+
99
209
  ## Diagrams (drawing canvas)
100
210
 
101
211
  The toolbar's insert-drawing button embeds a canvas; the drawing persists
@@ -117,6 +227,10 @@ in the markdown as a ` ```drawing ` fenced JSON block, fully specified in
117
227
  bends). One-way / two-way arrowhead toggle; midpoint **labels**.
118
228
  - **Canvas**: resizable height, dot grid, white surface that inverts
119
229
  Excalidraw-style in dark mode (`.dark` ancestor class).
230
+ - **Width**: the toggle at the right end of the canvas toolbar switches
231
+ between **full width** (spans the editor) and **content width** (the
232
+ canvas fits the rightmost shape and grows as shapes move). Stored as
233
+ `"width":"content"` in the payload; omitted when full.
120
234
 
121
235
  ## Outline & section folding
122
236
 
@@ -150,9 +264,12 @@ diagrams:
150
264
 
151
265
  | Export | Purpose |
152
266
  |--------|---------|
153
- | `MarkdownEditor`, `MarkdownEditorProps` | The component |
267
+ | `MarkdownEditor`, `MarkdownEditorProps` | The component; compound parts as statics (`.Root`, `.Content`, `.Toolbar`, …) |
268
+ | `useMarkdownEditor`, `MarkdownEditorApi` | Headless editor hook |
269
+ | `Toolbar`, `ToolbarButton`, `ToolbarDivider`, `FormatButtons`, `InsertButtons`, `HistoryButtons` | Toolbar primitives |
154
270
  | `@zuilib/text-editor/styles.css` | Editor chrome + theme styles (required) |
155
271
  | `TABLE` | GFM table markdown transformer |
272
+ | `BlockWidth`, `$getTableWidth`, `$setTableWidth`, `$getSelectedTable`, `TABLE_WIDTH_MARKER` | Table full/content width helpers |
156
273
  | `DRAWING`, `DrawingNode`, `$createDrawingNode`, `$isDrawingNode` | Drawing node + markdown transformer |
157
274
  | `FRONTMATTER`, `FrontmatterNode`, `$createFrontmatterNode`, `$isFrontmatterNode` | Frontmatter node + transformer |
158
275
  | `DrawingData`, `DrawingShape`, `DrawingShapeType` | Drawing payload types |
@@ -175,7 +292,9 @@ ZUI convention: a `dark` class on `<html>`.
175
292
 
176
293
  ## Architecture notes (for extenders)
177
294
 
178
- - Source: `src/MarkdownEditor.tsx`; plugins in `src/plugins/`; drawing
295
+ - Source: `src/EditorRoot.tsx` (composer + plugins), `src/EditorContent.tsx`,
296
+ `src/MarkdownEditor.tsx` (default composition), `src/useMarkdownEditor.ts`,
297
+ `src/components/Toolbar.tsx`; plugins in `src/plugins/`; drawing
179
298
  canvas in `src/components/`; custom nodes in `src/nodes/`;
180
299
  transformers in `src/transformers/`
181
300
  - Markdown import/export via `@lexical/markdown` transformers; order
package/dist/index.d.ts CHANGED
@@ -1,24 +1,147 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ElementNode, NodeKey, EditorConfig, SerializedElementNode, LexicalNode, DecoratorNode, Spread, SerializedLexicalNode, DOMExportOutput, DOMConversionMap, LexicalEditor } from 'lexical';
2
+ import { ReactNode, ReactElement } from 'react';
3
+ import { LexicalEditor, TextFormatType, ElementNode, NodeKey, EditorConfig, SerializedElementNode, LexicalNode, DecoratorNode, Spread, SerializedLexicalNode, DOMExportOutput, DOMConversionMap } from 'lexical';
3
4
  import { MultilineElementTransformer, ElementTransformer } from '@lexical/markdown';
4
- import { ReactElement } from 'react';
5
+ import { TableNode } from '@lexical/table';
5
6
 
6
- type Props = Readonly<{
7
+ type EditorMode = 'edit-raw' | 'edit-md' | 'view';
8
+ type EditorRootProps = Readonly<{
7
9
  value?: string;
8
10
  onChange?: (value: string) => void;
9
- placeholder?: string;
10
11
  readOnly?: boolean;
11
12
  className?: string;
12
- mode?: 'edit-raw' | 'edit-md' | 'view';
13
+ mode?: EditorMode;
13
14
  autoFocus?: boolean;
14
- /** Show the formatting/insert toolbar in edit-md mode (default true) */
15
- toolbar?: boolean;
15
+ children: ReactNode;
16
+ }>;
17
+ /**
18
+ * Owns the Lexical composer and every non-visual plugin. Anything rendered
19
+ * beneath it (`Content`, `Toolbar`, `Outline`, or your own components using
20
+ * `useMarkdownEditor`) shares the same editor instance.
21
+ */
22
+ declare function EditorRoot({ value, onChange, readOnly, className, mode, autoFocus, children, }: EditorRootProps): ReactElement;
23
+
24
+ type EditorContentProps = Readonly<{
25
+ placeholder?: string;
26
+ /** Allow collapsing sections under their headings (default true) */
27
+ foldable?: boolean;
28
+ /** Sidebars docked next to the content, e.g. `<MarkdownEditor.Outline />` */
29
+ children?: ReactNode;
30
+ }>;
31
+ /**
32
+ * The editable surface. Renders a plain textarea in `edit-raw` mode and the
33
+ * Lexical rich-text surface otherwise.
34
+ */
35
+ declare function EditorContent({ placeholder, foldable, children, }: EditorContentProps): ReactElement;
36
+
37
+ /**
38
+ * Docked, collapsible table-of-contents sidebar. Lists the document's
39
+ * headings (live), scrolls to a heading on click, and highlights the section
40
+ * the viewport is currently in. Pure UI — nothing is added to the document.
41
+ */
42
+ declare function OutlinePlugin(): ReactElement;
43
+
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
+ type MarkdownEditorApi = Readonly<{
52
+ /** The underlying Lexical editor, for dispatching your own commands */
53
+ editor: LexicalEditor;
54
+ /** Text formats active at the current selection */
55
+ activeFormats: ReadonlySet<TextFormatType>;
56
+ toggleFormat: (format: TextFormatType) => void;
57
+ insertTable: (options?: {
58
+ rows?: number;
59
+ columns?: number;
60
+ }) => void;
61
+ insertDrawing: () => void;
62
+ /** Width of the table containing the selection; `null` outside tables */
63
+ tableWidth: BlockWidth | null;
64
+ /** Resize the table containing the selection; no-op outside tables */
65
+ setTableWidth: (width: BlockWidth) => void;
66
+ canUndo: boolean;
67
+ canRedo: boolean;
68
+ undo: () => void;
69
+ redo: () => void;
70
+ }>;
71
+ /**
72
+ * Headless access to the editor. Must be rendered under `MarkdownEditor.Root`
73
+ * (or `MarkdownEditor`). Use it to wire editor actions into your own buttons.
74
+ */
75
+ declare function useMarkdownEditor(): MarkdownEditorApi;
76
+
77
+ /** Default toolbar groups, handed to a `toolbar` render function */
78
+ type ToolbarItems = Readonly<{
79
+ format: ReactElement;
80
+ insert: ReactElement;
81
+ history: ReactElement;
82
+ }>;
83
+ type Props = Omit<EditorRootProps, 'children'> & Readonly<{
84
+ placeholder?: string;
85
+ /**
86
+ * Toolbar in edit-md mode (default true). Pass a function to customise
87
+ * it: it receives the default groups and returns the toolbar to render.
88
+ */
89
+ toolbar?: boolean | ((items: ToolbarItems) => ReactNode);
16
90
  /** Show a table-of-contents sidebar listing the document's headings */
17
91
  outline?: boolean;
18
92
  /** Allow collapsing sections under their headings (default true) */
19
93
  foldable?: boolean;
20
94
  }>;
21
- declare function MarkdownEditor({ value, onChange, placeholder, readOnly, className, mode, autoFocus, toolbar, outline, foldable, }: Props): react_jsx_runtime.JSX.Element;
95
+ /**
96
+ * Toolbar that only shows while the document is editable in `edit-md` mode.
97
+ * Used by `MarkdownEditor` and available as `MarkdownEditor.Toolbar` for
98
+ * compound layouts.
99
+ */
100
+ declare function EditorToolbar({ children, className, }: Readonly<{
101
+ children?: ReactNode;
102
+ className?: string;
103
+ }>): ReactElement | null;
104
+ declare function MarkdownEditor({ placeholder, toolbar, outline, foldable, ...rootProps }: Props): react_jsx_runtime.JSX.Element;
105
+ declare namespace MarkdownEditor {
106
+ var Root: typeof EditorRoot;
107
+ var Content: typeof EditorContent;
108
+ var Toolbar: typeof EditorToolbar;
109
+ var ToolbarButton: typeof ToolbarButton;
110
+ var ToolbarDivider: typeof ToolbarDivider;
111
+ var FormatButtons: typeof FormatButtons;
112
+ var InsertButtons: typeof InsertButtons;
113
+ var HistoryButtons: typeof HistoryButtons;
114
+ var Outline: typeof OutlinePlugin;
115
+ var useEditor: typeof useMarkdownEditor;
116
+ }
117
+
118
+ type ToolbarProps = Readonly<{
119
+ children?: ReactNode;
120
+ className?: string;
121
+ }>;
122
+ /** Toolbar container. Renders the default items when given no children. */
123
+ declare function Toolbar({ children, className }: ToolbarProps): ReactElement;
124
+ declare function ToolbarDivider(): ReactElement;
125
+ type ToolbarButtonProps = Readonly<{
126
+ label: string;
127
+ onClick: () => void;
128
+ /** Icon content — an SVG, emoji, or text. 16px SVGs match the built-ins. */
129
+ children: ReactNode;
130
+ active?: boolean;
131
+ disabled?: boolean;
132
+ className?: string;
133
+ }>;
134
+ /**
135
+ * Button styled like the built-in toolbar buttons. Prevents focus from
136
+ * leaving the editor on click so the selection is preserved.
137
+ */
138
+ declare function ToolbarButton({ label, onClick, children, active, disabled, className, }: ToolbarButtonProps): ReactElement;
139
+ /** Bold / italic / strikethrough / inline-code buttons */
140
+ declare function FormatButtons(): ReactElement;
141
+ /** Insert-table / insert-drawing buttons */
142
+ declare function InsertButtons(): ReactElement;
143
+ /** Undo / redo buttons */
144
+ declare function HistoryButtons(): ReactElement;
22
145
 
23
146
  type SerializedFrontmatterNode = SerializedElementNode;
24
147
  /**
@@ -102,6 +225,11 @@ type DrawingShape = Readonly<{
102
225
  type DrawingData = Readonly<{
103
226
  version: 1;
104
227
  height: number;
228
+ /**
229
+ * Canvas width: `full` (default, omitted when serialized) spans the editor;
230
+ * `content` fits the shapes' horizontal extent.
231
+ */
232
+ width?: BlockWidth;
105
233
  shapes: readonly DrawingShape[];
106
234
  }>;
107
235
  declare function serializeDrawingData(data: DrawingData): string;
@@ -146,9 +274,23 @@ declare const DRAWING: MultilineElementTransformer;
146
274
  * Markdown transformer for GFM tables. Adapted from the Lexical playground.
147
275
  * Rows are matched line-by-line on import and stitched into a single
148
276
  * 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.
149
280
  */
150
281
  declare const TABLE: ElementTransformer;
151
282
 
283
+ /**
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
+
152
294
  /**
153
295
  * JSON Schema (draft-07) for the payload of a ```drawing fenced block.
154
296
  *
@@ -171,7 +313,11 @@ declare const DRAWING_DATA_JSON_SCHEMA: {
171
313
  readonly height: {
172
314
  readonly type: "number";
173
315
  readonly minimum: 80;
174
- readonly description: "Canvas height in pixels (width is fluid)";
316
+ readonly description: "Canvas height in pixels";
317
+ };
318
+ readonly width: {
319
+ 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";
175
321
  };
176
322
  readonly shapes: {
177
323
  readonly type: "array";
@@ -281,4 +427,4 @@ declare const DRAWING_DATA_JSON_SCHEMA: {
281
427
  };
282
428
  };
283
429
 
284
- export { $createDrawingNode, $createFrontmatterNode, $isDrawingNode, $isFrontmatterNode, DRAWING, DRAWING_DATA_JSON_SCHEMA, type DrawingData, DrawingNode, type DrawingShape, type DrawingShapeType, FRONTMATTER, FrontmatterNode, MarkdownEditor, type Props as MarkdownEditorProps, type SerializedDrawingNode, type SerializedFrontmatterNode, TABLE, parseDrawingData, serializeDrawingData };
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 };