@fastkit/vui-wysiwyg 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/pm/changeset.d.ts +1 -0
  4. package/dist/pm/changeset.mjs +3 -0
  5. package/dist/pm/changeset.mjs.map +1 -0
  6. package/dist/pm/collab.d.ts +1 -0
  7. package/dist/pm/collab.mjs +3 -0
  8. package/dist/pm/collab.mjs.map +1 -0
  9. package/dist/pm/commands.d.ts +1 -0
  10. package/dist/pm/commands.mjs +3 -0
  11. package/dist/pm/commands.mjs.map +1 -0
  12. package/dist/pm/dropcursor.d.ts +1 -0
  13. package/dist/pm/dropcursor.mjs +3 -0
  14. package/dist/pm/dropcursor.mjs.map +1 -0
  15. package/dist/pm/gapcursor.d.ts +1 -0
  16. package/dist/pm/gapcursor.mjs +3 -0
  17. package/dist/pm/gapcursor.mjs.map +1 -0
  18. package/dist/pm/history.d.ts +1 -0
  19. package/dist/pm/history.mjs +3 -0
  20. package/dist/pm/history.mjs.map +1 -0
  21. package/dist/pm/inputrules.d.ts +1 -0
  22. package/dist/pm/inputrules.mjs +3 -0
  23. package/dist/pm/inputrules.mjs.map +1 -0
  24. package/dist/pm/keymap.d.ts +1 -0
  25. package/dist/pm/keymap.mjs +3 -0
  26. package/dist/pm/keymap.mjs.map +1 -0
  27. package/dist/pm/markdown.d.ts +1 -0
  28. package/dist/pm/markdown.mjs +3 -0
  29. package/dist/pm/markdown.mjs.map +1 -0
  30. package/dist/pm/menu.d.ts +1 -0
  31. package/dist/pm/menu.mjs +3 -0
  32. package/dist/pm/menu.mjs.map +1 -0
  33. package/dist/pm/model.d.ts +1 -0
  34. package/dist/pm/model.mjs +3 -0
  35. package/dist/pm/model.mjs.map +1 -0
  36. package/dist/pm/schema-basic.d.ts +1 -0
  37. package/dist/pm/schema-basic.mjs +3 -0
  38. package/dist/pm/schema-basic.mjs.map +1 -0
  39. package/dist/pm/schema-list.d.ts +1 -0
  40. package/dist/pm/schema-list.mjs +3 -0
  41. package/dist/pm/schema-list.mjs.map +1 -0
  42. package/dist/pm/state.d.ts +1 -0
  43. package/dist/pm/state.mjs +3 -0
  44. package/dist/pm/state.mjs.map +1 -0
  45. package/dist/pm/tables.d.ts +1 -0
  46. package/dist/pm/tables.mjs +3 -0
  47. package/dist/pm/tables.mjs.map +1 -0
  48. package/dist/pm/trailing-node.d.ts +1 -0
  49. package/dist/pm/trailing-node.mjs +3 -0
  50. package/dist/pm/trailing-node.mjs.map +1 -0
  51. package/dist/pm/transform.d.ts +1 -0
  52. package/dist/pm/transform.mjs +3 -0
  53. package/dist/pm/transform.mjs.map +1 -0
  54. package/dist/pm/view.d.ts +1 -0
  55. package/dist/pm/view.mjs +3 -0
  56. package/dist/pm/view.mjs.map +1 -0
  57. package/dist/tiptap/core.d.ts +1 -0
  58. package/dist/tiptap/core.mjs +3 -0
  59. package/dist/tiptap/core.mjs.map +1 -0
  60. package/dist/tiptap/extensions/bold.d.ts +1 -0
  61. package/dist/tiptap/extensions/bold.mjs +3 -0
  62. package/dist/tiptap/extensions/bold.mjs.map +1 -0
  63. package/dist/tiptap/extensions/bullet-list.d.ts +1 -0
  64. package/dist/tiptap/extensions/bullet-list.mjs +3 -0
  65. package/dist/tiptap/extensions/bullet-list.mjs.map +1 -0
  66. package/dist/tiptap/extensions/history.d.ts +1 -0
  67. package/dist/tiptap/extensions/history.mjs +3 -0
  68. package/dist/tiptap/extensions/history.mjs.map +1 -0
  69. package/dist/tiptap/extensions/italic.d.ts +1 -0
  70. package/dist/tiptap/extensions/italic.mjs +3 -0
  71. package/dist/tiptap/extensions/italic.mjs.map +1 -0
  72. package/dist/tiptap/extensions/link.d.ts +1 -0
  73. package/dist/tiptap/extensions/link.mjs +3 -0
  74. package/dist/tiptap/extensions/link.mjs.map +1 -0
  75. package/dist/tiptap/extensions/ordered-list.d.ts +1 -0
  76. package/dist/tiptap/extensions/ordered-list.mjs +3 -0
  77. package/dist/tiptap/extensions/ordered-list.mjs.map +1 -0
  78. package/dist/tiptap/extensions/text-style.d.ts +1 -0
  79. package/dist/tiptap/extensions/text-style.mjs +3 -0
  80. package/dist/tiptap/extensions/text-style.mjs.map +1 -0
  81. package/dist/tiptap/extensions/underline.d.ts +1 -0
  82. package/dist/tiptap/extensions/underline.mjs +3 -0
  83. package/dist/tiptap/extensions/underline.mjs.map +1 -0
  84. package/dist/vui-wysiwyg.css +271 -0
  85. package/dist/vui-wysiwyg.css.map +1 -0
  86. package/dist/vui-wysiwyg.d.ts +415 -0
  87. package/dist/vui-wysiwyg.mjs +924 -0
  88. package/dist/vui-wysiwyg.mjs.map +1 -0
  89. package/package.json +312 -0
@@ -0,0 +1,924 @@
1
+ import { defineComponent, ref, computed, watch, onBeforeUnmount, createVNode, mergeProps, createTextVNode, isVNode } from 'vue';
2
+ import { Extension, useEditor, EditorContent, BubbleMenu } from '@tiptap/vue-3';
3
+ import { Decoration, DecorationSet } from '@tiptap/pm/view';
4
+ import { Plugin, PluginKey, TextSelection } from '@tiptap/pm/state';
5
+ import TextStyle from '@tiptap/extension-text-style';
6
+ import { BulletList } from '@tiptap/extension-bullet-list';
7
+ import { Bold } from '@tiptap/extension-bold';
8
+ import { Italic } from '@tiptap/extension-italic';
9
+ import { Underline } from '@tiptap/extension-underline';
10
+ import { History } from '@tiptap/extension-history';
11
+ import { Link } from '@tiptap/extension-link';
12
+ import { createTextableProps, createFormControlProps, createControlFieldProps, createControlFieldProviderProps, createControlProps, defineSlotsProps, createTextableEmits, useVui, useControl, useControlField, TextableControl, VFormControl, VControlField, VTextCounter, validateIf, url, VButtonGroup, VButton, VIcon } from '@fastkit/vui';
13
+ import { OrderedList } from '@tiptap/extension-ordered-list';
14
+ import { StarterKit } from '@tiptap/starter-kit';
15
+
16
+ // src/schemes.ts
17
+ var EDITOR_EVENTS = [
18
+ "beforeCreate",
19
+ "create",
20
+ "update",
21
+ "selectionUpdate",
22
+ "transaction",
23
+ "focus",
24
+ "blur",
25
+ "destroy"
26
+ ];
27
+ var prefixedEventName = (source) => {
28
+ return `on${source.charAt(0).toUpperCase()}${source.slice(1)}`;
29
+ };
30
+ var WysiwygEditorInitializeContext = class {
31
+ listeners = {};
32
+ _vui;
33
+ get vui() {
34
+ return this._vui();
35
+ }
36
+ constructor(vuiGetter, opts = {}) {
37
+ this._vui = vuiGetter;
38
+ EDITOR_EVENTS.forEach((event) => {
39
+ this.listeners[event] = [];
40
+ const prefixed = prefixedEventName(event);
41
+ const fn = opts[prefixed];
42
+ fn && this.listeners[event].push(fn);
43
+ });
44
+ }
45
+ on(ev, handler) {
46
+ this.listeners[ev].push(handler);
47
+ return () => this.off(ev, handler);
48
+ }
49
+ off(ev, handler) {
50
+ this.listeners[ev] = this.listeners[ev].filter(
51
+ (_handler) => _handler !== handler
52
+ );
53
+ }
54
+ editorOptions() {
55
+ const opts = {};
56
+ EDITOR_EVENTS.forEach((event) => {
57
+ const prefixed = prefixedEventName(event);
58
+ opts[prefixed] = (props) => {
59
+ const handlers = this.listeners[event];
60
+ handlers.forEach((handler) => {
61
+ handler(props);
62
+ });
63
+ };
64
+ });
65
+ return opts;
66
+ }
67
+ };
68
+ function isCreatedWysiwygExtension(source) {
69
+ return !!source && typeof source === "object" && source.__isCreatedWysiwygExtension === true;
70
+ }
71
+ function createWysiwygExtension(extension) {
72
+ const ext = {
73
+ __isCreatedWysiwygExtension: true,
74
+ _configs: [],
75
+ configure: (opts) => {
76
+ opts && ext._configs.push(opts);
77
+ return ext;
78
+ },
79
+ raw: extension
80
+ };
81
+ return ext;
82
+ }
83
+ function resolveRawWysiwygExtension(raw, ctx) {
84
+ if (isCreatedWysiwygExtension(raw)) {
85
+ const { raw: _raw, _configs } = raw;
86
+ let ext = typeof _raw === "function" ? _raw(ctx) : _raw;
87
+ _configs.forEach((config) => {
88
+ ext = ext.configure(config);
89
+ });
90
+ return ext;
91
+ }
92
+ return typeof raw === "function" ? raw(ctx) : raw;
93
+ }
94
+ function resolveRawWysiwygExtensions(raws, ctx) {
95
+ return raws.map((raw) => resolveRawWysiwygExtension(raw, ctx));
96
+ }
97
+ function resolveRawWysiwygEditorTool(raw, vui) {
98
+ return typeof raw === "function" ? raw(vui) : raw;
99
+ }
100
+ function resolveRawWysiwygEditorTools(rawTools, vui) {
101
+ const tools = [];
102
+ const extensions = [];
103
+ rawTools.forEach((raw) => {
104
+ let resolved = resolveRawWysiwygEditorTool(raw, vui);
105
+ if (!Array.isArray(resolved)) {
106
+ resolved = [resolved];
107
+ }
108
+ resolved.forEach((tool) => {
109
+ tools.push(tool);
110
+ if (tool.extensions) {
111
+ extensions.push(...tool.extensions);
112
+ }
113
+ });
114
+ });
115
+ return {
116
+ tools,
117
+ extensions
118
+ };
119
+ }
120
+
121
+ // src/injections.ts
122
+ var VUI_WYSIWYG_EDITOR_SYMBOL = "vui-wysiwyg-editor";
123
+ var PROBLEM_CLASS_NAME = "v-linter__problem";
124
+ var ISSUE_ICON_CLASS_NAME = "v-linter__issue-icon";
125
+ var ISSUE_DATASET_NAME = "data-issue-id";
126
+ function resolveWysiwygLinterFixMessage(message) {
127
+ return typeof message === "function" ? message() : message;
128
+ }
129
+ function renderIcon(view, issue) {
130
+ const {
131
+ level = "warning"
132
+ } = issue;
133
+ const icon = document.createElement("div");
134
+ const message = resolveWysiwygLinterFixMessage(issue.message);
135
+ icon.className = `${ISSUE_ICON_CLASS_NAME} ${level}-scope`;
136
+ icon.setAttribute(ISSUE_DATASET_NAME, issue.id);
137
+ if (typeof message === "string") {
138
+ icon.title = message;
139
+ }
140
+ return icon;
141
+ }
142
+ function runAllLinterPlugins(doc, plugins) {
143
+ const decorations = [];
144
+ const issues = plugins.map((RegisteredLinterPlugin) => {
145
+ return new RegisteredLinterPlugin(doc).scan().getResults();
146
+ }).flat();
147
+ issues.forEach((issue) => {
148
+ const {
149
+ level = "warning",
150
+ icon
151
+ } = issue;
152
+ const message = resolveWysiwygLinterFixMessage(issue.message);
153
+ decorations.push(Decoration.inline(issue.from, issue.to, {
154
+ class: `${PROBLEM_CLASS_NAME} ${level}-scope`,
155
+ "data-issue-id": issue.id,
156
+ title: typeof message === "string" ? message : void 0
157
+ }));
158
+ if (icon) {
159
+ decorations.push(Decoration.widget(issue.from, (view) => renderIcon(view, issue)));
160
+ }
161
+ });
162
+ const decorationSet = DecorationSet.create(doc, decorations);
163
+ return {
164
+ issues,
165
+ decorationSet
166
+ };
167
+ }
168
+ var WysiwygLinter = createWysiwygExtension((ctx) => {
169
+ function showMenu(view, issue, event) {
170
+ const message = resolveWysiwygLinterFixMessage(issue.message);
171
+ const variant = ctx.vui.setting("containedVariant");
172
+ const scope = ctx.vui.setting(`${issue.level}Scope`);
173
+ return ctx.vui.menu({
174
+ activator: event,
175
+ content: (stack) => createVNode("div", {
176
+ "class": "v-linter__issue-menu__body"
177
+ }, [createVNode("div", {
178
+ "class": ["v-linter__issue-menu__message", `${scope}-scope ${variant}`]
179
+ }, [message]), issue.fix.length && createVNode("div", {
180
+ "class": "v-linter__issue-menu__fixers"
181
+ }, [issue.fix.map((fixer, index) => createVNode("div", {
182
+ "key": index,
183
+ "class": "v-linter__issue-menu__fixer"
184
+ }, [createVNode("button", {
185
+ "type": "button",
186
+ "class": "v-linter__issue-menu__fixer__button",
187
+ "onClick": () => {
188
+ stack.close();
189
+ fixer.handler(view, issue);
190
+ }
191
+ }, [createVNode("span", {
192
+ "class": "v-linter__issue-menu__fixer__button__message"
193
+ }, [resolveWysiwygLinterFixMessage(fixer.message)])])]))])])
194
+ });
195
+ }
196
+ return Extension.create({
197
+ name: "linter",
198
+ addOptions() {
199
+ return {
200
+ plugins: []
201
+ };
202
+ },
203
+ addStorage() {
204
+ return {
205
+ issues: []
206
+ };
207
+ },
208
+ addProseMirrorPlugins() {
209
+ const {
210
+ plugins
211
+ } = this.options;
212
+ const {
213
+ storage
214
+ } = this;
215
+ const runAll = (doc) => {
216
+ const {
217
+ issues,
218
+ decorationSet
219
+ } = runAllLinterPlugins(doc, plugins);
220
+ storage.issues = issues;
221
+ return decorationSet;
222
+ };
223
+ const getIssue = (id) => storage.issues.find((issue) => issue.id === id);
224
+ const getIssueElementByEvent = (source) => {
225
+ if (!source || !(source instanceof HTMLElement)) {
226
+ return;
227
+ }
228
+ const issueId = source.getAttribute(ISSUE_DATASET_NAME);
229
+ const issue = issueId && getIssue(issueId);
230
+ if (!issue)
231
+ return;
232
+ return {
233
+ issue
234
+ };
235
+ };
236
+ const linterPlugin = new Plugin({
237
+ key: new PluginKey("linter"),
238
+ state: {
239
+ init(_, {
240
+ doc
241
+ }) {
242
+ return runAll(doc);
243
+ },
244
+ apply(transaction, oldState) {
245
+ return transaction.docChanged ? runAll(transaction.doc) : oldState;
246
+ }
247
+ },
248
+ props: {
249
+ decorations(state) {
250
+ return linterPlugin.getState(state);
251
+ },
252
+ handleClick(view, _, event) {
253
+ const info = getIssueElementByEvent(event.target);
254
+ if (!info) {
255
+ return false;
256
+ }
257
+ const {
258
+ issue
259
+ } = info;
260
+ const {
261
+ from,
262
+ to
263
+ } = issue;
264
+ const focus = () => view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, from, to)).scrollIntoView());
265
+ focus();
266
+ showMenu(view, issue, event);
267
+ return true;
268
+ }
269
+ }
270
+ });
271
+ return [linterPlugin];
272
+ }
273
+ });
274
+ });
275
+
276
+ // src/extensions/linter/utils.ts
277
+ var IDX = 256;
278
+ var BUFFER;
279
+ var HEX = [];
280
+ while (IDX--)
281
+ HEX[IDX] = (IDX + 256).toString(16).substring(1);
282
+ function cheepUUID() {
283
+ let i = 0, num, out = "";
284
+ if (!BUFFER || IDX + 16 > 256) {
285
+ BUFFER = Array(i = 256);
286
+ while (i--)
287
+ BUFFER[i] = 256 * Math.random() | 0;
288
+ i = IDX = 0;
289
+ }
290
+ for (; i < 16; i++) {
291
+ num = BUFFER[IDX + i];
292
+ if (i == 6)
293
+ out += HEX[num & 15 | 64];
294
+ else if (i == 8)
295
+ out += HEX[num & 63 | 128];
296
+ else
297
+ out += HEX[num];
298
+ if (i & 1 && i > 1 && i < 11)
299
+ out += "-";
300
+ }
301
+ IDX++;
302
+ return out;
303
+ }
304
+
305
+ // src/extensions/linter/LinterPlugin.ts
306
+ var WysiwygLinterPlugin = class {
307
+ doc;
308
+ results = [];
309
+ constructor(doc) {
310
+ this.doc = doc;
311
+ }
312
+ record(result) {
313
+ const { fix = [], icon = false } = result;
314
+ this.results.push({
315
+ level: "error",
316
+ id: cheepUUID(),
317
+ ...result,
318
+ fix: Array.isArray(fix) ? fix : [fix],
319
+ icon
320
+ });
321
+ }
322
+ scan() {
323
+ return this;
324
+ }
325
+ getResults() {
326
+ return this.results;
327
+ }
328
+ };
329
+ function WysiwygLinterBadWords(words) {
330
+ const regex = new RegExp(`\\b(${words.join("|")})\\b`);
331
+ return class WysiwygLinterBadWords extends WysiwygLinterPlugin {
332
+ scan() {
333
+ this.doc.descendants((node, position) => {
334
+ if (!node.isText) {
335
+ return;
336
+ }
337
+ const matches = regex.exec(node.text);
338
+ if (matches) {
339
+ const fixValue = matches[0] + "!!!!!";
340
+ this.record({
341
+ level: "warning",
342
+ message: `Try not to say '${matches[0]}'`,
343
+ from: position + matches.index,
344
+ to: position + matches.index + matches[0].length,
345
+ fix: [{
346
+ message: () => createVNode("span", null, [createVNode("code", null, [fixValue]), createTextVNode("\u306B\u4FEE\u6B63\u3059\u308B\u3002")]),
347
+ handler: () => {
348
+ console.log("hoge");
349
+ }
350
+ }, {
351
+ message: "\u3069\u3046\u306B\u304B\u3059\u308B",
352
+ handler: () => {
353
+ console.log("hoge");
354
+ }
355
+ }]
356
+ });
357
+ }
358
+ });
359
+ return this;
360
+ }
361
+ };
362
+ }
363
+
364
+ // src/extensions/linter/plugins/HeadingLevel.ts
365
+ var WysiwygLinterHeadingLevel = class extends WysiwygLinterPlugin {
366
+ fixHeader(level) {
367
+ return function({ state, dispatch }, issue) {
368
+ dispatch(state.tr.setNodeMarkup(issue.from - 1, void 0, { level }));
369
+ };
370
+ }
371
+ scan() {
372
+ let lastHeadLevel = null;
373
+ this.doc.descendants((node, position) => {
374
+ if (node.type.name === "heading") {
375
+ const { level } = node.attrs;
376
+ if (lastHeadLevel != null && level > lastHeadLevel + 1) {
377
+ this.record({
378
+ message: `Heading too small (${level} under ${lastHeadLevel})`,
379
+ from: position + 1,
380
+ to: position + 1 + node.content.size,
381
+ fix: {
382
+ message: "\u4FEE\u6B63\u3059\u308B",
383
+ handler: this.fixHeader(lastHeadLevel + 1)
384
+ }
385
+ });
386
+ }
387
+ lastHeadLevel = level;
388
+ }
389
+ });
390
+ return this;
391
+ }
392
+ };
393
+
394
+ // src/extensions/linter/plugins/Punctuation.ts
395
+ var WysiwygLinterPunctuation = class extends WysiwygLinterPlugin {
396
+ regex = / ([,.!?:]) ?/g;
397
+ fix(replacement) {
398
+ return function({ state, dispatch }, issue) {
399
+ dispatch(
400
+ state.tr.replaceWith(
401
+ issue.from,
402
+ issue.to,
403
+ state.schema.text(replacement)
404
+ )
405
+ );
406
+ };
407
+ }
408
+ scan() {
409
+ this.doc.descendants((node, position) => {
410
+ if (!node.isText) {
411
+ return;
412
+ }
413
+ if (!node.text) {
414
+ return;
415
+ }
416
+ const matches = this.regex.exec(node.text);
417
+ if (matches) {
418
+ this.record({
419
+ message: "Suspicious spacing around punctuation",
420
+ from: position + matches.index,
421
+ to: position + matches.index + matches[0].length,
422
+ fix: {
423
+ message: "Fix it!!!",
424
+ handler: this.fix(`${matches[1]} `)
425
+ }
426
+ });
427
+ }
428
+ });
429
+ return this;
430
+ }
431
+ };
432
+ var WysiwygColorExtension = Extension.create({
433
+ name: "color",
434
+ addOptions() {
435
+ return {
436
+ types: ["textStyle"]
437
+ };
438
+ },
439
+ addGlobalAttributes() {
440
+ return [
441
+ {
442
+ types: this.options.types,
443
+ attributes: {
444
+ color: {
445
+ default: null,
446
+ parseHTML: (element) => element.style.color.replace(/['"]+/g, ""),
447
+ renderHTML: (attributes) => {
448
+ if (!attributes.color) {
449
+ return {};
450
+ }
451
+ return {
452
+ style: `color: ${attributes.color}`
453
+ };
454
+ }
455
+ }
456
+ }
457
+ }
458
+ ];
459
+ },
460
+ addCommands() {
461
+ return {
462
+ setColor: (color) => ({ chain }) => {
463
+ return chain().setMark("textStyle", { color }).run();
464
+ },
465
+ unsetColor: () => ({ chain }) => {
466
+ return chain().setMark("textStyle", { color: null }).removeEmptyTextStyle().run();
467
+ }
468
+ };
469
+ }
470
+ });
471
+ var WysiwygBulletListTool = (vui, options) => {
472
+ const tool = {
473
+ key: "bulletList",
474
+ icon: vui.icon("editorformatListBulleted"),
475
+ active: ({ editor }) => editor.isActive("bulletList"),
476
+ onClick: ({ editor }) => {
477
+ editor.chain().focus().toggleBulletList().run();
478
+ },
479
+ floating: true,
480
+ extensions: [BulletList.configure(options)]
481
+ };
482
+ return tool;
483
+ };
484
+ var WysiwygFormatBoldTool = (vui, options) => {
485
+ const tool = {
486
+ key: "formatBold",
487
+ icon: vui.icon("editorformatBold"),
488
+ active: ({ editor }) => editor.isActive("bold"),
489
+ onClick: ({ editor }) => {
490
+ editor.chain().focus().toggleBold().run();
491
+ },
492
+ floating: true,
493
+ extensions: [Bold.configure(options)]
494
+ };
495
+ return tool;
496
+ };
497
+ var WysiwygFormatItalicTool = (vui, options) => {
498
+ const tool = {
499
+ key: "formatItalic",
500
+ icon: vui.icon("editorformatItalic"),
501
+ active: ({ editor }) => editor.isActive("italic"),
502
+ onClick: ({ editor }) => {
503
+ editor.chain().focus().toggleItalic().run();
504
+ },
505
+ floating: true,
506
+ extensions: [Italic.configure(options)]
507
+ };
508
+ return tool;
509
+ };
510
+ var WysiwygFormatUnderlineTool = (vui, options) => {
511
+ const tool = {
512
+ key: "formatUnderline",
513
+ icon: vui.icon("editorformatUnderline"),
514
+ active: ({ editor }) => editor.isActive("underline"),
515
+ onClick: ({ editor }) => {
516
+ editor.chain().focus().toggleUnderline().run();
517
+ },
518
+ floating: true,
519
+ extensions: [Underline.configure(options)]
520
+ };
521
+ return tool;
522
+ };
523
+ var WysiwygHistoryTool = (vui, options) => {
524
+ const undo = {
525
+ key: "history-undo",
526
+ icon: vui.icon("editorUndo"),
527
+ disabled: ({ editor }) => !editor.can().undo(),
528
+ onClick: ({ editor }) => {
529
+ editor.chain().focus().undo().run();
530
+ },
531
+ extensions: [History.configure(options)]
532
+ };
533
+ const redo = {
534
+ key: "history-redo",
535
+ icon: vui.icon("editorRedo"),
536
+ disabled: ({ editor }) => !editor.can().redo(),
537
+ onClick: ({ editor }) => {
538
+ editor.chain().focus().redo().run();
539
+ }
540
+ };
541
+ return [undo, redo];
542
+ };
543
+ var WysiwygLinkTool = (vui, options) => {
544
+ const tool = {
545
+ key: "link",
546
+ // icon: ({ editor }) => {
547
+ // return vui.icon(editor.isActive('link') ? 'editorLinkOff' : 'editorLink');
548
+ // },
549
+ icon: vui.icon("editorLink"),
550
+ active: ({ editor }) => editor.isActive("link"),
551
+ // disabled: ({ editor }) => {
552
+ // const { $from, $to } = editor.view.state.selection;
553
+ // return $to.pos - $from.pos === 0;
554
+ // },
555
+ onClick: async ({ vui: vui2, editor }) => {
556
+ const { href = "" } = editor.getAttributes("link");
557
+ const result = await vui2.prompt({
558
+ input: {
559
+ label: "Link URL",
560
+ rules: [validateIf, url],
561
+ initialValue: href,
562
+ size: "sm",
563
+ autofocus: true
564
+ }
565
+ });
566
+ if (result === void 0 || result === false) {
567
+ return;
568
+ }
569
+ const range = editor.chain().focus().extendMarkRange("link");
570
+ if (!result) {
571
+ range.unsetLink().run();
572
+ } else {
573
+ range.setLink({
574
+ href: result
575
+ }).run();
576
+ }
577
+ },
578
+ floating: true,
579
+ extensions: [
580
+ Link.configure({
581
+ openOnClick: false,
582
+ ...options
583
+ })
584
+ ]
585
+ };
586
+ return tool;
587
+ };
588
+ var WysiwygOrderedListTool = (vui, options) => {
589
+ const tool = {
590
+ key: "orderedList",
591
+ icon: vui.icon("editorformatListNumbered"),
592
+ active: ({ editor }) => editor.isActive("orderedList"),
593
+ onClick: ({ editor }) => {
594
+ editor.chain().focus().toggleOrderedList().run();
595
+ },
596
+ floating: true,
597
+ extensions: [OrderedList.configure(options)]
598
+ };
599
+ return tool;
600
+ };
601
+ function createWysiwygColorTool(opts) {
602
+ const WysiwygColorTool = (vui) => {
603
+ const tool = {
604
+ key: "textColor",
605
+ // active: ({ editor }) => editor.isActive('textStyle'),
606
+ icon: ({
607
+ editor
608
+ }) => () => {
609
+ const color = editor.getAttributes("textStyle").color;
610
+ const style = {
611
+ color
612
+ };
613
+ return createVNode("span", {
614
+ "class": "v-wysiwyg-color-tool__button"
615
+ }, [createVNode(VIcon, {
616
+ "class": "v-wysiwyg-color-tool__button__icon",
617
+ "name": vui.icon("editorTextColor")
618
+ }, null), createVNode("span", {
619
+ "class": "v-wysiwyg-color-tool__button__bar",
620
+ "style": style
621
+ }, null)]);
622
+ },
623
+ onClick: (ctx, ev) => {
624
+ ctx.vui.menu({
625
+ class: "v-wysiwyg-color-tool__menu",
626
+ activator: ev,
627
+ content: (stack) => createVNode("div", {
628
+ "class": ["v-wysiwyg-color-tool__items", {
629
+ "v-wysiwyg-color-tool__items--with-label": opts.withLabel
630
+ }]
631
+ }, [opts.items.map((item, index) => createVNode("button", {
632
+ "key": item.key == null ? index : item.key,
633
+ "class": "v-wysiwyg-color-tool__item",
634
+ "type": "button",
635
+ "onClick": () => {
636
+ const {
637
+ color
638
+ } = item;
639
+ let command = ctx.editor.chain().focus();
640
+ if (color) {
641
+ command = command.setColor(color);
642
+ } else {
643
+ command = command.unsetColor();
644
+ }
645
+ command.run();
646
+ stack.close();
647
+ }
648
+ }, [createVNode("span", {
649
+ "class": "v-wysiwyg-color-tool__item__color",
650
+ "style": item.color ? {
651
+ color: item.color
652
+ } : {}
653
+ }, null), opts.withLabel && createVNode("span", {
654
+ "class": "v-wysiwyg-color-tool__item__name"
655
+ }, [item.name])]))])
656
+ });
657
+ },
658
+ floating: true,
659
+ extensions: [TextStyle, WysiwygColorExtension]
660
+ };
661
+ return tool;
662
+ };
663
+ return WysiwygColorTool;
664
+ }
665
+ function _isSlot(s) {
666
+ return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
667
+ }
668
+ var VWysiwygEditor = defineComponent({
669
+ name: "VWysiwygEditor",
670
+ props: {
671
+ ...createTextableProps(),
672
+ ...createFormControlProps(),
673
+ ...createControlFieldProps(),
674
+ ...createControlFieldProviderProps(),
675
+ ...createControlProps(),
676
+ ...defineSlotsProps(),
677
+ extensions: {
678
+ type: Array,
679
+ default: () => []
680
+ },
681
+ tools: {
682
+ type: Array,
683
+ default: () => []
684
+ },
685
+ floatingToolbar: Boolean,
686
+ disabledMinHeight: Boolean,
687
+ disabledMaxHeight: Boolean
688
+ },
689
+ emits: {
690
+ ...createTextableEmits()
691
+ },
692
+ setup(props, ctx) {
693
+ const vui = useVui();
694
+ const textRef = ref("");
695
+ const toolButtonActiveColor = vui.setting("primaryScope");
696
+ const wysiwygSettings = computed(() => resolveRawWysiwygEditorTools(props.tools, vui));
697
+ const control = useControl(props);
698
+ useControlField(props);
699
+ const inputControl = new TextableControl(props, ctx, {
700
+ nodeType: VUI_WYSIWYG_EDITOR_SYMBOL,
701
+ validationValue: () => textRef.value
702
+ });
703
+ const initializeCtx = new WysiwygEditorInitializeContext(() => vui, {
704
+ onCreate: ({
705
+ editor: editor2
706
+ }) => {
707
+ textRef.value = editor2.getText();
708
+ updateEditable();
709
+ },
710
+ onFocus: ({
711
+ event
712
+ }) => {
713
+ inputControl.focusHandler(event);
714
+ },
715
+ onBlur: ({
716
+ event
717
+ }) => {
718
+ inputControl.blurHandler(event);
719
+ },
720
+ onUpdate: ({
721
+ editor: editor2
722
+ }) => {
723
+ inputControl.value = editor2.getHTML();
724
+ textRef.value = editor2.getText();
725
+ }
726
+ });
727
+ const extensions = [
728
+ StarterKit.configure({
729
+ bold: false,
730
+ bulletList: false,
731
+ orderedList: false,
732
+ history: false,
733
+ italic: false
734
+ }),
735
+ // Linter.configure({
736
+ // plugins: [BadWords(['abc', 'evidently']), Punctuation, HeadingLevel],
737
+ // }),
738
+ ...resolveRawWysiwygExtensions(props.extensions, initializeCtx),
739
+ ...wysiwygSettings.value.extensions
740
+ ];
741
+ const updateEditable = () => {
742
+ if (!editor.value)
743
+ return;
744
+ editor.value.setEditable(inputControl.canOperation);
745
+ };
746
+ watch(() => inputControl.canOperation, updateEditable);
747
+ watch(() => props.modelValue, (modelValue) => {
748
+ const $editor = editor.value;
749
+ if (!$editor || $editor.getHTML() === modelValue)
750
+ return;
751
+ $editor.commands.setContent(modelValue == null ? "" : modelValue, false);
752
+ textRef.value = $editor.getText();
753
+ });
754
+ initializeCtx.on("create", ({
755
+ editor: editor2
756
+ }) => {
757
+ textRef.value = editor2.getText();
758
+ updateEditable();
759
+ });
760
+ const editor = useEditor({
761
+ ...initializeCtx.editorOptions(),
762
+ autofocus: props.autofocus,
763
+ content: props.modelValue,
764
+ extensions,
765
+ editorProps: {
766
+ attributes: {
767
+ class: "v-wysiwyg-editor__input__prose"
768
+ }
769
+ }
770
+ });
771
+ const focus = (position, options) => {
772
+ if (!editor.value)
773
+ return;
774
+ return editor.value.chain().focus(position, options);
775
+ };
776
+ const blur = () => {
777
+ if (!editor.value)
778
+ return;
779
+ return editor.value.chain().blur();
780
+ };
781
+ const wysiwygContext = computed(() => {
782
+ const _editor = editor.value;
783
+ return {
784
+ vui,
785
+ editor: _editor
786
+ };
787
+ });
788
+ const createTools = (bubbleMenu = false) => {
789
+ let _slot;
790
+ const {
791
+ value: settings
792
+ } = wysiwygSettings;
793
+ const {
794
+ value: context
795
+ } = wysiwygContext;
796
+ const tools = bubbleMenu ? settings.tools.filter((t) => !!t.floating) : settings.tools;
797
+ const _editor = editor.value;
798
+ const variant = vui.setting(bubbleMenu ? "containedVariant" : "plainVariant");
799
+ return createVNode(VButtonGroup, {
800
+ "class": ["v-wysiwyg-editor__toolbar", {
801
+ "v-wysiwyg-editor__floating-toolbar": props.floatingToolbar
802
+ }],
803
+ "variant": variant
804
+ }, _isSlot(_slot = tools.map(({
805
+ key,
806
+ icon,
807
+ onClick,
808
+ disabled,
809
+ active
810
+ }) => {
811
+ const isActive = !!_editor && resolveContextableValue(context, active);
812
+ const isDisabled = !inputControl.canOperation || !!_editor && resolveContextableValue(context, disabled);
813
+ let iconName;
814
+ let child;
815
+ if (typeof icon === "function") {
816
+ if (_editor) {
817
+ const _child = icon(context);
818
+ if (typeof _child === "function") {
819
+ child = _child();
820
+ } else {
821
+ iconName = _child;
822
+ }
823
+ }
824
+ } else {
825
+ iconName = icon;
826
+ }
827
+ if (!iconName && child == null)
828
+ return;
829
+ return createVNode(VButton, {
830
+ "tabindex": -1,
831
+ "key": key,
832
+ "icon": iconName,
833
+ "onClick": (ev) => onClick(context, ev),
834
+ "color": isActive ? toolButtonActiveColor : void 0,
835
+ "disabled": isDisabled
836
+ }, _isSlot(child) ? child : {
837
+ default: () => [child]
838
+ });
839
+ })) ? _slot : {
840
+ default: () => [_slot]
841
+ });
842
+ };
843
+ onBeforeUnmount(() => {
844
+ editor.value && editor.value.destroy();
845
+ });
846
+ return {
847
+ editor,
848
+ ...inputControl.expose(),
849
+ ...control,
850
+ focus,
851
+ blur,
852
+ createTools
853
+ };
854
+ },
855
+ render() {
856
+ return createVNode(VFormControl, {
857
+ "nodeControl": this.nodeControl,
858
+ "focused": this.nodeControl.focused,
859
+ "class": ["v-wysiwyg-editor", this.classes, `v-wysiwyg-editor--${this.size}`, {
860
+ "v-wysiwyg-editor--disabled-min-heihgt": this.disabledMinHeight,
861
+ "v-wysiwyg-editor--disabled-max-heihgt": this.disabledMaxHeight
862
+ }],
863
+ "label": this.label,
864
+ "hint": this.hint,
865
+ "hinttip": this.hinttip,
866
+ "hiddenInfo": this.hiddenInfo,
867
+ "requiredChip": this.requiredChip,
868
+ "onClickLabel": (ev) => {
869
+ this.focus("start", {
870
+ scrollIntoView: true
871
+ });
872
+ }
873
+ }, {
874
+ ...this.$slots,
875
+ default: () => {
876
+ const {
877
+ editor
878
+ } = this;
879
+ return createVNode("div", {
880
+ "class": "v-wysiwyg-editor__wrapper"
881
+ }, [!this.isReadonly && this.createTools(), createVNode(VControlField, {
882
+ "class": "v-wysiwyg-editor__input",
883
+ "autoHeight": true,
884
+ "startAdornment": this.startAdornment,
885
+ "endAdornment": this.endAdornment,
886
+ "size": this.size
887
+ }, {
888
+ ...this.$slots,
889
+ default: () => {
890
+ let _slot2;
891
+ return createVNode("div", {
892
+ "class": "v-wysiwyg-editor__body"
893
+ }, [createVNode(EditorContent, mergeProps({
894
+ class: "v-wysiwyg-editor__input__element wysiwyg"
895
+ }, {
896
+ "editor": editor
897
+ }), null), !this.floatingToolbar && !!editor && !this.isReadonly && createVNode(BubbleMenu, mergeProps({
898
+ class: "v-wysiwyg-editor__bubble-menu"
899
+ }, {
900
+ "editor": editor
901
+ }), _isSlot(_slot2 = this.createTools(true)) ? _slot2 : {
902
+ default: () => [_slot2]
903
+ })]);
904
+ }
905
+ })]);
906
+ },
907
+ infoAppends: () => {
908
+ const {
909
+ counterResult
910
+ } = this;
911
+ if (!counterResult)
912
+ return;
913
+ return createVNode(VTextCounter, counterResult, null);
914
+ }
915
+ });
916
+ }
917
+ });
918
+ function resolveContextableValue(ctx, source) {
919
+ return typeof source === "function" ? source(ctx) : source;
920
+ }
921
+
922
+ export { VUI_WYSIWYG_EDITOR_SYMBOL, VWysiwygEditor, WysiwygBulletListTool, WysiwygColorExtension, WysiwygEditorInitializeContext, WysiwygFormatBoldTool, WysiwygFormatItalicTool, WysiwygFormatUnderlineTool, WysiwygHistoryTool, WysiwygLinkTool, WysiwygLinter, WysiwygLinterBadWords, WysiwygLinterHeadingLevel, WysiwygLinterPlugin, WysiwygLinterPunctuation, WysiwygOrderedListTool, createWysiwygColorTool, createWysiwygExtension, resolveRawWysiwygEditorTools, resolveRawWysiwygExtensions };
923
+ //# sourceMappingURL=out.js.map
924
+ //# sourceMappingURL=vui-wysiwyg.mjs.map