@canvist/vue 0.0.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mod.d.ts +582 -0
- package/dist/mod.js +153 -0
- package/package.json +42 -1
- package/readme.md +50 -0
- package/CHANGELOG.md +0 -3
- package/LICENSE +0 -24
- package/README.md +0 -3
package/dist/mod.d.ts
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vue bindings for the canvist canvas editor.
|
|
3
|
+
*
|
|
4
|
+
* `CanvistEditor` renders an editor; `useCanvistEditor` gives you the
|
|
5
|
+
* editor itself, and `useEditorState` keeps a ref in step with something
|
|
6
|
+
* read from the editor. Commands, queries, and plugin APIs are typed from
|
|
7
|
+
* the extensions and plugins you pass, as in `@canvist/web`. `BubbleMenu`
|
|
8
|
+
* and `FloatingMenu` keep their slot next to the selection.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const { element, editor } = useCanvistEditor({
|
|
12
|
+
* content: { format: "markdown", input: "Hello **world**" },
|
|
13
|
+
* });
|
|
14
|
+
* const bold = useEditorState(editor, (current) => current.can.toggleBold(), false);
|
|
15
|
+
* // <button :disabled="!bold" @click="editor?.commands.toggleBold()">Bold</button>
|
|
16
|
+
* // <div ref="element" />
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import { type Editor, type EditorOptions, type Extensions, type Plugins, type StarterKit } from "@canvist/web";
|
|
22
|
+
import { type MenuOptions } from "@canvist/web/menus";
|
|
23
|
+
import { type Ref, type ShallowRef } from "vue";
|
|
24
|
+
/** What {@link useCanvistEditor} returns. */
|
|
25
|
+
export interface CanvistEditorHandle<E extends Extensions, P extends Plugins> {
|
|
26
|
+
/** Bind as the template ref of the element the editor renders into. */
|
|
27
|
+
readonly element: ShallowRef<HTMLElement | null>;
|
|
28
|
+
/** The editor, once it has loaded; `null` before that and after unmounting. */
|
|
29
|
+
readonly editor: ShallowRef<Editor<E, P> | null>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create an editor in `element` when the component mounts, and destroy it
|
|
33
|
+
* when it unmounts. `options` are read when the editor is created.
|
|
34
|
+
*/
|
|
35
|
+
export declare function useCanvistEditor<const E extends Extensions = StarterKit, const P extends Plugins = []>(options?: EditorOptions<E, P>): CanvistEditorHandle<E, P>;
|
|
36
|
+
/**
|
|
37
|
+
* A ref holding `select(editor)`, updated after every edit or selection
|
|
38
|
+
* change. Until the editor exists, it holds `fallback`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function useEditorState<E extends Extensions, P extends Plugins, T>(editor: Readonly<Ref<Editor<E, P> | null>>, select: (editor: Editor<E, P>) => T, fallback: T): Readonly<ShallowRef<T>>;
|
|
41
|
+
/**
|
|
42
|
+
* Props for {@link CanvistEditor}: the editor's options, read once except
|
|
43
|
+
* `editable` and `placeholder`, which follow the props.
|
|
44
|
+
*/
|
|
45
|
+
export interface CanvistEditorProps<E extends Extensions, P extends Plugins> extends EditorOptions<E, P> {
|
|
46
|
+
/**
|
|
47
|
+
* Server-rendered HTML (`.cv-doc` markup from canvist's renderer) to
|
|
48
|
+
* show until the editor takes over. The editor reads the document from
|
|
49
|
+
* it when `content` is not given.
|
|
50
|
+
*/
|
|
51
|
+
readonly html?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A canvist editor. Give it a width; without a height it grows with its
|
|
55
|
+
* document. It emits `ready` once the editor has loaded and `update`
|
|
56
|
+
* after every change, each with the editor.
|
|
57
|
+
*/
|
|
58
|
+
export declare const CanvistEditor: new <const E extends Extensions = readonly [{
|
|
59
|
+
readonly commands: readonly [];
|
|
60
|
+
readonly name: "trailingNode";
|
|
61
|
+
readonly nodes: readonly [];
|
|
62
|
+
readonly queries: readonly [];
|
|
63
|
+
}, {
|
|
64
|
+
readonly commands: readonly [{
|
|
65
|
+
readonly args: readonly [{
|
|
66
|
+
readonly name: "level";
|
|
67
|
+
readonly type: {
|
|
68
|
+
readonly max: 6;
|
|
69
|
+
readonly min: 1;
|
|
70
|
+
readonly type: "int";
|
|
71
|
+
};
|
|
72
|
+
}];
|
|
73
|
+
readonly name: "toggleHeading";
|
|
74
|
+
}, {
|
|
75
|
+
readonly args: readonly [{
|
|
76
|
+
readonly name: "level";
|
|
77
|
+
readonly type: {
|
|
78
|
+
readonly max: 6;
|
|
79
|
+
readonly min: 1;
|
|
80
|
+
readonly type: "int";
|
|
81
|
+
};
|
|
82
|
+
}];
|
|
83
|
+
readonly name: "setHeading";
|
|
84
|
+
}];
|
|
85
|
+
readonly name: "heading";
|
|
86
|
+
readonly nodes: readonly [{
|
|
87
|
+
readonly attrs: readonly [{
|
|
88
|
+
readonly default: 1;
|
|
89
|
+
readonly name: "level";
|
|
90
|
+
readonly type: {
|
|
91
|
+
readonly max: 6;
|
|
92
|
+
readonly min: 1;
|
|
93
|
+
readonly type: "int";
|
|
94
|
+
};
|
|
95
|
+
}];
|
|
96
|
+
readonly kind: "block";
|
|
97
|
+
readonly name: "heading";
|
|
98
|
+
}];
|
|
99
|
+
readonly queries: readonly [{
|
|
100
|
+
readonly args: readonly [];
|
|
101
|
+
readonly name: "headingLevel";
|
|
102
|
+
readonly returns: {
|
|
103
|
+
readonly of: {
|
|
104
|
+
readonly max: 6;
|
|
105
|
+
readonly min: 1;
|
|
106
|
+
readonly type: "int";
|
|
107
|
+
};
|
|
108
|
+
readonly type: "nullable";
|
|
109
|
+
};
|
|
110
|
+
}];
|
|
111
|
+
}, {
|
|
112
|
+
readonly commands: readonly [{
|
|
113
|
+
readonly args: readonly [];
|
|
114
|
+
readonly name: "toggleBlockquote";
|
|
115
|
+
}];
|
|
116
|
+
readonly name: "blockquote";
|
|
117
|
+
readonly nodes: readonly [{
|
|
118
|
+
readonly attrs: readonly [];
|
|
119
|
+
readonly kind: "block";
|
|
120
|
+
readonly name: "blockquote";
|
|
121
|
+
}];
|
|
122
|
+
readonly queries: readonly [{
|
|
123
|
+
readonly args: readonly [];
|
|
124
|
+
readonly name: "isBlockquote";
|
|
125
|
+
readonly returns: {
|
|
126
|
+
readonly type: "bool";
|
|
127
|
+
};
|
|
128
|
+
}];
|
|
129
|
+
}, {
|
|
130
|
+
readonly commands: readonly [{
|
|
131
|
+
readonly args: readonly [{
|
|
132
|
+
readonly default: null;
|
|
133
|
+
readonly name: "language";
|
|
134
|
+
readonly type: {
|
|
135
|
+
readonly of: {
|
|
136
|
+
readonly type: "string";
|
|
137
|
+
};
|
|
138
|
+
readonly type: "nullable";
|
|
139
|
+
};
|
|
140
|
+
}];
|
|
141
|
+
readonly name: "toggleCodeBlock";
|
|
142
|
+
}, {
|
|
143
|
+
readonly args: readonly [{
|
|
144
|
+
readonly default: null;
|
|
145
|
+
readonly name: "language";
|
|
146
|
+
readonly type: {
|
|
147
|
+
readonly of: {
|
|
148
|
+
readonly type: "string";
|
|
149
|
+
};
|
|
150
|
+
readonly type: "nullable";
|
|
151
|
+
};
|
|
152
|
+
}];
|
|
153
|
+
readonly name: "setCodeBlock";
|
|
154
|
+
}];
|
|
155
|
+
readonly name: "codeBlock";
|
|
156
|
+
readonly nodes: readonly [{
|
|
157
|
+
readonly attrs: readonly [{
|
|
158
|
+
readonly default: null;
|
|
159
|
+
readonly name: "language";
|
|
160
|
+
readonly type: {
|
|
161
|
+
readonly of: {
|
|
162
|
+
readonly type: "string";
|
|
163
|
+
};
|
|
164
|
+
readonly type: "nullable";
|
|
165
|
+
};
|
|
166
|
+
}];
|
|
167
|
+
readonly kind: "block";
|
|
168
|
+
readonly name: "codeBlock";
|
|
169
|
+
}];
|
|
170
|
+
readonly queries: readonly [{
|
|
171
|
+
readonly args: readonly [];
|
|
172
|
+
readonly name: "isCodeBlock";
|
|
173
|
+
readonly returns: {
|
|
174
|
+
readonly type: "bool";
|
|
175
|
+
};
|
|
176
|
+
}, {
|
|
177
|
+
readonly args: readonly [];
|
|
178
|
+
readonly name: "codeBlockLanguage";
|
|
179
|
+
readonly returns: {
|
|
180
|
+
readonly of: {
|
|
181
|
+
readonly type: "string";
|
|
182
|
+
};
|
|
183
|
+
readonly type: "nullable";
|
|
184
|
+
};
|
|
185
|
+
}];
|
|
186
|
+
}, {
|
|
187
|
+
readonly commands: readonly [{
|
|
188
|
+
readonly args: readonly [];
|
|
189
|
+
readonly name: "setHardBreak";
|
|
190
|
+
}];
|
|
191
|
+
readonly name: "hardBreak";
|
|
192
|
+
readonly nodes: readonly [{
|
|
193
|
+
readonly attrs: readonly [];
|
|
194
|
+
readonly kind: "embed";
|
|
195
|
+
readonly name: "hardBreak";
|
|
196
|
+
}];
|
|
197
|
+
readonly queries: readonly [];
|
|
198
|
+
}, {
|
|
199
|
+
readonly commands: readonly [{
|
|
200
|
+
readonly args: readonly [];
|
|
201
|
+
readonly name: "setHorizontalRule";
|
|
202
|
+
}];
|
|
203
|
+
readonly name: "horizontalRule";
|
|
204
|
+
readonly nodes: readonly [{
|
|
205
|
+
readonly attrs: readonly [];
|
|
206
|
+
readonly kind: "block";
|
|
207
|
+
readonly name: "horizontalRule";
|
|
208
|
+
}];
|
|
209
|
+
readonly queries: readonly [];
|
|
210
|
+
}, {
|
|
211
|
+
readonly commands: readonly [{
|
|
212
|
+
readonly args: readonly [];
|
|
213
|
+
readonly name: "toggleBulletList";
|
|
214
|
+
}];
|
|
215
|
+
readonly name: "bulletList";
|
|
216
|
+
readonly nodes: readonly [{
|
|
217
|
+
readonly attrs: readonly [];
|
|
218
|
+
readonly kind: "block";
|
|
219
|
+
readonly name: "bulletList";
|
|
220
|
+
}];
|
|
221
|
+
readonly queries: readonly [{
|
|
222
|
+
readonly args: readonly [];
|
|
223
|
+
readonly name: "isBulletList";
|
|
224
|
+
readonly returns: {
|
|
225
|
+
readonly type: "bool";
|
|
226
|
+
};
|
|
227
|
+
}];
|
|
228
|
+
}, {
|
|
229
|
+
readonly commands: readonly [{
|
|
230
|
+
readonly args: readonly [];
|
|
231
|
+
readonly name: "toggleOrderedList";
|
|
232
|
+
}, {
|
|
233
|
+
readonly args: readonly [{
|
|
234
|
+
readonly name: "start";
|
|
235
|
+
readonly type: {
|
|
236
|
+
readonly type: "int";
|
|
237
|
+
};
|
|
238
|
+
}];
|
|
239
|
+
readonly name: "setOrderedListStart";
|
|
240
|
+
}];
|
|
241
|
+
readonly name: "orderedList";
|
|
242
|
+
readonly nodes: readonly [{
|
|
243
|
+
readonly attrs: readonly [{
|
|
244
|
+
readonly default: 1;
|
|
245
|
+
readonly name: "start";
|
|
246
|
+
readonly type: {
|
|
247
|
+
readonly type: "int";
|
|
248
|
+
};
|
|
249
|
+
}];
|
|
250
|
+
readonly kind: "block";
|
|
251
|
+
readonly name: "orderedList";
|
|
252
|
+
}];
|
|
253
|
+
readonly queries: readonly [{
|
|
254
|
+
readonly args: readonly [];
|
|
255
|
+
readonly name: "isOrderedList";
|
|
256
|
+
readonly returns: {
|
|
257
|
+
readonly type: "bool";
|
|
258
|
+
};
|
|
259
|
+
}, {
|
|
260
|
+
readonly args: readonly [];
|
|
261
|
+
readonly name: "orderedListStart";
|
|
262
|
+
readonly returns: {
|
|
263
|
+
readonly of: {
|
|
264
|
+
readonly type: "int";
|
|
265
|
+
};
|
|
266
|
+
readonly type: "nullable";
|
|
267
|
+
};
|
|
268
|
+
}];
|
|
269
|
+
}, {
|
|
270
|
+
readonly commands: readonly [{
|
|
271
|
+
readonly args: readonly [];
|
|
272
|
+
readonly name: "splitListItem";
|
|
273
|
+
}, {
|
|
274
|
+
readonly args: readonly [];
|
|
275
|
+
readonly name: "sinkListItem";
|
|
276
|
+
}, {
|
|
277
|
+
readonly args: readonly [];
|
|
278
|
+
readonly name: "liftListItem";
|
|
279
|
+
}];
|
|
280
|
+
readonly name: "listItem";
|
|
281
|
+
readonly nodes: readonly [{
|
|
282
|
+
readonly attrs: readonly [];
|
|
283
|
+
readonly kind: "block";
|
|
284
|
+
readonly name: "listItem";
|
|
285
|
+
}];
|
|
286
|
+
readonly queries: readonly [];
|
|
287
|
+
}, {
|
|
288
|
+
readonly commands: readonly [{
|
|
289
|
+
readonly args: readonly [];
|
|
290
|
+
readonly name: "toggleTaskList";
|
|
291
|
+
}, {
|
|
292
|
+
readonly args: readonly [];
|
|
293
|
+
readonly name: "toggleTask";
|
|
294
|
+
}, {
|
|
295
|
+
readonly args: readonly [{
|
|
296
|
+
readonly name: "checked";
|
|
297
|
+
readonly type: {
|
|
298
|
+
readonly type: "bool";
|
|
299
|
+
};
|
|
300
|
+
}];
|
|
301
|
+
readonly name: "setTaskChecked";
|
|
302
|
+
}, {
|
|
303
|
+
readonly args: readonly [];
|
|
304
|
+
readonly name: "splitTaskItem";
|
|
305
|
+
}, {
|
|
306
|
+
readonly args: readonly [];
|
|
307
|
+
readonly name: "sinkTaskItem";
|
|
308
|
+
}, {
|
|
309
|
+
readonly args: readonly [];
|
|
310
|
+
readonly name: "liftTaskItem";
|
|
311
|
+
}];
|
|
312
|
+
readonly name: "taskList";
|
|
313
|
+
readonly nodes: readonly [{
|
|
314
|
+
readonly attrs: readonly [];
|
|
315
|
+
readonly kind: "block";
|
|
316
|
+
readonly name: "taskList";
|
|
317
|
+
}, {
|
|
318
|
+
readonly attrs: readonly [{
|
|
319
|
+
readonly default: false;
|
|
320
|
+
readonly name: "checked";
|
|
321
|
+
readonly type: {
|
|
322
|
+
readonly type: "bool";
|
|
323
|
+
};
|
|
324
|
+
}];
|
|
325
|
+
readonly kind: "block";
|
|
326
|
+
readonly name: "taskItem";
|
|
327
|
+
}];
|
|
328
|
+
readonly queries: readonly [{
|
|
329
|
+
readonly args: readonly [];
|
|
330
|
+
readonly name: "isTaskList";
|
|
331
|
+
readonly returns: {
|
|
332
|
+
readonly type: "bool";
|
|
333
|
+
};
|
|
334
|
+
}, {
|
|
335
|
+
readonly args: readonly [];
|
|
336
|
+
readonly name: "isTaskChecked";
|
|
337
|
+
readonly returns: {
|
|
338
|
+
readonly of: {
|
|
339
|
+
readonly type: "bool";
|
|
340
|
+
};
|
|
341
|
+
readonly type: "nullable";
|
|
342
|
+
};
|
|
343
|
+
}];
|
|
344
|
+
}, {
|
|
345
|
+
readonly commands: readonly [{
|
|
346
|
+
readonly args: readonly [];
|
|
347
|
+
readonly name: "toggleBold";
|
|
348
|
+
}, {
|
|
349
|
+
readonly args: readonly [];
|
|
350
|
+
readonly name: "setBold";
|
|
351
|
+
}, {
|
|
352
|
+
readonly args: readonly [];
|
|
353
|
+
readonly name: "unsetBold";
|
|
354
|
+
}];
|
|
355
|
+
readonly name: "bold";
|
|
356
|
+
readonly nodes: readonly [{
|
|
357
|
+
readonly attrs: readonly [];
|
|
358
|
+
readonly kind: "mark";
|
|
359
|
+
readonly name: "bold";
|
|
360
|
+
}];
|
|
361
|
+
readonly queries: readonly [{
|
|
362
|
+
readonly args: readonly [];
|
|
363
|
+
readonly name: "isBold";
|
|
364
|
+
readonly returns: {
|
|
365
|
+
readonly type: "bool";
|
|
366
|
+
};
|
|
367
|
+
}];
|
|
368
|
+
}, {
|
|
369
|
+
readonly commands: readonly [{
|
|
370
|
+
readonly args: readonly [];
|
|
371
|
+
readonly name: "toggleItalic";
|
|
372
|
+
}, {
|
|
373
|
+
readonly args: readonly [];
|
|
374
|
+
readonly name: "setItalic";
|
|
375
|
+
}, {
|
|
376
|
+
readonly args: readonly [];
|
|
377
|
+
readonly name: "unsetItalic";
|
|
378
|
+
}];
|
|
379
|
+
readonly name: "italic";
|
|
380
|
+
readonly nodes: readonly [{
|
|
381
|
+
readonly attrs: readonly [];
|
|
382
|
+
readonly kind: "mark";
|
|
383
|
+
readonly name: "italic";
|
|
384
|
+
}];
|
|
385
|
+
readonly queries: readonly [{
|
|
386
|
+
readonly args: readonly [];
|
|
387
|
+
readonly name: "isItalic";
|
|
388
|
+
readonly returns: {
|
|
389
|
+
readonly type: "bool";
|
|
390
|
+
};
|
|
391
|
+
}];
|
|
392
|
+
}, {
|
|
393
|
+
readonly commands: readonly [{
|
|
394
|
+
readonly args: readonly [];
|
|
395
|
+
readonly name: "toggleUnderline";
|
|
396
|
+
}, {
|
|
397
|
+
readonly args: readonly [];
|
|
398
|
+
readonly name: "setUnderline";
|
|
399
|
+
}, {
|
|
400
|
+
readonly args: readonly [];
|
|
401
|
+
readonly name: "unsetUnderline";
|
|
402
|
+
}];
|
|
403
|
+
readonly name: "underline";
|
|
404
|
+
readonly nodes: readonly [{
|
|
405
|
+
readonly attrs: readonly [];
|
|
406
|
+
readonly kind: "mark";
|
|
407
|
+
readonly name: "underline";
|
|
408
|
+
}];
|
|
409
|
+
readonly queries: readonly [{
|
|
410
|
+
readonly args: readonly [];
|
|
411
|
+
readonly name: "isUnderline";
|
|
412
|
+
readonly returns: {
|
|
413
|
+
readonly type: "bool";
|
|
414
|
+
};
|
|
415
|
+
}];
|
|
416
|
+
}, {
|
|
417
|
+
readonly commands: readonly [{
|
|
418
|
+
readonly args: readonly [];
|
|
419
|
+
readonly name: "toggleStrike";
|
|
420
|
+
}, {
|
|
421
|
+
readonly args: readonly [];
|
|
422
|
+
readonly name: "setStrike";
|
|
423
|
+
}, {
|
|
424
|
+
readonly args: readonly [];
|
|
425
|
+
readonly name: "unsetStrike";
|
|
426
|
+
}];
|
|
427
|
+
readonly name: "strike";
|
|
428
|
+
readonly nodes: readonly [{
|
|
429
|
+
readonly attrs: readonly [];
|
|
430
|
+
readonly kind: "mark";
|
|
431
|
+
readonly name: "strike";
|
|
432
|
+
}];
|
|
433
|
+
readonly queries: readonly [{
|
|
434
|
+
readonly args: readonly [];
|
|
435
|
+
readonly name: "isStrike";
|
|
436
|
+
readonly returns: {
|
|
437
|
+
readonly type: "bool";
|
|
438
|
+
};
|
|
439
|
+
}];
|
|
440
|
+
}, {
|
|
441
|
+
readonly commands: readonly [{
|
|
442
|
+
readonly args: readonly [];
|
|
443
|
+
readonly name: "toggleCode";
|
|
444
|
+
}, {
|
|
445
|
+
readonly args: readonly [];
|
|
446
|
+
readonly name: "setCode";
|
|
447
|
+
}, {
|
|
448
|
+
readonly args: readonly [];
|
|
449
|
+
readonly name: "unsetCode";
|
|
450
|
+
}];
|
|
451
|
+
readonly name: "code";
|
|
452
|
+
readonly nodes: readonly [{
|
|
453
|
+
readonly attrs: readonly [];
|
|
454
|
+
readonly kind: "mark";
|
|
455
|
+
readonly name: "code";
|
|
456
|
+
}];
|
|
457
|
+
readonly queries: readonly [{
|
|
458
|
+
readonly args: readonly [];
|
|
459
|
+
readonly name: "isCode";
|
|
460
|
+
readonly returns: {
|
|
461
|
+
readonly type: "bool";
|
|
462
|
+
};
|
|
463
|
+
}];
|
|
464
|
+
}, {
|
|
465
|
+
readonly commands: readonly [{
|
|
466
|
+
readonly args: readonly [{
|
|
467
|
+
readonly name: "href";
|
|
468
|
+
readonly type: {
|
|
469
|
+
readonly type: "string";
|
|
470
|
+
};
|
|
471
|
+
}];
|
|
472
|
+
readonly name: "setLink";
|
|
473
|
+
}, {
|
|
474
|
+
readonly args: readonly [];
|
|
475
|
+
readonly name: "unsetLink";
|
|
476
|
+
}];
|
|
477
|
+
readonly name: "link";
|
|
478
|
+
readonly nodes: readonly [{
|
|
479
|
+
readonly attrs: readonly [{
|
|
480
|
+
readonly default: null;
|
|
481
|
+
readonly name: "href";
|
|
482
|
+
readonly type: {
|
|
483
|
+
readonly of: {
|
|
484
|
+
readonly type: "string";
|
|
485
|
+
};
|
|
486
|
+
readonly type: "nullable";
|
|
487
|
+
};
|
|
488
|
+
}];
|
|
489
|
+
readonly kind: "mark";
|
|
490
|
+
readonly name: "link";
|
|
491
|
+
}];
|
|
492
|
+
readonly queries: readonly [{
|
|
493
|
+
readonly args: readonly [];
|
|
494
|
+
readonly name: "linkHref";
|
|
495
|
+
readonly returns: {
|
|
496
|
+
readonly of: {
|
|
497
|
+
readonly type: "string";
|
|
498
|
+
};
|
|
499
|
+
readonly type: "nullable";
|
|
500
|
+
};
|
|
501
|
+
}];
|
|
502
|
+
}, {
|
|
503
|
+
readonly commands: readonly [{
|
|
504
|
+
readonly args: readonly [];
|
|
505
|
+
readonly name: "undo";
|
|
506
|
+
}, {
|
|
507
|
+
readonly args: readonly [];
|
|
508
|
+
readonly name: "redo";
|
|
509
|
+
}];
|
|
510
|
+
readonly name: "history";
|
|
511
|
+
readonly nodes: readonly [];
|
|
512
|
+
readonly queries: readonly [];
|
|
513
|
+
}], const P extends Plugins = []>(props: CanvistEditorProps<E, P> & {
|
|
514
|
+
onReady?: (...args: any[]) => any;
|
|
515
|
+
onUpdate?: (...args: any[]) => any;
|
|
516
|
+
} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps) => import("vue").CreateComponentPublicInstanceWithMixins<CanvistEditorProps<E, P> & {
|
|
517
|
+
onReady?: (...args: any[]) => any;
|
|
518
|
+
onUpdate?: (...args: any[]) => any;
|
|
519
|
+
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("ready" | "update")[], import("vue").PublicProps, {}, false, {}, {}, {}, {}, string, {}, any, import("vue").ComponentProvideOptions, {
|
|
520
|
+
P: {};
|
|
521
|
+
B: {};
|
|
522
|
+
D: {};
|
|
523
|
+
C: {};
|
|
524
|
+
M: {};
|
|
525
|
+
Defaults: {};
|
|
526
|
+
}, CanvistEditorProps<E, P> & {
|
|
527
|
+
onReady?: (...args: any[]) => any;
|
|
528
|
+
onUpdate?: (...args: any[]) => any;
|
|
529
|
+
}, {}, {}, {}, {}, {}>;
|
|
530
|
+
/** Props for {@link BubbleMenu} and {@link FloatingMenu}. */
|
|
531
|
+
export interface MenuProps<E extends Extensions, P extends Plugins> extends MenuOptions<E, P> {
|
|
532
|
+
/** The editor to follow; the menu stays hidden while it is `null`. */
|
|
533
|
+
readonly editor: Editor<E, P> | null;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* A menu over selected text, as `bubbleMenu` from `@canvist/web/menus`
|
|
537
|
+
* places it. Pressing inside it keeps the editor's focus and selection.
|
|
538
|
+
*/
|
|
539
|
+
export declare const BubbleMenu: new <E extends Extensions, P extends Plugins>(props: (MenuProps<E, P> & ({
|
|
540
|
+
[x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined;
|
|
541
|
+
} | {
|
|
542
|
+
[x: `on${Capitalize<string>}`]: ((...args: never) => any) | undefined;
|
|
543
|
+
})) & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps) => import("vue").CreateComponentPublicInstanceWithMixins<MenuProps<E, P> & ({
|
|
544
|
+
[x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined;
|
|
545
|
+
} | {
|
|
546
|
+
[x: `on${Capitalize<string>}`]: ((...args: never) => any) | undefined;
|
|
547
|
+
}), {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, import("vue").EmitsOptions, import("vue").PublicProps, {}, false, {}, {}, {}, {}, string, {}, any, import("vue").ComponentProvideOptions, {
|
|
548
|
+
P: {};
|
|
549
|
+
B: {};
|
|
550
|
+
D: {};
|
|
551
|
+
C: {};
|
|
552
|
+
M: {};
|
|
553
|
+
Defaults: {};
|
|
554
|
+
}, (MenuProps<E, P> & {
|
|
555
|
+
[x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined;
|
|
556
|
+
}) | (MenuProps<E, P> & {
|
|
557
|
+
[x: `on${Capitalize<string>}`]: ((...args: never) => any) | undefined;
|
|
558
|
+
}), {}, {}, {}, {}, {}>;
|
|
559
|
+
/**
|
|
560
|
+
* A menu beside the caret on an empty line, as `floatingMenu` from
|
|
561
|
+
* `@canvist/web/menus` places it.
|
|
562
|
+
*/
|
|
563
|
+
export declare const FloatingMenu: new <E extends Extensions, P extends Plugins>(props: (MenuProps<E, P> & ({
|
|
564
|
+
[x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined;
|
|
565
|
+
} | {
|
|
566
|
+
[x: `on${Capitalize<string>}`]: ((...args: never) => any) | undefined;
|
|
567
|
+
})) & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps) => import("vue").CreateComponentPublicInstanceWithMixins<MenuProps<E, P> & ({
|
|
568
|
+
[x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined;
|
|
569
|
+
} | {
|
|
570
|
+
[x: `on${Capitalize<string>}`]: ((...args: never) => any) | undefined;
|
|
571
|
+
}), {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, import("vue").EmitsOptions, import("vue").PublicProps, {}, false, {}, {}, {}, {}, string, {}, any, import("vue").ComponentProvideOptions, {
|
|
572
|
+
P: {};
|
|
573
|
+
B: {};
|
|
574
|
+
D: {};
|
|
575
|
+
C: {};
|
|
576
|
+
M: {};
|
|
577
|
+
Defaults: {};
|
|
578
|
+
}, (MenuProps<E, P> & {
|
|
579
|
+
[x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined;
|
|
580
|
+
}) | (MenuProps<E, P> & {
|
|
581
|
+
[x: `on${Capitalize<string>}`]: ((...args: never) => any) | undefined;
|
|
582
|
+
}), {}, {}, {}, {}, {}>;
|
package/dist/mod.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vue bindings for the canvist canvas editor.
|
|
3
|
+
*
|
|
4
|
+
* `CanvistEditor` renders an editor; `useCanvistEditor` gives you the
|
|
5
|
+
* editor itself, and `useEditorState` keeps a ref in step with something
|
|
6
|
+
* read from the editor. Commands, queries, and plugin APIs are typed from
|
|
7
|
+
* the extensions and plugins you pass, as in `@canvist/web`. `BubbleMenu`
|
|
8
|
+
* and `FloatingMenu` keep their slot next to the selection.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const { element, editor } = useCanvistEditor({
|
|
12
|
+
* content: { format: "markdown", input: "Hello **world**" },
|
|
13
|
+
* });
|
|
14
|
+
* const bold = useEditorState(editor, (current) => current.can.toggleBold(), false);
|
|
15
|
+
* // <button :disabled="!bold" @click="editor?.commands.toggleBold()">Bold</button>
|
|
16
|
+
* // <div ref="element" />
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import { createEditor, } from "@canvist/web";
|
|
22
|
+
import { bubbleMenu, floatingMenu, } from "@canvist/web/menus";
|
|
23
|
+
import { defineComponent, h, onBeforeUnmount, onMounted, shallowRef, watch, } from "vue";
|
|
24
|
+
/**
|
|
25
|
+
* Create an editor in `element` when the component mounts, and destroy it
|
|
26
|
+
* when it unmounts. `options` are read when the editor is created.
|
|
27
|
+
*/
|
|
28
|
+
export function useCanvistEditor(options = {}) {
|
|
29
|
+
const element = shallowRef(null);
|
|
30
|
+
const editor = shallowRef(null);
|
|
31
|
+
const mount = { live: true, editor };
|
|
32
|
+
onMounted(() => {
|
|
33
|
+
if (element.value !== null) {
|
|
34
|
+
void create(element.value, options, mount);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
onBeforeUnmount(() => {
|
|
38
|
+
mount.live = false;
|
|
39
|
+
editor.value?.destroy();
|
|
40
|
+
editor.value = null;
|
|
41
|
+
});
|
|
42
|
+
return { element, editor };
|
|
43
|
+
}
|
|
44
|
+
/** Create the editor for `mount`, destroying it if the component unmounted while it loaded. */
|
|
45
|
+
async function create(element, options, mount) {
|
|
46
|
+
try {
|
|
47
|
+
const editor = await createEditor(element, options);
|
|
48
|
+
if (mount.live) {
|
|
49
|
+
mount.editor.value = editor;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
editor.destroy();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (mount.live) {
|
|
57
|
+
reportError(error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A ref holding `select(editor)`, updated after every edit or selection
|
|
63
|
+
* change. Until the editor exists, it holds `fallback`.
|
|
64
|
+
*/
|
|
65
|
+
export function useEditorState(editor, select, fallback) {
|
|
66
|
+
const state = shallowRef(fallback);
|
|
67
|
+
watch(editor, (current, _previous, onCleanup) => {
|
|
68
|
+
if (current === null) {
|
|
69
|
+
state.value = fallback;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
state.value = select(current);
|
|
73
|
+
onCleanup(current.subscribe(() => {
|
|
74
|
+
state.value = select(current);
|
|
75
|
+
}));
|
|
76
|
+
}, { immediate: true });
|
|
77
|
+
return state;
|
|
78
|
+
}
|
|
79
|
+
/** The option props {@link CanvistEditor} passes to the editor. */
|
|
80
|
+
const OPTION_PROPS = [
|
|
81
|
+
"extensions",
|
|
82
|
+
"plugins",
|
|
83
|
+
"content",
|
|
84
|
+
"theme",
|
|
85
|
+
"breaks",
|
|
86
|
+
"client",
|
|
87
|
+
"overscan",
|
|
88
|
+
"wasm",
|
|
89
|
+
"input",
|
|
90
|
+
"label",
|
|
91
|
+
"platform",
|
|
92
|
+
"editable",
|
|
93
|
+
"placeholder",
|
|
94
|
+
];
|
|
95
|
+
/**
|
|
96
|
+
* A canvist editor. Give it a width; without a height it grows with its
|
|
97
|
+
* document. It emits `ready` once the editor has loaded and `update`
|
|
98
|
+
* after every change, each with the editor.
|
|
99
|
+
*/
|
|
100
|
+
export const CanvistEditor = defineComponent((props, { emit }) => {
|
|
101
|
+
const { html, ...options } = props;
|
|
102
|
+
const { element, editor } = useCanvistEditor(options);
|
|
103
|
+
watch([editor, () => props.editable, () => props.placeholder], ([current, editable, placeholder]) => {
|
|
104
|
+
current?.setEditable(editable ?? true);
|
|
105
|
+
current?.setPlaceholder(placeholder ?? "");
|
|
106
|
+
});
|
|
107
|
+
watch(editor, (current, _previous, onCleanup) => {
|
|
108
|
+
if (current === null) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
emit("ready", current);
|
|
112
|
+
onCleanup(current.subscribe(() => emit("update", current)));
|
|
113
|
+
});
|
|
114
|
+
// `innerHTML` is set once: Vue leaves the editor's elements alone
|
|
115
|
+
// while it is unchanged.
|
|
116
|
+
return () => h("div", { ref: element, innerHTML: html });
|
|
117
|
+
}, { props: ["html", ...OPTION_PROPS], emits: ["ready", "update"] });
|
|
118
|
+
/** A component that keeps its default slot where `attach` places it. */
|
|
119
|
+
function followingMenu(attach) {
|
|
120
|
+
return defineComponent((props, { slots }) => {
|
|
121
|
+
const element = shallowRef(null);
|
|
122
|
+
watch([
|
|
123
|
+
() => props.editor,
|
|
124
|
+
element,
|
|
125
|
+
() => props.placement,
|
|
126
|
+
() => props.offset,
|
|
127
|
+
() => props.padding,
|
|
128
|
+
() => props.shouldShow,
|
|
129
|
+
], ([editor, current, placement, offset, padding, shouldShow], _, onCleanup) => {
|
|
130
|
+
if (editor === null || current === null) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const menu = attach(editor, current, {
|
|
134
|
+
...(placement === undefined ? {} : { placement }),
|
|
135
|
+
...(offset === undefined ? {} : { offset }),
|
|
136
|
+
...(padding === undefined ? {} : { padding }),
|
|
137
|
+
...(shouldShow === undefined ? {} : { shouldShow }),
|
|
138
|
+
});
|
|
139
|
+
onCleanup(() => menu.destroy());
|
|
140
|
+
}, { flush: "post" });
|
|
141
|
+
return () => h("div", { ref: element, hidden: true }, slots["default"]?.());
|
|
142
|
+
}, { props: ["editor", "placement", "offset", "padding", "shouldShow"] });
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* A menu over selected text, as `bubbleMenu` from `@canvist/web/menus`
|
|
146
|
+
* places it. Pressing inside it keeps the editor's focus and selection.
|
|
147
|
+
*/
|
|
148
|
+
export const BubbleMenu = followingMenu(bubbleMenu);
|
|
149
|
+
/**
|
|
150
|
+
* A menu beside the caret on an empty line, as `floatingMenu` from
|
|
151
|
+
* `@canvist/web/menus` places it.
|
|
152
|
+
*/
|
|
153
|
+
export const FloatingMenu = followingMenu(floatingMenu);
|
package/package.json
CHANGED
|
@@ -1 +1,42 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "@canvist/vue",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Vue bindings for the canvist canvas editor: a component, and composables typed from the extensions you register.",
|
|
5
|
+
"license": "Unlicense",
|
|
6
|
+
"homepage": "https://github.com/canvist/canvist/tree/main/packages/canvist-vue#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/canvist/canvist.git",
|
|
10
|
+
"directory": "packages/canvist-vue"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/canvist/canvist/issues",
|
|
14
|
+
"email": "support@canvist.dev"
|
|
15
|
+
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/mod.d.ts",
|
|
20
|
+
"default": "./dist/mod.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"scripts": {
|
|
28
|
+
"check:types": "tsc --noEmit",
|
|
29
|
+
"build": "tsc -p tsconfig.build.json",
|
|
30
|
+
"prepack": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@canvist/web": "^0.2.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"vue": "^3.4.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"typescript": "^7.0.2",
|
|
40
|
+
"vue": "^3.5.0"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://github.com/canvist/canvist">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/canvist/canvist/main/assets/brand/vector/lockup-dark.svg">
|
|
5
|
+
<img width="220" src="https://raw.githubusercontent.com/canvist/canvist/main/assets/brand/vector/lockup.svg" alt="canvist" />
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://github.com/canvist/canvist/blob/main/docs/src/quick-start/vue.md"><strong>Quick start</strong></a> ·
|
|
12
|
+
<a href="https://github.com/canvist/canvist/blob/main/docs/src/readme.md"><strong>Docs</strong></a> ·
|
|
13
|
+
<a href="https://github.com/canvist/canvist/blob/main/docs/src/reference/contributing.md"><strong>Contributing</strong></a> ·
|
|
14
|
+
<a href="https://github.com/canvist/canvist"><strong>canvist</strong></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<a href="https://www.npmjs.com/package/@canvist/vue"><img src="https://img.shields.io/npm/v/%40canvist%2Fvue?color=3B2CF5" alt="npm version" /></a>
|
|
19
|
+
<a href="https://github.com/canvist/canvist/actions/workflows/web.yml"><img src="https://github.com/canvist/canvist/actions/workflows/web.yml/badge.svg?branch=main" alt="web status" /></a>
|
|
20
|
+
<a href="https://unlicense.org"><img src="https://img.shields.io/badge/license-Unlicense-3B2CF5" alt="Unlicense" /></a>
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
# @canvist/vue
|
|
24
|
+
|
|
25
|
+
Vue bindings for [`@canvist/web`](../canvist-web), the canvist canvas editor. Commands, queries, and plugin APIs are typed from the extensions and plugins you pass.
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm install @canvist/vue
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```vue
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
import { useCanvistEditor, useEditorState } from "@canvist/vue";
|
|
34
|
+
|
|
35
|
+
const { element, editor } = useCanvistEditor({ label: "Notes" });
|
|
36
|
+
const isBold = useEditorState(editor, (current) => current.query.isBold(), false);
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<button :aria-pressed="isBold" @click="editor?.commands.toggleBold()">Bold</button>
|
|
41
|
+
<div ref="element" />
|
|
42
|
+
</template>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- `useCanvistEditor(options)` creates the editor in `element` on mount and destroys it on unmount.
|
|
46
|
+
- `useEditorState(editor, select, fallback)` returns a ref updated after every change.
|
|
47
|
+
- `<CanvistEditor />` takes the editor's options as props, emits `ready` and `update`, and takes `html` for server-rendered HTML to hydrate. `editable` and `placeholder` follow their props.
|
|
48
|
+
- `<BubbleMenu :editor="editor">` and `<FloatingMenu :editor="editor">` keep their slot next to the selection.
|
|
49
|
+
|
|
50
|
+
See [Quick start: Vue](../../docs/src/quick-start/vue.md).
|
package/CHANGELOG.md
DELETED
package/LICENSE
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
This is free and unencumbered software released into the public domain.
|
|
2
|
-
|
|
3
|
-
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
-
distribute this software, either in source code form or as a compiled
|
|
5
|
-
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
-
means.
|
|
7
|
-
|
|
8
|
-
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
-
of this software dedicate any and all copyright interest in the
|
|
10
|
-
software to the public domain. We make this dedication for the benefit
|
|
11
|
-
of the public at large and to the detriment of our heirs and
|
|
12
|
-
successors. We intend this dedication to be an overt act of
|
|
13
|
-
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
-
software under copyright law.
|
|
15
|
-
|
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
-
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
-
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
-
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
-
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
-
|
|
24
|
-
For more information, please refer to <http://unlicense.org/>
|
package/README.md
DELETED