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