@fastkit/vui-wysiwyg 8.2.0 → 8.3.0-next.1

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