@fastkit/vui-wysiwyg 8.2.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 (118) hide show
  1. package/dist/pm/changeset.d.mts +1 -0
  2. package/dist/pm/changeset.mjs +3 -3
  3. package/dist/pm/collab.d.mts +1 -0
  4. package/dist/pm/collab.mjs +3 -3
  5. package/dist/pm/commands.d.mts +1 -0
  6. package/dist/pm/commands.mjs +3 -3
  7. package/dist/pm/dropcursor.d.mts +1 -0
  8. package/dist/pm/dropcursor.mjs +3 -3
  9. package/dist/pm/gapcursor.d.mts +1 -0
  10. package/dist/pm/gapcursor.mjs +3 -3
  11. package/dist/pm/history.d.mts +1 -0
  12. package/dist/pm/history.mjs +3 -3
  13. package/dist/pm/inputrules.d.mts +1 -0
  14. package/dist/pm/inputrules.mjs +3 -3
  15. package/dist/pm/keymap.d.mts +1 -0
  16. package/dist/pm/keymap.mjs +3 -3
  17. package/dist/pm/markdown.d.mts +1 -0
  18. package/dist/pm/markdown.mjs +3 -3
  19. package/dist/pm/menu.d.mts +1 -0
  20. package/dist/pm/menu.mjs +3 -3
  21. package/dist/pm/model.d.mts +1 -0
  22. package/dist/pm/model.mjs +3 -3
  23. package/dist/pm/schema-basic.d.mts +1 -0
  24. package/dist/pm/schema-basic.mjs +3 -3
  25. package/dist/pm/schema-list.d.mts +1 -0
  26. package/dist/pm/schema-list.mjs +3 -3
  27. package/dist/pm/state.d.mts +1 -0
  28. package/dist/pm/state.mjs +3 -3
  29. package/dist/pm/tables.d.mts +1 -0
  30. package/dist/pm/tables.mjs +3 -3
  31. package/dist/pm/trailing-node.d.mts +1 -0
  32. package/dist/pm/trailing-node.mjs +3 -3
  33. package/dist/pm/transform.d.mts +1 -0
  34. package/dist/pm/transform.mjs +3 -3
  35. package/dist/pm/view.d.mts +1 -0
  36. package/dist/pm/view.mjs +3 -3
  37. package/dist/tiptap/core.d.mts +1 -0
  38. package/dist/tiptap/core.mjs +3 -3
  39. package/dist/tiptap/extensions/bold.d.mts +1 -0
  40. package/dist/tiptap/extensions/bold.mjs +3 -3
  41. package/dist/tiptap/extensions/bullet-list.d.mts +1 -0
  42. package/dist/tiptap/extensions/bullet-list.mjs +3 -3
  43. package/dist/tiptap/extensions/history.d.mts +1 -0
  44. package/dist/tiptap/extensions/history.mjs +3 -3
  45. package/dist/tiptap/extensions/italic.d.mts +1 -0
  46. package/dist/tiptap/extensions/italic.mjs +3 -3
  47. package/dist/tiptap/extensions/link.d.mts +1 -0
  48. package/dist/tiptap/extensions/link.mjs +3 -3
  49. package/dist/tiptap/extensions/ordered-list.d.mts +1 -0
  50. package/dist/tiptap/extensions/ordered-list.mjs +3 -3
  51. package/dist/tiptap/extensions/text-align.d.mts +1 -0
  52. package/dist/tiptap/extensions/text-align.mjs +3 -3
  53. package/dist/tiptap/extensions/text-style.d.mts +1 -0
  54. package/dist/tiptap/extensions/text-style.mjs +3 -3
  55. package/dist/tiptap/extensions/underline.d.mts +1 -0
  56. package/dist/tiptap/extensions/underline.mjs +3 -3
  57. package/dist/vui-wysiwyg.css +105 -104
  58. package/dist/vui-wysiwyg.d.mts +3576 -0
  59. package/dist/vui-wysiwyg.mjs +857 -979
  60. package/dist/vui-wysiwyg.mjs.map +1 -1
  61. package/package.json +70 -70
  62. package/dist/pm/changeset.d.ts +0 -1
  63. package/dist/pm/changeset.mjs.map +0 -1
  64. package/dist/pm/collab.d.ts +0 -1
  65. package/dist/pm/collab.mjs.map +0 -1
  66. package/dist/pm/commands.d.ts +0 -1
  67. package/dist/pm/commands.mjs.map +0 -1
  68. package/dist/pm/dropcursor.d.ts +0 -1
  69. package/dist/pm/dropcursor.mjs.map +0 -1
  70. package/dist/pm/gapcursor.d.ts +0 -1
  71. package/dist/pm/gapcursor.mjs.map +0 -1
  72. package/dist/pm/history.d.ts +0 -1
  73. package/dist/pm/history.mjs.map +0 -1
  74. package/dist/pm/inputrules.d.ts +0 -1
  75. package/dist/pm/inputrules.mjs.map +0 -1
  76. package/dist/pm/keymap.d.ts +0 -1
  77. package/dist/pm/keymap.mjs.map +0 -1
  78. package/dist/pm/markdown.d.ts +0 -1
  79. package/dist/pm/markdown.mjs.map +0 -1
  80. package/dist/pm/menu.d.ts +0 -1
  81. package/dist/pm/menu.mjs.map +0 -1
  82. package/dist/pm/model.d.ts +0 -1
  83. package/dist/pm/model.mjs.map +0 -1
  84. package/dist/pm/schema-basic.d.ts +0 -1
  85. package/dist/pm/schema-basic.mjs.map +0 -1
  86. package/dist/pm/schema-list.d.ts +0 -1
  87. package/dist/pm/schema-list.mjs.map +0 -1
  88. package/dist/pm/state.d.ts +0 -1
  89. package/dist/pm/state.mjs.map +0 -1
  90. package/dist/pm/tables.d.ts +0 -1
  91. package/dist/pm/tables.mjs.map +0 -1
  92. package/dist/pm/trailing-node.d.ts +0 -1
  93. package/dist/pm/trailing-node.mjs.map +0 -1
  94. package/dist/pm/transform.d.ts +0 -1
  95. package/dist/pm/transform.mjs.map +0 -1
  96. package/dist/pm/view.d.ts +0 -28
  97. package/dist/pm/view.mjs.map +0 -1
  98. package/dist/tiptap/core.d.ts +0 -1
  99. package/dist/tiptap/core.mjs.map +0 -1
  100. package/dist/tiptap/extensions/bold.d.ts +0 -1
  101. package/dist/tiptap/extensions/bold.mjs.map +0 -1
  102. package/dist/tiptap/extensions/bullet-list.d.ts +0 -1
  103. package/dist/tiptap/extensions/bullet-list.mjs.map +0 -1
  104. package/dist/tiptap/extensions/history.d.ts +0 -1
  105. package/dist/tiptap/extensions/history.mjs.map +0 -1
  106. package/dist/tiptap/extensions/italic.d.ts +0 -1
  107. package/dist/tiptap/extensions/italic.mjs.map +0 -1
  108. package/dist/tiptap/extensions/link.d.ts +0 -1
  109. package/dist/tiptap/extensions/link.mjs.map +0 -1
  110. package/dist/tiptap/extensions/ordered-list.d.ts +0 -1
  111. package/dist/tiptap/extensions/ordered-list.mjs.map +0 -1
  112. package/dist/tiptap/extensions/text-align.d.ts +0 -1
  113. package/dist/tiptap/extensions/text-align.mjs.map +0 -1
  114. package/dist/tiptap/extensions/text-style.d.ts +0 -1
  115. package/dist/tiptap/extensions/text-style.mjs.map +0 -1
  116. package/dist/tiptap/extensions/underline.d.ts +0 -1
  117. package/dist/tiptap/extensions/underline.mjs.map +0 -1
  118. package/dist/vui-wysiwyg.d.ts +0 -511
@@ -1,1049 +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
- onClick: async ({ vui: vui2, editor }) => {
590
- const { href = "" } = editor.getAttributes("link");
591
- const result = await vui2.prompt({
592
- input: {
593
- label: "Link URL",
594
- rules: [validateIf, url],
595
- initialValue: href,
596
- size: "sm",
597
- autofocus: true
598
- }
599
- });
600
- if (result === void 0 || result === false) {
601
- return;
602
- }
603
- const range = editor.chain().focus().extendMarkRange("link");
604
- if (!result) {
605
- range.unsetLink().run();
606
- } else {
607
- range.setLink({
608
- href: result
609
- }).run();
610
- }
611
- },
612
- floating: true,
613
- extensions: [
614
- Link.configure({
615
- openOnClick: false,
616
- ...options
617
- })
618
- ]
619
- };
620
- 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
+ };
621
562
  };
622
- var WysiwygOrderedListTool = (vui, options) => {
623
- const tool = {
624
- key: "orderedList",
625
- icon: vui.icon("editorformatListNumbered"),
626
- active: ({ editor }) => editor.isActive("orderedList"),
627
- onClick: ({ editor }) => {
628
- editor.chain().focus().toggleOrderedList().run();
629
- },
630
- floating: true,
631
- extensions: [OrderedList.configure(options)]
632
- };
633
- 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
+ };
634
577
  };
578
+
579
+ //#endregion
580
+ //#region src/tools/color.tsx
635
581
  function createWysiwygColorTool(opts) {
636
- const WysiwygColorTool = (vui) => {
637
- const tool = {
638
- key: "textColor",
639
- // active: ({ editor }) => editor.isActive('textStyle'),
640
- icon: ({
641
- editor
642
- }) => () => {
643
- const {
644
- color
645
- } = editor.getAttributes("textStyle");
646
- const style = {
647
- color
648
- };
649
- return createVNode("span", {
650
- "class": "v-wysiwyg-color-tool__button"
651
- }, [createVNode(VIcon, {
652
- "class": "v-wysiwyg-color-tool__button__icon",
653
- "name": vui.icon("editorTextColor")
654
- }, null), createVNode("span", {
655
- "class": "v-wysiwyg-color-tool__button__bar",
656
- "style": style
657
- }, null)]);
658
- },
659
- onClick: (ctx, ev) => {
660
- ctx.vui.menu({
661
- class: "v-wysiwyg-color-tool__menu",
662
- activator: ev,
663
- content: (stack) => createVNode("div", {
664
- "class": ["v-wysiwyg-color-tool__items", {
665
- "v-wysiwyg-color-tool__items--with-label": opts.withLabel
666
- }]
667
- }, [opts.items.map((item, index) => createVNode("button", {
668
- "key": item.key == null ? index : item.key,
669
- "class": "v-wysiwyg-color-tool__item",
670
- "type": "button",
671
- "onClick": () => {
672
- const {
673
- color
674
- } = item;
675
- let command = ctx.editor.chain().focus();
676
- if (color) {
677
- command = command.setColor(color);
678
- } else {
679
- command = command.unsetColor();
680
- }
681
- command.run();
682
- stack.close();
683
- }
684
- }, [createVNode("span", {
685
- "class": "v-wysiwyg-color-tool__item__color",
686
- "style": item.color ? {
687
- color: item.color
688
- } : {}
689
- }, null), opts.withLabel && createVNode("span", {
690
- "class": "v-wysiwyg-color-tool__item__name"
691
- }, [item.name])]))])
692
- });
693
- },
694
- floating: true,
695
- extensions: [TextStyle, WysiwygColorExtension]
696
- };
697
- return tool;
698
- };
699
- 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;
700
623
  }
701
- function _isSlot(s) {
702
- 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);
703
634
  }
704
- var WYSIWYG_TEXT_ALIGN_VALUES = [
705
- "left",
706
- "center",
707
- "right"
708
- // 'justify',
635
+ const WYSIWYG_TEXT_ALIGN_VALUES = [
636
+ "left",
637
+ "center",
638
+ "right"
709
639
  ];
710
- var DEFAULT_TYPES = ["heading", "paragraph"];
711
- var conditions = WYSIWYG_TEXT_ALIGN_VALUES.map((value) => [value, {
712
- textAlign: value
713
- }]);
714
- var ICON_AT = {
715
- left: "editorAlignLeft",
716
- center: "editorAlignCenter",
717
- 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"
718
649
  };
719
650
  function resolveOptions(rawOptions) {
720
- const types = rawOptions?.types || DEFAULT_TYPES.slice();
721
- const alignments = rawOptions?.alignments || WYSIWYG_TEXT_ALIGN_VALUES.slice();
722
- const defaultAlignment = rawOptions?.defaultAlignment || "left";
723
- return {
724
- types,
725
- alignments,
726
- defaultAlignment
727
- };
651
+ return {
652
+ types: rawOptions?.types || DEFAULT_TYPES.slice(),
653
+ alignments: rawOptions?.alignments || WYSIWYG_TEXT_ALIGN_VALUES.slice(),
654
+ defaultAlignment: rawOptions?.defaultAlignment || "left"
655
+ };
728
656
  }
729
657
  function getCurrentAlign(editor, options) {
730
- for (const [align, condition] of conditions) {
731
- if (editor.isActive(condition)) return align;
732
- }
733
- return options.defaultAlignment;
658
+ for (const [align, condition] of conditions) if (editor.isActive(condition)) return align;
659
+ return options.defaultAlignment;
734
660
  }
735
- var WysiwygTextAlignTool = (vui, options) => {
736
- const resolvedOptions = resolveOptions(options);
737
- const {
738
- alignments
739
- } = resolvedOptions;
740
- const getIcon = (value) => {
741
- const iconKey = ICON_AT[value];
742
- const icon = vui.icon(iconKey);
743
- if (icon === "$empty" || typeof icon === "function") return;
744
- return icon;
745
- };
746
- const variant = vui.setting("plainVariant");
747
- const toolButtonActiveColor = vui.setting("primaryScope");
748
- const tool = {
749
- key: "textAlign",
750
- icon: ({
751
- editor
752
- }) => getIcon(getCurrentAlign(editor, resolvedOptions)),
753
- onClick: async ({
754
- vui: vui2,
755
- editor
756
- }, ev) => {
757
- vui2.menu({
758
- distance: 0,
759
- activator: ev,
760
- content: (menu) => {
761
- let _slot;
762
- return createVNode(VButtonGroup, {
763
- "variant": variant
764
- }, _isSlot(_slot = alignments.map((value) => {
765
- const isActive = editor.isActive({
766
- textAlign: value
767
- });
768
- return createVNode(VButton, {
769
- "tabindex": -1,
770
- "color": isActive ? toolButtonActiveColor : void 0,
771
- "key": value,
772
- "icon": getIcon(value),
773
- "onClick": () => {
774
- editor.chain().focus().setTextAlign(value).run();
775
- }
776
- }, null);
777
- })) ? _slot : {
778
- default: () => [_slot]
779
- });
780
- }
781
- });
782
- },
783
- floating: true,
784
- extensions: [TextAlign.configure(resolvedOptions)]
785
- };
786
- 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
+ };
787
699
  };
788
700
 
789
- // 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
+ */
790
710
  function createWysiwygCustomTagTool(markName, settings) {
791
- const Mark2 = createWysiwygCustomTagMark(markName, settings);
792
- const { icon, floating = true } = settings;
793
- return (vui) => {
794
- const tool = {
795
- key: `customTag:${markName}`,
796
- icon,
797
- floating,
798
- active: ({ editor }) => editor.isActive(markName),
799
- onClick: ({ editor }) => {
800
- editor.chain().focus().toggleCustomTag(markName).run();
801
- },
802
- extensions: [WysiwygCustomTagExtension, Mark2.configure(settings)]
803
- };
804
- return tool;
805
- };
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
+ };
806
725
  }
807
- function _isSlot2(s) {
808
- 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);
809
731
  }
810
- var slots = defineSlots();
811
- var VWysiwygEditor = defineComponent({
812
- name: "VWysiwygEditor",
813
- props: {
814
- ...createTextableProps(),
815
- ...createFormNodeWrapperProps(),
816
- ...createControlFieldProps(),
817
- ...createControlFieldProviderProps(),
818
- ...createControlProps(),
819
- ...slots(),
820
- extensions: {
821
- type: Array,
822
- default: () => []
823
- },
824
- tools: {
825
- type: Array,
826
- default: () => []
827
- },
828
- floatingToolbar: Boolean,
829
- disabledMinHeight: Boolean,
830
- disabledMaxHeight: Boolean,
831
- removeDefaultWrapper: {
832
- type: Boolean,
833
- default: true
834
- }
835
- },
836
- emits: {
837
- ...createTextableEmits()
838
- },
839
- slots,
840
- setup(props, ctx) {
841
- const vui = useVui();
842
- const textRef = ref("");
843
- const toolButtonActiveColor = vui.setting("primaryScope");
844
- const wysiwygSettings = computed(() => resolveRawWysiwygEditorTools(props.tools, vui));
845
- const control = useControl(props);
846
- useControlField(props);
847
- const classes = computed(() => ["v-wysiwyg-editor", control.classes.value, `v-wysiwyg-editor--${control.size.value}`, {
848
- "v-wysiwyg-editor--disabled-min-height": props.disabledMinHeight,
849
- "v-wysiwyg-editor--disabled-max-height": props.disabledMaxHeight
850
- }]);
851
- const inputControl = new TextableControl(props, ctx, {
852
- nodeType: VUI_WYSIWYG_EDITOR_SYMBOL,
853
- validationValue: () => textRef.value
854
- });
855
- const getOutput = (editor2, type) => {
856
- if (props.removeDefaultWrapper && editor2.isEmpty) return "";
857
- if (type === "html") return editor2.getHTML();
858
- if (type === "text") return editor2.getText();
859
- return "";
860
- };
861
- const initializeCtx = new WysiwygEditorInitializeContext(() => vui, {
862
- onCreate: ({
863
- editor: editor2
864
- }) => {
865
- textRef.value = getOutput(editor2, "text");
866
- updateEditable();
867
- },
868
- onFocus: ({
869
- event
870
- }) => {
871
- inputControl.focusHandler(event);
872
- },
873
- onBlur: ({
874
- event
875
- }) => {
876
- inputControl.blurHandler(event);
877
- },
878
- onUpdate: ({
879
- editor: editor2
880
- }) => {
881
- inputControl.value = getOutput(editor2, "html");
882
- textRef.value = getOutput(editor2, "text");
883
- }
884
- });
885
- const extensions = [StarterKit.configure({
886
- bold: false,
887
- bulletList: false,
888
- orderedList: false,
889
- undoRedo: false,
890
- italic: false
891
- }), ...resolveRawWysiwygExtensions(props.extensions, initializeCtx), ...wysiwygSettings.value.extensions];
892
- const updateEditable = () => {
893
- if (!editor.value) return;
894
- editor.value.setEditable(inputControl.canOperation);
895
- };
896
- watch(() => inputControl.canOperation, updateEditable);
897
- watch(() => props.modelValue, (modelValue) => {
898
- const $editor = editor.value;
899
- if (!$editor || getOutput($editor, "html") === modelValue) return;
900
- $editor.commands.setContent(modelValue == null ? "" : modelValue, {
901
- emitUpdate: false
902
- });
903
- textRef.value = getOutput($editor, "text");
904
- });
905
- initializeCtx.on("create", ({
906
- editor: editor2
907
- }) => {
908
- textRef.value = getOutput(editor2, "text");
909
- updateEditable();
910
- });
911
- const editor = useEditor({
912
- ...initializeCtx.editorOptions(),
913
- autofocus: props.autofocus,
914
- content: props.modelValue,
915
- extensions,
916
- editorProps: {
917
- attributes: {
918
- class: "v-wysiwyg-editor__input__prose"
919
- }
920
- }
921
- });
922
- const focus = (position, options) => editor.value?.chain().focus(position, options);
923
- const wysiwygContext = computed(() => ({
924
- vui,
925
- editor: editor.value
926
- }));
927
- const createTools = (bubbleMenu = false) => {
928
- let _slot;
929
- const {
930
- value: settings
931
- } = wysiwygSettings;
932
- const {
933
- value: context
934
- } = wysiwygContext;
935
- const tools = bubbleMenu ? settings.tools.filter((t) => !!t.floating) : settings.tools;
936
- const _editor = editor.value;
937
- const variant = vui.setting(bubbleMenu ? "containedVariant" : "plainVariant");
938
- return createVNode(VButtonGroup, {
939
- "class": ["v-wysiwyg-editor__toolbar", {
940
- "v-wysiwyg-editor__floating-toolbar": props.floatingToolbar
941
- }],
942
- "variant": variant
943
- }, _isSlot2(_slot = tools.map(({
944
- key,
945
- icon,
946
- onClick,
947
- disabled,
948
- active
949
- }) => {
950
- const isActive = !!_editor && resolveContextualValue(context, active);
951
- const isDisabled = !inputControl.canOperation || !!_editor && resolveContextualValue(context, disabled);
952
- let iconName;
953
- let child;
954
- if (typeof icon === "function") {
955
- if (_editor) {
956
- const _child = icon(context);
957
- if (typeof _child === "function") {
958
- child = _child();
959
- } else {
960
- iconName = _child;
961
- }
962
- }
963
- } else {
964
- iconName = icon;
965
- }
966
- if (!iconName && child == null) return;
967
- return createVNode(VButton, {
968
- "tabindex": -1,
969
- "key": key,
970
- "icon": iconName,
971
- "onClick": (ev) => onClick(context, ev),
972
- "color": isActive ? toolButtonActiveColor : void 0,
973
- "disabled": isDisabled
974
- }, _isSlot2(child) ? child : {
975
- default: () => [child]
976
- });
977
- })) ? _slot : {
978
- default: () => [_slot]
979
- });
980
- };
981
- onBeforeUnmount(() => {
982
- editor.value?.destroy();
983
- });
984
- const api = {
985
- get editor() {
986
- return editor.value;
987
- },
988
- control: inputControl
989
- };
990
- ctx.expose(api);
991
- const handleClickLabel = (ev) => {
992
- focus("start", {
993
- scrollIntoView: true
994
- });
995
- };
996
- const defaultSlot = () => createVNode("div", {
997
- "class": "v-wysiwyg-editor__body"
998
- }, [createVNode(EditorContent, {
999
- "class": "v-wysiwyg-editor__input__element wysiwyg",
1000
- "editor": editor.value
1001
- }, null), !props.floatingToolbar && !!editor.value && !inputControl.isReadonly && createVNode(BubbleMenu, {
1002
- "editor": editor.value
1003
- }, {
1004
- default: () => [createVNode("div", {
1005
- "class": "v-wysiwyg-editor__bubble-menu"
1006
- }, [createTools(true)])]
1007
- })]);
1008
- const formControlDefaultSlot = () => createVNode("div", {
1009
- "class": "v-wysiwyg-editor__wrapper"
1010
- }, [!inputControl.isReadonly && createTools(), createVNode(VControlField, {
1011
- "class": "v-wysiwyg-editor__input",
1012
- "autoHeight": true,
1013
- "startAdornment": props.startAdornment,
1014
- "endAdornment": props.endAdornment,
1015
- "size": control.size.value
1016
- }, {
1017
- ...ctx.slots,
1018
- default: withCtx(defaultSlot)
1019
- })]);
1020
- const infoAppendsSlot = () => {
1021
- const {
1022
- counterResult
1023
- } = inputControl;
1024
- if (!counterResult) return;
1025
- return createVNode(VTextCounter, counterResult, null);
1026
- };
1027
- return () => createVNode(VFormControl, {
1028
- "nodeControl": inputControl,
1029
- "class": classes.value,
1030
- "label": props.label,
1031
- "hint": props.hint,
1032
- "hinttip": props.hinttip,
1033
- "hiddenInfo": props.hiddenInfo,
1034
- "requiredChip": props.requiredChip,
1035
- "onClickLabel": handleClickLabel
1036
- }, {
1037
- ...ctx.slots,
1038
- default: withCtx(formControlDefaultSlot),
1039
- infoAppends: withCtx(infoAppendsSlot)
1040
- });
1041
- }
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
+ }
1042
920
  });
1043
921
  function resolveContextualValue(ctx, source) {
1044
- return typeof source === "function" ? source(ctx) : source;
922
+ return typeof source === "function" ? source(ctx) : source;
1045
923
  }
1046
924
 
925
+ //#endregion
1047
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 };
1048
- //# sourceMappingURL=vui-wysiwyg.mjs.map
1049
927
  //# sourceMappingURL=vui-wysiwyg.mjs.map