@nerd-bible/wordgard 0.0.0-beta3

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/schema.js ADDED
@@ -0,0 +1,1432 @@
1
+ import { ChangeSet, Leaf, Plot, Elt } from 'wordgard/doc';
2
+ import { GardState, GardSelection, BidiSpan, Transaction } from 'wordgard/state';
3
+ import { Paragraph, Heading, Direction, Blockquote, HorizontalRule, Alignment, Doc, InlineDoc, BulletList, OrderedList, InlineListItem, ListItem, CodeBlock, CodeBlockLanguage, Strong, Emphasis, Code, Underline, Strikethrough, Superscript, Subscript, ImageSize, ImageAlt, Image, Figure, CaptionedFigure, Color, BackgroundColor, Link, LineBreak } from 'wordgard/types';
4
+ import { phrases, imagePhrases, colorNames } from 'wordgard/phrases';
5
+ import { Command, setTextblockType, Menu, setAlignment, setDirection, toggleBlock, listIsActive, toggleList, enter, toggleMark } from 'wordgard/command';
6
+ import { history } from 'wordgard/history';
7
+ import { KeyBinding, InputRule, Wordgard, Widget, Decoration, Panel, Dialog, PointSet, Tooltip } from 'wordgard/editor';
8
+ import cr from 'crelt';
9
+
10
+ function blockDoc() {
11
+ return GardState.schemaElement.of(Doc);
12
+ }
13
+ function inlineDoc() {
14
+ return GardState.schemaElement.of(InlineDoc);
15
+ }
16
+ function selectionInType(tag) {
17
+ return (state) => {
18
+ let { sel } = state, block = sel.head.textblockParent;
19
+ return !!block && block.start == sel.anchor.textblockParent?.start && block.node.tag.eq(tag);
20
+ };
21
+ }
22
+ function paragraph() {
23
+ return [GardState.schemaElement.of(Paragraph), paragraph.button, paragraph.keyBinding];
24
+ }
25
+ ;paragraph = /*@__PURE__*/(function (paragraph) {
26
+ paragraph.keyBinding = KeyBinding.of({
27
+ key: "Ctrl-Shift-0",
28
+ run: Command.bind(setTextblockType, Paragraph)
29
+ });
30
+ paragraph.button = Menu.Button.define({
31
+ run: Command.bind(setTextblockType, Paragraph),
32
+ active: selectionInType(Paragraph),
33
+ label: phrases.ref("paragraph"),
34
+ enable: s => !s.readOnly,
35
+ parent: Menu.Submenu.textblockStyle,
36
+ rank: 10
37
+ });
38
+ ;return paragraph})(paragraph);
39
+ function heading() {
40
+ return [GardState.schemaElement.of(Heading),
41
+ heading.button1, heading.button2, heading.button3,
42
+ heading.keyBindings, heading.createOnHash];
43
+ }
44
+ ;heading = /*@__PURE__*/(function (heading) {
45
+ heading.keyBindings = [
46
+ KeyBinding.of({ key: "Ctrl-Shift-1", run: Command.bind(setTextblockType, Heading.of(1)) }),
47
+ KeyBinding.of({ key: "Ctrl-Shift-2", run: Command.bind(setTextblockType, Heading.of(2)) }),
48
+ KeyBinding.of({ key: "Ctrl-Shift-3", run: Command.bind(setTextblockType, Heading.of(3)) }),
49
+ KeyBinding.of({ key: "Ctrl-Shift-4", run: Command.bind(setTextblockType, Heading.of(4)) }),
50
+ KeyBinding.of({ key: "Ctrl-Shift-5", run: Command.bind(setTextblockType, Heading.of(5)) }),
51
+ KeyBinding.of({ key: "Ctrl-Shift-6", run: Command.bind(setTextblockType, Heading.of(6)) })
52
+ ];
53
+ heading.button1 = Menu.Button.define({
54
+ run: Command.bind(setTextblockType, Heading.of(1)),
55
+ active: selectionInType(Heading.of(1)),
56
+ label: phrases.ref("heading_1"),
57
+ enable: s => !s.readOnly,
58
+ parent: Menu.Submenu.textblockStyle,
59
+ rank: 50
60
+ });
61
+ heading.button2 = Menu.Button.define({
62
+ run: Command.bind(setTextblockType, Heading.of(2)),
63
+ active: selectionInType(Heading.of(2)),
64
+ label: phrases.ref("heading_2"),
65
+ enable: s => !s.readOnly,
66
+ parent: Menu.Submenu.textblockStyle,
67
+ rank: 51
68
+ });
69
+ heading.button3 = Menu.Button.define({
70
+ run: Command.bind(setTextblockType, Heading.of(3)),
71
+ active: selectionInType(Heading.of(3)),
72
+ label: phrases.ref("heading_3"),
73
+ enable: s => !s.readOnly,
74
+ parent: Menu.Submenu.textblockStyle,
75
+ rank: 52
76
+ });
77
+ heading.createOnHash = InputRule.textblockType(/^(#{1,6}) $/, m => Heading.of(m[1].to.pos - m[1].from.pos), true);
78
+ ;return heading})(heading);
79
+ function alignment() {
80
+ return [GardState.schemaElement.of(Alignment), alignment.button, alignment.keyBindings];
81
+ }
82
+ function alignmentAtCursor(state) {
83
+ let block = state.sel.head.textblockParent;
84
+ return (block && block.node.tag.mark(Alignment)) || null;
85
+ }
86
+ ;alignment = /*@__PURE__*/(function (alignment) {
87
+ alignment.keyBindings = [
88
+ KeyBinding.of({ key: "Mod-Shift-l", run: Command.bind(setAlignment, "left") }),
89
+ KeyBinding.of({ key: "Mod-Shift-r", run: Command.bind(setAlignment, "right") }),
90
+ KeyBinding.of({ key: "Mod-Shift-e", run: Command.bind(setAlignment, "center") })
91
+ ];
92
+ alignment.buttonStart = Menu.Button.define({
93
+ run: Command.bind(setAlignment, null),
94
+ active: state => alignmentAtCursor(state) == null,
95
+ label: {
96
+ icon: "M16 81a3 3 0 0 1 0-6h44a3 3 0 0 1 0 6h-44m0-19a3 3 0 0 1 0-6h69a3 3 0 0 1 0 6h-69m0-19a3 3 0 0 1 0-6h44a3 3 0 0 1 0 6h-44m0-19a3 3 0 0 1 0-6h69a3 3 0 0 1 0 6h-69",
97
+ directional: true
98
+ },
99
+ description: phrases.ref("align_start"),
100
+ });
101
+ alignment.buttonEnd = Menu.Button.define({
102
+ run: Command.bind(setAlignment, "end"),
103
+ active: state => alignmentAtCursor(state) == "end",
104
+ label: {
105
+ icon: "M41 81a3 3 0 0 1 0-6h44a3 3 0 0 1 0 6h-44m-25-19a3 3 0 0 1 0-6h69a3 3 0 0 1 0 6h-69m25-19a3 3 0 0 1 0-6h44a3 3 0 0 1 0 6h-44m-25-19a3 3 0 0 1 0-6h69a3 3 0 0 1 0 6h-69",
106
+ directional: true
107
+ },
108
+ description: phrases.ref("align_end"),
109
+ });
110
+ alignment.buttonCenter = Menu.Button.define({
111
+ run: Command.bind(setAlignment, "center"),
112
+ active: state => alignmentAtCursor(state) == "center",
113
+ label: {
114
+ icon: "M29 81a3 3 0 0 1 0-6h44a3 3 0 0 1 0 6h-44m-13-19a3 3 0 0 1 0-6h69a3 3 0 0 1 0 6h-69m13-19a3 3 0 0 1 0-6h44a3 3 0 0 1 0 6h-44m-13-19a3 3 0 0 1 0-6h69a3 3 0 0 1 0 6h-69"
115
+ },
116
+ description: phrases.ref("align_center"),
117
+ });
118
+ alignment.button = Menu.Submenu.define({
119
+ description: phrases.ref("alignment"),
120
+ parent: Menu.Group.block,
121
+ arrow: false,
122
+ enable: s => !s.readOnly,
123
+ rank: 10,
124
+ content: [alignment.buttonStart, alignment.buttonEnd, alignment.buttonCenter]
125
+ });
126
+ ;return alignment})(alignment);
127
+ function direction() {
128
+ return [GardState.schemaElement.of(Direction), direction.textblockDir, direction.button];
129
+ }
130
+ function autoDir(plot) {
131
+ for (let ch of plot.content)
132
+ if (ch.is(Leaf.Text)) {
133
+ for (let i = 0; i < ch.param.length; i++) {
134
+ let dir = BidiSpan.strongDir(ch.param.charCodeAt(i));
135
+ if (dir != null)
136
+ return dir;
137
+ }
138
+ }
139
+ return null;
140
+ }
141
+ function directionAtCursor(state) {
142
+ let block = state.sel.head.textblockParent;
143
+ return (block && block.node.mark(Direction)) || (state.textLTR ? "ltr" : "rtl");
144
+ }
145
+ ;direction = /*@__PURE__*/(function (direction) {
146
+ direction.textblockDir = GardState.textblockLTR.of(plot => {
147
+ let dir = plot.mark(Direction);
148
+ return !dir ? null : dir == "auto" ? autoDir(plot) : dir == "ltr";
149
+ });
150
+ direction.buttonLTR = Menu.Button.define({
151
+ run: Command.bind(setDirection, "ltr"),
152
+ active: state => directionAtCursor(state) == "ltr",
153
+ label: {
154
+ icon: "M70 35l20 15l-20 15l0-30M45 83v-63h-5v63a3 3 0 0 1-6 0v-28h-4a20 20 0 1 1 0-40h28a3 3 0 0 1 0 6h-7v62a3 3 0 0 1-6 0"
155
+ },
156
+ description: phrases.ref("text_dir_ltr")
157
+ });
158
+ direction.buttonRTL = Menu.Button.define({
159
+ run: Command.bind(setDirection, "rtl"),
160
+ active: state => directionAtCursor(state) == "rtl",
161
+ label: {
162
+ icon: "M30 35l-20 15l20 15l0-30M75 83v-63h-5v63a3 3 0 0 1-6 0v-28h-4a20 20 0 1 1 0-40h28a3 3 0 0 1 0 6h-7v62a3 3 0 0 1-6 0"
163
+ },
164
+ description: phrases.ref("text_dir_rtl")
165
+ });
166
+ direction.buttonAuto = Menu.Button.define({
167
+ run: Command.bind(setDirection, "auto"),
168
+ active: state => directionAtCursor(state) == "auto",
169
+ label: {
170
+ icon: "M35 30l-23 20l23 20l0-40M60 30l23 20l-23 20l0-40"
171
+ },
172
+ description: phrases.ref("text_dir_auto")
173
+ });
174
+ direction.button = Menu.Submenu.define({
175
+ description: phrases.ref("text_dir"),
176
+ parent: Menu.Group.block,
177
+ arrow: false,
178
+ enable: s => !s.readOnly,
179
+ rank: 20,
180
+ content: [direction.buttonLTR, direction.buttonRTL, direction.buttonAuto]
181
+ });
182
+ ;return direction})(direction);
183
+ function blockquote() {
184
+ return [GardState.schemaElement.of(Blockquote), blockquote.button, blockquote.createOnGT, blockquote.theme];
185
+ }
186
+ ;blockquote = /*@__PURE__*/(function (blockquote) {
187
+ blockquote.button = Menu.Button.define({
188
+ run: Command.bind(toggleBlock, Blockquote),
189
+ active: state => {
190
+ for (let cur = state.sel.head.parent; cur; cur = cur.parent)
191
+ if (cur.node.type == Blockquote.type)
192
+ return true;
193
+ return false;
194
+ },
195
+ label: {
196
+ icon: "M75 75a6 6 0 0 0 6-6V53a6 6 0 0 0-6-6h-9q0-3 0-7 1-3 2-6t3-4q2-2 5-2V19q-5 0-9 2a21 21 0 0 0-7 6 31 31 0 0 0-4 9A48 48 0 0 0 56 47V69a5 5 0 0 0 6 6zm-37 0a6 6 0 0 0 6-6V53a6 6 0 0 0-6-6H29q0-3 0-7 1-3 2-6 1-3 3-4 2-2 5-2V19q-5 0-9 2a21 21 0 0 0-7 6 31 31 0 0 0-4 9A48 48 0 0 0 19 47V69a6 6 0 0 0 6 6z"
197
+ },
198
+ description: phrases.ref("toggle_quote"),
199
+ enable: s => !s.readOnly,
200
+ parent: Menu.Group.block,
201
+ rank: 40
202
+ });
203
+ blockquote.createOnGT = InputRule.wrapping(/^> $/, Blockquote, true);
204
+ blockquote.theme = Wordgard.theme({
205
+ blockquote: {
206
+ marginInline: "3px",
207
+ paddingInlineStart: "12px",
208
+ borderInlineStart: "4px solid silver"
209
+ }
210
+ });
211
+ ;return blockquote})(blockquote);
212
+ function horizontalRule() {
213
+ return [GardState.schemaElement.of(HorizontalRule), horizontalRule.createOnDashes];
214
+ }
215
+ ;horizontalRule = /*@__PURE__*/(function (horizontalRule) {
216
+ horizontalRule.createOnDashes = InputRule.define({
217
+ expr: /^---$/,
218
+ lookahead: /^$/,
219
+ apply: (state, m) => {
220
+ let changes = ChangeSet.create(state.doc, {
221
+ from: m[0].from.pos, to: m[0].to.pos,
222
+ insert: [HorizontalRule],
223
+ fit: true
224
+ });
225
+ let hr = changes.findInserted(t => t == HorizontalRule);
226
+ if (hr == null)
227
+ return null;
228
+ return {
229
+ changes,
230
+ selection: cx => GardSelection.near(cx, hr + 1, 1),
231
+ annotations: history.isolate.of(true),
232
+ userEvent: "insert.horizontalrule"
233
+ };
234
+ }
235
+ });
236
+ ;return horizontalRule})(horizontalRule);
237
+
238
+ function bulletList(config = {}) {
239
+ return [GardState.schemaElement.of(BulletList),
240
+ GardState.schemaElement.of(config.blockItems == false ? InlineListItem : ListItem),
241
+ bulletList.toggleButton, bulletList.createOnDash];
242
+ }
243
+ ;bulletList = /*@__PURE__*/(function (bulletList) {
244
+ bulletList.createOnDash = InputRule.wrapping(/^ ?- $/, BulletList, true);
245
+ bulletList.toggleButton = Menu.Button.define({
246
+ run: Command.bind(toggleList, BulletList),
247
+ active: listIsActive(BulletList),
248
+ label: {
249
+ icon: "M34 75a3 3 0 0 1 0-6h56a3 3 0 0 1 0 6h-56m0-25a3 3 0 0 1 0-6h56a3 3 0 0 1 0 6h-56m0-25a3 3 0 0 1 0-6h56a3 3 0 0 1 0 6h-56m-22 3a6 6 0 1 0 0-12 6 6 0 0 0 0 12m0 25a6 6 0 1 0 0-12 6 6 0 0 0 0 12m0 25a6 6 0 1 0 0-12 6 6 0 0 0 0 12",
250
+ directional: true
251
+ },
252
+ description: phrases.ref("toggle_bullet_list"),
253
+ enable: s => !s.readOnly,
254
+ parent: Menu.Group.block,
255
+ rank: 20
256
+ });
257
+ ;return bulletList})(bulletList);
258
+ function orderedList(config = {}) {
259
+ return [GardState.schemaElement.of(OrderedList),
260
+ GardState.schemaElement.of(config.blockItems == false ? InlineListItem : ListItem),
261
+ orderedList.toggleButton, orderedList.createOnNumber];
262
+ }
263
+ ;orderedList = /*@__PURE__*/(function (orderedList) {
264
+ orderedList.createOnNumber = InputRule.wrapping(/^ ?(\d+)\. $/, match => OrderedList.of(+match[1].text), true);
265
+ orderedList.toggleButton = Menu.Button.define({
266
+ run: Command.bind(toggleList, OrderedList.default),
267
+ active: listIsActive(OrderedList.default),
268
+ label: {
269
+ icon: "M34 75a3 3 0 0 1 0-6h56a3 3 0 0 1 0 6h-56m0-25a3 3 0 0 1 0-6h56a3 3 0 0 1 0 6h-56m0-25a3 3 0 0 1 0-6h56a3 3 0 0 1 0 6h-56M11 74v-3H13c1 0 2-1 2-2 0-1-1-2-2-2-1 0-2 1-2 2h-4c0-3 2-5 6-5 4 0 6 2 6 4a4 4 0 0 1-3 4v0a4 4 0 0 1 4 4c0 3-3 5-7 5-4 0-6-2-6-5h4c0 1 1 2 3 2 2 0 3-1 3-2 0-1-1-2-3-2h-2zm0-29h-4v0c0-3 2-5 6-5 4 0 6 2 6 5 0 2-2 4-3 5l-3 4h7V57H7v-3l6-6c1-1 2-2 2-3 0-1-1-2-2-2a2 2 0 0 0-2 2zM16 31h-4V18h0l-4 3v-4l4-3h4z",
270
+ directional: true
271
+ },
272
+ description: phrases.ref("toggle_ordered_list"),
273
+ enable: s => !s.readOnly,
274
+ parent: Menu.Group.block,
275
+ rank: 30
276
+ });
277
+ ;return orderedList})(orderedList);
278
+
279
+ function codeBlock() {
280
+ return [GardState.schemaElement.of(CodeBlock),
281
+ codeBlock.button, codeBlock.keyBinding, codeBlock.createOnBackticks];
282
+ }
283
+ ;codeBlock = /*@__PURE__*/(function (codeBlock) {
284
+ codeBlock.keyBinding = KeyBinding.of({
285
+ key: "Ctrl-Shift-\\",
286
+ run: Command.bind(setTextblockType, CodeBlock)
287
+ });
288
+ codeBlock.button = Menu.Button.define({
289
+ run: Command.bind(setTextblockType, CodeBlock),
290
+ active: selectionInType(CodeBlock),
291
+ label: phrases.ref("code_block"),
292
+ enable: s => !s.readOnly,
293
+ parent: Menu.Submenu.textblockStyle,
294
+ rank: 30
295
+ });
296
+ codeBlock.createOnBackticks = GardState.prec.high(Command.handler(enter, wg => {
297
+ let { sel } = wg.state, parent = sel.head.parent;
298
+ if (!sel.selection.isCursor || !parent.node.isTextblock || sel.head.pos != parent.end ||
299
+ parent.node.length > 20 || parent.node.type == CodeBlock.type || !parent.parent ||
300
+ !wg.state.doc.schema.canContain(parent.parent.node.type, CodeBlock.type))
301
+ return false;
302
+ let text = wg.state.textblockMap(sel.head.parent);
303
+ let match = /^```\s*([^\s`]+\s*)?$/.exec(text.text);
304
+ if (!match)
305
+ return false;
306
+ let tag = CodeBlock;
307
+ if (match[1] && wg.state.schema.has(CodeBlockLanguage))
308
+ tag = tag.withMarks([CodeBlockLanguage.of(match[1])]);
309
+ return {
310
+ changes: { from: parent.before, to: parent.end, insert: [tag] },
311
+ selection: { anchor: parent.start },
312
+ scrollIntoView: true
313
+ };
314
+ }));
315
+ ;return codeBlock})(codeBlock);
316
+ function codeBlockLanguage(options = {}) {
317
+ return [
318
+ GardState.schemaElement.of(CodeBlockLanguage),
319
+ options.languages ? [
320
+ languageStyles,
321
+ languageOptions.of(options.languages),
322
+ languageSelect,
323
+ codeBlockLanguage.selectLanguageBinding
324
+ ] : []
325
+ ];
326
+ }
327
+ const languageStyles = /*@__PURE__*/Wordgard.styles({
328
+ pre: {
329
+ position: "relative",
330
+ "& select.wg-code-language": {
331
+ font: "var(--wg-dialog-font)",
332
+ fontSize: "70%",
333
+ position: "absolute",
334
+ top: "2px",
335
+ right: "4px",
336
+ border: "none",
337
+ borderRadius: "4px"
338
+ }
339
+ }
340
+ });
341
+ const languageOptions = /*@__PURE__*/GardState.Facet.define({
342
+ combine: input => input.reduce((a, b) => a.concat(b), [])
343
+ });
344
+ function option(text, selected, value) {
345
+ let node = document.createElement("option");
346
+ node.textContent = text;
347
+ node.value = value;
348
+ if (selected)
349
+ node.selected = true;
350
+ return node;
351
+ }
352
+ const languageWidget = /*@__PURE__*/Widget.define({
353
+ render({ options, value }, wg) {
354
+ let sel = document.createElement("select");
355
+ sel.className = "wg-code-language";
356
+ sel.tabIndex = -1;
357
+ sel.appendChild(option("Plain", value == null, ""));
358
+ let selected = value && options.find(o => o.toLowerCase() == value);
359
+ if (value && !selected)
360
+ sel.appendChild(option(value, true, value));
361
+ for (let opt of options)
362
+ sel.appendChild(option(opt, opt == selected, opt.toLowerCase()));
363
+ sel.onchange = () => {
364
+ let value = sel.value || undefined;
365
+ let pos = wg.posAtDOM(sel.parentNode);
366
+ let block = pos > 0 && wg.state.doc.nodeAt(pos - 1);
367
+ if (block && block.type == CodeBlock.type && block.mark(CodeBlockLanguage) != value) {
368
+ wg.dispatch({
369
+ changes: value ? { from: pos - 1, add: CodeBlockLanguage.of(value) } :
370
+ { from: pos - 1, remove: CodeBlockLanguage.isInSet(block.tag.marks) }
371
+ });
372
+ wg.focus();
373
+ }
374
+ };
375
+ return sel;
376
+ },
377
+ propagateEvent: false,
378
+ eq(a, b) {
379
+ return a.value == b.value && a.options.length == b.options.length &&
380
+ a.options.every((o, i) => o == b.options[i]);
381
+ },
382
+ inFlow: false
383
+ });
384
+ const languageSelect = /*@__PURE__*/Decoration.Tag.widget.dynamic(CodeBlock, "end", state => {
385
+ let options = state.facet(languageOptions);
386
+ return tag => {
387
+ return languageWidget.of({ options, value: tag.mark(CodeBlockLanguage) });
388
+ };
389
+ });
390
+ ;codeBlockLanguage = /*@__PURE__*/(function (codeBlockLanguage) {
391
+ codeBlockLanguage.selectLanguage = wg => {
392
+ let blk = wg.state.sel.head.textblockParent;
393
+ if (!blk || blk.node.type != CodeBlock.type)
394
+ return false;
395
+ let sel = wg.nodeDOM(blk.before)?.querySelector("select.wg-code-language");
396
+ if (!sel)
397
+ return false;
398
+ sel.focus();
399
+ sel.showPicker();
400
+ return true;
401
+ };
402
+ codeBlockLanguage.selectLanguageBinding = KeyBinding.of({
403
+ key: "Shift-Mod-l",
404
+ run: codeBlockLanguage.selectLanguage
405
+ });
406
+ ;return codeBlockLanguage})(codeBlockLanguage);
407
+
408
+ function strong() {
409
+ return [GardState.schemaElement.of(Strong), strong.button, strong.keyBinding];
410
+ }
411
+ ;strong = /*@__PURE__*/(function (strong) {
412
+ strong.keyBinding = KeyBinding.of({
413
+ key: "Mod-b",
414
+ run: Command.bind(toggleMark, Strong),
415
+ });
416
+ strong.button = Menu.Button.toggleMark({
417
+ mark: Strong,
418
+ parent: Menu.Group.inline,
419
+ rank: 10,
420
+ description: phrases.ref("toggle_strong"),
421
+ label: {
422
+ icon: "M51 81c13 0 21-7 21-18 0-8-6-14-14-15v0a14 14 0 0 0 12-13c0-9-7-15-19-15H24V81zM37 29h11c6 0 10 3 10 8 0 5-4 8-11 8H37V29zm0 42V54h11c8 0 12 3 12 9 0 6-4 9-11 9H37z"
423
+ }
424
+ });
425
+ ;return strong})(strong);
426
+ function emphasis() {
427
+ return [GardState.schemaElement.of(Emphasis), emphasis.button, emphasis.keyBinding];
428
+ }
429
+ ;emphasis = /*@__PURE__*/(function (emphasis) {
430
+ emphasis.keyBinding = KeyBinding.of({
431
+ key: "Mod-i",
432
+ run: Command.bind(toggleMark, Emphasis),
433
+ });
434
+ emphasis.button = Menu.Button.toggleMark({
435
+ mark: Emphasis,
436
+ parent: Menu.Group.inline,
437
+ rank: 15,
438
+ description: phrases.ref("toggle_em"),
439
+ label: {
440
+ icon: "M50 73 60 28c1-4 2-4 8-5l1-3H45l-1 3c7 1 7 1 6 5L41 73c-1 4-2 4-8 5l-1 3h24l1-3c-7-1-7-1-7-5z"
441
+ }
442
+ });
443
+ ;return emphasis})(emphasis);
444
+ function code() {
445
+ return [GardState.schemaElement.of(Code), code.button, code.keyBinding];
446
+ }
447
+ ;code = /*@__PURE__*/(function (code) {
448
+ code.keyBinding = KeyBinding.of({
449
+ key: "Mod-`",
450
+ run: Command.bind(toggleMark, Code),
451
+ });
452
+ code.button = Menu.Button.toggleMark({
453
+ mark: Code,
454
+ parent: Menu.Group.inline,
455
+ rank: 30,
456
+ description: phrases.ref("toggle_code"),
457
+ label: {
458
+ icon: "M37 30a2 2 0 1 0-4-4l-22 22a3 3 0 0 0 0 4l22 22a2 2 0 0 0 4-4L17 50zm27 0a2 2 0 0 1 4-4l22 22a3 3 0 0 1 0 4l-22 22a2 2 0 0 1-4-4L83 50z"
459
+ }
460
+ });
461
+ ;return code})(code);
462
+ function underline() {
463
+ return [GardState.schemaElement.of(Underline), underline.button, underline.keyBinding];
464
+ }
465
+ ;underline = /*@__PURE__*/(function (underline) {
466
+ underline.keyBinding = KeyBinding.of({
467
+ key: "Mod-u",
468
+ run: Command.bind(toggleMark, Underline)
469
+ });
470
+ underline.button = Menu.Button.toggleMark({
471
+ mark: Underline,
472
+ parent: Menu.Group.inline,
473
+ rank: 60,
474
+ description: phrases.ref("toggle_underline"),
475
+ label: {
476
+ icon: "M33 20h-8V60c0 13 9 23 24 23s24-9 24-23V20h-8v40c0 9-6 16-17 16s-15-7-15-16M78 94h-56v-6h56z"
477
+ }
478
+ });
479
+ ;return underline})(underline);
480
+ function strikethrough() {
481
+ return [GardState.schemaElement.of(Strikethrough), strikethrough.button, strikethrough.keyBinding];
482
+ }
483
+ ;strikethrough = /*@__PURE__*/(function (strikethrough) {
484
+ strikethrough.keyBinding = KeyBinding.of({
485
+ key: "Mod-/",
486
+ run: Command.bind(toggleMark, Strikethrough),
487
+ });
488
+ strikethrough.button = Menu.Button.toggleMark({
489
+ mark: Strikethrough,
490
+ parent: Menu.Group.inline,
491
+ rank: 65,
492
+ description: phrases.ref("toggle_strikethrough"),
493
+ label: {
494
+ icon: "M38 37c0 2 0 3 2 5H31a17 17 0 0 1-1-5c0-10 9-16 21-16 12 0 20 7 20 17h-7c-1-6-6-10-13-10-7 0-13 4-13 10zm13 44c-13 0-21-7-22-17h7c1 6 7 10 15 10c8 0 14-4 14-10c0-5-3-8-11-10L48 53h20c3 3 4 6 4 10 0 11-9 18-22 18M11 50v-6h75v6H11"
495
+ }
496
+ });
497
+ ;return strikethrough})(strikethrough);
498
+ function superscript() {
499
+ return [GardState.schemaElement.of(Superscript), superscript.button, superscript.keyBinding];
500
+ }
501
+ ;superscript = /*@__PURE__*/(function (superscript) {
502
+ superscript.keyBinding = KeyBinding.of({
503
+ key: "Mod-.",
504
+ run: Command.bind(toggleMark, Superscript),
505
+ });
506
+ superscript.button = Menu.Button.toggleMark({
507
+ mark: Superscript,
508
+ parent: Menu.Group.inline,
509
+ rank: 70,
510
+ description: phrases.ref("toggle_super"),
511
+ label: {
512
+ icon: "m27 78 6-18H55l6 18H69L48 19H40L19 78zm17-50 9 26h-18l9-26zm32-11v0c4 -10 12 0 5 6l-11 11V38h22v-6h-12v0l6-6c3-3 5-5 5-10 0-5-4-9-11-9C72 6 69 11 69 16v0z"
513
+ }
514
+ });
515
+ ;return superscript})(superscript);
516
+ function subscript() {
517
+ return [GardState.schemaElement.of(Subscript), subscript.button, subscript.keyBinding];
518
+ }
519
+ ;subscript = /*@__PURE__*/(function (subscript) {
520
+ subscript.keyBinding = KeyBinding.of({
521
+ key: "Mod-,",
522
+ run: Command.bind(toggleMark, Subscript),
523
+ });
524
+ subscript.button = Menu.Button.toggleMark({
525
+ mark: Subscript,
526
+ parent: Menu.Group.inline,
527
+ rank: 75,
528
+ description: phrases.ref("toggle_sub"),
529
+ label: {
530
+ icon: "m21 78 6-18H49l6 18H63L41 19H34L13 78zm17-50 9 26h-18l9-26zm38 45v0c4 -10 12 0 5 6l-11 11V94h22v-6h-12v0l6-6c3-3 5-5 5-10 0-5-4-9-11-9-8 0-11 5-11 10v0z"
531
+ }
532
+ });
533
+ ;return subscript})(subscript);
534
+
535
+ const imageUploader = /*@__PURE__*/GardState.Facet.define();
536
+ const imageTypes = [Image, Figure, CaptionedFigure];
537
+ function activeImage(sel) {
538
+ if (sel.selection instanceof GardSelection.Node && imageTypes.includes(sel.selection.node.type))
539
+ return sel.selection.node.tag;
540
+ if (sel.head.parent.start == sel.anchor.parent.start && sel.head.parent.node.type == CaptionedFigure)
541
+ return sel.head.parent.node.tag;
542
+ return null;
543
+ }
544
+ const svg = "http://www.w3.org/2000/svg";
545
+ function rect(x, y, w, h, cls) {
546
+ let elt = document.createElementNS(svg, "rect");
547
+ elt.setAttribute("x", String(x));
548
+ elt.setAttribute("y", String(y));
549
+ elt.setAttribute("width", String(w));
550
+ elt.setAttribute("height", String(h));
551
+ elt.setAttribute("class", cls);
552
+ return elt;
553
+ }
554
+ function imageTypeButtons(state, active) {
555
+ let hasImg = state.schema.has(Image), hasFig = state.schema.has(Figure), hasCap = state.schema.has(CaptionedFigure);
556
+ let align = (hasFig || hasCap) && state.schema.markAllowed(Alignment, hasFig ? Figure : CaptionedFigure);
557
+ if (!align && !(hasImg && (hasFig || hasCap)))
558
+ return null;
559
+ let buttons = [];
560
+ function button(type, label, active) {
561
+ let labelText = imagePhrases.get(state, label);
562
+ let icon = document.createElementNS(svg, "svg");
563
+ icon.setAttribute("viewbox", "0 0 24 22");
564
+ icon.setAttribute("width", "24");
565
+ icon.setAttribute("height", "22");
566
+ icon.appendChild(rect(1, 1, 22, 3, "wg-img-icon-text"));
567
+ let flip = !state.textLTR;
568
+ icon.appendChild(rect(type == "start" ? (flip ? 12 : 2) : type == "end" ? (flip ? 2 : 12) : 7, 6, 10, 10, "wg-img-icon-image"));
569
+ if (type == "inline") {
570
+ icon.appendChild(rect(1, 12, 5, 3, "wg-img-icon-text"));
571
+ icon.appendChild(rect(18, 12, 5, 3, "wg-img-icon-text"));
572
+ }
573
+ icon.appendChild(rect(1, 18, 22, 3, "wg-img-icon-text"));
574
+ return cr("label", { class: "wg-img-radio", title: labelText }, cr("input", { type: "radio", "aria-label": labelText,
575
+ name: "type", value: type, checked: active ? "checked" : null }), icon);
576
+ }
577
+ let aligned = !active || active.type == Image ? null : active.mark(Alignment) || "start";
578
+ if (hasImg)
579
+ buttons.push(button("inline", "inline", aligned == null));
580
+ buttons.push(button("start", "figure", aligned == "start"));
581
+ if (align) {
582
+ buttons.push(button("center", "figure_center", aligned == "center"));
583
+ buttons.push(button("end", "figure_end", aligned == "end"));
584
+ }
585
+ if (hasFig && hasCap) {
586
+ let caption = cr("label", " ", cr("input", { type: "checkbox", name: "caption",
587
+ checked: active && active.type == CaptionedFigure ? "checked" : null }), " ", imagePhrases.get(state, "captioned"));
588
+ if (hasImg) {
589
+ let imageRadio = buttons[0].querySelector("input");
590
+ for (let b of buttons)
591
+ b.querySelector("input").addEventListener("change", () => {
592
+ caption.style.display = imageRadio.checked ? "none" : "";
593
+ });
594
+ if (!aligned)
595
+ caption.style.display = "none";
596
+ }
597
+ buttons.push(caption);
598
+ }
599
+ return [cr("span", { class: "wg-label" }, imagePhrases.get(state, "image_style"), ":"), cr("span", buttons)];
600
+ }
601
+ const setImageDialog = /*@__PURE__*/Transaction.Effect.define();
602
+ const createImagePanel = wg => {
603
+ let dom = buildImagePanel(wg), mustFocus = true;
604
+ return {
605
+ top: true,
606
+ dom,
607
+ connect() {
608
+ if (mustFocus) {
609
+ mustFocus = false;
610
+ let target = dom.querySelector("input[name=src]");
611
+ if (target)
612
+ target.focus();
613
+ }
614
+ }
615
+ };
616
+ };
617
+ function startUpload(wg, file, set) {
618
+ let imageFile = file.files?.[0], handler = wg.state.facet(imageUploader)[0];
619
+ if (!imageFile || !handler)
620
+ return;
621
+ let promise = handler(imageFile, wg, percent => {
622
+ progress.lastChild.textContent = Math.round(percent) + "%";
623
+ });
624
+ let progress = cr("span", { class: "wg-img-upload", style: `width: ${file.offsetWidth}px` }, imagePhrases.get(wg.state, "uploading"), " ", cr("span"));
625
+ file.parentNode.replaceChild(progress, file);
626
+ function reset() {
627
+ if (progress.parentNode)
628
+ progress.parentNode.replaceChild(file, progress);
629
+ }
630
+ promise.then(url => {
631
+ reset();
632
+ set(url);
633
+ }, err => {
634
+ reset();
635
+ Dialog.show(wg, { label: imagePhrases.get(wg.state, "upload_failed") + ": " + err });
636
+ });
637
+ }
638
+ function buildImagePanel(wg) {
639
+ let { state } = wg;
640
+ let sel = (state.field(imageDialog) || state.selection).resolve(state.doc);
641
+ let active = activeImage(sel);
642
+ let size = !wg.state.schema.has(ImageSize) ? null :
643
+ [cr("label", { for: "wg-img-size" }, imagePhrases.get(state, "width"), ":"),
644
+ cr("input", { type: "number", id: "wg-img-size", name: "size", value: active && active.mark(ImageSize) || "",
645
+ placeholder: imagePhrases.get(state, "auto") })];
646
+ let src = cr("input", { type: "text", id: "wg-img-src", name: "src", required: "required",
647
+ value: active ? active.param : "", placeholder: "https://..." });
648
+ let file = null;
649
+ if (wg.state.facet(imageUploader).length) {
650
+ file = cr("input", { type: "file", id: "wg-img-file", name: "file", "aria-label": imagePhrases.get(state, "upload_image"),
651
+ onchange: (e) => startUpload(wg, e.target, url => src.value = url) });
652
+ }
653
+ let form = cr("form", { class: "wg-img-form", onkeydown }, cr("div", { class: "wg-dialog-title" }, imagePhrases.get(state, active ? "update_image" : "insert_image")), cr("label", { for: "wg-img-src" }, imagePhrases.get(state, "image_source"), ":"), cr("span", { class: "wg-img-src-line" }, src, file), cr("label", { for: "wg-img-alt" }, imagePhrases.get(state, "alt_text"), ":"), cr("input", { type: "text", id: "wg-img-alt", name: "alt",
654
+ value: active && active.mark(ImageAlt) || "",
655
+ placeholder: imagePhrases.get(state, "describe_image") }), imageTypeButtons(state, active), size, cr("div", { class: "wg-img-buttons" }, cr("button", { type: "submit", class: "wg-dialog-button" }, imagePhrases.get(state, active ? "update" : "insert")), " ", cr("button", { type: "button", class: "wg-dialog-button", onclick: close }, imagePhrases.get(state, "cancel"))));
656
+ function onsubmit(e) {
657
+ e.preventDefault();
658
+ let { state } = wg, sel = (state.field(imageDialog) || state.selection).resolve(state.doc);
659
+ let data = new FormData(form);
660
+ let src = data.get("src");
661
+ if (!src)
662
+ return;
663
+ let type = data.get("type") ?? (state.schema.has(Image) ? "inline" : "start");
664
+ let cap = !!data.get("caption") || !state.schema.has(Figure);
665
+ let marks = [];
666
+ if (type == "center" || type == "end")
667
+ marks = Alignment.of(type).addToSet(marks);
668
+ if (data.get("alt"))
669
+ marks = ImageAlt.of(data.get("alt")).addToSet(marks);
670
+ if (data.get("size"))
671
+ marks = ImageSize.of(Number(data.get("size"))).addToSet(marks);
672
+ let tag = type == "inline" ? Image.of(src, marks) : cap ? CaptionedFigure.of(src, marks) : Figure.of(src, marks);
673
+ let change;
674
+ if (sel.from.parent.node.type == CaptionedFigure && sel.to.parent.start == sel.from.parent.start) {
675
+ let from = sel.from.parent.before;
676
+ if (tag instanceof Plot.Tag)
677
+ change = { from, to: from + 1, insert: [tag] };
678
+ else
679
+ change = { from, to: sel.from.parent.after, insert: [tag], fit: true };
680
+ }
681
+ else {
682
+ change = { from: sel.from.pos, to: sel.to.pos, insert: [tag instanceof Plot.Tag ? tag.create() : tag], fit: true };
683
+ }
684
+ wg.focus();
685
+ let changes = ChangeSet.create(state.doc, change), pos = changes.findInserted(t => t == tag) ?? change.from;
686
+ wg.dispatch({
687
+ changes: change,
688
+ effects: setImageDialog.of(false),
689
+ userEvent: "insert.image",
690
+ selection: tag instanceof Plot.Tag ? { anchor: pos + 1 } : GardSelection.node(pos, tag)
691
+ });
692
+ }
693
+ function close() {
694
+ wg.focus();
695
+ wg.dispatch({ effects: setImageDialog.of(false) });
696
+ }
697
+ function onkeydown(e) {
698
+ if (e.key == "Escape") {
699
+ e.preventDefault();
700
+ close();
701
+ }
702
+ }
703
+ return cr("wg-dialog", { class: "wg-img-dialog", onsubmit }, form);
704
+ }
705
+ const insertImage = wg => {
706
+ let val = wg.state.field(imageDialog, false);
707
+ if (val) {
708
+ wg.dispatch({ effects: setImageDialog.of(false) });
709
+ }
710
+ else {
711
+ let effects = [setImageDialog.of(true)];
712
+ if (val === undefined)
713
+ effects.push(GardState.appendConfig.of(imageDialog));
714
+ wg.dispatch({ effects });
715
+ }
716
+ return true;
717
+ };
718
+ const imageDialogTheme = /*@__PURE__*/Wordgard.styles({
719
+ ".wg-img-dialog": {
720
+ borderBottom: "1px solid var(--wg-border-color)"
721
+ },
722
+ ".wg-img-form": {
723
+ padding: "5px 3px",
724
+ display: "grid",
725
+ gap: "8px",
726
+ alignItems: "center",
727
+ gridTemplateColumns: "max-content auto",
728
+ "& label, & .wg-label": {
729
+ textAlign: "right"
730
+ }
731
+ },
732
+ ".wg-dialog-title": {
733
+ gridColumn: "span 2",
734
+ fontSize: "90%",
735
+ fontWeight: "bold",
736
+ textAlign: "center"
737
+ },
738
+ ".wg-img-buttons": {
739
+ gridColumn: "2"
740
+ },
741
+ ".wg-img-src-line": {
742
+ display: "flex",
743
+ gap: "7px",
744
+ "& [type=text]": {
745
+ flex: "1"
746
+ }
747
+ },
748
+ ".wg-img-radio": {
749
+ display: "inline-block",
750
+ verticalAlign: "middle",
751
+ "& input[type=radio]": {
752
+ opacity: "0",
753
+ position: "absolute",
754
+ pointerEvents: "none"
755
+ },
756
+ "& svg": {
757
+ marginRight: "6px",
758
+ width: "24px",
759
+ "& .wg-img-icon-text": { fill: "#bbb" },
760
+ "& .wg-img-icon-image": { fill: "#888" },
761
+ },
762
+ "& input:checked + svg .wg-img-icon-image": {
763
+ fill: "var(--wg-highlight-color)"
764
+ },
765
+ "& input:focus + svg": {
766
+ borderRadius: "2px",
767
+ outline: "2px solid var(--wg-highlight-color)",
768
+ },
769
+ },
770
+ ".wg-img-upload": {
771
+ boxSizing: "border-box",
772
+ padding: "4px",
773
+ fontSize: "80%"
774
+ }
775
+ });
776
+ const imageDialog = /*@__PURE__*/GardState.Field.define({
777
+ create: () => null,
778
+ update(value, tr) {
779
+ for (let e of tr.effects)
780
+ if (e.is(setImageDialog))
781
+ return e.value ? tr.state.selection : null;
782
+ return value && value.map(tr.changes, tr.state);
783
+ },
784
+ provide: f => [
785
+ GardState.prec.lowest(Panel.show.from(f, val => val && createImagePanel)),
786
+ imageDialogTheme
787
+ ]
788
+ });
789
+
790
+ function baseSupport() {
791
+ return [GardState.schemaElement.of(ImageAlt), image.button, imageDialog, image.keyBinding, image.dropHandler];
792
+ }
793
+ function image() {
794
+ return [GardState.schemaElement.of(Image), baseSupport()];
795
+ }
796
+ function figure(conf = {}) {
797
+ return [GardState.schemaElement.of(Figure), conf?.captioned ? [GardState.schemaElement.of(CaptionedFigure)] : [], baseSupport()];
798
+ }
799
+ function imageResizing() {
800
+ return [GardState.schemaElement.of(ImageSize), imageResizing.keyBindings, imageResizing.dragHandle];
801
+ }
802
+ const resizeTheme = /*@__PURE__*/Wordgard.theme({
803
+ ".wg-resize-hover": {
804
+ display: "inline-block",
805
+ lineHeight: "0.1",
806
+ position: "relative"
807
+ },
808
+ ".wg-resize-handle": {
809
+ position: "absolute",
810
+ right: "1px", bottom: "1px",
811
+ width: "min(60%, 20px)",
812
+ height: "min(60%, 20px)",
813
+ },
814
+ ".wg-resize-handle-active": {
815
+ cursor: "nwse-resize"
816
+ }
817
+ });
818
+ const setResizing = /*@__PURE__*/Transaction.Effect.define({
819
+ map: (value, mapping) => {
820
+ let newPos = mapping.mapPos(value.target, 1, "after");
821
+ return newPos == null ? undefined : { target: newPos, resizing: value.resizing };
822
+ }
823
+ });
824
+ const handleElt = /*@__PURE__*/(() => Elt.mk("svg:svg", { class: "wg-resize-handle", viewBox: "0 0 20 20" }, [
825
+ Elt.mk("svg:path", { d: "M20 0L0 20M20 5L5 20M20 10L10 20", stroke: "#000000aa", "stroke-width": "1.5" }),
826
+ Elt.mk("svg:polygon", { points: "0,20 20,20 20,0", fill: "transparent", class: "wg-resize-handle-active" })
827
+ ]))();
828
+ const resizeWrapper = /*@__PURE__*/(() => Decoration.Point.wrapper(Elt.mk("span", { class: "wg-resize-hover" }, [handleElt, 0]), { target: "img" }))();
829
+ const resizeState = /*@__PURE__*/GardState.Field.define({
830
+ create: () => ({ target: -1, resizing: -1, deco: PointSet.empty }),
831
+ update: (value, tr) => {
832
+ for (let e of tr.effects) {
833
+ if (e.is(setResizing)) {
834
+ let { target, resizing } = e.value;
835
+ if (target < 0)
836
+ return { target: -1, resizing: -1, deco: PointSet.empty };
837
+ let deco = [[target, resizeWrapper]];
838
+ if (resizing > -1)
839
+ deco.push([target, Decoration.Point.attributes({ style: `width: ${resizing}px` }, { target: "img" })]);
840
+ return { target, resizing, deco: PointSet.create(deco) };
841
+ }
842
+ }
843
+ return value.target < 0 || !tr.docChanged ? value
844
+ : { target: value.target, resizing: value.resizing, deco: value.deco.map(tr.changes) };
845
+ }
846
+ });
847
+ const MIN_SIZE = 10;
848
+ function imageNode(wg, pos) {
849
+ let dom = wg.nodeDOM(pos);
850
+ return dom.nodeName == "IMG" ? dom : dom.querySelector("img[src]");
851
+ }
852
+ const resizeHandlers = /*@__PURE__*/(() => [
853
+ Wordgard.domEventHandler("mousedown", (event, wg) => {
854
+ let resizing = wg.state.field(resizeState);
855
+ if (resizing.target < 0)
856
+ return;
857
+ for (let dom = event.target;;) {
858
+ if (dom.classList.contains("wg-resize-handle-active"))
859
+ break;
860
+ let next = dom.parentNode;
861
+ if (!next || next == wg.contentDOM)
862
+ return;
863
+ dom = next;
864
+ }
865
+ let node = wg.state.doc.nodeAt(resizing.target);
866
+ let width = node.tag.mark(ImageSize) ?? imageNode(wg, resizing.target).getBoundingClientRect().width;
867
+ wg.dispatch({ effects: setResizing.of({ target: resizing.target, resizing: width }) });
868
+ event.preventDefault();
869
+ }),
870
+ Wordgard.domEventHandler("mousemove", (event, wg) => {
871
+ let resizing = wg.state.field(resizeState);
872
+ if (resizing.resizing > -1) {
873
+ let dom = imageNode(wg, resizing.target);
874
+ let width = event.clientX - dom.getBoundingClientRect().left;
875
+ if (width >= MIN_SIZE && Math.abs(width - resizing.resizing) >= 1)
876
+ wg.dispatch({ effects: setResizing.of({ target: resizing.target, resizing: width }) });
877
+ }
878
+ else {
879
+ let elt = event.target.closest("img, .wg-resize-handle");
880
+ let node = elt && wg.nodeFromDOM(elt);
881
+ let target = node && wg.state.schema.markAllowed(ImageSize, node.node.type) ? node.pos : -1;
882
+ if (target != resizing.target)
883
+ wg.dispatch({ effects: setResizing.of({ target, resizing: -1 }) });
884
+ }
885
+ }),
886
+ Wordgard.domEventHandler("mouseup", (event, wg) => {
887
+ let resizing = wg.state.field(resizeState);
888
+ if (resizing.resizing < 0)
889
+ return;
890
+ wg.dispatch({
891
+ effects: setResizing.of({ target: resizing.target, resizing: -1 }),
892
+ changes: { from: resizing.target, add: ImageSize.of(Math.round(resizing.resizing)) }
893
+ });
894
+ })
895
+ ])();
896
+ ;imageResizing = /*@__PURE__*/(function (imageResizing) {
897
+ imageResizing.resizeCommand = (by, relative = false) => wg => {
898
+ let { selection } = wg.state;
899
+ if (selection instanceof GardSelection.Node && wg.state.schema.markAllowed(ImageSize, selection.node.type)) {
900
+ let curWidth = selection.node.mark(ImageSize) ?? imageNode(wg, wg.state.selection.from).getBoundingClientRect().width;
901
+ let newWidth = Math.max(MIN_SIZE, relative ? curWidth * by : curWidth + by);
902
+ if (newWidth != curWidth) {
903
+ wg.dispatch({
904
+ changes: { from: wg.state.selection.from, add: ImageSize.of(newWidth) },
905
+ userEvent: "image.resize"
906
+ });
907
+ return true;
908
+ }
909
+ }
910
+ return false;
911
+ };
912
+ imageResizing.keyBindings = [
913
+ KeyBinding.of({ key: "Ctrl-Alt-l", mac: "Ctrl-Cmd-l", run: imageResizing.resizeCommand(1.1, true) }),
914
+ KeyBinding.of({ key: "Ctrl-Alt-k", mac: "Ctrl-Cmd-k", run: imageResizing.resizeCommand(0.9091, true) }),
915
+ ];
916
+ imageResizing.dragHandle = [
917
+ GardState.prec.high(resizeHandlers),
918
+ resizeState,
919
+ Decoration.Point.source.of(s => s.field(resizeState).deco),
920
+ resizeTheme
921
+ ];
922
+ ;return imageResizing})(imageResizing);
923
+ ;image = /*@__PURE__*/(function (image) {
924
+ image.keyBinding = KeyBinding.of({ key: "Ctrl-Alt-i", mac: "Ctrl-Cmd-i", run: insertImage });
925
+ image.button = Menu.Button.define({
926
+ run: insertImage,
927
+ active: state => !!activeImage(state.sel),
928
+ label: {
929
+ icon: "M38 34a9 9 0 1 1-19 0 9 9 0 0 1 19 0M9 13A9 9 0 0 0 0 22v56A9 9 0 0 0 9 88h81a9 9 0 0 0 9-9v-56A9 9 0 0 0 91 13zm81 6a3 3 0 0 1 3 3v38l-24-12a3 3 0 0 0-4 1l-23 23-17-11a3 3 0 0 0-4 0L6 75v3L6 78v-56a3 3 0 0 1 3-3z"
930
+ },
931
+ description: imagePhrases.ref("insert_image"),
932
+ enable: s => !s.readOnly,
933
+ parent: Menu.Group.insert,
934
+ rank: 30,
935
+ });
936
+ image.dropHandler = GardState.prec.lowest(Wordgard.domEventHandler("drop", (event, wg) => {
937
+ let { state } = wg, upload = state.facet(imageUploader)[0];
938
+ const type = state.schema.has(Image) ? Image : state.schema.has(Figure) ? Figure : null;
939
+ if (state.readOnly || !type || !upload || !event.dataTransfer)
940
+ return false;
941
+ let files = event.dataTransfer.files, uploads = [];
942
+ for (let i = 0; i < files.length; i++) {
943
+ let file = files[i];
944
+ if (/^image\//.test(file.type))
945
+ uploads.push(upload(file, wg, () => { }));
946
+ }
947
+ if (!uploads.length)
948
+ return false;
949
+ let dropPos = { x: event.clientX, y: event.clientY };
950
+ Promise.all(uploads).then(urls => {
951
+ wg.dispatch({
952
+ changes: { from: wg.posAtCoords(dropPos).pos, insert: urls.map(u => type.of(u)), fit: true },
953
+ userEvent: "drop.image"
954
+ });
955
+ }, err => {
956
+ Wordgard.logException(state, err, "Dropped image upload");
957
+ });
958
+ return true;
959
+ }));
960
+ image.insert = insertImage;
961
+ image.uploader = imageUploader;
962
+ ;return image})(image);
963
+
964
+ function setColor(wg, mark, value) {
965
+ let { state } = wg, { selection } = state;
966
+ if (state.readOnly)
967
+ return;
968
+ if (selection instanceof GardSelection.Text && selection.empty) {
969
+ let selMarks = selection.marks || state.sel.head.marks();
970
+ let newMarks = value ? mark.of(value).addToSet(selMarks) : mark.removeFromSet(selMarks);
971
+ wg.dispatch({
972
+ selection: GardSelection.Text.create({ anchor: selection.anchor, headSide: selection.headSide,
973
+ goalColumn: selection.goalColumn, marks: newMarks }),
974
+ userEvent: value ? "mark.add" : "mark.remove"
975
+ });
976
+ }
977
+ else if (value) {
978
+ wg.dispatch({
979
+ changes: selection.ranges.map(r => ({ from: r.from, to: r.to, add: mark.of(value) })),
980
+ userEvent: "mark.add"
981
+ });
982
+ }
983
+ else {
984
+ let changes = [];
985
+ for (let { from, to } of selection.ranges) {
986
+ state.doc.iterate(from, to, (node, pos) => {
987
+ let has = mark.isInSet(node.marks);
988
+ if (has)
989
+ changes.push({ from: Math.max(from, pos), to: Math.min(to, pos + node.length), remove: has });
990
+ });
991
+ }
992
+ wg.dispatch({ changes, userEvent: "mark.remove" });
993
+ }
994
+ }
995
+ class ColorPicker {
996
+ wg;
997
+ finish;
998
+ dom;
999
+ width;
1000
+ selPos = 0;
1001
+ options;
1002
+ constructor(
1003
+ wg,
1004
+ finish) {
1005
+ this.wg = wg;
1006
+ this.finish = finish;
1007
+ this.width = wg.state.facet(ColorPicker.width);
1008
+ this.dom = document.createElement("wg-color-picker");
1009
+ this.dom.role = "listbox";
1010
+ this.dom.style.gridTemplateColumns = `repeat(${this.width}, max-content)`;
1011
+ this.options = wg.state.facet(ColorPicker.options).map(({ name, detail, value }, i) => {
1012
+ let option = this.dom.appendChild(document.createElement("wg-color-picker-color"));
1013
+ let label = name(wg.state);
1014
+ if (detail)
1015
+ label += ` (${detail(wg.state)})`;
1016
+ option.role = "option";
1017
+ option.setAttribute("aria-label", label);
1018
+ option.title = label;
1019
+ if (i == this.selPos)
1020
+ option.setAttribute("aria-selected", "true");
1021
+ if (value)
1022
+ option.style.backgroundColor = value;
1023
+ else
1024
+ option.className = "wg-no-color";
1025
+ option.setAttribute("data-value", value);
1026
+ return option;
1027
+ });
1028
+ this.dom.addEventListener("mousedown", e => {
1029
+ if (e.button == 0) {
1030
+ let target = e.target.closest("wg-color-picker-color");
1031
+ if (target)
1032
+ this.finish(target.getAttribute("data-value"));
1033
+ }
1034
+ });
1035
+ this.dom.addEventListener("keydown", e => {
1036
+ let ltr = this.wg.state.textLTR;
1037
+ if (e.key == (ltr ? "ArrowLeft" : "ArrowRight") && this.selPos > 0) {
1038
+ this.move(this.selPos - 1);
1039
+ }
1040
+ else if (e.key == (ltr ? "ArrowRight" : "ArrowLeft") && this.selPos < this.options.length - 1) {
1041
+ this.move(this.selPos + 1);
1042
+ }
1043
+ else if (e.key == "ArrowUp" || e.key == "ArrowDown") {
1044
+ let next = e.key == "ArrowUp" ? this.selPos - this.width : this.selPos + this.width;
1045
+ if (next < 0 || next >= this.options.length - 1) {
1046
+ let col = this.selPos % this.width;
1047
+ if (next < 0)
1048
+ next = (Math.ceil(this.options.length / this.width) - 1) * this.width + col - 1;
1049
+ else
1050
+ next = col + 1;
1051
+ }
1052
+ this.move(Math.max(0, Math.min(this.options.length - 1, next)));
1053
+ }
1054
+ else if (e.key == " " || e.key == "Enter") {
1055
+ this.finish(this.options[this.selPos].getAttribute("data-value"));
1056
+ }
1057
+ else {
1058
+ return;
1059
+ }
1060
+ e.preventDefault();
1061
+ });
1062
+ }
1063
+ static create(wg, finish) {
1064
+ return new ColorPicker(wg, finish);
1065
+ }
1066
+ move(selPos) {
1067
+ if (selPos != this.selPos) {
1068
+ let prev = this.options[this.selPos];
1069
+ let cur = this.options[this.selPos = selPos];
1070
+ prev.removeAttribute("aria-selected");
1071
+ cur.setAttribute("aria-selected", "true");
1072
+ }
1073
+ }
1074
+ }
1075
+ ;ColorPicker = /*@__PURE__*/(function (ColorPicker) {
1076
+ function col(rgb, name, mod) {
1077
+ let detail = mod == 3 ? colorNames.ref("lightest") : mod == 2 ? colorNames.ref("lighter") :
1078
+ mod == 1 ? colorNames.ref("light") : mod == -1 ? colorNames.ref("dark") :
1079
+ mod == -2 ? colorNames.ref("darker") : mod ? colorNames.ref("darkest") : undefined;
1080
+ return { name: colorNames.ref(name), detail, value: rgb };
1081
+ }
1082
+ function defaultColors() {
1083
+ return [
1084
+ col("", "none"),
1085
+ col("#000000", "black"),
1086
+ col("#434343", "grey", -3),
1087
+ col("#666666", "grey", -2),
1088
+ col("#999999", "grey", -1),
1089
+ col("#cccccc", "grey"),
1090
+ col("#d9d9d9", "grey", 1),
1091
+ col("#efefef", "grey", 2),
1092
+ col("#f3f3f3", "grey", 3),
1093
+ col("#ffffff", "white"),
1094
+ col("#980000", "red_berry"),
1095
+ col("#ff0000", "red"),
1096
+ col("#ff9900", "orange"),
1097
+ col("#ffff00", "yellow"),
1098
+ col("#00ff00", "green"),
1099
+ col("#00ffff", "cyan"),
1100
+ col("#4a86e8", "cornflower"),
1101
+ col("#0000ff", "blue"),
1102
+ col("#9900ff", "purple"),
1103
+ col("#ff00ff", "magenta"),
1104
+ col("#e6b8af", "red_berry", 3),
1105
+ col("#f4cccc", "red", 3),
1106
+ col("#fce5cd", "orange", 3),
1107
+ col("#fff2cc", "yellow", 3),
1108
+ col("#d9ead3", "green", 3),
1109
+ col("#d0e0e3", "cyan", 3),
1110
+ col("#c9daf8", "cornflower", 3),
1111
+ col("#cfe2f3", "blue", 3),
1112
+ col("#d9d2e9", "purple", 3),
1113
+ col("#ead1dc", "magenta", 3),
1114
+ col("#dd7e6b", "red_berry", 2),
1115
+ col("#ea9999", "red", 2),
1116
+ col("#f9cb9c", "orange", 2),
1117
+ col("#ffe599", "yellow", 2),
1118
+ col("#b6d7a8", "green", 2),
1119
+ col("#a2c4c9", "cyan", 2),
1120
+ col("#a4c2f4", "cornflower", 2),
1121
+ col("#9fc5e8", "blue", 2),
1122
+ col("#b4a7d6", "purple", 2),
1123
+ col("#d5a6bd", "magenta", 2),
1124
+ col("#cc4125", "red_berry", 1),
1125
+ col("#e06666", "red", 1),
1126
+ col("#f6b26b", "orange", 1),
1127
+ col("#ffd966", "yellow", 1),
1128
+ col("#93c47d", "green", 1),
1129
+ col("#76a5af", "cyan", 1),
1130
+ col("#6d9eeb", "cornflower", 1),
1131
+ col("#6fa8dc", "blue", 1),
1132
+ col("#8e7cc3", "purple", 1),
1133
+ col("#c27ba0", "magenta", 1),
1134
+ col("#a61c00", "red_berry", -1),
1135
+ col("#cc0000", "red", -1),
1136
+ col("#e69138", "orange", -1),
1137
+ col("#f1c232", "yellow", -1),
1138
+ col("#6aa84f", "green", -1),
1139
+ col("#45818e", "cyan", -1),
1140
+ col("#3c78d8", "cornflower", -1),
1141
+ col("#3d85c6", "blue", -1),
1142
+ col("#674ea7", "purple", -1),
1143
+ col("#a64d79", "magenta", -1),
1144
+ col("#85200c", "red_berry", -2),
1145
+ col("#990000", "red", -2),
1146
+ col("#b45f06", "orange", -2),
1147
+ col("#bf9000", "yellow", -2),
1148
+ col("#38761d", "green", -2),
1149
+ col("#134f5c", "cyan", -2),
1150
+ col("#1155cc", "cornflower", -2),
1151
+ col("#0b5394", "blue", -2),
1152
+ col("#351c75", "purple", -2),
1153
+ col("#741b47", "magenta", -2),
1154
+ col("#5b0f00", "red_berry", -3),
1155
+ col("#660000", "red", -3),
1156
+ col("#783f04", "orange", -3),
1157
+ col("#7f6000", "yellow", -3),
1158
+ col("#274e13", "green", -3),
1159
+ col("#0c343d", "cyan", -3),
1160
+ col("#1c4587", "cornflower", -3),
1161
+ col("#073763", "blue", -3),
1162
+ col("#20124d", "purple", -3),
1163
+ col("#4c1130", "magenta", -3),
1164
+ ];
1165
+ }
1166
+ ColorPicker.width = GardState.Facet.define({
1167
+ combine: values => values.length ? values[0] : 10
1168
+ });
1169
+ ColorPicker.options = GardState.Facet.define({
1170
+ combine: values => values.length ? values[0] : defaultColors()
1171
+ });
1172
+ ColorPicker.theme = Wordgard.styles({
1173
+ "wg-color-picker": {
1174
+ display: "grid",
1175
+ gap: "4px",
1176
+ padding: "3px",
1177
+ },
1178
+ "wg-color-picker-color": {
1179
+ borderRadius: "50%",
1180
+ border: "1px solid var(--wg-border-color)",
1181
+ width: "12px",
1182
+ height: "12px",
1183
+ "wg-color-picker:focus &[aria-selected], &:hover": {
1184
+ outline: "2px solid var(--wg-highlight-color)"
1185
+ },
1186
+ "&.wg-no-color": {
1187
+ border: "none",
1188
+ background: `${crossGradient(45)}, ${crossGradient(135)}`
1189
+ }
1190
+ },
1191
+ });
1192
+ ;return ColorPicker})(ColorPicker);
1193
+ function crossGradient(angle) {
1194
+ return `linear-gradient(${angle}deg, transparent, transparent 44%, currentColor 44%, currentColor 56%, transparent 56%)`;
1195
+ }
1196
+ const colorPicker = /*@__PURE__*/Menu.CustomControl.define({
1197
+ render(wg, done) {
1198
+ return ColorPicker.create(wg, color => {
1199
+ done();
1200
+ setColor(wg, Color, color);
1201
+ wg.focus();
1202
+ });
1203
+ }
1204
+ });
1205
+ function color() {
1206
+ return [GardState.schemaElement.of(Color), color.button, ColorPicker.theme];
1207
+ }
1208
+ ;color = /*@__PURE__*/(function (color) {
1209
+ color.button = Menu.Submenu.define({
1210
+ label: {
1211
+ icon: "M5 8A3 3 0 0 1 8 5h28a3 3 0 0 1 3 3v30l23-23a3 3 0 0 1 4 0l20 20a3 3 0 0 1 0 4L63 61H92a3 3 0 0 1 3 3v28a3 3 0 0 1-3 3H22a17 17 0 0 1-12-5A17 17 0 0 1 5 78m34-1 41-41-16-16L39 45zM30 78a8 8 0 1 0-17 0 8 8 0 0 0 17 0M89 89v-22H57l-23 23zM5 8v70zm0 70V78z",
1212
+ },
1213
+ description: phrases.ref("text_color"),
1214
+ arrow: false,
1215
+ parent: Menu.Group.inline,
1216
+ enable: s => !s.readOnly,
1217
+ rank: 80,
1218
+ content: [colorPicker]
1219
+ });
1220
+ ;return color})(color);
1221
+ function backgroundColor() {
1222
+ return [GardState.schemaElement.of(BackgroundColor), backgroundColor.button, ColorPicker.theme];
1223
+ }
1224
+ const backgroundPicker = /*@__PURE__*/Menu.CustomControl.define({
1225
+ render(wg, done) {
1226
+ return ColorPicker.create(wg, color => {
1227
+ done();
1228
+ setColor(wg, BackgroundColor, color);
1229
+ wg.focus();
1230
+ });
1231
+ }
1232
+ });
1233
+ ;backgroundColor = /*@__PURE__*/(function (backgroundColor) {
1234
+ backgroundColor.button = Menu.Submenu.define({
1235
+ label: {
1236
+ icon: "M67 9a11 11 0 0 1 16 0l8 8a11 11 0 0 1 0 16l-2 2-45 51a3 3 0 0 1-2 1h-17a3 3 0 0 1-1 0l-2 2A3 3 0 0 1 19 89h-11a3 3 0 0 1-2-5l8-8A3 3 0 0 1 13 75v-17a3 3 0 0 1 1-2l51-45zm-1 8L20 59l21 21 42-46zm20 12 0 0a6 6 0 0 0 0-8L79 13a6 6 0 0 0-8 0l0 0zM35 81 19 65v9L26 81z"
1237
+ },
1238
+ description: phrases.ref("background_color"),
1239
+ arrow: false,
1240
+ parent: Menu.Group.inline,
1241
+ enable: s => !s.readOnly,
1242
+ rank: 85,
1243
+ content: [backgroundPicker]
1244
+ });
1245
+ ;return backgroundColor})(backgroundColor);
1246
+
1247
+ function toggleLink(wg) {
1248
+ if (wg.state.readOnly)
1249
+ return false;
1250
+ let open = Dialog.get(wg, "wg-link-dialog");
1251
+ if (open) {
1252
+ if (open.dom.contains(wg.contentDOM.ownerDocument.activeElement))
1253
+ wg.focus();
1254
+ Dialog.close(wg, "wg-link-dialog");
1255
+ return true;
1256
+ }
1257
+ let { selection, doc } = wg.state;
1258
+ if (selection.empty)
1259
+ return false;
1260
+ let remove = [];
1261
+ for (let { from, to } of selection.ranges)
1262
+ doc.iterate(from, to, (node, pos) => {
1263
+ let has = Link.isInSet(node.marks);
1264
+ if (has)
1265
+ remove.push({ from: pos, to: pos + node.length, remove: has });
1266
+ });
1267
+ if (remove.length) {
1268
+ wg.dispatch({ changes: remove, userEvent: "mark.remove" });
1269
+ }
1270
+ else {
1271
+ Dialog.show(wg, {
1272
+ label: phrases.get(wg.state, "link_target"),
1273
+ input: { type: "text", name: "url" },
1274
+ submitLabel: phrases.get(wg.state, "create_link"),
1275
+ class: "wg-link-dialog",
1276
+ focus: true
1277
+ }).result.then(form => {
1278
+ wg.focus();
1279
+ let url = form && form.elements.namedItem("url")?.value;
1280
+ if (url)
1281
+ wg.dispatch({
1282
+ changes: wg.state.selection.ranges.map(r => ({ from: r.from, to: r.to, add: Link.of(url) })),
1283
+ userEvent: "mark.add"
1284
+ });
1285
+ });
1286
+ }
1287
+ return true;
1288
+ }
1289
+ function computeLinkTooltip(state) {
1290
+ if (!state.selection.isCursor)
1291
+ return null;
1292
+ let { head } = state.sel, before = head.nodeBefore, link = before && Link.isInSet(before.marks);
1293
+ if (!link || head.matchingParent(plot => state.isAtom(plot.type)))
1294
+ return null;
1295
+ let start = head.pos - before.length, end = head.pos, siblings = head.parent.node.content;
1296
+ for (let index = head.index - 1; index > 0 && link.isInSet(siblings[index - 1].marks);)
1297
+ start -= siblings[--index].length;
1298
+ for (let index = head.index; index < siblings.length && link.isInSet(siblings[index].marks);)
1299
+ end += siblings[index++].length;
1300
+ return {
1301
+ pos: start,
1302
+ end,
1303
+ above: false,
1304
+ create: () => renderLinkTooltip(link.value)
1305
+ };
1306
+ }
1307
+ const closeLinkTooltip = /*@__PURE__*/Transaction.Effect.define();
1308
+ const linkTooltipField = /*@__PURE__*/GardState.Field.define({
1309
+ create: computeLinkTooltip,
1310
+ update(value, tr) {
1311
+ if (tr.effects.some(e => e.is(closeLinkTooltip)))
1312
+ return null;
1313
+ let sel = tr.selection;
1314
+ if (!tr.docChanged && (!sel || value && sel.isCursor && sel.head >= value.pos && sel.head <= value.end))
1315
+ return value;
1316
+ return computeLinkTooltip(tr.state);
1317
+ },
1318
+ provide: f => Tooltip.show.from(f)
1319
+ });
1320
+ function renderLinkTooltip(target) {
1321
+ let dom = document.createElement("wg-link-tooltip");
1322
+ let link = dom.appendChild(document.createElement("a"));
1323
+ link.href = target;
1324
+ link.textContent = target;
1325
+ return { dom };
1326
+ }
1327
+ const linkTooltipTheme = /*@__PURE__*/Wordgard.styles({
1328
+ "wg-link-tooltip": {
1329
+ maxWidth: "30em",
1330
+ fontSize: "90%",
1331
+ textOverflow: "ellipsis",
1332
+ whiteSpace: "pre",
1333
+ overflow: "hidden",
1334
+ borderRadius: "3px",
1335
+ padding: "2px 5px",
1336
+ marginTop: "1px",
1337
+ "& a": {
1338
+ textDecoration: "none",
1339
+ color: "inherit"
1340
+ }
1341
+ }
1342
+ });
1343
+ function link() {
1344
+ return [GardState.schemaElement.of(Link), link.button, link.keyBinding, link.tooltip, link.pasteOver];
1345
+ }
1346
+ ;link = /*@__PURE__*/(function (link_1) {
1347
+ link_1.keyBinding = KeyBinding.of({
1348
+ key: "Mod-k",
1349
+ run: toggleLink,
1350
+ });
1351
+ link_1.button = Menu.Button.define({
1352
+ run: toggleLink,
1353
+ active(state) {
1354
+ let { selection, doc } = state, found = false;
1355
+ if (!selection.empty)
1356
+ for (let { from, to } of selection.ranges)
1357
+ doc.iterate(from, to, node => {
1358
+ if (found)
1359
+ return false;
1360
+ if (Link.isInSet(node.marks))
1361
+ found = true;
1362
+ });
1363
+ return found;
1364
+ },
1365
+ enable(state) {
1366
+ return !state.readOnly && !state.selection.empty;
1367
+ },
1368
+ label: {
1369
+ icon: "M29 41 21 49a19 19 0 1 0 27 27l11-11A19 19 0 0 0 54 34L50 38a6 6 0 0 0-1 1 13 13 0 0 1 5 22L43 72a12 12 0 1 1-18-18l5-5a25 25 0 0 1-1-8zM41 29A19 19 0 0 0 46 59l5-5a13 13 0 0 1-6-21L57 22a12 12 0 1 1 18 18l-5 5c1 3 1 5 1 8l9-9a19 19 0 1 0-27-27z"
1370
+ },
1371
+ description: phrases.ref("create_link"),
1372
+ parent: Menu.Group.inline,
1373
+ rank: 50,
1374
+ });
1375
+ link_1.tooltip = [
1376
+ linkTooltipField,
1377
+ GardState.prec.low(KeyBinding.of({
1378
+ key: "Escape",
1379
+ run: wg => {
1380
+ if (!wg.state.field(linkTooltipField))
1381
+ return false;
1382
+ wg.dispatch({ effects: closeLinkTooltip.of(null) });
1383
+ return true;
1384
+ }
1385
+ })),
1386
+ linkTooltipTheme
1387
+ ];
1388
+ link_1.pasteOver = Wordgard.pasteHandler.of((wg, event) => {
1389
+ let { selection } = wg.state, data = event.clipboardData;
1390
+ if (!data || selection.empty)
1391
+ return false;
1392
+ let text = data.getData("text/plain") || data.getData("Text") || data.getData("text/uri-list");
1393
+ if (!text || !/^(https?|mailto|xmpp|data):[^ ]+$/.test(text))
1394
+ return false;
1395
+ let link = Link.of(text);
1396
+ let changes = ChangeSet.create(wg.state.doc, { from: selection.from, to: selection.to, add: link });
1397
+ if (changes.empty)
1398
+ return false;
1399
+ wg.dispatch({
1400
+ changes,
1401
+ userEvent: "paste.link",
1402
+ scrollIntoView: true
1403
+ });
1404
+ return true;
1405
+ });
1406
+ ;return link})(link);
1407
+
1408
+ function lineBreak() {
1409
+ return GardState.schemaElement.of(LineBreak);
1410
+ }
1411
+ function basicMarks() {
1412
+ return [strong(), emphasis(), link()];
1413
+ }
1414
+ function inlineMarks() {
1415
+ return [basicMarks(), code(), underline(), strikethrough(), superscript(), subscript(), color(), backgroundColor()];
1416
+ }
1417
+ function basicSchema() {
1418
+ return [blockDoc(), basicMarks(), paragraph(), heading(), lineBreak()];
1419
+ }
1420
+ function inlineSchema() {
1421
+ return [inlineDoc(), basicMarks(), image(), lineBreak()];
1422
+ }
1423
+ function fullSchema() {
1424
+ return [
1425
+ blockDoc(), paragraph(), heading(), lineBreak(),
1426
+ codeBlock(), alignment(), direction(), blockquote(), horizontalRule(),
1427
+ bulletList(), orderedList(),
1428
+ inlineMarks(), image(), figure(), imageResizing()
1429
+ ];
1430
+ }
1431
+
1432
+ export { ColorPicker, alignment, backgroundColor, basicMarks, basicSchema, blockDoc, blockquote, bulletList, code, codeBlock, color, direction, emphasis, figure, fullSchema, heading, horizontalRule, image, imageResizing, inlineDoc, inlineMarks, inlineSchema, lineBreak, link, orderedList, paragraph, strikethrough, strong, subscript, superscript, underline };