@zuilib/text-editor 0.11.0 → 0.12.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 +180 -17
- package/DRAWING_FORMAT.md +23 -21
- package/README.md +486 -68
- package/dist/chunk-32RX4GZF.js +2 -0
- package/dist/chunk-3TZVOXWX.js +16 -0
- package/dist/chunk-5VRVC56Y.js +2 -0
- package/dist/chunk-7Z3CW6Q3.js +2 -0
- package/dist/chunk-A7MCBSAZ.js +2 -0
- package/dist/chunk-AGTPMKLK.js +2 -0
- package/dist/chunk-C7VEINKX.js +2 -0
- package/dist/chunk-LDVPFZCN.js +2 -0
- package/dist/chunk-N5JWZ2VW.js +9 -0
- package/dist/chunk-QKHMJQO3.js +2 -0
- package/dist/chunk-R5PL4Q7X.js +5 -0
- package/dist/chunk-SDICQI2B.js +2 -0
- package/dist/chunk-TGVEPLDM.js +1 -0
- package/dist/chunk-XP3MZRCW.js +2 -0
- package/dist/chunk-XRJNLGI4.js +2 -0
- package/dist/chunk-YFFSTMIR.js +2 -0
- package/dist/chunk-ZXZMYJ7F.js +2 -0
- package/dist/comment-markers-BrrrAdSL.d.ts +27 -0
- package/dist/comments.d.ts +68 -0
- package/dist/comments.js +2 -0
- package/dist/drawing-data-EWzEQ1_i.d.ts +111 -0
- package/dist/drawing-preset-Ag7a7F9h.d.ts +69 -0
- package/dist/drawing.d.ts +7 -0
- package/dist/drawing.js +2 -0
- package/dist/image-node-kR1Zf5kz.d.ts +70 -0
- package/dist/images.d.ts +66 -0
- package/dist/images.js +2 -0
- package/dist/index-A4S7bRwQ.d.ts +425 -0
- package/dist/index.d.ts +36 -1394
- package/dist/index.js +2 -7447
- package/dist/lexical.d.ts +117 -0
- package/dist/lexical.js +2 -0
- package/dist/markdown.d.ts +29 -0
- package/dist/markdown.js +2 -0
- package/dist/mention-node-eSsjUpaE.d.ts +44 -0
- package/dist/mentions-plugin-gio3_XKd.d.ts +74 -0
- package/dist/mentions.d.ts +5 -0
- package/dist/mentions.js +2 -0
- package/dist/mermaid-BwGHjwpk.d.ts +553 -0
- package/dist/paste.d.ts +45 -0
- package/dist/paste.js +2 -0
- package/dist/presets-BtNPH0pa.d.ts +78 -0
- package/dist/styles.css +406 -99
- package/dist/table-grid-D70tNhp2.d.ts +459 -0
- package/package.json +57 -12
- package/dist/index.css +0 -79
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { Klass, LexicalNode, EditorThemeClasses, LexicalEditor } from 'lexical';
|
|
3
|
+
import { N as NewBlockWidths, D as DrawingStyle, T as TransformersInput, E as EditorPreset, a as BlockWidth } from './presets-BtNPH0pa.js';
|
|
4
|
+
import { TableNode, TableCellNode, TableRowNode } from '@lexical/table';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Docked, collapsible table-of-contents sidebar. Lists the document's
|
|
8
|
+
* headings (live), scrolls to a heading on click, and highlights the section
|
|
9
|
+
* the viewport is currently in. Pure UI — nothing is added to the document.
|
|
10
|
+
*/
|
|
11
|
+
declare function OutlinePlugin(): ReactElement;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Every string the editor chrome shows or announces. Pass a deep partial as
|
|
15
|
+
* the `labels` prop to translate; anything left out keeps its English
|
|
16
|
+
* default. Document content is never touched.
|
|
17
|
+
*/
|
|
18
|
+
type EditorLabels = Readonly<{
|
|
19
|
+
/** Empty-state hint of the editable surface (the `placeholder` prop wins when given) */
|
|
20
|
+
placeholder: string;
|
|
21
|
+
toolbar: Readonly<{
|
|
22
|
+
bold: string;
|
|
23
|
+
italic: string;
|
|
24
|
+
strikethrough: string;
|
|
25
|
+
code: string;
|
|
26
|
+
link: string;
|
|
27
|
+
removeLink: string;
|
|
28
|
+
heading1: string;
|
|
29
|
+
heading2: string;
|
|
30
|
+
heading3: string;
|
|
31
|
+
paragraph: string;
|
|
32
|
+
bulletList: string;
|
|
33
|
+
numberedList: string;
|
|
34
|
+
checklist: string;
|
|
35
|
+
quote: string;
|
|
36
|
+
insertTable: string;
|
|
37
|
+
insertDrawing: string;
|
|
38
|
+
undo: string;
|
|
39
|
+
redo: string;
|
|
40
|
+
/** `aria-label` of the link bubble's URL input */
|
|
41
|
+
linkUrl: string;
|
|
42
|
+
/** Placeholder of the link bubble's URL input */
|
|
43
|
+
linkUrlPlaceholder: string;
|
|
44
|
+
linkApply: string;
|
|
45
|
+
}>;
|
|
46
|
+
/** Character counter: `count(12, 200)` renders "12 / 200" */
|
|
47
|
+
count: (length: number, max: number | undefined) => string;
|
|
48
|
+
/** Announced (not shown) by the counter when the document passes `maxLength` */
|
|
49
|
+
limitExceeded: (max: number) => string;
|
|
50
|
+
/** Announced by the counter when the document is back within `maxLength` */
|
|
51
|
+
limitRestored: (max: number) => string;
|
|
52
|
+
outline: Readonly<{
|
|
53
|
+
show: string;
|
|
54
|
+
hide: string;
|
|
55
|
+
/** `aria-label` of the list of headings */
|
|
56
|
+
title: string;
|
|
57
|
+
empty: string;
|
|
58
|
+
untitled: string;
|
|
59
|
+
}>;
|
|
60
|
+
collapsibleHeadings: Readonly<{
|
|
61
|
+
collapse: string;
|
|
62
|
+
expand: string;
|
|
63
|
+
collapsed: string;
|
|
64
|
+
expanded: string;
|
|
65
|
+
}>;
|
|
66
|
+
table: Readonly<{
|
|
67
|
+
settings: string;
|
|
68
|
+
rowInserted: string;
|
|
69
|
+
rowDeleted: string;
|
|
70
|
+
columnInserted: string;
|
|
71
|
+
columnDeleted: string;
|
|
72
|
+
addRow: string;
|
|
73
|
+
addColumn: string;
|
|
74
|
+
insertRowBefore: (row: number) => string;
|
|
75
|
+
insertColumnBefore: (column: number) => string;
|
|
76
|
+
deleteRow: (row: number) => string;
|
|
77
|
+
deleteColumn: (column: number) => string;
|
|
78
|
+
}>;
|
|
79
|
+
/** The three layout presets shared by tables and drawings */
|
|
80
|
+
layout: Readonly<{
|
|
81
|
+
compact: string;
|
|
82
|
+
comfortable: string;
|
|
83
|
+
full: string;
|
|
84
|
+
}>;
|
|
85
|
+
drawing: Readonly<{
|
|
86
|
+
/** `aria-label` of a canvas without a title */
|
|
87
|
+
canvas: string;
|
|
88
|
+
tools: string;
|
|
89
|
+
select: string;
|
|
90
|
+
rect: string;
|
|
91
|
+
ellipse: string;
|
|
92
|
+
diamond: string;
|
|
93
|
+
arrow: string;
|
|
94
|
+
line: string;
|
|
95
|
+
text: string;
|
|
96
|
+
note: string;
|
|
97
|
+
cylinder: string;
|
|
98
|
+
cloud: string;
|
|
99
|
+
queue: string;
|
|
100
|
+
actor: string;
|
|
101
|
+
moreShapes: string;
|
|
102
|
+
copyMermaid: string;
|
|
103
|
+
copiedMermaid: string;
|
|
104
|
+
/** `aria-label` of the swatch group */
|
|
105
|
+
colors: string;
|
|
106
|
+
color: (name: string) => string;
|
|
107
|
+
connectorRouting: string;
|
|
108
|
+
straight: string;
|
|
109
|
+
elbow: string;
|
|
110
|
+
arrowDirection: string;
|
|
111
|
+
oneWay: string;
|
|
112
|
+
twoWay: string;
|
|
113
|
+
deleteShape: string;
|
|
114
|
+
deleteShapes: (count: number) => string;
|
|
115
|
+
resize: string;
|
|
116
|
+
waypoint: string;
|
|
117
|
+
elbowHandle: string;
|
|
118
|
+
labelPlaceholder: string;
|
|
119
|
+
textPlaceholder: string;
|
|
120
|
+
footerPlaceholder: string;
|
|
121
|
+
}>;
|
|
122
|
+
}>;
|
|
123
|
+
/** Recursive partial that leaves functions whole */
|
|
124
|
+
type DeepPartial<T> = {
|
|
125
|
+
[K in keyof T]?: T[K] extends (...args: never[]) => unknown ? T[K] : T[K] extends object ? DeepPartial<T[K]> : T[K];
|
|
126
|
+
};
|
|
127
|
+
type EditorLabelsInput = DeepPartial<EditorLabels>;
|
|
128
|
+
declare const DEFAULT_LABELS: EditorLabels;
|
|
129
|
+
/** Fills a partial labels object with the English defaults, group by group. */
|
|
130
|
+
declare function resolveLabels(labels?: EditorLabelsInput): EditorLabels;
|
|
131
|
+
/** The resolved labels of the nearest editor; English defaults outside one. */
|
|
132
|
+
declare function useLabels(): EditorLabels;
|
|
133
|
+
|
|
134
|
+
type EditorMode = 'edit-raw' | 'edit-rich' | 'view';
|
|
135
|
+
/** Attributes forwarded to the editable surface for form integration */
|
|
136
|
+
type EditorFieldProps = Readonly<{
|
|
137
|
+
id?: string;
|
|
138
|
+
name?: string;
|
|
139
|
+
'aria-label'?: string;
|
|
140
|
+
'aria-labelledby'?: string;
|
|
141
|
+
'aria-describedby'?: string;
|
|
142
|
+
'aria-invalid'?: boolean | 'true' | 'false' | 'grammar' | 'spelling';
|
|
143
|
+
'aria-required'?: boolean | 'true' | 'false';
|
|
144
|
+
}>;
|
|
145
|
+
type EditorContextValue = Readonly<{
|
|
146
|
+
mode: EditorMode;
|
|
147
|
+
readOnly: boolean;
|
|
148
|
+
autoFocus: boolean;
|
|
149
|
+
/** Current raw markdown (for the `edit-raw` textarea) */
|
|
150
|
+
rawValue: string;
|
|
151
|
+
onRawChange: (value: string) => void;
|
|
152
|
+
/** Width written when a new table / drawing is inserted */
|
|
153
|
+
newBlockWidth: NewBlockWidths;
|
|
154
|
+
/** How drawing canvases render their shapes */
|
|
155
|
+
drawingStyle: DrawingStyle;
|
|
156
|
+
/** Resolved chrome strings */
|
|
157
|
+
labels: EditorLabels;
|
|
158
|
+
/** Maximum plain-text length, when enforced */
|
|
159
|
+
maxLength?: number;
|
|
160
|
+
/** Form attributes for the editable surface */
|
|
161
|
+
field: EditorFieldProps;
|
|
162
|
+
}>;
|
|
163
|
+
declare function useEditorContext(): EditorContextValue;
|
|
164
|
+
|
|
165
|
+
type EditorRootProps = Readonly<{
|
|
166
|
+
value?: string;
|
|
167
|
+
/** Initial markdown of an uncontrolled editor (no `value`) */
|
|
168
|
+
defaultValue?: string;
|
|
169
|
+
onValueChange?: (value: string) => void;
|
|
170
|
+
/**
|
|
171
|
+
* Milliseconds to wait after the last edit before `onValueChange` fires; `0`
|
|
172
|
+
* (default) fires on every edit. The editor's own state is never delayed.
|
|
173
|
+
*/
|
|
174
|
+
debounceMs?: number;
|
|
175
|
+
readOnly?: boolean;
|
|
176
|
+
className?: string;
|
|
177
|
+
mode?: EditorMode;
|
|
178
|
+
autoFocus?: boolean;
|
|
179
|
+
/**
|
|
180
|
+
* Maximum width of the text column, as a CSS length (`'48rem'`
|
|
181
|
+
* recommended). Text blocks are capped at this width and centred; tables
|
|
182
|
+
* and drawings choose per block whether to align with the column
|
|
183
|
+
* (`text`), span the pane (`full`) or hug their content. Sugar for
|
|
184
|
+
* setting `--zui-text-editor-measure` on the root; the variable can
|
|
185
|
+
* equally be set from a stylesheet. Unset: no cap, every block spans the
|
|
186
|
+
* pane.
|
|
187
|
+
*/
|
|
188
|
+
maxTextWidth?: string;
|
|
189
|
+
/**
|
|
190
|
+
* Width written into the markdown when the toolbar or
|
|
191
|
+
* `useMarkdownEditor()` inserts a new table / drawing. Only affects
|
|
192
|
+
* insertion; markdown without a width marker always means `full`.
|
|
193
|
+
*/
|
|
194
|
+
newBlockWidth?: NewBlockWidths;
|
|
195
|
+
/**
|
|
196
|
+
* `clean` (default) draws crisp geometry; `ink` draws every shape as a
|
|
197
|
+
* single pen stroke with pressure and slightly misregistered fills, and
|
|
198
|
+
* sets the casual face (Recursive, if the host loads it).
|
|
199
|
+
*/
|
|
200
|
+
drawingStyle?: DrawingStyle;
|
|
201
|
+
/** Called when Lexical throws inside an update; defaults to `console.error` */
|
|
202
|
+
onError?: (error: Error) => void;
|
|
203
|
+
/** Extra Lexical node classes, appended to the built-ins. Read on mount only. */
|
|
204
|
+
nodes?: ReadonlyArray<Klass<LexicalNode>>;
|
|
205
|
+
/**
|
|
206
|
+
* Extra markdown transformers. An array goes before the built-ins so it
|
|
207
|
+
* claims its syntax first; a function receives the built-ins and returns
|
|
208
|
+
* the whole list. Read on mount only.
|
|
209
|
+
*/
|
|
210
|
+
transformers?: TransformersInput;
|
|
211
|
+
/** Class names for the rendered nodes, merged over the built-ins (one level deep). Read on mount only. */
|
|
212
|
+
nodeClassNames?: EditorThemeClasses;
|
|
213
|
+
/** The Lexical editor instance, once it exists */
|
|
214
|
+
onEditorReady?: (editor: LexicalEditor) => void;
|
|
215
|
+
/** Chrome strings; a deep partial over the English defaults */
|
|
216
|
+
labels?: EditorLabelsInput;
|
|
217
|
+
/**
|
|
218
|
+
* Maximum length of the document's plain text (characters). Typing or
|
|
219
|
+
* pasting past it is rejected at the caret; a controlled `value` is never
|
|
220
|
+
* trimmed.
|
|
221
|
+
*/
|
|
222
|
+
maxLength?: number;
|
|
223
|
+
/** Plain-text length after every change (and once on mount) */
|
|
224
|
+
onCharacterCountChange?: (length: number) => void;
|
|
225
|
+
/** Form attributes forwarded to the editable surface */
|
|
226
|
+
id?: string;
|
|
227
|
+
name?: string;
|
|
228
|
+
'aria-label'?: string;
|
|
229
|
+
'aria-labelledby'?: string;
|
|
230
|
+
'aria-describedby'?: string;
|
|
231
|
+
'aria-invalid'?: EditorFieldProps['aria-invalid'];
|
|
232
|
+
'aria-required'?: EditorFieldProps['aria-required'];
|
|
233
|
+
/** Wired by the entry point (`.` adds drawings); hosts do not set it */
|
|
234
|
+
preset?: EditorPreset;
|
|
235
|
+
children: ReactNode;
|
|
236
|
+
}>;
|
|
237
|
+
|
|
238
|
+
type EditorContentProps = Readonly<{
|
|
239
|
+
/** Empty-state hint; defaults to `labels.placeholder` */
|
|
240
|
+
placeholder?: string;
|
|
241
|
+
/** Allow collapsing sections under their headings (default true) */
|
|
242
|
+
collapsible?: boolean;
|
|
243
|
+
/** Show the character counter below the surface (needs `maxLength` for the "/ max" part) */
|
|
244
|
+
showCharacterCount?: boolean;
|
|
245
|
+
/** Sidebars docked next to the content, e.g. `<MarkdownEditor.Outline />` */
|
|
246
|
+
children?: ReactNode;
|
|
247
|
+
}>;
|
|
248
|
+
/**
|
|
249
|
+
* The editable surface. Renders a plain textarea in `edit-raw` mode and the
|
|
250
|
+
* Lexical rich-text surface otherwise. Form attributes given to the root
|
|
251
|
+
* (`id`, `name`, `aria-*`) land on whichever element is editable.
|
|
252
|
+
*/
|
|
253
|
+
declare function EditorContent({ placeholder, collapsible, showCharacterCount, children, }: EditorContentProps): ReactElement;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Plain-text length of the document, with the limit when `maxLength` is
|
|
257
|
+
* set. In `edit-raw` mode it counts the markdown itself. The visible count
|
|
258
|
+
* is not a live region (it would be read on every keystroke); a hidden
|
|
259
|
+
* status announces only when the document passes the limit or comes back
|
|
260
|
+
* within it.
|
|
261
|
+
*/
|
|
262
|
+
declare function CharacterCount({ className }?: {
|
|
263
|
+
className?: string;
|
|
264
|
+
}): ReactElement;
|
|
265
|
+
|
|
266
|
+
type ToolbarProps = Readonly<{
|
|
267
|
+
children?: ReactNode;
|
|
268
|
+
className?: string;
|
|
269
|
+
/** `aria-label` of the toolbar; defaults to nothing (one toolbar per editor) */
|
|
270
|
+
label?: string;
|
|
271
|
+
}>;
|
|
272
|
+
/** Toolbar container. Renders the default items when given no children. */
|
|
273
|
+
declare function Toolbar({ children, className, label }: ToolbarProps): ReactElement;
|
|
274
|
+
declare function ToolbarDivider(): ReactElement;
|
|
275
|
+
type ToolbarButtonProps = Readonly<{
|
|
276
|
+
label: string;
|
|
277
|
+
onClick: () => void;
|
|
278
|
+
/** Icon content: an SVG, emoji, or text. 16px SVGs match the built-ins. */
|
|
279
|
+
children: ReactNode;
|
|
280
|
+
active?: boolean;
|
|
281
|
+
disabled?: boolean;
|
|
282
|
+
className?: string;
|
|
283
|
+
}>;
|
|
284
|
+
/**
|
|
285
|
+
* Button styled like the built-in toolbar buttons. Prevents focus from
|
|
286
|
+
* leaving the editor on click so the selection is preserved, and takes part
|
|
287
|
+
* in the toolbar's arrow-key navigation.
|
|
288
|
+
*/
|
|
289
|
+
declare function ToolbarButton({ label, onClick, children, active, disabled, className, }: ToolbarButtonProps): ReactElement;
|
|
290
|
+
/** Bold / italic / strikethrough / inline-code / link buttons */
|
|
291
|
+
declare function FormatButtons(): ReactElement;
|
|
292
|
+
/** Heading 1-3 / bullet, numbered and check list / quote buttons. Pressing the active one returns to a paragraph. */
|
|
293
|
+
declare function BlockButtons(): ReactElement;
|
|
294
|
+
/** Insert-table / insert-drawing buttons. `drawing={false}` hides the drawing button (the `./core` entry does). */
|
|
295
|
+
declare function InsertButtons({ drawing }?: {
|
|
296
|
+
drawing?: boolean;
|
|
297
|
+
}): ReactElement;
|
|
298
|
+
/** Undo / redo buttons */
|
|
299
|
+
declare function HistoryButtons(): ReactElement;
|
|
300
|
+
|
|
301
|
+
/** Default toolbar groups, handed to a `toolbar` render function */
|
|
302
|
+
type ToolbarItems = Readonly<{
|
|
303
|
+
format: ReactElement;
|
|
304
|
+
block: ReactElement;
|
|
305
|
+
insert: ReactElement;
|
|
306
|
+
history: ReactElement;
|
|
307
|
+
}>;
|
|
308
|
+
type MarkdownEditorProps = Omit<EditorRootProps, 'children' | 'preset'> & Readonly<{
|
|
309
|
+
placeholder?: string;
|
|
310
|
+
/**
|
|
311
|
+
* Toolbar in edit-rich mode (default true). Pass a function to customise
|
|
312
|
+
* it: it receives the default groups and returns the toolbar to render.
|
|
313
|
+
*/
|
|
314
|
+
toolbar?: boolean | ((items: ToolbarItems) => ReactNode);
|
|
315
|
+
/** Show a table-of-contents sidebar listing the document's headings */
|
|
316
|
+
outline?: boolean;
|
|
317
|
+
/** Allow collapsing sections under their headings (default true) */
|
|
318
|
+
collapsible?: boolean;
|
|
319
|
+
/** Show the character counter under the document */
|
|
320
|
+
showCharacterCount?: boolean;
|
|
321
|
+
/** Extra plugins and UI rendered under the root, next to the content */
|
|
322
|
+
children?: ReactNode;
|
|
323
|
+
}>;
|
|
324
|
+
/**
|
|
325
|
+
* Toolbar that only shows while the document is editable in `edit-rich` mode.
|
|
326
|
+
* Used by `MarkdownEditor` and available as `MarkdownEditor.Toolbar` for
|
|
327
|
+
* compound layouts.
|
|
328
|
+
*/
|
|
329
|
+
declare function EditorToolbar({ children, className, }: Readonly<{
|
|
330
|
+
children?: ReactNode;
|
|
331
|
+
className?: string;
|
|
332
|
+
}>): ReactElement | null;
|
|
333
|
+
/**
|
|
334
|
+
* Builds a `MarkdownEditor` (and its compound parts) around a preset. The
|
|
335
|
+
* default entry uses the preset with drawings, `./core` the one without;
|
|
336
|
+
* both share every other part.
|
|
337
|
+
*/
|
|
338
|
+
declare function createMarkdownEditor(preset?: EditorPreset): {
|
|
339
|
+
({ placeholder, toolbar, outline, collapsible, showCharacterCount, children, ...rootProps }: MarkdownEditorProps): ReactElement;
|
|
340
|
+
Root: (props: Omit<EditorRootProps, "preset">) => ReactElement;
|
|
341
|
+
Content: typeof EditorContent;
|
|
342
|
+
Toolbar: typeof EditorToolbar;
|
|
343
|
+
ToolbarButton: typeof ToolbarButton;
|
|
344
|
+
ToolbarDivider: typeof ToolbarDivider;
|
|
345
|
+
FormatButtons: typeof FormatButtons;
|
|
346
|
+
BlockButtons: typeof BlockButtons;
|
|
347
|
+
InsertButtons: typeof InsertButtons;
|
|
348
|
+
HistoryButtons: typeof HistoryButtons;
|
|
349
|
+
Outline: typeof OutlinePlugin;
|
|
350
|
+
CharacterCount: typeof CharacterCount;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/** Cell padding / font size preset */
|
|
354
|
+
type TableDensity = 'compact' | 'comfortable' | 'spacious';
|
|
355
|
+
type TableSettings = Readonly<{
|
|
356
|
+
width: BlockWidth;
|
|
357
|
+
density: TableDensity;
|
|
358
|
+
}>;
|
|
359
|
+
declare const DEFAULT_TABLE_SETTINGS: TableSettings;
|
|
360
|
+
type TableSettingsOptions = Readonly<{
|
|
361
|
+
/** Persist the width even when it is `full` */
|
|
362
|
+
explicitWidth?: boolean;
|
|
363
|
+
}>;
|
|
364
|
+
declare function $getTableSettings(table: TableNode): TableSettings;
|
|
365
|
+
declare function $setTableSettings(table: TableNode, settings: Partial<TableSettings>, options?: TableSettingsOptions): void;
|
|
366
|
+
/** Whether the table's width should be persisted even when it is `full` */
|
|
367
|
+
declare function $isTableWidthExplicit(table: TableNode): boolean;
|
|
368
|
+
declare function $getTableWidth(table: TableNode): BlockWidth;
|
|
369
|
+
declare function $setTableWidth(table: TableNode, width: BlockWidth): void;
|
|
370
|
+
declare function $getTableDensity(table: TableNode): TableDensity;
|
|
371
|
+
declare function $setTableDensity(table: TableNode, density: TableDensity): void;
|
|
372
|
+
/** The table containing the current selection (caret or cell range), if any */
|
|
373
|
+
declare function $getSelectedTable(): TableNode | null;
|
|
374
|
+
/** @deprecated Use `formatTableSettingsMarker({ ...DEFAULT_TABLE_SETTINGS, width: 'content' })` */
|
|
375
|
+
declare const TABLE_WIDTH_MARKER = "<!-- width: content -->";
|
|
376
|
+
/**
|
|
377
|
+
* Settings encoded in a marker line, or null if the text is not a marker.
|
|
378
|
+
* A marker naming a known setting with an unknown value yields that setting
|
|
379
|
+
* omitted (possibly an empty object): the line is still a settings marker.
|
|
380
|
+
*/
|
|
381
|
+
declare function parseTableSettingsMarker(text: string): Partial<TableSettings> | null;
|
|
382
|
+
/**
|
|
383
|
+
* Marker line for the given settings, or null when everything is default.
|
|
384
|
+
* With `explicitWidth` the width is listed even when it is `full`.
|
|
385
|
+
*/
|
|
386
|
+
declare function formatTableSettingsMarker(settings: TableSettings, options?: TableSettingsOptions): string | null;
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Row and column operations for GFM tables. Markdown tables have no merged
|
|
390
|
+
* cells, every row has the same number of cells and there is exactly one
|
|
391
|
+
* header row (the first), so these helpers work on plain indices and keep
|
|
392
|
+
* that shape: a row can't be inserted above the header, deleting the
|
|
393
|
+
* header promotes the row below it, and new cells in the header row are
|
|
394
|
+
* header cells.
|
|
395
|
+
*/
|
|
396
|
+
/** Where the selection sits in its table */
|
|
397
|
+
type TableCellPosition = Readonly<{
|
|
398
|
+
/** Row index of the caret (or of the anchor cell of a cell range) */
|
|
399
|
+
row: number;
|
|
400
|
+
/** Column index of that cell */
|
|
401
|
+
column: number;
|
|
402
|
+
/** Number of rows in the table */
|
|
403
|
+
rows: number;
|
|
404
|
+
/** Number of columns in the table */
|
|
405
|
+
columns: number;
|
|
406
|
+
/** Whether the first row is a header row */
|
|
407
|
+
hasHeader: boolean;
|
|
408
|
+
}>;
|
|
409
|
+
/** The cell containing the selection (caret or the anchor of a cell range) */
|
|
410
|
+
declare function $getSelectedTableCell(): TableCellNode | null;
|
|
411
|
+
/** Where the selection sits in its table, or null outside tables */
|
|
412
|
+
declare function $getTableCellPosition(): TableCellPosition | null;
|
|
413
|
+
/**
|
|
414
|
+
* The row boundaries a new row may be inserted at: `0..rows`, minus `0`
|
|
415
|
+
* when the first row is a header (a table's header is always its first row).
|
|
416
|
+
*/
|
|
417
|
+
declare function insertableRowIndices(position: Pick<TableCellPosition, 'rows' | 'hasHeader'>): number[];
|
|
418
|
+
/** A row can be removed as long as one row stays */
|
|
419
|
+
declare function canDeleteRow(position: Pick<TableCellPosition, 'rows'>): boolean;
|
|
420
|
+
/**
|
|
421
|
+
* Insert an empty row so that it becomes row `index` (`0` = first, `rows`
|
|
422
|
+
* = last). Column header state is copied from the row above; the header
|
|
423
|
+
* row itself is never displaced, so `index` is clamped to `1` when the
|
|
424
|
+
* table has a header. The caret moves into the new row, at `column`.
|
|
425
|
+
*/
|
|
426
|
+
declare function $insertTableRowAt(table: TableNode, index: number, column?: number): TableRowNode;
|
|
427
|
+
/**
|
|
428
|
+
* Remove row `index`. No-op on a single-row table (see `canDeleteRow`).
|
|
429
|
+
* Removing the header row makes the next row the header so the markdown
|
|
430
|
+
* keeps its divider. The caret moves to the row that takes the removed
|
|
431
|
+
* row's place (or the last row), at `column`.
|
|
432
|
+
*/
|
|
433
|
+
declare function $deleteTableRowAt(table: TableNode, index: number, column?: number): boolean;
|
|
434
|
+
/** Insert a row next to the selection's row. Returns the new row, or null outside tables. */
|
|
435
|
+
declare function $insertTableRowNear(table: TableNode, position: 'above' | 'below'): TableRowNode | null;
|
|
436
|
+
/** Remove the selection's row. Returns false when nothing was removed. */
|
|
437
|
+
declare function $deleteTableRowNear(table: TableNode): boolean;
|
|
438
|
+
/** The column boundaries a new column may be inserted at: `0..columns` */
|
|
439
|
+
declare function insertableColumnIndices(position: Pick<TableCellPosition, 'columns'>): number[];
|
|
440
|
+
/** A column can be removed as long as one column stays */
|
|
441
|
+
declare function canDeleteColumn(position: Pick<TableCellPosition, 'columns'>): boolean;
|
|
442
|
+
/**
|
|
443
|
+
* Insert an empty column so that it becomes column `index` (`0` = first,
|
|
444
|
+
* `columns` = last). Cells in the header row are header cells. The caret
|
|
445
|
+
* moves into the new column, at `row`.
|
|
446
|
+
*/
|
|
447
|
+
declare function $insertTableColumnAt(table: TableNode, index: number, row?: number): void;
|
|
448
|
+
/**
|
|
449
|
+
* Remove column `index`. No-op on a single-column table (see
|
|
450
|
+
* `canDeleteColumn`). The caret moves to the column that takes the removed
|
|
451
|
+
* column's place (or the last column), at `row`.
|
|
452
|
+
*/
|
|
453
|
+
declare function $deleteTableColumnAt(table: TableNode, index: number, row?: number): boolean;
|
|
454
|
+
/** Insert a column next to the selection's column; no-op outside tables. */
|
|
455
|
+
declare function $insertTableColumnNear(table: TableNode, position: 'before' | 'after'): boolean;
|
|
456
|
+
/** Remove the selection's column. Returns false when nothing was removed. */
|
|
457
|
+
declare function $deleteTableColumnNear(table: TableNode): boolean;
|
|
458
|
+
|
|
459
|
+
export { $deleteTableColumnAt as $, $deleteTableRowAt as A, BlockButtons as B, CharacterCount as C, DEFAULT_LABELS as D, type EditorRootProps as E, FormatButtons as F, $deleteTableRowNear as G, HistoryButtons as H, InsertButtons as I, $getSelectedTable as J, $getSelectedTableCell as K, $getTableCellPosition as L, type MarkdownEditorProps as M, $getTableDensity as N, OutlinePlugin as O, $getTableSettings as P, $getTableWidth as Q, $insertTableColumnAt as R, $insertTableColumnNear as S, ToolbarButton as T, $insertTableRowAt as U, $insertTableRowNear as V, $isTableWidthExplicit as W, $setTableDensity as X, $setTableSettings as Y, $setTableWidth as Z, createMarkdownEditor as _, EditorContent as a, ToolbarDivider as b, DEFAULT_TABLE_SETTINGS as c, type DeepPartial as d, type EditorContentProps as e, type EditorFieldProps as f, type EditorLabels as g, type EditorLabelsInput as h, type EditorMode as i, TABLE_WIDTH_MARKER as j, type TableCellPosition as k, type TableDensity as l, type TableSettings as m, type TableSettingsOptions as n, Toolbar as o, type ToolbarItems as p, canDeleteColumn as q, canDeleteRow as r, formatTableSettingsMarker as s, insertableColumnIndices as t, insertableRowIndices as u, parseTableSettingsMarker as v, resolveLabels as w, useEditorContext as x, useLabels as y, $deleteTableColumnNear as z };
|
package/package.json
CHANGED
|
@@ -1,65 +1,104 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zuilib/text-editor",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "ZUI
|
|
3
|
+
"version": "0.12.0",
|
|
4
|
+
"description": "ZUI — Markdown editor with tables, drawings, code blocks, comments and mentions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"sideEffects": [
|
|
9
|
-
"**/*.css"
|
|
9
|
+
"**/*.css",
|
|
10
|
+
"**/suppress-global-highlighter.*"
|
|
10
11
|
],
|
|
11
12
|
"files": [
|
|
12
13
|
"dist",
|
|
13
14
|
"DRAWING_FORMAT.md",
|
|
14
15
|
"CHANGELOG.md"
|
|
15
16
|
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"build": "tsup",
|
|
18
|
-
"test": "node tests/roundtrip.mjs && node --test tests/*.test.mjs"
|
|
19
|
-
},
|
|
20
17
|
"exports": {
|
|
21
18
|
".": {
|
|
22
19
|
"types": "./dist/index.d.ts",
|
|
23
20
|
"import": "./dist/index.js"
|
|
24
21
|
},
|
|
22
|
+
"./markdown": {
|
|
23
|
+
"types": "./dist/markdown.d.ts",
|
|
24
|
+
"import": "./dist/markdown.js"
|
|
25
|
+
},
|
|
26
|
+
"./lexical": {
|
|
27
|
+
"types": "./dist/lexical.d.ts",
|
|
28
|
+
"import": "./dist/lexical.js"
|
|
29
|
+
},
|
|
30
|
+
"./drawing": {
|
|
31
|
+
"types": "./dist/drawing.d.ts",
|
|
32
|
+
"import": "./dist/drawing.js"
|
|
33
|
+
},
|
|
34
|
+
"./mentions": {
|
|
35
|
+
"types": "./dist/mentions.d.ts",
|
|
36
|
+
"import": "./dist/mentions.js"
|
|
37
|
+
},
|
|
38
|
+
"./comments": {
|
|
39
|
+
"types": "./dist/comments.d.ts",
|
|
40
|
+
"import": "./dist/comments.js"
|
|
41
|
+
},
|
|
42
|
+
"./images": {
|
|
43
|
+
"types": "./dist/images.d.ts",
|
|
44
|
+
"import": "./dist/images.js"
|
|
45
|
+
},
|
|
46
|
+
"./paste": {
|
|
47
|
+
"types": "./dist/paste.d.ts",
|
|
48
|
+
"import": "./dist/paste.js"
|
|
49
|
+
},
|
|
25
50
|
"./styles.css": "./dist/styles.css",
|
|
26
51
|
"./package.json": "./package.json"
|
|
27
52
|
},
|
|
28
53
|
"peerDependencies": {
|
|
54
|
+
"@lexical/clipboard": "^0.35.0",
|
|
29
55
|
"@lexical/code": "^0.35.0",
|
|
56
|
+
"@lexical/html": "^0.35.0",
|
|
30
57
|
"@lexical/link": "^0.35.0",
|
|
31
58
|
"@lexical/list": "^0.35.0",
|
|
59
|
+
"@lexical/mark": "^0.35.0",
|
|
32
60
|
"@lexical/markdown": "^0.35.0",
|
|
33
61
|
"@lexical/react": "^0.35.0",
|
|
34
62
|
"@lexical/rich-text": "^0.35.0",
|
|
63
|
+
"@lexical/selection": "^0.35.0",
|
|
35
64
|
"@lexical/table": "^0.35.0",
|
|
36
65
|
"@lexical/utils": "^0.35.0",
|
|
37
|
-
"@zuilib/tokens": "^0.0
|
|
66
|
+
"@zuilib/tokens": "^0.2.0",
|
|
38
67
|
"lexical": "^0.35.0",
|
|
39
68
|
"react": "^18.0.0 || ^19.0.0",
|
|
40
|
-
"react-dom": "^18.0.0 || ^19.0.0"
|
|
69
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
70
|
+
"tailwindcss": "^4"
|
|
41
71
|
},
|
|
42
72
|
"peerDependenciesMeta": {
|
|
43
73
|
"@zuilib/tokens": {
|
|
44
74
|
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"tailwindcss": {
|
|
77
|
+
"optional": true
|
|
45
78
|
}
|
|
46
79
|
},
|
|
47
80
|
"devDependencies": {
|
|
81
|
+
"@lexical/clipboard": "^0.35.0",
|
|
48
82
|
"@lexical/code": "^0.35.0",
|
|
49
83
|
"@lexical/headless": "0.35.0",
|
|
84
|
+
"@lexical/html": "^0.35.0",
|
|
50
85
|
"@lexical/link": "^0.35.0",
|
|
51
86
|
"@lexical/list": "^0.35.0",
|
|
87
|
+
"@lexical/mark": "^0.35.0",
|
|
52
88
|
"@lexical/markdown": "^0.35.0",
|
|
53
89
|
"@lexical/react": "^0.35.0",
|
|
54
90
|
"@lexical/rich-text": "^0.35.0",
|
|
91
|
+
"@lexical/selection": "^0.35.0",
|
|
55
92
|
"@lexical/table": "^0.35.0",
|
|
56
93
|
"@lexical/utils": "^0.35.0",
|
|
57
94
|
"@types/react": "^18.0.0 || ^19.0.0",
|
|
58
95
|
"@types/react-dom": "^18.0.0 || ^19.0.0",
|
|
96
|
+
"axe-core": "^4.13.0",
|
|
97
|
+
"jsdom": "^30.0.1",
|
|
59
98
|
"lexical": "^0.35.0",
|
|
60
99
|
"react": "^18.0.0 || ^19.0.0",
|
|
61
100
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
62
|
-
"@zuilib/tokens": "
|
|
101
|
+
"@zuilib/tokens": "^0.2.0"
|
|
63
102
|
},
|
|
64
103
|
"keywords": [
|
|
65
104
|
"lexical",
|
|
@@ -69,5 +108,11 @@
|
|
|
69
108
|
"design-system",
|
|
70
109
|
"react",
|
|
71
110
|
"typescript"
|
|
72
|
-
]
|
|
73
|
-
|
|
111
|
+
],
|
|
112
|
+
"scripts": {
|
|
113
|
+
"build": "tsup",
|
|
114
|
+
"pretest": "npm run build",
|
|
115
|
+
"test": "node --test tests/*.test.mjs",
|
|
116
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
117
|
+
}
|
|
118
|
+
}
|
package/dist/index.css
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/* src/styles.css */
|
|
2
|
-
.zui-text-editor {
|
|
3
|
-
position: relative;
|
|
4
|
-
width: 100%;
|
|
5
|
-
height: 100%;
|
|
6
|
-
overflow-y: auto;
|
|
7
|
-
}
|
|
8
|
-
.zui-text-editor-content {
|
|
9
|
-
min-height: 100%;
|
|
10
|
-
padding: 1.5rem 2rem;
|
|
11
|
-
outline: none;
|
|
12
|
-
}
|
|
13
|
-
.zui-text-editor-placeholder {
|
|
14
|
-
position: absolute;
|
|
15
|
-
top: 1.5rem;
|
|
16
|
-
left: 2rem;
|
|
17
|
-
pointer-events: none;
|
|
18
|
-
user-select: none;
|
|
19
|
-
}
|
|
20
|
-
.zui-checklist {
|
|
21
|
-
list-style: none;
|
|
22
|
-
margin-left: 0;
|
|
23
|
-
padding-left: 0;
|
|
24
|
-
}
|
|
25
|
-
.zui-checklist li[role=checkbox] {
|
|
26
|
-
position: relative;
|
|
27
|
-
padding-left: 1.75rem;
|
|
28
|
-
margin-left: 0;
|
|
29
|
-
cursor: pointer;
|
|
30
|
-
list-style: none;
|
|
31
|
-
}
|
|
32
|
-
.zui-checklist li[role=checkbox]::before {
|
|
33
|
-
content: "";
|
|
34
|
-
position: absolute;
|
|
35
|
-
left: 0;
|
|
36
|
-
top: 0.25em;
|
|
37
|
-
width: 1rem;
|
|
38
|
-
height: 1rem;
|
|
39
|
-
border: 2px solid currentColor;
|
|
40
|
-
border-radius: 0.2rem;
|
|
41
|
-
opacity: 0.5;
|
|
42
|
-
background: transparent;
|
|
43
|
-
}
|
|
44
|
-
.zui-checklist li[role=checkbox][aria-checked=true]::before {
|
|
45
|
-
background: currentColor;
|
|
46
|
-
opacity: 0.5;
|
|
47
|
-
}
|
|
48
|
-
.zui-checklist li[role=checkbox][aria-checked=true]::after {
|
|
49
|
-
content: "";
|
|
50
|
-
position: absolute;
|
|
51
|
-
left: 0.3rem;
|
|
52
|
-
top: 0.35em;
|
|
53
|
-
width: 0.4rem;
|
|
54
|
-
height: 0.7rem;
|
|
55
|
-
border: solid white;
|
|
56
|
-
border-width: 0 2px 2px 0;
|
|
57
|
-
transform: rotate(45deg);
|
|
58
|
-
}
|
|
59
|
-
.zui-text-editor-textarea {
|
|
60
|
-
width: 100%;
|
|
61
|
-
height: 100%;
|
|
62
|
-
min-height: 100%;
|
|
63
|
-
padding: 1.5rem 2rem;
|
|
64
|
-
outline: none;
|
|
65
|
-
resize: none;
|
|
66
|
-
background: transparent;
|
|
67
|
-
color: inherit;
|
|
68
|
-
font-family:
|
|
69
|
-
ui-monospace,
|
|
70
|
-
SFMono-Regular,
|
|
71
|
-
"SF Mono",
|
|
72
|
-
Menlo,
|
|
73
|
-
Consolas,
|
|
74
|
-
"Liberation Mono",
|
|
75
|
-
monospace;
|
|
76
|
-
font-size: 0.875rem;
|
|
77
|
-
line-height: 1.6;
|
|
78
|
-
border: none;
|
|
79
|
-
}
|