@zuilib/text-editor 0.5.0 → 0.6.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 +52 -0
- package/DRAWING_FORMAT.md +11 -5
- package/README.md +87 -26
- package/dist/index.d.ts +108 -24
- package/dist/index.js +182 -55
- package/dist/styles.css +55 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# Changelog — @zuilib/text-editor
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
**Text measure and `text` block width.** Additive: markdown, JSON, class
|
|
6
|
+
names and props keep their meaning; with no configuration the layout is
|
|
7
|
+
unchanged.
|
|
8
|
+
|
|
9
|
+
- **Measure** (opt in): `measure="48rem"` on `MarkdownEditor` /
|
|
10
|
+
`MarkdownEditor.Root`, or `--zui-text-editor-measure: 48rem` in a
|
|
11
|
+
stylesheet — the CSS custom property is the contract, the prop is sugar.
|
|
12
|
+
Text blocks (paragraphs, headings, lists, quotes, code, frontmatter) are
|
|
13
|
+
capped at the measure and centred in the content pane; the placeholder
|
|
14
|
+
and fold chevrons follow the column. The pane itself is never capped and
|
|
15
|
+
full-width blocks stop short of the outline sidebar
|
|
16
|
+
- **`BlockWidth` gains `'text'`**: `'full' | 'text' | 'content'`. `text`
|
|
17
|
+
aligns a table or drawing with the text column; without a measure it is
|
|
18
|
+
visually identical to `full` (resolved in CSS through the variable's
|
|
19
|
+
fallback). `full` (default, omitted) and `content` (shrink to fit) are
|
|
20
|
+
unchanged
|
|
21
|
+
- **Persistence**: tables `<!-- width: text -->` (combinable with
|
|
22
|
+
`density`); drawings and ` ```diagram ` skeletons `"width":"text"`.
|
|
23
|
+
`DRAWING_DATA_JSON_SCHEMA`, `DRAWING_SKELETON_JSON_SCHEMA` and
|
|
24
|
+
`DRAWING_FORMAT.md` updated. Unknown width values are ignored (treated as
|
|
25
|
+
`full`) instead of being rejected, so documents from newer versions still
|
|
26
|
+
open — `parseTableSettingsMarker` now returns `{}` (rather than `null`)
|
|
27
|
+
for a marker whose only known key carries an unknown value, and the
|
|
28
|
+
transformer consumes that line
|
|
29
|
+
- **Insertion defaults**: `defaultBlockWidth={{ table?, drawing? }}` on
|
|
30
|
+
Root applies when the toolbar / `useMarkdownEditor()` inserts a new table
|
|
31
|
+
or drawing. The chosen width is written to the markdown explicitly, even
|
|
32
|
+
`full`, so the document reads the same in an app with other defaults; a
|
|
33
|
+
width named in the source (`<!-- width: full -->`, `"width":"full"`) is
|
|
34
|
+
preserved on round trip
|
|
35
|
+
- **UI / headless**: the floating table toolbar and the drawing toolbar
|
|
36
|
+
offer all three widths with distinct icons (`BLOCK_WIDTH_OPTIONS`).
|
|
37
|
+
`useMarkdownEditor()` gains `blockWidth` / `setBlockWidth` for the block
|
|
38
|
+
containing the selection — the focused drawing or the table the caret is
|
|
39
|
+
in; `insertTable` / `insertDrawing` accept a `width` option. `tableWidth`
|
|
40
|
+
/ `setTableWidth` keep working and are deprecated
|
|
41
|
+
- **CSS**: the new layout lives in zero-specificity `:where()` rules. The
|
|
42
|
+
content pane exposes `--zui-text-editor-gutter` and
|
|
43
|
+
`--zui-text-editor-bleed`; every top-level block reads
|
|
44
|
+
`--zui-text-editor-block-bleed`, so one class rule overrides any block
|
|
45
|
+
kind. New block classes (added next to the existing utility classes):
|
|
46
|
+
`.zui-paragraph`, `.zui-heading` / `.zui-heading-1`…`6`, `.zui-list` /
|
|
47
|
+
`.zui-list-ordered` / `.zui-list-unordered`, `.zui-quote`, `.zui-code`;
|
|
48
|
+
`.zui-drawing-canvas` gains `.is-text-width`. Nothing is renamed
|
|
49
|
+
- New exports: `BLOCK_WIDTHS`, `isBlockWidth`, `BlockWidthDefaults`,
|
|
50
|
+
`TableSettingsOptions`, `$isTableWidthExplicit`; `$setTableSettings` and
|
|
51
|
+
`formatTableSettingsMarker` take an optional `{ explicitWidth }`
|
|
52
|
+
- **Adopting**: set `measure` (or the CSS variable) and delete any external
|
|
53
|
+
`max-width` / `margin-inline` overrides on `.zui-text-editor-content > *`
|
|
54
|
+
|
|
3
55
|
## 0.5.0
|
|
4
56
|
|
|
5
57
|
**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
|
-
- `
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
- **
|
|
17
|
-
|
|
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
|
|
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
|
-
|
|
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().
|
|
126
|
-
|
|
127
|
-
`$
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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`, `
|
|
216
|
-
`
|
|
217
|
-
|
|
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
|
|
255
|
-
between **full
|
|
256
|
-
|
|
257
|
-
|
|
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
|
|
|
@@ -335,8 +395,9 @@ diagrams:
|
|
|
335
395
|
| `Toolbar`, `ToolbarButton`, `ToolbarDivider`, `FormatButtons`, `InsertButtons`, `HistoryButtons` | Toolbar primitives |
|
|
336
396
|
| `@zuilib/text-editor/styles.css` | Editor chrome + theme styles (required) |
|
|
337
397
|
| `TABLE` | GFM table markdown transformer |
|
|
338
|
-
| `BlockWidth`, `
|
|
339
|
-
|
|
|
398
|
+
| `BlockWidth`, `BLOCK_WIDTHS`, `isBlockWidth`, `BlockWidthDefaults` | Block width (`full` / `text` / `content`) type, values, guard, insertion defaults |
|
|
399
|
+
| `TableDensity`, `TableSettings`, `TableSettingsOptions`, `DEFAULT_TABLE_SETTINGS` | Table setting types |
|
|
400
|
+
| `$getTableSettings`, `$setTableSettings`, `$isTableWidthExplicit`, `$getTableWidth`, `$setTableWidth`, `$getTableDensity`, `$setTableDensity`, `$getSelectedTable` | Table setting helpers (inside `editor.update`/`read`) |
|
|
340
401
|
| `parseTableSettingsMarker`, `formatTableSettingsMarker` | Marker comment ⇄ `TableSettings` |
|
|
341
402
|
| `DRAWING`, `DIAGRAM`, `DrawingNode`, `$createDrawingNode`, `$isDrawingNode` | Drawing node + markdown transformers (` ```drawing ` and ` ```diagram `) |
|
|
342
403
|
| `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
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
71
|
-
|
|
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
|
-
|
|
84
|
-
|
|
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
|
-
/**
|
|
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
|
|
287
|
-
*
|
|
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:
|
|
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
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// src/EditorRoot.tsx
|
|
2
2
|
import {
|
|
3
|
-
createContext,
|
|
4
3
|
useCallback as useCallback2,
|
|
5
|
-
useContext,
|
|
6
4
|
useEffect as useEffect8,
|
|
7
5
|
useMemo as useMemo2,
|
|
8
6
|
useRef as useRef5,
|
|
@@ -308,6 +306,18 @@ import { $getNodeByKey as $getNodeByKey2 } from "lexical";
|
|
|
308
306
|
import { useLexicalComposerContext as useLexicalComposerContext5 } from "@lexical/react/LexicalComposerContext";
|
|
309
307
|
import { useLexicalEditable } from "@lexical/react/useLexicalEditable";
|
|
310
308
|
|
|
309
|
+
// src/drawing/focusCommand.ts
|
|
310
|
+
import { createCommand } from "lexical";
|
|
311
|
+
var DRAWING_FOCUS_COMMAND = createCommand(
|
|
312
|
+
"DRAWING_FOCUS_COMMAND"
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
// src/blockWidth.ts
|
|
316
|
+
var BLOCK_WIDTHS = ["full", "text", "content"];
|
|
317
|
+
function isBlockWidth(value) {
|
|
318
|
+
return typeof value === "string" && BLOCK_WIDTHS.includes(value);
|
|
319
|
+
}
|
|
320
|
+
|
|
311
321
|
// src/drawing/types.ts
|
|
312
322
|
var BOX_TYPES = [
|
|
313
323
|
"rect",
|
|
@@ -393,8 +403,9 @@ function normalizeDrawingData(parsed) {
|
|
|
393
403
|
version: 2,
|
|
394
404
|
canvasHeight: Number.isFinite(height) && height >= MIN_CANVAS_HEIGHT ? height : DEFAULT_CANVAS_HEIGHT,
|
|
395
405
|
...Number.isFinite(canvasWidth) && canvasWidth >= 120 ? { canvasWidth } : {},
|
|
396
|
-
// `full`
|
|
397
|
-
|
|
406
|
+
// `full` stays implicit unless the payload spells it out; unknown
|
|
407
|
+
// values (newer versions) are dropped rather than rejected
|
|
408
|
+
...isBlockWidth(parsed.width) ? { width: parsed.width } : {},
|
|
398
409
|
// Bindings to ids that don't exist (or aren't boxes) are dropped
|
|
399
410
|
shapes: shapes.map((shape) => {
|
|
400
411
|
if (!isConnectorType(shape.type)) return shape;
|
|
@@ -2335,6 +2346,14 @@ var BLOCK_WIDTH_OPTIONS = [
|
|
|
2335
2346
|
/* @__PURE__ */ jsx7("path", { d: "M6 10h8M8.5 7.5L6 10l2.5 2.5M11.5 7.5L14 10l-2.5 2.5" })
|
|
2336
2347
|
] })
|
|
2337
2348
|
},
|
|
2349
|
+
{
|
|
2350
|
+
width: "text",
|
|
2351
|
+
label: "Text width",
|
|
2352
|
+
icon: /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
2353
|
+
/* @__PURE__ */ jsx7("path", { d: "M3 4v12M17 4v12" }),
|
|
2354
|
+
/* @__PURE__ */ jsx7("path", { d: "M6.5 7h7M6.5 10h7M6.5 13h4.5" })
|
|
2355
|
+
] })
|
|
2356
|
+
},
|
|
2338
2357
|
{
|
|
2339
2358
|
width: "content",
|
|
2340
2359
|
label: "Content width",
|
|
@@ -2482,6 +2501,11 @@ function DrawingToolbar({
|
|
|
2482
2501
|
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2483
2502
|
var MIN_HEIGHT = 120;
|
|
2484
2503
|
var MAX_HEIGHT = 1200;
|
|
2504
|
+
var WIDTH_CLASS = {
|
|
2505
|
+
full: "",
|
|
2506
|
+
text: "is-text-width",
|
|
2507
|
+
content: "is-content-width"
|
|
2508
|
+
};
|
|
2485
2509
|
var MIN_CONTENT_WIDTH = 240;
|
|
2486
2510
|
var CONTENT_WIDTH_PADDING = 40;
|
|
2487
2511
|
var EMPTY_SET = /* @__PURE__ */ new Set();
|
|
@@ -2564,11 +2588,12 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
2564
2588
|
const commit = useCallback(
|
|
2565
2589
|
(nextShapes, options) => {
|
|
2566
2590
|
const nextWidth = options?.width ?? widthRef.current;
|
|
2591
|
+
const explicitFull = options?.width === void 0 && data.width !== void 0;
|
|
2567
2592
|
const payload = {
|
|
2568
2593
|
version: 2,
|
|
2569
2594
|
...canvasWidth ? { canvasWidth } : {},
|
|
2570
2595
|
canvasHeight: options?.height ?? heightRef.current,
|
|
2571
|
-
...nextWidth
|
|
2596
|
+
...nextWidth !== "full" || explicitFull ? { width: nextWidth } : {},
|
|
2572
2597
|
shapes: nextShapes
|
|
2573
2598
|
};
|
|
2574
2599
|
const json = serializeDrawingData(payload);
|
|
@@ -2579,7 +2604,7 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
2579
2604
|
if ($isDrawingNode(node)) node.setData(payload);
|
|
2580
2605
|
});
|
|
2581
2606
|
},
|
|
2582
|
-
[editor, nodeKey, canvasWidth]
|
|
2607
|
+
[editor, nodeKey, canvasWidth, data.width]
|
|
2583
2608
|
);
|
|
2584
2609
|
const updateShapes = useCallback(
|
|
2585
2610
|
(updater, options) => {
|
|
@@ -2965,8 +2990,13 @@ function DrawingCanvas({ nodeKey, data }) {
|
|
|
2965
2990
|
"div",
|
|
2966
2991
|
{
|
|
2967
2992
|
ref: rootRef,
|
|
2968
|
-
className: `zui-drawing-canvas ${width
|
|
2993
|
+
className: `zui-drawing-canvas ${WIDTH_CLASS[width]} ${isEditable ? "is-editable" : ""}`,
|
|
2969
2994
|
tabIndex: isEditable ? 0 : void 0,
|
|
2995
|
+
onFocus: () => editor.dispatchCommand(DRAWING_FOCUS_COMMAND, nodeKey),
|
|
2996
|
+
onBlur: (e) => {
|
|
2997
|
+
if (rootRef.current?.contains(e.relatedTarget)) return;
|
|
2998
|
+
editor.dispatchCommand(DRAWING_FOCUS_COMMAND, null);
|
|
2999
|
+
},
|
|
2970
3000
|
children: [
|
|
2971
3001
|
isEditable && /* @__PURE__ */ jsxs8("div", { className: "zui-drawing-toolbar", onPointerDown: (e) => e.stopPropagation(), children: [
|
|
2972
3002
|
/* @__PURE__ */ jsx9(
|
|
@@ -3214,7 +3244,7 @@ function expandSkeleton(skeleton) {
|
|
|
3214
3244
|
version: 2,
|
|
3215
3245
|
...skeleton.canvasWidth !== void 0 ? { canvasWidth: skeleton.canvasWidth } : {},
|
|
3216
3246
|
canvasHeight: skeleton.canvasHeight ?? Math.max(MIN_AUTO_CANVAS_HEIGHT, Math.ceil(bottom + CANVAS_MARGIN)),
|
|
3217
|
-
...skeleton.width
|
|
3247
|
+
...skeleton.width !== void 0 ? { width: skeleton.width } : {},
|
|
3218
3248
|
shapes
|
|
3219
3249
|
});
|
|
3220
3250
|
}
|
|
@@ -3418,7 +3448,7 @@ function normalizeSkeleton(raw) {
|
|
|
3418
3448
|
direction: value.direction === "down" ? "down" : "right",
|
|
3419
3449
|
...canvasWidth !== void 0 ? { canvasWidth } : {},
|
|
3420
3450
|
...canvasHeight !== void 0 ? { canvasHeight } : {},
|
|
3421
|
-
...value.width
|
|
3451
|
+
...isBlockWidth(value.width) ? { width: value.width } : {},
|
|
3422
3452
|
boxes,
|
|
3423
3453
|
connectors,
|
|
3424
3454
|
texts
|
|
@@ -3551,8 +3581,8 @@ var DRAWING_SKELETON_JSON_SCHEMA = {
|
|
|
3551
3581
|
description: "Canvas height in px. Omit to fit the content"
|
|
3552
3582
|
},
|
|
3553
3583
|
width: {
|
|
3554
|
-
enum: ["content"],
|
|
3555
|
-
description: 'Block width: "content" fits the drawing to its shapes and left-aligns it with the text; omit to span the editor'
|
|
3584
|
+
enum: ["full", "text", "content"],
|
|
3585
|
+
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'
|
|
3556
3586
|
},
|
|
3557
3587
|
boxes: {
|
|
3558
3588
|
type: "array",
|
|
@@ -3788,10 +3818,12 @@ var DEFAULT_TABLE_SETTINGS = {
|
|
|
3788
3818
|
width: "full",
|
|
3789
3819
|
density: "comfortable"
|
|
3790
3820
|
};
|
|
3821
|
+
var BLOCK_BLEED_PROPERTY = "--zui-text-editor-block-bleed";
|
|
3791
3822
|
var OPTION_DECLARATIONS = {
|
|
3792
3823
|
width: {
|
|
3793
3824
|
full: {},
|
|
3794
|
-
content: { width: "auto", "table-layout": "auto" }
|
|
3825
|
+
content: { width: "auto", "table-layout": "auto", [BLOCK_BLEED_PROPERTY]: "0px" },
|
|
3826
|
+
text: { [BLOCK_BLEED_PROPERTY]: "0px" }
|
|
3795
3827
|
},
|
|
3796
3828
|
density: {
|
|
3797
3829
|
comfortable: {},
|
|
@@ -3806,6 +3838,7 @@ var OPTION_DECLARATIONS = {
|
|
|
3806
3838
|
}
|
|
3807
3839
|
};
|
|
3808
3840
|
var SETTING_KEYS = Object.keys(OPTION_DECLARATIONS);
|
|
3841
|
+
var EXPLICIT_WIDTH_PROPERTY = "--zui-table-width";
|
|
3809
3842
|
function parseStyle(style) {
|
|
3810
3843
|
const declarations = /* @__PURE__ */ new Map();
|
|
3811
3844
|
for (const part of style.split(";")) {
|
|
@@ -3848,14 +3881,22 @@ function $getTableSettings(table) {
|
|
|
3848
3881
|
density: readSetting(declarations, "density")
|
|
3849
3882
|
};
|
|
3850
3883
|
}
|
|
3851
|
-
function $setTableSettings(table, settings) {
|
|
3884
|
+
function $setTableSettings(table, settings, options = {}) {
|
|
3852
3885
|
const declarations = parseStyle(table.getStyle());
|
|
3853
3886
|
for (const key of SETTING_KEYS) {
|
|
3854
3887
|
const option = settings[key];
|
|
3855
3888
|
if (option !== void 0) writeSetting(declarations, key, option);
|
|
3856
3889
|
}
|
|
3890
|
+
if (settings.width !== void 0) {
|
|
3891
|
+
if (options.explicitWidth) declarations.set(EXPLICIT_WIDTH_PROPERTY, settings.width);
|
|
3892
|
+
else declarations.delete(EXPLICIT_WIDTH_PROPERTY);
|
|
3893
|
+
}
|
|
3857
3894
|
table.setStyle(serializeStyle(declarations));
|
|
3858
3895
|
}
|
|
3896
|
+
function $isTableWidthExplicit(table) {
|
|
3897
|
+
const declarations = parseStyle(table.getStyle());
|
|
3898
|
+
return declarations.get(EXPLICIT_WIDTH_PROPERTY) === readSetting(declarations, "width");
|
|
3899
|
+
}
|
|
3859
3900
|
function $getTableWidth(table) {
|
|
3860
3901
|
return $getTableSettings(table).width;
|
|
3861
3902
|
}
|
|
@@ -3890,16 +3931,19 @@ function parseTableSettingsMarker(text) {
|
|
|
3890
3931
|
const match = MARKER_REG_EXP.exec(text);
|
|
3891
3932
|
if (!match) return null;
|
|
3892
3933
|
const settings = {};
|
|
3934
|
+
let recognised = false;
|
|
3893
3935
|
for (const pair of match[1].split(";")) {
|
|
3894
3936
|
const [key, value] = pair.split(":").map((s) => s.trim());
|
|
3937
|
+
if (key !== "width" && key !== "density") continue;
|
|
3938
|
+
recognised = true;
|
|
3895
3939
|
if (key === "width" && isOption("width", value)) settings.width = value;
|
|
3896
3940
|
if (key === "density" && isOption("density", value)) settings.density = value;
|
|
3897
3941
|
}
|
|
3898
|
-
return
|
|
3942
|
+
return recognised ? settings : null;
|
|
3899
3943
|
}
|
|
3900
|
-
function formatTableSettingsMarker(settings) {
|
|
3944
|
+
function formatTableSettingsMarker(settings, options = {}) {
|
|
3901
3945
|
const pairs = SETTING_KEYS.filter(
|
|
3902
|
-
(key) => settings[key] !== DEFAULT_TABLE_SETTINGS[key]
|
|
3946
|
+
(key) => settings[key] !== DEFAULT_TABLE_SETTINGS[key] || key === "width" && options.explicitWidth
|
|
3903
3947
|
).map((key) => `${key}: ${settings[key]}`);
|
|
3904
3948
|
return pairs.length > 0 ? `<!-- ${pairs.join("; ")} -->` : null;
|
|
3905
3949
|
}
|
|
@@ -3932,7 +3976,9 @@ var TABLE = {
|
|
|
3932
3976
|
export: (node) => {
|
|
3933
3977
|
if (!$isTableNode2(node)) return null;
|
|
3934
3978
|
const output = [];
|
|
3935
|
-
const marker = formatTableSettingsMarker($getTableSettings(node)
|
|
3979
|
+
const marker = formatTableSettingsMarker($getTableSettings(node), {
|
|
3980
|
+
explicitWidth: $isTableWidthExplicit(node)
|
|
3981
|
+
});
|
|
3936
3982
|
if (marker) output.push(marker);
|
|
3937
3983
|
for (const row of node.getChildren()) {
|
|
3938
3984
|
if (!$isTableRowNode(row)) continue;
|
|
@@ -4001,7 +4047,7 @@ var TABLE = {
|
|
|
4001
4047
|
} else {
|
|
4002
4048
|
const markerSettings = $getMarkerSettings(previousSibling);
|
|
4003
4049
|
if (markerSettings) {
|
|
4004
|
-
$setTableSettings(table, markerSettings);
|
|
4050
|
+
$setTableSettings(table, markerSettings, { explicitWidth: true });
|
|
4005
4051
|
previousSibling?.remove();
|
|
4006
4052
|
}
|
|
4007
4053
|
parentNode.replace(table);
|
|
@@ -4016,14 +4062,14 @@ var editorTheme = {
|
|
|
4016
4062
|
ltr: "text-left",
|
|
4017
4063
|
rtl: "text-right",
|
|
4018
4064
|
placeholder: "text-muted-foreground opacity-50",
|
|
4019
|
-
paragraph: "mb-2",
|
|
4065
|
+
paragraph: "zui-paragraph mb-2",
|
|
4020
4066
|
heading: {
|
|
4021
|
-
h1: "text-4xl font-bold mb-4",
|
|
4022
|
-
h2: "text-3xl font-bold mb-3",
|
|
4023
|
-
h3: "text-2xl font-bold mb-2",
|
|
4024
|
-
h4: "text-xl font-bold mb-2",
|
|
4025
|
-
h5: "text-lg font-bold mb-1",
|
|
4026
|
-
h6: "text-base font-bold mb-1"
|
|
4067
|
+
h1: "zui-heading zui-heading-1 text-4xl font-bold mb-4",
|
|
4068
|
+
h2: "zui-heading zui-heading-2 text-3xl font-bold mb-3",
|
|
4069
|
+
h3: "zui-heading zui-heading-3 text-2xl font-bold mb-2",
|
|
4070
|
+
h4: "zui-heading zui-heading-4 text-xl font-bold mb-2",
|
|
4071
|
+
h5: "zui-heading zui-heading-5 text-lg font-bold mb-1",
|
|
4072
|
+
h6: "zui-heading zui-heading-6 text-base font-bold mb-1"
|
|
4027
4073
|
},
|
|
4028
4074
|
list: {
|
|
4029
4075
|
listitem: "ml-8",
|
|
@@ -4033,8 +4079,8 @@ var editorTheme = {
|
|
|
4033
4079
|
listitem: "ml-8"
|
|
4034
4080
|
},
|
|
4035
4081
|
checklist: "zui-checklist",
|
|
4036
|
-
ol: "list-decimal ml-4",
|
|
4037
|
-
ul: "list-disc ml-4"
|
|
4082
|
+
ol: "zui-list zui-list-ordered list-decimal ml-4",
|
|
4083
|
+
ul: "zui-list zui-list-unordered list-disc ml-4"
|
|
4038
4084
|
},
|
|
4039
4085
|
link: "text-primary underline hover:opacity-80 cursor-pointer",
|
|
4040
4086
|
text: {
|
|
@@ -4047,7 +4093,7 @@ var editorTheme = {
|
|
|
4047
4093
|
underline: "underline",
|
|
4048
4094
|
underlineStrikethrough: "underline line-through"
|
|
4049
4095
|
},
|
|
4050
|
-
code: "bg-muted rounded-md p-4 font-mono text-sm block my-2 overflow-x-auto",
|
|
4096
|
+
code: "zui-code bg-muted rounded-md p-4 font-mono text-sm block my-2 overflow-x-auto",
|
|
4051
4097
|
codeHighlight: {
|
|
4052
4098
|
atrule: "text-blue-500",
|
|
4053
4099
|
attr: "text-yellow-500",
|
|
@@ -4080,7 +4126,7 @@ var editorTheme = {
|
|
|
4080
4126
|
url: "text-blue-500",
|
|
4081
4127
|
variable: "text-blue-500"
|
|
4082
4128
|
},
|
|
4083
|
-
quote: "border-l-4 border-border pl-4 italic",
|
|
4129
|
+
quote: "zui-quote border-l-4 border-border pl-4 italic",
|
|
4084
4130
|
frontmatter: "zui-frontmatter",
|
|
4085
4131
|
table: "zui-table",
|
|
4086
4132
|
tableCell: "zui-table-cell",
|
|
@@ -4090,10 +4136,8 @@ var editorTheme = {
|
|
|
4090
4136
|
drawing: "zui-drawing"
|
|
4091
4137
|
};
|
|
4092
4138
|
|
|
4093
|
-
// src/
|
|
4094
|
-
import {
|
|
4095
|
-
var SYNC_TRANSFORMERS = [FRONTMATTER, DRAWING, DIAGRAM, CHECK_LIST, TABLE, ...TRANSFORMERS2];
|
|
4096
|
-
var SHORTCUT_TRANSFORMERS = [TABLE, ...TRANSFORMERS2.filter((t) => t !== CODE)];
|
|
4139
|
+
// src/editorContext.ts
|
|
4140
|
+
import { createContext, useContext } from "react";
|
|
4097
4141
|
var EditorContext = createContext(null);
|
|
4098
4142
|
function useEditorContext() {
|
|
4099
4143
|
const ctx = useContext(EditorContext);
|
|
@@ -4104,6 +4148,12 @@ function useEditorContext() {
|
|
|
4104
4148
|
}
|
|
4105
4149
|
return ctx;
|
|
4106
4150
|
}
|
|
4151
|
+
|
|
4152
|
+
// src/EditorRoot.tsx
|
|
4153
|
+
import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
4154
|
+
var SYNC_TRANSFORMERS = [FRONTMATTER, DRAWING, DIAGRAM, CHECK_LIST, TABLE, ...TRANSFORMERS2];
|
|
4155
|
+
var SHORTCUT_TRANSFORMERS = [TABLE, ...TRANSFORMERS2.filter((t) => t !== CODE)];
|
|
4156
|
+
var NO_DEFAULT_BLOCK_WIDTH = {};
|
|
4107
4157
|
function onError(error) {
|
|
4108
4158
|
console.error(error);
|
|
4109
4159
|
}
|
|
@@ -4136,6 +4186,8 @@ function EditorRoot({
|
|
|
4136
4186
|
className,
|
|
4137
4187
|
mode = "edit-md",
|
|
4138
4188
|
autoFocus = false,
|
|
4189
|
+
measure,
|
|
4190
|
+
defaultBlockWidth = NO_DEFAULT_BLOCK_WIDTH,
|
|
4139
4191
|
children
|
|
4140
4192
|
}) {
|
|
4141
4193
|
const latestValueRef = useRef5(value ?? "");
|
|
@@ -4176,12 +4228,17 @@ function EditorRoot({
|
|
|
4176
4228
|
readOnly,
|
|
4177
4229
|
autoFocus,
|
|
4178
4230
|
rawValue: value ?? "",
|
|
4179
|
-
onRawChange: handleChange
|
|
4231
|
+
onRawChange: handleChange,
|
|
4232
|
+
defaultBlockWidth
|
|
4180
4233
|
}),
|
|
4181
|
-
[mode, readOnly, autoFocus, value, handleChange]
|
|
4234
|
+
[mode, readOnly, autoFocus, value, handleChange, defaultBlockWidth]
|
|
4182
4235
|
);
|
|
4183
4236
|
const isRaw = mode === "edit-raw";
|
|
4184
|
-
|
|
4237
|
+
const rootStyle = useMemo2(
|
|
4238
|
+
() => measure !== void 0 ? { "--zui-text-editor-measure": measure } : void 0,
|
|
4239
|
+
[measure]
|
|
4240
|
+
);
|
|
4241
|
+
return /* @__PURE__ */ jsx11(LexicalComposer, { initialConfig, children: /* @__PURE__ */ jsx11(EditorContext.Provider, { value: context, children: /* @__PURE__ */ jsxs9("div", { className: `zui-text-editor ${className ?? ""}`, style: rootStyle, children: [
|
|
4185
4242
|
children,
|
|
4186
4243
|
!isRaw && /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
4187
4244
|
/* @__PURE__ */ jsx11(
|
|
@@ -4355,8 +4412,9 @@ import { useLexicalComposerContext as useLexicalComposerContext9 } from "@lexica
|
|
|
4355
4412
|
import { useLexicalEditable as useLexicalEditable2 } from "@lexical/react/useLexicalEditable";
|
|
4356
4413
|
|
|
4357
4414
|
// src/useMarkdownEditor.ts
|
|
4358
|
-
import { useCallback as useCallback4, useEffect as useEffect10, useState as useState6 } from "react";
|
|
4415
|
+
import { useCallback as useCallback4, useEffect as useEffect10, useRef as useRef7, useState as useState6 } from "react";
|
|
4359
4416
|
import {
|
|
4417
|
+
$getNodeByKey as $getNodeByKey4,
|
|
4360
4418
|
$getSelection as $getSelection4,
|
|
4361
4419
|
$isRangeSelection as $isRangeSelection4,
|
|
4362
4420
|
CAN_REDO_COMMAND,
|
|
@@ -4376,20 +4434,29 @@ var TRACKED_FORMATS = [
|
|
|
4376
4434
|
"strikethrough",
|
|
4377
4435
|
"code"
|
|
4378
4436
|
];
|
|
4437
|
+
function $readDrawingWidth(key) {
|
|
4438
|
+
if (key === null) return null;
|
|
4439
|
+
const node = $getNodeByKey4(key);
|
|
4440
|
+
return $isDrawingNode(node) ? node.getData().width ?? "full" : null;
|
|
4441
|
+
}
|
|
4379
4442
|
function useMarkdownEditor() {
|
|
4380
4443
|
const [editor] = useLexicalComposerContext8();
|
|
4444
|
+
const { defaultBlockWidth } = useEditorContext();
|
|
4381
4445
|
const [activeFormats, setActiveFormats] = useState6(
|
|
4382
4446
|
/* @__PURE__ */ new Set()
|
|
4383
4447
|
);
|
|
4384
4448
|
const [canUndo, setCanUndo] = useState6(false);
|
|
4385
4449
|
const [canRedo, setCanRedo] = useState6(false);
|
|
4386
4450
|
const [tableSettings, setTableSettingsState] = useState6(null);
|
|
4451
|
+
const activeDrawingRef = useRef7(null);
|
|
4452
|
+
const [drawingWidth, setDrawingWidth] = useState6(null);
|
|
4387
4453
|
useEffect10(
|
|
4388
4454
|
() => mergeRegister(
|
|
4389
4455
|
editor.registerUpdateListener(({ editorState }) => {
|
|
4390
4456
|
editorState.read(() => {
|
|
4391
4457
|
const table = $getSelectedTable();
|
|
4392
4458
|
setTableSettingsState(table ? $getTableSettings(table) : null);
|
|
4459
|
+
setDrawingWidth($readDrawingWidth(activeDrawingRef.current));
|
|
4393
4460
|
const selection = $getSelection4();
|
|
4394
4461
|
if (!$isRangeSelection4(selection)) {
|
|
4395
4462
|
setActiveFormats(/* @__PURE__ */ new Set());
|
|
@@ -4402,6 +4469,15 @@ function useMarkdownEditor() {
|
|
|
4402
4469
|
setActiveFormats(next);
|
|
4403
4470
|
});
|
|
4404
4471
|
}),
|
|
4472
|
+
editor.registerCommand(
|
|
4473
|
+
DRAWING_FOCUS_COMMAND,
|
|
4474
|
+
(key) => {
|
|
4475
|
+
activeDrawingRef.current = key;
|
|
4476
|
+
setDrawingWidth(editor.getEditorState().read(() => $readDrawingWidth(key)));
|
|
4477
|
+
return false;
|
|
4478
|
+
},
|
|
4479
|
+
COMMAND_PRIORITY_LOW2
|
|
4480
|
+
),
|
|
4405
4481
|
editor.registerCommand(
|
|
4406
4482
|
CAN_UNDO_COMMAND,
|
|
4407
4483
|
(payload) => {
|
|
@@ -4428,20 +4504,36 @@ function useMarkdownEditor() {
|
|
|
4428
4504
|
[editor]
|
|
4429
4505
|
);
|
|
4430
4506
|
const insertTable = useCallback4(
|
|
4431
|
-
({
|
|
4507
|
+
({
|
|
4508
|
+
rows = 3,
|
|
4509
|
+
columns = 3,
|
|
4510
|
+
width = defaultBlockWidth.table
|
|
4511
|
+
} = {}) => {
|
|
4512
|
+
const before = editor.getEditorState().read(() => $getSelectedTable()?.getKey());
|
|
4432
4513
|
editor.dispatchCommand(INSERT_TABLE_COMMAND, {
|
|
4433
4514
|
columns: String(columns),
|
|
4434
4515
|
rows: String(rows),
|
|
4435
4516
|
includeHeaders: { rows: true, columns: false }
|
|
4436
4517
|
});
|
|
4518
|
+
if (width === void 0) return;
|
|
4519
|
+
editor.update(() => {
|
|
4520
|
+
const table = $getSelectedTable();
|
|
4521
|
+
if (table && table.getKey() !== before) {
|
|
4522
|
+
$setTableSettings(table, { width }, { explicitWidth: true });
|
|
4523
|
+
}
|
|
4524
|
+
});
|
|
4437
4525
|
},
|
|
4438
|
-
[editor]
|
|
4526
|
+
[editor, defaultBlockWidth.table]
|
|
4527
|
+
);
|
|
4528
|
+
const insertDrawing = useCallback4(
|
|
4529
|
+
({ width = defaultBlockWidth.drawing } = {}) => {
|
|
4530
|
+
editor.update(() => {
|
|
4531
|
+
const data = width === void 0 ? EMPTY_DRAWING : { version: 2, canvasHeight: EMPTY_DRAWING.canvasHeight, width, shapes: [] };
|
|
4532
|
+
$insertNodeToNearestRoot($createDrawingNode(serializeDrawingData(data)));
|
|
4533
|
+
});
|
|
4534
|
+
},
|
|
4535
|
+
[editor, defaultBlockWidth.drawing]
|
|
4439
4536
|
);
|
|
4440
|
-
const insertDrawing = useCallback4(() => {
|
|
4441
|
-
editor.update(() => {
|
|
4442
|
-
$insertNodeToNearestRoot($createDrawingNode());
|
|
4443
|
-
});
|
|
4444
|
-
}, [editor]);
|
|
4445
4537
|
const updateTableSettings = useCallback4(
|
|
4446
4538
|
(settings) => {
|
|
4447
4539
|
editor.update(() => {
|
|
@@ -4459,6 +4551,22 @@ function useMarkdownEditor() {
|
|
|
4459
4551
|
(density) => updateTableSettings({ density }),
|
|
4460
4552
|
[updateTableSettings]
|
|
4461
4553
|
);
|
|
4554
|
+
const setBlockWidth = useCallback4(
|
|
4555
|
+
(width) => {
|
|
4556
|
+
const key = activeDrawingRef.current;
|
|
4557
|
+
if (key === null) {
|
|
4558
|
+
updateTableSettings({ width });
|
|
4559
|
+
return;
|
|
4560
|
+
}
|
|
4561
|
+
editor.update(() => {
|
|
4562
|
+
const node = $getNodeByKey4(key);
|
|
4563
|
+
if (!$isDrawingNode(node)) return;
|
|
4564
|
+
const { width: _previous, ...data } = node.getData();
|
|
4565
|
+
node.setData(width === "full" ? data : { ...data, width });
|
|
4566
|
+
});
|
|
4567
|
+
},
|
|
4568
|
+
[editor, updateTableSettings]
|
|
4569
|
+
);
|
|
4462
4570
|
const undo = useCallback4(() => {
|
|
4463
4571
|
editor.dispatchCommand(UNDO_COMMAND, void 0);
|
|
4464
4572
|
}, [editor]);
|
|
@@ -4471,6 +4579,8 @@ function useMarkdownEditor() {
|
|
|
4471
4579
|
toggleFormat,
|
|
4472
4580
|
insertTable,
|
|
4473
4581
|
insertDrawing,
|
|
4582
|
+
blockWidth: drawingWidth ?? tableSettings?.width ?? null,
|
|
4583
|
+
setBlockWidth,
|
|
4474
4584
|
tableWidth: tableSettings?.width ?? null,
|
|
4475
4585
|
setTableWidth,
|
|
4476
4586
|
tableDensity: tableSettings?.density ?? null,
|
|
@@ -4641,14 +4751,18 @@ function Icon3({ children }) {
|
|
|
4641
4751
|
function TableSettingsPlugin() {
|
|
4642
4752
|
const [editor] = useLexicalComposerContext9();
|
|
4643
4753
|
const isEditable = useLexicalEditable2();
|
|
4644
|
-
const { tableWidth, setTableWidth, tableDensity, setTableDensity } = useMarkdownEditor();
|
|
4645
4754
|
const [anchor, setAnchor] = useState7(null);
|
|
4755
|
+
const [settings, setSettings] = useState7(null);
|
|
4646
4756
|
const sync = useCallback5(() => {
|
|
4647
|
-
const
|
|
4648
|
-
|
|
4757
|
+
const table = editor.getEditorState().read(() => {
|
|
4758
|
+
const node = $getSelectedTable();
|
|
4759
|
+
return node ? { key: node.getKey(), settings: $getTableSettings(node) } : null;
|
|
4760
|
+
});
|
|
4761
|
+
const element = table ? editor.getElementByKey(table.key) : null;
|
|
4649
4762
|
const main = editor.getRootElement()?.parentElement;
|
|
4650
|
-
if (!element || !main) {
|
|
4763
|
+
if (!table || !element || !main) {
|
|
4651
4764
|
setAnchor(null);
|
|
4765
|
+
setSettings(null);
|
|
4652
4766
|
return;
|
|
4653
4767
|
}
|
|
4654
4768
|
const rect = element.getBoundingClientRect();
|
|
@@ -4657,6 +4771,7 @@ function TableSettingsPlugin() {
|
|
|
4657
4771
|
top: rect.top - mainRect.top,
|
|
4658
4772
|
right: mainRect.right - rect.right + 8
|
|
4659
4773
|
});
|
|
4774
|
+
setSettings(table.settings);
|
|
4660
4775
|
}, [editor]);
|
|
4661
4776
|
useEffect11(() => {
|
|
4662
4777
|
sync();
|
|
@@ -4669,7 +4784,16 @@ function TableSettingsPlugin() {
|
|
|
4669
4784
|
observer?.disconnect();
|
|
4670
4785
|
};
|
|
4671
4786
|
}, [editor, sync]);
|
|
4672
|
-
|
|
4787
|
+
const update = useCallback5(
|
|
4788
|
+
(next) => {
|
|
4789
|
+
editor.update(() => {
|
|
4790
|
+
const table = $getSelectedTable();
|
|
4791
|
+
if (table) $setTableSettings(table, next);
|
|
4792
|
+
});
|
|
4793
|
+
},
|
|
4794
|
+
[editor]
|
|
4795
|
+
);
|
|
4796
|
+
if (!isEditable || !anchor || !settings) return null;
|
|
4673
4797
|
return /* @__PURE__ */ jsxs11(
|
|
4674
4798
|
"div",
|
|
4675
4799
|
{
|
|
@@ -4682,8 +4806,8 @@ function TableSettingsPlugin() {
|
|
|
4682
4806
|
ToolbarButton,
|
|
4683
4807
|
{
|
|
4684
4808
|
label,
|
|
4685
|
-
active:
|
|
4686
|
-
onClick: () =>
|
|
4809
|
+
active: settings.width === width,
|
|
4810
|
+
onClick: () => update({ width }),
|
|
4687
4811
|
children: /* @__PURE__ */ jsx14(Icon3, { children: icon })
|
|
4688
4812
|
},
|
|
4689
4813
|
width
|
|
@@ -4693,8 +4817,8 @@ function TableSettingsPlugin() {
|
|
|
4693
4817
|
ToolbarButton,
|
|
4694
4818
|
{
|
|
4695
4819
|
label,
|
|
4696
|
-
active:
|
|
4697
|
-
onClick: () =>
|
|
4820
|
+
active: settings.density === density,
|
|
4821
|
+
onClick: () => update({ density }),
|
|
4698
4822
|
children: /* @__PURE__ */ jsx14(Icon3, { children: icon })
|
|
4699
4823
|
},
|
|
4700
4824
|
density
|
|
@@ -4923,8 +5047,8 @@ var DRAWING_DATA_JSON_SCHEMA = {
|
|
|
4923
5047
|
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."
|
|
4924
5048
|
},
|
|
4925
5049
|
width: {
|
|
4926
|
-
enum: ["full", "content"],
|
|
4927
|
-
description: `Block width: "full" (default, omit it) spans the editor; "content" fits the shapes' horizontal extent and left-aligns with the text`
|
|
5050
|
+
enum: ["full", "text", "content"],
|
|
5051
|
+
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`
|
|
4928
5052
|
},
|
|
4929
5053
|
shapes: {
|
|
4930
5054
|
type: "array",
|
|
@@ -5067,9 +5191,11 @@ export {
|
|
|
5067
5191
|
$getTableWidth,
|
|
5068
5192
|
$isDrawingNode,
|
|
5069
5193
|
$isFrontmatterNode,
|
|
5194
|
+
$isTableWidthExplicit,
|
|
5070
5195
|
$setTableDensity,
|
|
5071
5196
|
$setTableSettings,
|
|
5072
5197
|
$setTableWidth,
|
|
5198
|
+
BLOCK_WIDTHS,
|
|
5073
5199
|
BOX_DEFINITIONS,
|
|
5074
5200
|
BOX_TYPES,
|
|
5075
5201
|
COLOR_PRESETS,
|
|
@@ -5105,6 +5231,7 @@ export {
|
|
|
5105
5231
|
findBoxAt,
|
|
5106
5232
|
fixedPointFor,
|
|
5107
5233
|
formatTableSettingsMarker,
|
|
5234
|
+
isBlockWidth,
|
|
5108
5235
|
isDrawingSkeleton,
|
|
5109
5236
|
makeBinding,
|
|
5110
5237
|
normalizeDrawingData,
|
package/dist/styles.css
CHANGED
|
@@ -11,21 +11,62 @@
|
|
|
11
11
|
min-height: 100%;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
/*
|
|
15
|
+
* Text measure (opt in). `--zui-text-editor-measure` — a CSS length, unset
|
|
16
|
+
* by default — caps the text column. The pane's gutter grows from the base
|
|
17
|
+
* 2rem to centre that column, and `--zui-text-editor-bleed` is how far a
|
|
18
|
+
* full-width block extends past the column on each side. With the measure
|
|
19
|
+
* unset both resolve to the previous layout (2rem gutter, no bleed).
|
|
20
|
+
*
|
|
21
|
+
* The pane is a container so `cqw` measures *its* width in every
|
|
22
|
+
* descendant, whatever the descendant's own width; the outline sidebar is
|
|
23
|
+
* a sibling, so full-width blocks stop short of it.
|
|
24
|
+
*/
|
|
14
25
|
.zui-text-editor-main {
|
|
15
26
|
position: relative;
|
|
16
27
|
display: flex;
|
|
17
28
|
flex-direction: column;
|
|
18
29
|
flex: 1;
|
|
19
30
|
min-width: 0;
|
|
31
|
+
container-type: inline-size;
|
|
32
|
+
--zui-text-editor-gutter: max(
|
|
33
|
+
2rem,
|
|
34
|
+
calc((100cqw - var(--zui-text-editor-measure, 100cqw)) / 2)
|
|
35
|
+
);
|
|
36
|
+
--zui-text-editor-bleed: calc(var(--zui-text-editor-gutter) - 2rem);
|
|
20
37
|
}
|
|
21
38
|
|
|
22
39
|
.zui-text-editor-content {
|
|
23
40
|
flex: 1;
|
|
24
41
|
min-height: 100%;
|
|
25
|
-
padding: 1.5rem 2rem;
|
|
42
|
+
padding: 1.5rem var(--zui-text-editor-gutter, 2rem);
|
|
26
43
|
outline: none;
|
|
27
44
|
}
|
|
28
45
|
|
|
46
|
+
/*
|
|
47
|
+
* Block width. Every top-level block sits in the text column and may bleed
|
|
48
|
+
* past it by `--zui-text-editor-block-bleed` (0 unless set). Tables and
|
|
49
|
+
* drawings default it to the pane's bleed (`full`); their `text` and
|
|
50
|
+
* `content` settings pin it to 0 — as an inline style on the table (see
|
|
51
|
+
* tableSettings.ts) and a class on the drawing canvas. Zero-specificity
|
|
52
|
+
* selectors, so one class rule overrides any block kind, e.g.
|
|
53
|
+
* `.zui-code { --zui-text-editor-block-bleed: var(--zui-text-editor-bleed) }`.
|
|
54
|
+
*/
|
|
55
|
+
:where(.zui-text-editor-content > *) {
|
|
56
|
+
margin-inline: calc(-1 * var(--zui-text-editor-block-bleed, 0px));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
:where(.zui-table, .zui-drawing) {
|
|
60
|
+
--zui-text-editor-block-bleed: var(--zui-text-editor-bleed, 0px);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
:where(
|
|
64
|
+
.zui-drawing:has(> .is-text-width),
|
|
65
|
+
.zui-drawing:has(> .is-content-width)
|
|
66
|
+
) {
|
|
67
|
+
--zui-text-editor-block-bleed: 0px;
|
|
68
|
+
}
|
|
69
|
+
|
|
29
70
|
/* Outline (table of contents) sidebar */
|
|
30
71
|
.zui-text-editor-outline {
|
|
31
72
|
position: sticky;
|
|
@@ -115,7 +156,8 @@
|
|
|
115
156
|
|
|
116
157
|
.zui-text-editor-fold {
|
|
117
158
|
position: absolute;
|
|
118
|
-
left
|
|
159
|
+
/* Just left of the text column; 0.45rem with the default gutter */
|
|
160
|
+
left: calc(var(--zui-text-editor-gutter, 2rem) - 1.55rem);
|
|
119
161
|
display: inline-flex;
|
|
120
162
|
align-items: center;
|
|
121
163
|
justify-content: center;
|
|
@@ -155,7 +197,7 @@
|
|
|
155
197
|
.zui-text-editor-placeholder {
|
|
156
198
|
position: absolute;
|
|
157
199
|
top: 1.5rem;
|
|
158
|
-
left: 2rem;
|
|
200
|
+
left: var(--zui-text-editor-gutter, 2rem);
|
|
159
201
|
pointer-events: none;
|
|
160
202
|
user-select: none;
|
|
161
203
|
}
|
|
@@ -209,7 +251,7 @@
|
|
|
209
251
|
.zui-frontmatter {
|
|
210
252
|
display: block;
|
|
211
253
|
white-space: pre-wrap;
|
|
212
|
-
margin: 0
|
|
254
|
+
margin-block: 0 1rem;
|
|
213
255
|
padding: 0.75rem 1rem;
|
|
214
256
|
border: 1px solid currentColor;
|
|
215
257
|
border-radius: 0.375rem;
|
|
@@ -272,11 +314,15 @@
|
|
|
272
314
|
background: color-mix(in srgb, currentColor 15%, transparent);
|
|
273
315
|
}
|
|
274
316
|
|
|
275
|
-
/*
|
|
317
|
+
/*
|
|
318
|
+
* Tables — artifact-style: rounded outer border, subtle header, tight rules.
|
|
319
|
+
* Width follows the block bleed above (inline margins come from the shared
|
|
320
|
+
* block rule); a `content` table sets `width: auto` inline instead.
|
|
321
|
+
*/
|
|
276
322
|
.zui-table {
|
|
277
|
-
width: 100
|
|
278
|
-
max-width: 100
|
|
279
|
-
margin: 1rem
|
|
323
|
+
width: calc(100% + 2 * var(--zui-text-editor-block-bleed, 0px));
|
|
324
|
+
max-width: calc(100% + 2 * var(--zui-text-editor-block-bleed, 0px));
|
|
325
|
+
margin-block: 1rem;
|
|
280
326
|
border-collapse: separate;
|
|
281
327
|
border-spacing: 0;
|
|
282
328
|
border: 1px solid color-mix(in srgb, currentColor 15%, transparent);
|
|
@@ -347,7 +393,7 @@
|
|
|
347
393
|
|
|
348
394
|
/* Drawing canvas */
|
|
349
395
|
.zui-drawing {
|
|
350
|
-
margin: 1rem
|
|
396
|
+
margin-block: 1rem;
|
|
351
397
|
}
|
|
352
398
|
|
|
353
399
|
.zui-drawing-canvas {
|