@m3ui-vue/m3ui-vue 0.1.11 → 0.2.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.
- package/dist/{MMenuItem-_n5OG5MT.js → MMenuItem-DpoEsH91.js} +215 -122
- package/dist/MMenuItem-DpoEsH91.js.map +1 -0
- package/dist/components/MAlert.vue.d.ts +1 -0
- package/dist/components/MButton.vue.d.ts +1 -1
- package/dist/components/MCalendar.vue.d.ts +3 -0
- package/dist/components/MCarousel.vue.d.ts +36 -0
- package/dist/components/MChip.vue.d.ts +3 -3
- package/dist/components/MCommandPalette.vue.d.ts +3 -2
- package/dist/components/MConfirmDialog.vue.d.ts +0 -2
- package/dist/components/MDataTable.vue.d.ts +25 -2
- package/dist/components/MDatePicker.vue.d.ts +2 -0
- package/dist/components/MDateRangePicker.vue.d.ts +5 -0
- package/dist/components/MDialog.vue.d.ts +1 -0
- package/dist/components/MFab.vue.d.ts +1 -1
- package/dist/components/MFileUpload.vue.d.ts +15 -1
- package/dist/components/MFlex.vue.d.ts +1 -1
- package/dist/components/MInfiniteScroll.vue.d.ts +7 -5
- package/dist/components/MMaskField.vue.d.ts +24 -0
- package/dist/components/MMultiSelect.vue.d.ts +20 -6
- package/dist/components/MNavigationDrawer.vue.d.ts +9 -3
- package/dist/components/MNumberField.vue.d.ts +27 -0
- package/dist/components/MRichTextEditor.vue.d.ts +28 -1
- package/dist/components/MScheduler.vue.d.ts +5 -0
- package/dist/components/MSelect.vue.d.ts +12 -9
- package/dist/components/MSnackbar.vue.d.ts +4 -1
- package/dist/components/MSpinner.vue.d.ts +1 -0
- package/dist/components/MSplitter.vue.d.ts +1 -1
- package/dist/components/MSpotlightSearch.vue.d.ts +3 -2
- package/dist/components/MStack.vue.d.ts +1 -1
- package/dist/components/MTable.vue.d.ts +3 -2
- package/dist/components/MTextField.vue.d.ts +2 -5
- package/dist/components/MTimePicker.vue.d.ts +1 -0
- package/dist/components/MTour.vue.d.ts +3 -0
- package/dist/components/MTransferList.vue.d.ts +19 -3
- package/dist/components/MTree.vue.d.ts +1 -1
- package/dist/components/_MDrawerItemList.vue.d.ts +57 -0
- package/dist/composables/useLocale.d.ts +74 -0
- package/dist/index.d.ts +10 -1
- package/dist/locales/de.d.ts +2 -0
- package/dist/locales/es.d.ts +2 -0
- package/dist/locales/fr.d.ts +2 -0
- package/dist/locales/index.d.ts +8 -0
- package/dist/locales/ja.d.ts +2 -0
- package/dist/locales/ko.d.ts +2 -0
- package/dist/locales/pt.d.ts +2 -0
- package/dist/locales/zh.d.ts +2 -0
- package/dist/m3ui-vue.css +1 -1
- package/dist/m3ui.js +3278 -2489
- package/dist/m3ui.js.map +1 -1
- package/dist/plugin.d.ts +3 -1
- package/dist/rich-text-editor.d.ts +1 -0
- package/dist/rich-text-editor.js +141 -113
- package/dist/rich-text-editor.js.map +1 -1
- package/dist/styles/palettes.css +660 -0
- package/dist/styles.css +1 -1
- package/package.json +6 -2
- package/src/components/MAlert.vue +5 -1
- package/src/components/MCalendar.vue +14 -5
- package/src/components/MCarousel.vue +203 -0
- package/src/components/MCommandPalette.vue +11 -7
- package/src/components/MConfirmDialog.vue +6 -5
- package/src/components/MDataTable.vue +78 -14
- package/src/components/MDatePicker.vue +11 -4
- package/src/components/MDateRangePicker.vue +15 -5
- package/src/components/MDialog.vue +5 -1
- package/src/components/MFileUpload.vue +22 -10
- package/src/components/MInfiniteScroll.vue +14 -9
- package/src/components/MMaskField.vue +198 -0
- package/src/components/MMultiSelect.vue +53 -24
- package/src/components/MNavigationDrawer.vue +282 -107
- package/src/components/MNumberField.vue +176 -0
- package/src/components/MRichTextEditor.vue +95 -34
- package/src/components/MScheduler.vue +12 -4
- package/src/components/MSelect.vue +41 -14
- package/src/components/MSnackbar.vue +8 -1
- package/src/components/MSpinner.vue +5 -1
- package/src/components/MSpotlightSearch.vue +11 -7
- package/src/components/MTable.vue +8 -4
- package/src/components/MTextField.vue +19 -10
- package/src/components/MTimePicker.vue +5 -1
- package/src/components/MTour.vue +12 -9
- package/src/components/MTransferList.vue +30 -15
- package/src/components/_MDrawerItemList.vue +105 -0
- package/src/composables/useColorPalette.ts +30 -20
- package/src/composables/useLocale.ts +181 -0
- package/src/index.ts +10 -1
- package/src/locales/de.ts +93 -0
- package/src/locales/es.ts +93 -0
- package/src/locales/fr.ts +93 -0
- package/src/locales/index.ts +8 -0
- package/src/locales/ja.ts +93 -0
- package/src/locales/ko.ts +93 -0
- package/src/locales/pt.ts +93 -0
- package/src/locales/zh.ts +93 -0
- package/src/plugin.ts +7 -1
- package/src/rich-text-editor.ts +1 -0
- package/src/styles/palettes.css +660 -0
- package/dist/MMenuItem-_n5OG5MT.js.map +0 -1
package/dist/plugin.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { App } from 'vue';
|
|
2
2
|
import type { Palette } from './composables/useColorPalette';
|
|
3
|
+
import type { M3Locale } from './composables/useLocale';
|
|
3
4
|
export interface M3UIOptions {
|
|
4
5
|
palette?: string;
|
|
5
6
|
customPalettes?: Palette[];
|
|
7
|
+
locale?: Partial<M3Locale>;
|
|
6
8
|
}
|
|
7
9
|
export declare function createM3UI(options?: M3UIOptions): {
|
|
8
|
-
install(
|
|
10
|
+
install(app: App): void;
|
|
9
11
|
};
|
package/dist/rich-text-editor.js
CHANGED
|
@@ -1,32 +1,60 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
3
|
-
import { t as
|
|
4
|
-
import { Fragment as
|
|
1
|
+
import { d as e, i as t, n, o as r, r as i, t as a } from "./MMenuItem-DpoEsH91.js";
|
|
2
|
+
import { t as o } from "./MIcon-CaEooCmZ.js";
|
|
3
|
+
import { t as s } from "./_plugin-vue_export-helper-B3ysoDQm.js";
|
|
4
|
+
import { Fragment as c, computed as l, createCommentVNode as u, createElementBlock as d, createElementVNode as f, createTextVNode as p, createVNode as m, defineComponent as h, normalizeClass as g, normalizeStyle as _, onBeforeUnmount as v, onMounted as y, openBlock as b, ref as x, renderList as S, shallowRef as C, toDisplayString as w, watch as T, withCtx as E, withKeys as D } from "vue";
|
|
5
5
|
//#region src/components/MRichTextEditor.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
-
var
|
|
6
|
+
var O = {
|
|
7
7
|
key: 0,
|
|
8
8
|
class: "flex flex-wrap items-center gap-0.5 border-b border-outline-variant bg-surface-container px-2 py-1.5"
|
|
9
|
-
},
|
|
9
|
+
}, k = {
|
|
10
10
|
type: "button",
|
|
11
11
|
class: "flex h-8 cursor-pointer items-center gap-1 rounded px-2 text-label-large text-on-surface-variant hover:bg-on-surface/8"
|
|
12
|
-
},
|
|
12
|
+
}, A = ["title", "onClick"], j = {
|
|
13
13
|
key: 0,
|
|
14
14
|
class: "mx-1 h-6 w-px bg-outline-variant"
|
|
15
|
-
},
|
|
15
|
+
}, M = ["title"], N = ["title"], P = /*#__PURE__*/ s(/* @__PURE__ */ h({
|
|
16
16
|
__name: "MRichTextEditor",
|
|
17
17
|
props: {
|
|
18
18
|
modelValue: {},
|
|
19
|
-
placeholder: {
|
|
19
|
+
placeholder: {},
|
|
20
20
|
disabled: {
|
|
21
21
|
type: Boolean,
|
|
22
22
|
default: !1
|
|
23
23
|
},
|
|
24
|
-
minHeight: { default: "200px" }
|
|
24
|
+
minHeight: { default: "200px" },
|
|
25
|
+
labels: {}
|
|
25
26
|
},
|
|
26
27
|
emits: ["update:modelValue"],
|
|
27
|
-
setup(
|
|
28
|
-
let
|
|
29
|
-
|
|
28
|
+
setup(s, { emit: h }) {
|
|
29
|
+
let P = e(), F = s, I = l(() => ({
|
|
30
|
+
bold: P.bold,
|
|
31
|
+
italic: P.italic,
|
|
32
|
+
underline: P.underline,
|
|
33
|
+
strikethrough: P.strikethrough,
|
|
34
|
+
highlight: P.highlight,
|
|
35
|
+
bulletList: P.bulletList,
|
|
36
|
+
orderedList: P.orderedList,
|
|
37
|
+
blockquote: P.blockquote,
|
|
38
|
+
code: P.code,
|
|
39
|
+
alignLeft: P.alignLeft,
|
|
40
|
+
alignCenter: P.alignCenter,
|
|
41
|
+
alignRight: P.alignRight,
|
|
42
|
+
undo: P.undo,
|
|
43
|
+
redo: P.redo,
|
|
44
|
+
link: P.link,
|
|
45
|
+
image: P.image,
|
|
46
|
+
paragraph: P.paragraph,
|
|
47
|
+
heading1: P.heading1,
|
|
48
|
+
heading2: P.heading2,
|
|
49
|
+
heading3: P.heading3,
|
|
50
|
+
insertLink: P.insertLink,
|
|
51
|
+
insertImage: P.insertImage,
|
|
52
|
+
imageUrlLabel: P.imageUrlLabel,
|
|
53
|
+
cancel: P.cancel,
|
|
54
|
+
insert: P.insert,
|
|
55
|
+
...F.labels
|
|
56
|
+
})), L = h, R = x(!1), z = C(null), B = x(null), V = x([]);
|
|
57
|
+
y(async () => {
|
|
30
58
|
let [{ Editor: e }, { default: t }, { default: n }, { default: r }, { default: i }, { default: a }, { default: o }, { default: s }, { TextStyle: c }, { default: l }] = await Promise.all([
|
|
31
59
|
import("@tiptap/vue-3"),
|
|
32
60
|
import("@tiptap/starter-kit"),
|
|
@@ -39,9 +67,9 @@ var D = {
|
|
|
39
67
|
import("@tiptap/extension-text-style"),
|
|
40
68
|
import("@tiptap/extension-color")
|
|
41
69
|
]), u = new e({
|
|
42
|
-
element:
|
|
43
|
-
content:
|
|
44
|
-
editable: !
|
|
70
|
+
element: B.value,
|
|
71
|
+
content: F.modelValue,
|
|
72
|
+
editable: !F.disabled,
|
|
45
73
|
extensions: [
|
|
46
74
|
t,
|
|
47
75
|
n,
|
|
@@ -49,41 +77,41 @@ var D = {
|
|
|
49
77
|
i.configure({ openOnClick: !1 }),
|
|
50
78
|
a,
|
|
51
79
|
o.configure({ multicolor: !0 }),
|
|
52
|
-
s.configure({ placeholder:
|
|
80
|
+
s.configure({ placeholder: F.placeholder ?? "Start writing..." }),
|
|
53
81
|
c,
|
|
54
82
|
l
|
|
55
83
|
],
|
|
56
|
-
onUpdate: ({ editor: e }) =>
|
|
84
|
+
onUpdate: ({ editor: e }) => L("update:modelValue", e.getHTML())
|
|
57
85
|
});
|
|
58
|
-
|
|
86
|
+
z.value = u, V.value = [
|
|
59
87
|
[
|
|
60
88
|
{
|
|
61
89
|
icon: "format_bold",
|
|
62
|
-
label:
|
|
90
|
+
label: I.value.bold,
|
|
63
91
|
action: () => u.chain().focus().toggleBold().run(),
|
|
64
92
|
active: () => !!u.isActive("bold")
|
|
65
93
|
},
|
|
66
94
|
{
|
|
67
95
|
icon: "format_italic",
|
|
68
|
-
label:
|
|
96
|
+
label: I.value.italic,
|
|
69
97
|
action: () => u.chain().focus().toggleItalic().run(),
|
|
70
98
|
active: () => !!u.isActive("italic")
|
|
71
99
|
},
|
|
72
100
|
{
|
|
73
101
|
icon: "format_underlined",
|
|
74
|
-
label:
|
|
102
|
+
label: I.value.underline,
|
|
75
103
|
action: () => u.chain().focus().toggleUnderline().run(),
|
|
76
104
|
active: () => !!u.isActive("underline")
|
|
77
105
|
},
|
|
78
106
|
{
|
|
79
107
|
icon: "format_strikethrough",
|
|
80
|
-
label:
|
|
108
|
+
label: I.value.strikethrough,
|
|
81
109
|
action: () => u.chain().focus().toggleStrike().run(),
|
|
82
110
|
active: () => !!u.isActive("strike")
|
|
83
111
|
},
|
|
84
112
|
{
|
|
85
113
|
icon: "ink_highlighter",
|
|
86
|
-
label:
|
|
114
|
+
label: I.value.highlight,
|
|
87
115
|
action: () => u.chain().focus().toggleHighlight().run(),
|
|
88
116
|
active: () => !!u.isActive("highlight")
|
|
89
117
|
}
|
|
@@ -91,25 +119,25 @@ var D = {
|
|
|
91
119
|
[
|
|
92
120
|
{
|
|
93
121
|
icon: "format_list_bulleted",
|
|
94
|
-
label:
|
|
122
|
+
label: I.value.bulletList,
|
|
95
123
|
action: () => u.chain().focus().toggleBulletList().run(),
|
|
96
124
|
active: () => !!u.isActive("bulletList")
|
|
97
125
|
},
|
|
98
126
|
{
|
|
99
127
|
icon: "format_list_numbered",
|
|
100
|
-
label:
|
|
128
|
+
label: I.value.orderedList,
|
|
101
129
|
action: () => u.chain().focus().toggleOrderedList().run(),
|
|
102
130
|
active: () => !!u.isActive("orderedList")
|
|
103
131
|
},
|
|
104
132
|
{
|
|
105
133
|
icon: "format_quote",
|
|
106
|
-
label:
|
|
134
|
+
label: I.value.blockquote,
|
|
107
135
|
action: () => u.chain().focus().toggleBlockquote().run(),
|
|
108
136
|
active: () => !!u.isActive("blockquote")
|
|
109
137
|
},
|
|
110
138
|
{
|
|
111
139
|
icon: "code",
|
|
112
|
-
label:
|
|
140
|
+
label: I.value.code,
|
|
113
141
|
action: () => u.chain().focus().toggleCode().run(),
|
|
114
142
|
active: () => !!u.isActive("code")
|
|
115
143
|
}
|
|
@@ -117,171 +145,171 @@ var D = {
|
|
|
117
145
|
[
|
|
118
146
|
{
|
|
119
147
|
icon: "format_align_left",
|
|
120
|
-
label:
|
|
148
|
+
label: I.value.alignLeft,
|
|
121
149
|
action: () => u.chain().focus().setTextAlign("left").run(),
|
|
122
150
|
active: () => !!u.isActive({ textAlign: "left" })
|
|
123
151
|
},
|
|
124
152
|
{
|
|
125
153
|
icon: "format_align_center",
|
|
126
|
-
label:
|
|
154
|
+
label: I.value.alignCenter,
|
|
127
155
|
action: () => u.chain().focus().setTextAlign("center").run(),
|
|
128
156
|
active: () => !!u.isActive({ textAlign: "center" })
|
|
129
157
|
},
|
|
130
158
|
{
|
|
131
159
|
icon: "format_align_right",
|
|
132
|
-
label:
|
|
160
|
+
label: I.value.alignRight,
|
|
133
161
|
action: () => u.chain().focus().setTextAlign("right").run(),
|
|
134
162
|
active: () => !!u.isActive({ textAlign: "right" })
|
|
135
163
|
}
|
|
136
164
|
],
|
|
137
165
|
[{
|
|
138
166
|
icon: "undo",
|
|
139
|
-
label:
|
|
167
|
+
label: I.value.undo,
|
|
140
168
|
action: () => u.chain().focus().undo().run()
|
|
141
169
|
}, {
|
|
142
170
|
icon: "redo",
|
|
143
|
-
label:
|
|
171
|
+
label: I.value.redo,
|
|
144
172
|
action: () => u.chain().focus().redo().run()
|
|
145
173
|
}]
|
|
146
|
-
],
|
|
174
|
+
], v(() => u.destroy()), T(() => F.modelValue, (e) => {
|
|
147
175
|
u.getHTML() !== e && u.commands.setContent(e);
|
|
148
|
-
}),
|
|
176
|
+
}), T(() => F.disabled, (e) => u.setEditable(!e)), R.value = !0;
|
|
149
177
|
});
|
|
150
|
-
let
|
|
151
|
-
let e =
|
|
152
|
-
return e ? e.isActive("heading", { level: 1 }) ?
|
|
178
|
+
let H = x(!1), U = x(""), W = x(!1), G = x(""), K = l(() => {
|
|
179
|
+
let e = z.value;
|
|
180
|
+
return e ? e.isActive("heading", { level: 1 }) ? I.value.heading1 : e.isActive("heading", { level: 2 }) ? I.value.heading2 : e.isActive("heading", { level: 3 }) ? I.value.heading3 : I.value.paragraph : I.value.paragraph;
|
|
153
181
|
});
|
|
154
|
-
function
|
|
155
|
-
e === 0 ?
|
|
182
|
+
function q(e) {
|
|
183
|
+
e === 0 ? z.value?.chain().focus().setParagraph().run() : z.value?.chain().focus().toggleHeading({ level: e }).run();
|
|
156
184
|
}
|
|
157
|
-
function
|
|
158
|
-
|
|
185
|
+
function J() {
|
|
186
|
+
U.value = "", H.value = !0;
|
|
159
187
|
}
|
|
160
|
-
function
|
|
161
|
-
|
|
188
|
+
function Y() {
|
|
189
|
+
U.value && z.value?.chain().focus().setLink({ href: U.value }).run(), H.value = !1;
|
|
162
190
|
}
|
|
163
|
-
function
|
|
164
|
-
|
|
191
|
+
function X() {
|
|
192
|
+
G.value = "", W.value = !0;
|
|
165
193
|
}
|
|
166
|
-
function
|
|
167
|
-
|
|
194
|
+
function Z() {
|
|
195
|
+
G.value && z.value?.chain().focus().setImage({ src: G.value }).run(), W.value = !1;
|
|
168
196
|
}
|
|
169
|
-
return (
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
trigger:
|
|
197
|
+
return (e, l) => (b(), d("div", { class: g(["overflow-hidden rounded-lg border transition-colors duration-150", s.disabled ? "border-outline-variant/50 opacity-60" : "border-outline-variant focus-within:border-primary"]) }, [
|
|
198
|
+
R.value ? (b(), d("div", O, [
|
|
199
|
+
m(n, { align: "left" }, {
|
|
200
|
+
trigger: E(() => [f("button", k, [p(w(K.value) + " ", 1), m(o, {
|
|
173
201
|
name: "arrow_drop_down",
|
|
174
202
|
size: 20
|
|
175
203
|
})])]),
|
|
176
|
-
default:
|
|
177
|
-
|
|
178
|
-
default:
|
|
204
|
+
default: E(() => [
|
|
205
|
+
m(a, { onClick: l[0] ||= (e) => q(0) }, {
|
|
206
|
+
default: E(() => [p(w(I.value.paragraph), 1)]),
|
|
179
207
|
_: 1
|
|
180
208
|
}),
|
|
181
|
-
|
|
182
|
-
default:
|
|
209
|
+
m(a, { onClick: l[1] ||= (e) => q(1) }, {
|
|
210
|
+
default: E(() => [p(w(I.value.heading1), 1)]),
|
|
183
211
|
_: 1
|
|
184
212
|
}),
|
|
185
|
-
|
|
186
|
-
default:
|
|
213
|
+
m(a, { onClick: l[2] ||= (e) => q(2) }, {
|
|
214
|
+
default: E(() => [p(w(I.value.heading2), 1)]),
|
|
187
215
|
_: 1
|
|
188
216
|
}),
|
|
189
|
-
|
|
190
|
-
default:
|
|
217
|
+
m(a, { onClick: l[3] ||= (e) => q(3) }, {
|
|
218
|
+
default: E(() => [p(w(I.value.heading3), 1)]),
|
|
191
219
|
_: 1
|
|
192
220
|
})
|
|
193
221
|
]),
|
|
194
222
|
_: 1
|
|
195
223
|
}),
|
|
196
|
-
|
|
197
|
-
(
|
|
224
|
+
l[10] ||= f("div", { class: "mx-1 h-6 w-px bg-outline-variant" }, null, -1),
|
|
225
|
+
(b(!0), d(c, null, S(V.value, (e, t) => (b(), d(c, { key: t }, [(b(!0), d(c, null, S(e, (e) => (b(), d("button", {
|
|
198
226
|
key: e.icon,
|
|
199
227
|
type: "button",
|
|
200
228
|
title: e.label,
|
|
201
|
-
class:
|
|
229
|
+
class: g(["flex h-8 w-8 cursor-pointer items-center justify-center rounded transition-colors duration-100", e.active?.() ? "bg-secondary-container text-on-secondary-container" : "text-on-surface-variant hover:bg-on-surface/8"]),
|
|
202
230
|
onClick: e.action
|
|
203
|
-
}, [
|
|
231
|
+
}, [m(o, {
|
|
204
232
|
name: e.icon,
|
|
205
233
|
size: 20
|
|
206
|
-
}, null, 8, ["name"])], 10,
|
|
207
|
-
|
|
208
|
-
|
|
234
|
+
}, null, 8, ["name"])], 10, A))), 128)), t < V.value.length - 1 ? (b(), d("div", j)) : u("", !0)], 64))), 128)),
|
|
235
|
+
l[11] ||= f("div", { class: "mx-1 h-6 w-px bg-outline-variant" }, null, -1),
|
|
236
|
+
f("button", {
|
|
209
237
|
type: "button",
|
|
210
|
-
title:
|
|
238
|
+
title: I.value.link,
|
|
211
239
|
class: "flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8",
|
|
212
|
-
onClick:
|
|
213
|
-
}, [
|
|
240
|
+
onClick: J
|
|
241
|
+
}, [m(o, {
|
|
214
242
|
name: "link",
|
|
215
243
|
size: 20
|
|
216
|
-
})]),
|
|
217
|
-
|
|
244
|
+
})], 8, M),
|
|
245
|
+
f("button", {
|
|
218
246
|
type: "button",
|
|
219
|
-
title:
|
|
247
|
+
title: I.value.image,
|
|
220
248
|
class: "flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8",
|
|
221
|
-
onClick:
|
|
222
|
-
}, [
|
|
249
|
+
onClick: X
|
|
250
|
+
}, [m(o, {
|
|
223
251
|
name: "image",
|
|
224
252
|
size: 20
|
|
225
|
-
})])
|
|
226
|
-
])) :
|
|
227
|
-
|
|
253
|
+
})], 8, N)
|
|
254
|
+
])) : u("", !0),
|
|
255
|
+
f("div", {
|
|
228
256
|
ref_key: "editorContainer",
|
|
229
|
-
ref:
|
|
257
|
+
ref: B,
|
|
230
258
|
class: "rte-content bg-surface px-4 py-3 text-body-large text-on-surface",
|
|
231
|
-
style:
|
|
259
|
+
style: _({ minHeight: s.minHeight })
|
|
232
260
|
}, null, 4),
|
|
233
|
-
|
|
234
|
-
modelValue:
|
|
235
|
-
"onUpdate:modelValue":
|
|
236
|
-
title:
|
|
261
|
+
m(t, {
|
|
262
|
+
modelValue: H.value,
|
|
263
|
+
"onUpdate:modelValue": l[6] ||= (e) => H.value = e,
|
|
264
|
+
title: I.value.insertLink
|
|
237
265
|
}, {
|
|
238
|
-
actions:
|
|
266
|
+
actions: E(() => [m(r, {
|
|
239
267
|
variant: "text",
|
|
240
|
-
onClick:
|
|
268
|
+
onClick: l[5] ||= (e) => H.value = !1
|
|
241
269
|
}, {
|
|
242
|
-
default:
|
|
270
|
+
default: E(() => [p(w(I.value.cancel), 1)]),
|
|
243
271
|
_: 1
|
|
244
|
-
}),
|
|
245
|
-
default:
|
|
272
|
+
}), m(r, { onClick: Y }, {
|
|
273
|
+
default: E(() => [p(w(I.value.insert), 1)]),
|
|
246
274
|
_: 1
|
|
247
275
|
})]),
|
|
248
|
-
default:
|
|
249
|
-
modelValue:
|
|
250
|
-
"onUpdate:modelValue":
|
|
276
|
+
default: E(() => [m(i, {
|
|
277
|
+
modelValue: U.value,
|
|
278
|
+
"onUpdate:modelValue": l[4] ||= (e) => U.value = e,
|
|
251
279
|
label: "URL",
|
|
252
280
|
placeholder: " ",
|
|
253
|
-
onKeydown:
|
|
281
|
+
onKeydown: D(Y, ["enter"])
|
|
254
282
|
}, null, 8, ["modelValue"])]),
|
|
255
283
|
_: 1
|
|
256
|
-
}, 8, ["modelValue"]),
|
|
257
|
-
|
|
258
|
-
modelValue:
|
|
259
|
-
"onUpdate:modelValue":
|
|
260
|
-
title:
|
|
284
|
+
}, 8, ["modelValue", "title"]),
|
|
285
|
+
m(t, {
|
|
286
|
+
modelValue: W.value,
|
|
287
|
+
"onUpdate:modelValue": l[9] ||= (e) => W.value = e,
|
|
288
|
+
title: I.value.insertImage
|
|
261
289
|
}, {
|
|
262
|
-
actions:
|
|
290
|
+
actions: E(() => [m(r, {
|
|
263
291
|
variant: "text",
|
|
264
|
-
onClick:
|
|
292
|
+
onClick: l[8] ||= (e) => W.value = !1
|
|
265
293
|
}, {
|
|
266
|
-
default:
|
|
294
|
+
default: E(() => [p(w(I.value.cancel), 1)]),
|
|
267
295
|
_: 1
|
|
268
|
-
}),
|
|
269
|
-
default:
|
|
296
|
+
}), m(r, { onClick: Z }, {
|
|
297
|
+
default: E(() => [p(w(I.value.insert), 1)]),
|
|
270
298
|
_: 1
|
|
271
299
|
})]),
|
|
272
|
-
default:
|
|
273
|
-
modelValue:
|
|
274
|
-
"onUpdate:modelValue":
|
|
275
|
-
label:
|
|
300
|
+
default: E(() => [m(i, {
|
|
301
|
+
modelValue: G.value,
|
|
302
|
+
"onUpdate:modelValue": l[7] ||= (e) => G.value = e,
|
|
303
|
+
label: I.value.imageUrlLabel,
|
|
276
304
|
placeholder: " ",
|
|
277
|
-
onKeydown:
|
|
278
|
-
}, null, 8, ["modelValue"])]),
|
|
305
|
+
onKeydown: D(Z, ["enter"])
|
|
306
|
+
}, null, 8, ["modelValue", "label"])]),
|
|
279
307
|
_: 1
|
|
280
|
-
}, 8, ["modelValue"])
|
|
308
|
+
}, 8, ["modelValue", "title"])
|
|
281
309
|
], 2));
|
|
282
310
|
}
|
|
283
|
-
}), [["__scopeId", "data-v-
|
|
311
|
+
}), [["__scopeId", "data-v-e6829e5c"]]);
|
|
284
312
|
//#endregion
|
|
285
|
-
export {
|
|
313
|
+
export { P as MRichTextEditor };
|
|
286
314
|
|
|
287
315
|
//# sourceMappingURL=rich-text-editor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rich-text-editor.js","names":[],"sources":["../src/components/MRichTextEditor.vue","../src/components/MRichTextEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount, shallowRef, computed } from 'vue'\nimport MIcon from './MIcon.vue'\nimport MMenu from './MMenu.vue'\nimport MMenuItem from './MMenuItem.vue'\nimport MDialog from './MDialog.vue'\nimport MTextField from './MTextField.vue'\nimport MButton from './MButton.vue'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string\n placeholder?: string\n disabled?: boolean\n minHeight?: string\n }>(),\n { placeholder: 'Escribe aquí...', disabled: false, minHeight: '200px' },\n)\n\nconst emit = defineEmits<{ 'update:modelValue': [string] }>()\n\nconst ready = ref(false)\nconst editorRef = shallowRef<any>(null)\nconst editorContainer = ref<HTMLElement | null>(null)\n\ninterface ToolBtn {\n icon: string\n label: string\n action: () => void\n active?: () => boolean\n}\n\nconst toolGroups = ref<ToolBtn[][]>([])\n\nonMounted(async () => {\n const [\n { Editor },\n { default: StarterKit },\n { default: Underline },\n { default: TextAlign },\n { default: Link },\n { default: Image },\n { default: Highlight },\n { default: Placeholder },\n { TextStyle },\n { default: Color },\n ] = await Promise.all([\n import('@tiptap/vue-3'),\n import('@tiptap/starter-kit'),\n import('@tiptap/extension-underline'),\n import('@tiptap/extension-text-align'),\n import('@tiptap/extension-link'),\n import('@tiptap/extension-image'),\n import('@tiptap/extension-highlight'),\n import('@tiptap/extension-placeholder'),\n import('@tiptap/extension-text-style'),\n import('@tiptap/extension-color'),\n ])\n\n const editor = new Editor({\n element: editorContainer.value!,\n content: props.modelValue,\n editable: !props.disabled,\n extensions: [\n StarterKit,\n Underline,\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Link.configure({ openOnClick: false }),\n Image,\n Highlight.configure({ multicolor: true }),\n Placeholder.configure({ placeholder: props.placeholder }),\n TextStyle,\n Color,\n ],\n onUpdate: ({ editor: e }) => emit('update:modelValue', e.getHTML()),\n })\n\n editorRef.value = editor\n\n toolGroups.value = [\n [\n { icon: 'format_bold', label: 'Negrita', action: () => editor.chain().focus().toggleBold().run(), active: () => !!editor.isActive('bold') },\n { icon: 'format_italic', label: 'Cursiva', action: () => editor.chain().focus().toggleItalic().run(), active: () => !!editor.isActive('italic') },\n { icon: 'format_underlined', label: 'Subrayado', action: () => editor.chain().focus().toggleUnderline().run(), active: () => !!editor.isActive('underline') },\n { icon: 'format_strikethrough', label: 'Tachado', action: () => editor.chain().focus().toggleStrike().run(), active: () => !!editor.isActive('strike') },\n { icon: 'ink_highlighter', label: 'Resaltar', action: () => editor.chain().focus().toggleHighlight().run(), active: () => !!editor.isActive('highlight') },\n ],\n [\n { icon: 'format_list_bulleted', label: 'Lista', action: () => editor.chain().focus().toggleBulletList().run(), active: () => !!editor.isActive('bulletList') },\n { icon: 'format_list_numbered', label: 'Lista numerada', action: () => editor.chain().focus().toggleOrderedList().run(), active: () => !!editor.isActive('orderedList') },\n { icon: 'format_quote', label: 'Cita', action: () => editor.chain().focus().toggleBlockquote().run(), active: () => !!editor.isActive('blockquote') },\n { icon: 'code', label: 'Código', action: () => editor.chain().focus().toggleCode().run(), active: () => !!editor.isActive('code') },\n ],\n [\n { icon: 'format_align_left', label: 'Izquierda', action: () => editor.chain().focus().setTextAlign('left').run(), active: () => !!editor.isActive({ textAlign: 'left' }) },\n { icon: 'format_align_center', label: 'Centro', action: () => editor.chain().focus().setTextAlign('center').run(), active: () => !!editor.isActive({ textAlign: 'center' }) },\n { icon: 'format_align_right', label: 'Derecha', action: () => editor.chain().focus().setTextAlign('right').run(), active: () => !!editor.isActive({ textAlign: 'right' }) },\n ],\n [\n { icon: 'undo', label: 'Deshacer', action: () => editor.chain().focus().undo().run() },\n { icon: 'redo', label: 'Rehacer', action: () => editor.chain().focus().redo().run() },\n ],\n ]\n\n onBeforeUnmount(() => editor.destroy())\n\n watch(() => props.modelValue, (val) => {\n if (editor.getHTML() !== val) editor.commands.setContent(val)\n })\n\n watch(() => props.disabled, (v) => editor.setEditable(!v))\n\n ready.value = true\n})\n\nconst linkDialogOpen = ref(false)\nconst linkUrl = ref('')\nconst imageDialogOpen = ref(false)\nconst imageUrl = ref('')\n\nconst headingLabel = computed(() => {\n const e = editorRef.value\n if (!e) return 'Párrafo'\n if (e.isActive('heading', { level: 1 })) return 'Título 1'\n if (e.isActive('heading', { level: 2 })) return 'Título 2'\n if (e.isActive('heading', { level: 3 })) return 'Título 3'\n return 'Párrafo'\n})\n\nfunction setHeading(level: 0 | 1 | 2 | 3) {\n if (level === 0) editorRef.value?.chain().focus().setParagraph().run()\n else editorRef.value?.chain().focus().toggleHeading({ level }).run()\n}\n\nfunction openLinkDialog() {\n linkUrl.value = ''\n linkDialogOpen.value = true\n}\n\nfunction confirmLink() {\n if (linkUrl.value) editorRef.value?.chain().focus().setLink({ href: linkUrl.value }).run()\n linkDialogOpen.value = false\n}\n\nfunction openImageDialog() {\n imageUrl.value = ''\n imageDialogOpen.value = true\n}\n\nfunction confirmImage() {\n if (imageUrl.value) editorRef.value?.chain().focus().setImage({ src: imageUrl.value }).run()\n imageDialogOpen.value = false\n}\n</script>\n\n<template>\n <div\n class=\"overflow-hidden rounded-lg border transition-colors duration-150\"\n :class=\"disabled ? 'border-outline-variant/50 opacity-60' : 'border-outline-variant focus-within:border-primary'\"\n >\n <!-- Toolbar -->\n <div v-if=\"ready\" class=\"flex flex-wrap items-center gap-0.5 border-b border-outline-variant bg-surface-container px-2 py-1.5\">\n <!-- Heading menu -->\n <MMenu align=\"left\">\n <template #trigger>\n <button\n type=\"button\"\n class=\"flex h-8 cursor-pointer items-center gap-1 rounded px-2 text-label-large text-on-surface-variant hover:bg-on-surface/8\"\n >\n {{ headingLabel }}\n <MIcon name=\"arrow_drop_down\" :size=\"20\" />\n </button>\n </template>\n <MMenuItem @click=\"setHeading(0)\">Párrafo</MMenuItem>\n <MMenuItem @click=\"setHeading(1)\">Título 1</MMenuItem>\n <MMenuItem @click=\"setHeading(2)\">Título 2</MMenuItem>\n <MMenuItem @click=\"setHeading(3)\">Título 3</MMenuItem>\n </MMenu>\n\n <div class=\"mx-1 h-6 w-px bg-outline-variant\" />\n\n <template v-for=\"(group, gi) in toolGroups\" :key=\"gi\">\n <button\n v-for=\"btn in group\"\n :key=\"btn.icon\"\n type=\"button\"\n :title=\"btn.label\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded transition-colors duration-100\"\n :class=\"btn.active?.() ? 'bg-secondary-container text-on-secondary-container' : 'text-on-surface-variant hover:bg-on-surface/8'\"\n @click=\"btn.action\"\n >\n <MIcon :name=\"btn.icon\" :size=\"20\" />\n </button>\n <div v-if=\"gi < toolGroups.length - 1\" class=\"mx-1 h-6 w-px bg-outline-variant\" />\n </template>\n\n <div class=\"mx-1 h-6 w-px bg-outline-variant\" />\n\n <button\n type=\"button\"\n title=\"Enlace\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8\"\n @click=\"openLinkDialog\"\n >\n <MIcon name=\"link\" :size=\"20\" />\n </button>\n <button\n type=\"button\"\n title=\"Imagen\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8\"\n @click=\"openImageDialog\"\n >\n <MIcon name=\"image\" :size=\"20\" />\n </button>\n </div>\n\n <!-- Editor content -->\n <div\n ref=\"editorContainer\"\n class=\"rte-content bg-surface px-4 py-3 text-body-large text-on-surface\"\n :style=\"{ minHeight: minHeight }\"\n />\n\n <!-- Link dialog -->\n <MDialog v-model=\"linkDialogOpen\" title=\"Insertar enlace\">\n <MTextField v-model=\"linkUrl\" label=\"URL\" placeholder=\" \" @keydown.enter=\"confirmLink\" />\n <template #actions>\n <MButton variant=\"text\" @click=\"linkDialogOpen = false\">Cancelar</MButton>\n <MButton @click=\"confirmLink\">Insertar</MButton>\n </template>\n </MDialog>\n\n <!-- Image dialog -->\n <MDialog v-model=\"imageDialogOpen\" title=\"Insertar imagen\">\n <MTextField v-model=\"imageUrl\" label=\"URL de la imagen\" placeholder=\" \" @keydown.enter=\"confirmImage\" />\n <template #actions>\n <MButton variant=\"text\" @click=\"imageDialogOpen = false\">Cancelar</MButton>\n <MButton @click=\"confirmImage\">Insertar</MButton>\n </template>\n </MDialog>\n </div>\n</template>\n\n<style scoped>\n.rte-content :deep(.tiptap) {\n outline: none;\n min-height: inherit;\n}\n\n.rte-content :deep(.tiptap p.is-editor-empty:first-child::before) {\n content: attr(data-placeholder);\n float: left;\n color: var(--color-on-surface-variant);\n opacity: 0.5;\n pointer-events: none;\n height: 0;\n}\n\n.rte-content :deep(h1) { font-size: var(--text-headline-large); line-height: var(--text-headline-large--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(h2) { font-size: var(--text-headline-medium); line-height: var(--text-headline-medium--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(h3) { font-size: var(--text-headline-small); line-height: var(--text-headline-small--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(p) { margin: 0.5em 0; }\n.rte-content :deep(ul) { list-style-type: disc; padding-left: 1.5em; margin: 0.5em 0; }\n.rte-content :deep(ol) { list-style-type: decimal; padding-left: 1.5em; margin: 0.5em 0; }\n.rte-content :deep(blockquote) { border-left: 3px solid var(--color-primary); padding-left: 1em; margin: 0.5em 0; color: var(--color-on-surface-variant); }\n.rte-content :deep(code) { background: var(--color-surface-container-highest); padding: 0.15em 0.4em; border-radius: 4px; font-size: 0.875em; }\n.rte-content :deep(pre) { background: var(--color-surface-container-highest); padding: 1em; border-radius: 8px; overflow-x: auto; margin: 0.5em 0; }\n.rte-content :deep(pre code) { background: none; padding: 0; }\n.rte-content :deep(a) { color: var(--color-primary); text-decoration: underline; }\n.rte-content :deep(mark) { background: var(--color-tertiary-container); color: var(--color-on-tertiary-container); padding: 0.1em 0.2em; border-radius: 2px; }\n.rte-content :deep(img) { max-width: 100%; height: auto; border-radius: 8px; margin: 0.5em 0; }\n</style>\n","<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount, shallowRef, computed } from 'vue'\nimport MIcon from './MIcon.vue'\nimport MMenu from './MMenu.vue'\nimport MMenuItem from './MMenuItem.vue'\nimport MDialog from './MDialog.vue'\nimport MTextField from './MTextField.vue'\nimport MButton from './MButton.vue'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string\n placeholder?: string\n disabled?: boolean\n minHeight?: string\n }>(),\n { placeholder: 'Escribe aquí...', disabled: false, minHeight: '200px' },\n)\n\nconst emit = defineEmits<{ 'update:modelValue': [string] }>()\n\nconst ready = ref(false)\nconst editorRef = shallowRef<any>(null)\nconst editorContainer = ref<HTMLElement | null>(null)\n\ninterface ToolBtn {\n icon: string\n label: string\n action: () => void\n active?: () => boolean\n}\n\nconst toolGroups = ref<ToolBtn[][]>([])\n\nonMounted(async () => {\n const [\n { Editor },\n { default: StarterKit },\n { default: Underline },\n { default: TextAlign },\n { default: Link },\n { default: Image },\n { default: Highlight },\n { default: Placeholder },\n { TextStyle },\n { default: Color },\n ] = await Promise.all([\n import('@tiptap/vue-3'),\n import('@tiptap/starter-kit'),\n import('@tiptap/extension-underline'),\n import('@tiptap/extension-text-align'),\n import('@tiptap/extension-link'),\n import('@tiptap/extension-image'),\n import('@tiptap/extension-highlight'),\n import('@tiptap/extension-placeholder'),\n import('@tiptap/extension-text-style'),\n import('@tiptap/extension-color'),\n ])\n\n const editor = new Editor({\n element: editorContainer.value!,\n content: props.modelValue,\n editable: !props.disabled,\n extensions: [\n StarterKit,\n Underline,\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Link.configure({ openOnClick: false }),\n Image,\n Highlight.configure({ multicolor: true }),\n Placeholder.configure({ placeholder: props.placeholder }),\n TextStyle,\n Color,\n ],\n onUpdate: ({ editor: e }) => emit('update:modelValue', e.getHTML()),\n })\n\n editorRef.value = editor\n\n toolGroups.value = [\n [\n { icon: 'format_bold', label: 'Negrita', action: () => editor.chain().focus().toggleBold().run(), active: () => !!editor.isActive('bold') },\n { icon: 'format_italic', label: 'Cursiva', action: () => editor.chain().focus().toggleItalic().run(), active: () => !!editor.isActive('italic') },\n { icon: 'format_underlined', label: 'Subrayado', action: () => editor.chain().focus().toggleUnderline().run(), active: () => !!editor.isActive('underline') },\n { icon: 'format_strikethrough', label: 'Tachado', action: () => editor.chain().focus().toggleStrike().run(), active: () => !!editor.isActive('strike') },\n { icon: 'ink_highlighter', label: 'Resaltar', action: () => editor.chain().focus().toggleHighlight().run(), active: () => !!editor.isActive('highlight') },\n ],\n [\n { icon: 'format_list_bulleted', label: 'Lista', action: () => editor.chain().focus().toggleBulletList().run(), active: () => !!editor.isActive('bulletList') },\n { icon: 'format_list_numbered', label: 'Lista numerada', action: () => editor.chain().focus().toggleOrderedList().run(), active: () => !!editor.isActive('orderedList') },\n { icon: 'format_quote', label: 'Cita', action: () => editor.chain().focus().toggleBlockquote().run(), active: () => !!editor.isActive('blockquote') },\n { icon: 'code', label: 'Código', action: () => editor.chain().focus().toggleCode().run(), active: () => !!editor.isActive('code') },\n ],\n [\n { icon: 'format_align_left', label: 'Izquierda', action: () => editor.chain().focus().setTextAlign('left').run(), active: () => !!editor.isActive({ textAlign: 'left' }) },\n { icon: 'format_align_center', label: 'Centro', action: () => editor.chain().focus().setTextAlign('center').run(), active: () => !!editor.isActive({ textAlign: 'center' }) },\n { icon: 'format_align_right', label: 'Derecha', action: () => editor.chain().focus().setTextAlign('right').run(), active: () => !!editor.isActive({ textAlign: 'right' }) },\n ],\n [\n { icon: 'undo', label: 'Deshacer', action: () => editor.chain().focus().undo().run() },\n { icon: 'redo', label: 'Rehacer', action: () => editor.chain().focus().redo().run() },\n ],\n ]\n\n onBeforeUnmount(() => editor.destroy())\n\n watch(() => props.modelValue, (val) => {\n if (editor.getHTML() !== val) editor.commands.setContent(val)\n })\n\n watch(() => props.disabled, (v) => editor.setEditable(!v))\n\n ready.value = true\n})\n\nconst linkDialogOpen = ref(false)\nconst linkUrl = ref('')\nconst imageDialogOpen = ref(false)\nconst imageUrl = ref('')\n\nconst headingLabel = computed(() => {\n const e = editorRef.value\n if (!e) return 'Párrafo'\n if (e.isActive('heading', { level: 1 })) return 'Título 1'\n if (e.isActive('heading', { level: 2 })) return 'Título 2'\n if (e.isActive('heading', { level: 3 })) return 'Título 3'\n return 'Párrafo'\n})\n\nfunction setHeading(level: 0 | 1 | 2 | 3) {\n if (level === 0) editorRef.value?.chain().focus().setParagraph().run()\n else editorRef.value?.chain().focus().toggleHeading({ level }).run()\n}\n\nfunction openLinkDialog() {\n linkUrl.value = ''\n linkDialogOpen.value = true\n}\n\nfunction confirmLink() {\n if (linkUrl.value) editorRef.value?.chain().focus().setLink({ href: linkUrl.value }).run()\n linkDialogOpen.value = false\n}\n\nfunction openImageDialog() {\n imageUrl.value = ''\n imageDialogOpen.value = true\n}\n\nfunction confirmImage() {\n if (imageUrl.value) editorRef.value?.chain().focus().setImage({ src: imageUrl.value }).run()\n imageDialogOpen.value = false\n}\n</script>\n\n<template>\n <div\n class=\"overflow-hidden rounded-lg border transition-colors duration-150\"\n :class=\"disabled ? 'border-outline-variant/50 opacity-60' : 'border-outline-variant focus-within:border-primary'\"\n >\n <!-- Toolbar -->\n <div v-if=\"ready\" class=\"flex flex-wrap items-center gap-0.5 border-b border-outline-variant bg-surface-container px-2 py-1.5\">\n <!-- Heading menu -->\n <MMenu align=\"left\">\n <template #trigger>\n <button\n type=\"button\"\n class=\"flex h-8 cursor-pointer items-center gap-1 rounded px-2 text-label-large text-on-surface-variant hover:bg-on-surface/8\"\n >\n {{ headingLabel }}\n <MIcon name=\"arrow_drop_down\" :size=\"20\" />\n </button>\n </template>\n <MMenuItem @click=\"setHeading(0)\">Párrafo</MMenuItem>\n <MMenuItem @click=\"setHeading(1)\">Título 1</MMenuItem>\n <MMenuItem @click=\"setHeading(2)\">Título 2</MMenuItem>\n <MMenuItem @click=\"setHeading(3)\">Título 3</MMenuItem>\n </MMenu>\n\n <div class=\"mx-1 h-6 w-px bg-outline-variant\" />\n\n <template v-for=\"(group, gi) in toolGroups\" :key=\"gi\">\n <button\n v-for=\"btn in group\"\n :key=\"btn.icon\"\n type=\"button\"\n :title=\"btn.label\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded transition-colors duration-100\"\n :class=\"btn.active?.() ? 'bg-secondary-container text-on-secondary-container' : 'text-on-surface-variant hover:bg-on-surface/8'\"\n @click=\"btn.action\"\n >\n <MIcon :name=\"btn.icon\" :size=\"20\" />\n </button>\n <div v-if=\"gi < toolGroups.length - 1\" class=\"mx-1 h-6 w-px bg-outline-variant\" />\n </template>\n\n <div class=\"mx-1 h-6 w-px bg-outline-variant\" />\n\n <button\n type=\"button\"\n title=\"Enlace\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8\"\n @click=\"openLinkDialog\"\n >\n <MIcon name=\"link\" :size=\"20\" />\n </button>\n <button\n type=\"button\"\n title=\"Imagen\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8\"\n @click=\"openImageDialog\"\n >\n <MIcon name=\"image\" :size=\"20\" />\n </button>\n </div>\n\n <!-- Editor content -->\n <div\n ref=\"editorContainer\"\n class=\"rte-content bg-surface px-4 py-3 text-body-large text-on-surface\"\n :style=\"{ minHeight: minHeight }\"\n />\n\n <!-- Link dialog -->\n <MDialog v-model=\"linkDialogOpen\" title=\"Insertar enlace\">\n <MTextField v-model=\"linkUrl\" label=\"URL\" placeholder=\" \" @keydown.enter=\"confirmLink\" />\n <template #actions>\n <MButton variant=\"text\" @click=\"linkDialogOpen = false\">Cancelar</MButton>\n <MButton @click=\"confirmLink\">Insertar</MButton>\n </template>\n </MDialog>\n\n <!-- Image dialog -->\n <MDialog v-model=\"imageDialogOpen\" title=\"Insertar imagen\">\n <MTextField v-model=\"imageUrl\" label=\"URL de la imagen\" placeholder=\" \" @keydown.enter=\"confirmImage\" />\n <template #actions>\n <MButton variant=\"text\" @click=\"imageDialogOpen = false\">Cancelar</MButton>\n <MButton @click=\"confirmImage\">Insertar</MButton>\n </template>\n </MDialog>\n </div>\n</template>\n\n<style scoped>\n.rte-content :deep(.tiptap) {\n outline: none;\n min-height: inherit;\n}\n\n.rte-content :deep(.tiptap p.is-editor-empty:first-child::before) {\n content: attr(data-placeholder);\n float: left;\n color: var(--color-on-surface-variant);\n opacity: 0.5;\n pointer-events: none;\n height: 0;\n}\n\n.rte-content :deep(h1) { font-size: var(--text-headline-large); line-height: var(--text-headline-large--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(h2) { font-size: var(--text-headline-medium); line-height: var(--text-headline-medium--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(h3) { font-size: var(--text-headline-small); line-height: var(--text-headline-small--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(p) { margin: 0.5em 0; }\n.rte-content :deep(ul) { list-style-type: disc; padding-left: 1.5em; margin: 0.5em 0; }\n.rte-content :deep(ol) { list-style-type: decimal; padding-left: 1.5em; margin: 0.5em 0; }\n.rte-content :deep(blockquote) { border-left: 3px solid var(--color-primary); padding-left: 1em; margin: 0.5em 0; color: var(--color-on-surface-variant); }\n.rte-content :deep(code) { background: var(--color-surface-container-highest); padding: 0.15em 0.4em; border-radius: 4px; font-size: 0.875em; }\n.rte-content :deep(pre) { background: var(--color-surface-container-highest); padding: 1em; border-radius: 8px; overflow-x: auto; margin: 0.5em 0; }\n.rte-content :deep(pre code) { background: none; padding: 0; }\n.rte-content :deep(a) { color: var(--color-primary); text-decoration: underline; }\n.rte-content :deep(mark) { background: var(--color-tertiary-container); color: var(--color-on-tertiary-container); padding: 0.1em 0.2em; border-radius: 2px; }\n.rte-content :deep(img) { max-width: 100%; height: auto; border-radius: 8px; margin: 0.5em 0; }\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rich-text-editor.js","names":[],"sources":["../src/components/MRichTextEditor.vue","../src/components/MRichTextEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount, shallowRef, computed } from 'vue'\nimport MIcon from './MIcon.vue'\nimport MMenu from './MMenu.vue'\nimport MMenuItem from './MMenuItem.vue'\nimport MDialog from './MDialog.vue'\nimport MTextField from './MTextField.vue'\nimport MButton from './MButton.vue'\nimport { useLocale } from '../composables/useLocale'\n\nexport interface RichTextEditorLabels {\n bold?: string\n italic?: string\n underline?: string\n strikethrough?: string\n highlight?: string\n bulletList?: string\n orderedList?: string\n blockquote?: string\n code?: string\n alignLeft?: string\n alignCenter?: string\n alignRight?: string\n undo?: string\n redo?: string\n link?: string\n image?: string\n paragraph?: string\n heading1?: string\n heading2?: string\n heading3?: string\n insertLink?: string\n insertImage?: string\n imageUrlLabel?: string\n cancel?: string\n insert?: string\n}\n\nconst locale = useLocale()\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string\n placeholder?: string\n disabled?: boolean\n minHeight?: string\n labels?: RichTextEditorLabels\n }>(),\n { disabled: false, minHeight: '200px' },\n)\n\nconst l = computed<Required<RichTextEditorLabels>>(() => ({\n bold: locale.bold,\n italic: locale.italic,\n underline: locale.underline,\n strikethrough: locale.strikethrough,\n highlight: locale.highlight,\n bulletList: locale.bulletList,\n orderedList: locale.orderedList,\n blockquote: locale.blockquote,\n code: locale.code,\n alignLeft: locale.alignLeft,\n alignCenter: locale.alignCenter,\n alignRight: locale.alignRight,\n undo: locale.undo,\n redo: locale.redo,\n link: locale.link,\n image: locale.image,\n paragraph: locale.paragraph,\n heading1: locale.heading1,\n heading2: locale.heading2,\n heading3: locale.heading3,\n insertLink: locale.insertLink,\n insertImage: locale.insertImage,\n imageUrlLabel: locale.imageUrlLabel,\n cancel: locale.cancel,\n insert: locale.insert,\n ...props.labels,\n}))\n\nconst emit = defineEmits<{ 'update:modelValue': [string] }>()\n\nconst ready = ref(false)\nconst editorRef = shallowRef<any>(null)\nconst editorContainer = ref<HTMLElement | null>(null)\n\ninterface ToolBtn {\n icon: string\n label: string\n action: () => void\n active?: () => boolean\n}\n\nconst toolGroups = ref<ToolBtn[][]>([])\n\nonMounted(async () => {\n const [\n { Editor },\n { default: StarterKit },\n { default: Underline },\n { default: TextAlign },\n { default: Link },\n { default: Image },\n { default: Highlight },\n { default: Placeholder },\n { TextStyle },\n { default: Color },\n ] = await Promise.all([\n import('@tiptap/vue-3'),\n import('@tiptap/starter-kit'),\n import('@tiptap/extension-underline'),\n import('@tiptap/extension-text-align'),\n import('@tiptap/extension-link'),\n import('@tiptap/extension-image'),\n import('@tiptap/extension-highlight'),\n import('@tiptap/extension-placeholder'),\n import('@tiptap/extension-text-style'),\n import('@tiptap/extension-color'),\n ])\n\n const editor = new Editor({\n element: editorContainer.value!,\n content: props.modelValue,\n editable: !props.disabled,\n extensions: [\n StarterKit,\n Underline,\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Link.configure({ openOnClick: false }),\n Image,\n Highlight.configure({ multicolor: true }),\n Placeholder.configure({ placeholder: props.placeholder ?? 'Start writing...' }),\n TextStyle,\n Color,\n ],\n onUpdate: ({ editor: e }) => emit('update:modelValue', e.getHTML()),\n })\n\n editorRef.value = editor\n\n toolGroups.value = [\n [\n { icon: 'format_bold', label: l.value.bold, action: () => editor.chain().focus().toggleBold().run(), active: () => !!editor.isActive('bold') },\n { icon: 'format_italic', label: l.value.italic, action: () => editor.chain().focus().toggleItalic().run(), active: () => !!editor.isActive('italic') },\n { icon: 'format_underlined', label: l.value.underline, action: () => editor.chain().focus().toggleUnderline().run(), active: () => !!editor.isActive('underline') },\n { icon: 'format_strikethrough', label: l.value.strikethrough, action: () => editor.chain().focus().toggleStrike().run(), active: () => !!editor.isActive('strike') },\n { icon: 'ink_highlighter', label: l.value.highlight, action: () => editor.chain().focus().toggleHighlight().run(), active: () => !!editor.isActive('highlight') },\n ],\n [\n { icon: 'format_list_bulleted', label: l.value.bulletList, action: () => editor.chain().focus().toggleBulletList().run(), active: () => !!editor.isActive('bulletList') },\n { icon: 'format_list_numbered', label: l.value.orderedList, action: () => editor.chain().focus().toggleOrderedList().run(), active: () => !!editor.isActive('orderedList') },\n { icon: 'format_quote', label: l.value.blockquote, action: () => editor.chain().focus().toggleBlockquote().run(), active: () => !!editor.isActive('blockquote') },\n { icon: 'code', label: l.value.code, action: () => editor.chain().focus().toggleCode().run(), active: () => !!editor.isActive('code') },\n ],\n [\n { icon: 'format_align_left', label: l.value.alignLeft, action: () => editor.chain().focus().setTextAlign('left').run(), active: () => !!editor.isActive({ textAlign: 'left' }) },\n { icon: 'format_align_center', label: l.value.alignCenter, action: () => editor.chain().focus().setTextAlign('center').run(), active: () => !!editor.isActive({ textAlign: 'center' }) },\n { icon: 'format_align_right', label: l.value.alignRight, action: () => editor.chain().focus().setTextAlign('right').run(), active: () => !!editor.isActive({ textAlign: 'right' }) },\n ],\n [\n { icon: 'undo', label: l.value.undo, action: () => editor.chain().focus().undo().run() },\n { icon: 'redo', label: l.value.redo, action: () => editor.chain().focus().redo().run() },\n ],\n ]\n\n onBeforeUnmount(() => editor.destroy())\n\n watch(() => props.modelValue, (val) => {\n if (editor.getHTML() !== val) editor.commands.setContent(val)\n })\n\n watch(() => props.disabled, (v) => editor.setEditable(!v))\n\n ready.value = true\n})\n\nconst linkDialogOpen = ref(false)\nconst linkUrl = ref('')\nconst imageDialogOpen = ref(false)\nconst imageUrl = ref('')\n\nconst headingLabel = computed(() => {\n const e = editorRef.value\n if (!e) return l.value.paragraph\n if (e.isActive('heading', { level: 1 })) return l.value.heading1\n if (e.isActive('heading', { level: 2 })) return l.value.heading2\n if (e.isActive('heading', { level: 3 })) return l.value.heading3\n return l.value.paragraph\n})\n\nfunction setHeading(level: 0 | 1 | 2 | 3) {\n if (level === 0) editorRef.value?.chain().focus().setParagraph().run()\n else editorRef.value?.chain().focus().toggleHeading({ level }).run()\n}\n\nfunction openLinkDialog() {\n linkUrl.value = ''\n linkDialogOpen.value = true\n}\n\nfunction confirmLink() {\n if (linkUrl.value) editorRef.value?.chain().focus().setLink({ href: linkUrl.value }).run()\n linkDialogOpen.value = false\n}\n\nfunction openImageDialog() {\n imageUrl.value = ''\n imageDialogOpen.value = true\n}\n\nfunction confirmImage() {\n if (imageUrl.value) editorRef.value?.chain().focus().setImage({ src: imageUrl.value }).run()\n imageDialogOpen.value = false\n}\n</script>\n\n<template>\n <div\n class=\"overflow-hidden rounded-lg border transition-colors duration-150\"\n :class=\"disabled ? 'border-outline-variant/50 opacity-60' : 'border-outline-variant focus-within:border-primary'\"\n >\n <!-- Toolbar -->\n <div v-if=\"ready\" class=\"flex flex-wrap items-center gap-0.5 border-b border-outline-variant bg-surface-container px-2 py-1.5\">\n <!-- Heading menu -->\n <MMenu align=\"left\">\n <template #trigger>\n <button\n type=\"button\"\n class=\"flex h-8 cursor-pointer items-center gap-1 rounded px-2 text-label-large text-on-surface-variant hover:bg-on-surface/8\"\n >\n {{ headingLabel }}\n <MIcon name=\"arrow_drop_down\" :size=\"20\" />\n </button>\n </template>\n <MMenuItem @click=\"setHeading(0)\">{{ l.paragraph }}</MMenuItem>\n <MMenuItem @click=\"setHeading(1)\">{{ l.heading1 }}</MMenuItem>\n <MMenuItem @click=\"setHeading(2)\">{{ l.heading2 }}</MMenuItem>\n <MMenuItem @click=\"setHeading(3)\">{{ l.heading3 }}</MMenuItem>\n </MMenu>\n\n <div class=\"mx-1 h-6 w-px bg-outline-variant\" />\n\n <template v-for=\"(group, gi) in toolGroups\" :key=\"gi\">\n <button\n v-for=\"btn in group\"\n :key=\"btn.icon\"\n type=\"button\"\n :title=\"btn.label\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded transition-colors duration-100\"\n :class=\"btn.active?.() ? 'bg-secondary-container text-on-secondary-container' : 'text-on-surface-variant hover:bg-on-surface/8'\"\n @click=\"btn.action\"\n >\n <MIcon :name=\"btn.icon\" :size=\"20\" />\n </button>\n <div v-if=\"gi < toolGroups.length - 1\" class=\"mx-1 h-6 w-px bg-outline-variant\" />\n </template>\n\n <div class=\"mx-1 h-6 w-px bg-outline-variant\" />\n\n <button\n type=\"button\"\n :title=\"l.link\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8\"\n @click=\"openLinkDialog\"\n >\n <MIcon name=\"link\" :size=\"20\" />\n </button>\n <button\n type=\"button\"\n :title=\"l.image\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8\"\n @click=\"openImageDialog\"\n >\n <MIcon name=\"image\" :size=\"20\" />\n </button>\n </div>\n\n <!-- Editor content -->\n <div\n ref=\"editorContainer\"\n class=\"rte-content bg-surface px-4 py-3 text-body-large text-on-surface\"\n :style=\"{ minHeight: minHeight }\"\n />\n\n <!-- Link dialog -->\n <MDialog v-model=\"linkDialogOpen\" :title=\"l.insertLink\">\n <MTextField v-model=\"linkUrl\" label=\"URL\" placeholder=\" \" @keydown.enter=\"confirmLink\" />\n <template #actions>\n <MButton variant=\"text\" @click=\"linkDialogOpen = false\">{{ l.cancel }}</MButton>\n <MButton @click=\"confirmLink\">{{ l.insert }}</MButton>\n </template>\n </MDialog>\n\n <!-- Image dialog -->\n <MDialog v-model=\"imageDialogOpen\" :title=\"l.insertImage\">\n <MTextField v-model=\"imageUrl\" :label=\"l.imageUrlLabel\" placeholder=\" \" @keydown.enter=\"confirmImage\" />\n <template #actions>\n <MButton variant=\"text\" @click=\"imageDialogOpen = false\">{{ l.cancel }}</MButton>\n <MButton @click=\"confirmImage\">{{ l.insert }}</MButton>\n </template>\n </MDialog>\n </div>\n</template>\n\n<style scoped>\n.rte-content :deep(.tiptap) {\n outline: none;\n min-height: inherit;\n}\n\n.rte-content :deep(.tiptap p.is-editor-empty:first-child::before) {\n content: attr(data-placeholder);\n float: left;\n color: var(--color-on-surface-variant);\n opacity: 0.5;\n pointer-events: none;\n height: 0;\n}\n\n.rte-content :deep(h1) { font-size: var(--text-headline-large); line-height: var(--text-headline-large--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(h2) { font-size: var(--text-headline-medium); line-height: var(--text-headline-medium--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(h3) { font-size: var(--text-headline-small); line-height: var(--text-headline-small--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(p) { margin: 0.5em 0; }\n.rte-content :deep(ul) { list-style-type: disc; padding-left: 1.5em; margin: 0.5em 0; }\n.rte-content :deep(ol) { list-style-type: decimal; padding-left: 1.5em; margin: 0.5em 0; }\n.rte-content :deep(blockquote) { border-left: 3px solid var(--color-primary); padding-left: 1em; margin: 0.5em 0; color: var(--color-on-surface-variant); }\n.rte-content :deep(code) { background: var(--color-surface-container-highest); padding: 0.15em 0.4em; border-radius: 4px; font-size: 0.875em; }\n.rte-content :deep(pre) { background: var(--color-surface-container-highest); padding: 1em; border-radius: 8px; overflow-x: auto; margin: 0.5em 0; }\n.rte-content :deep(pre code) { background: none; padding: 0; }\n.rte-content :deep(a) { color: var(--color-primary); text-decoration: underline; }\n.rte-content :deep(mark) { background: var(--color-tertiary-container); color: var(--color-on-tertiary-container); padding: 0.1em 0.2em; border-radius: 2px; }\n.rte-content :deep(img) { max-width: 100%; height: auto; border-radius: 8px; margin: 0.5em 0; }\n</style>\n","<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount, shallowRef, computed } from 'vue'\nimport MIcon from './MIcon.vue'\nimport MMenu from './MMenu.vue'\nimport MMenuItem from './MMenuItem.vue'\nimport MDialog from './MDialog.vue'\nimport MTextField from './MTextField.vue'\nimport MButton from './MButton.vue'\nimport { useLocale } from '../composables/useLocale'\n\nexport interface RichTextEditorLabels {\n bold?: string\n italic?: string\n underline?: string\n strikethrough?: string\n highlight?: string\n bulletList?: string\n orderedList?: string\n blockquote?: string\n code?: string\n alignLeft?: string\n alignCenter?: string\n alignRight?: string\n undo?: string\n redo?: string\n link?: string\n image?: string\n paragraph?: string\n heading1?: string\n heading2?: string\n heading3?: string\n insertLink?: string\n insertImage?: string\n imageUrlLabel?: string\n cancel?: string\n insert?: string\n}\n\nconst locale = useLocale()\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string\n placeholder?: string\n disabled?: boolean\n minHeight?: string\n labels?: RichTextEditorLabels\n }>(),\n { disabled: false, minHeight: '200px' },\n)\n\nconst l = computed<Required<RichTextEditorLabels>>(() => ({\n bold: locale.bold,\n italic: locale.italic,\n underline: locale.underline,\n strikethrough: locale.strikethrough,\n highlight: locale.highlight,\n bulletList: locale.bulletList,\n orderedList: locale.orderedList,\n blockquote: locale.blockquote,\n code: locale.code,\n alignLeft: locale.alignLeft,\n alignCenter: locale.alignCenter,\n alignRight: locale.alignRight,\n undo: locale.undo,\n redo: locale.redo,\n link: locale.link,\n image: locale.image,\n paragraph: locale.paragraph,\n heading1: locale.heading1,\n heading2: locale.heading2,\n heading3: locale.heading3,\n insertLink: locale.insertLink,\n insertImage: locale.insertImage,\n imageUrlLabel: locale.imageUrlLabel,\n cancel: locale.cancel,\n insert: locale.insert,\n ...props.labels,\n}))\n\nconst emit = defineEmits<{ 'update:modelValue': [string] }>()\n\nconst ready = ref(false)\nconst editorRef = shallowRef<any>(null)\nconst editorContainer = ref<HTMLElement | null>(null)\n\ninterface ToolBtn {\n icon: string\n label: string\n action: () => void\n active?: () => boolean\n}\n\nconst toolGroups = ref<ToolBtn[][]>([])\n\nonMounted(async () => {\n const [\n { Editor },\n { default: StarterKit },\n { default: Underline },\n { default: TextAlign },\n { default: Link },\n { default: Image },\n { default: Highlight },\n { default: Placeholder },\n { TextStyle },\n { default: Color },\n ] = await Promise.all([\n import('@tiptap/vue-3'),\n import('@tiptap/starter-kit'),\n import('@tiptap/extension-underline'),\n import('@tiptap/extension-text-align'),\n import('@tiptap/extension-link'),\n import('@tiptap/extension-image'),\n import('@tiptap/extension-highlight'),\n import('@tiptap/extension-placeholder'),\n import('@tiptap/extension-text-style'),\n import('@tiptap/extension-color'),\n ])\n\n const editor = new Editor({\n element: editorContainer.value!,\n content: props.modelValue,\n editable: !props.disabled,\n extensions: [\n StarterKit,\n Underline,\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Link.configure({ openOnClick: false }),\n Image,\n Highlight.configure({ multicolor: true }),\n Placeholder.configure({ placeholder: props.placeholder ?? 'Start writing...' }),\n TextStyle,\n Color,\n ],\n onUpdate: ({ editor: e }) => emit('update:modelValue', e.getHTML()),\n })\n\n editorRef.value = editor\n\n toolGroups.value = [\n [\n { icon: 'format_bold', label: l.value.bold, action: () => editor.chain().focus().toggleBold().run(), active: () => !!editor.isActive('bold') },\n { icon: 'format_italic', label: l.value.italic, action: () => editor.chain().focus().toggleItalic().run(), active: () => !!editor.isActive('italic') },\n { icon: 'format_underlined', label: l.value.underline, action: () => editor.chain().focus().toggleUnderline().run(), active: () => !!editor.isActive('underline') },\n { icon: 'format_strikethrough', label: l.value.strikethrough, action: () => editor.chain().focus().toggleStrike().run(), active: () => !!editor.isActive('strike') },\n { icon: 'ink_highlighter', label: l.value.highlight, action: () => editor.chain().focus().toggleHighlight().run(), active: () => !!editor.isActive('highlight') },\n ],\n [\n { icon: 'format_list_bulleted', label: l.value.bulletList, action: () => editor.chain().focus().toggleBulletList().run(), active: () => !!editor.isActive('bulletList') },\n { icon: 'format_list_numbered', label: l.value.orderedList, action: () => editor.chain().focus().toggleOrderedList().run(), active: () => !!editor.isActive('orderedList') },\n { icon: 'format_quote', label: l.value.blockquote, action: () => editor.chain().focus().toggleBlockquote().run(), active: () => !!editor.isActive('blockquote') },\n { icon: 'code', label: l.value.code, action: () => editor.chain().focus().toggleCode().run(), active: () => !!editor.isActive('code') },\n ],\n [\n { icon: 'format_align_left', label: l.value.alignLeft, action: () => editor.chain().focus().setTextAlign('left').run(), active: () => !!editor.isActive({ textAlign: 'left' }) },\n { icon: 'format_align_center', label: l.value.alignCenter, action: () => editor.chain().focus().setTextAlign('center').run(), active: () => !!editor.isActive({ textAlign: 'center' }) },\n { icon: 'format_align_right', label: l.value.alignRight, action: () => editor.chain().focus().setTextAlign('right').run(), active: () => !!editor.isActive({ textAlign: 'right' }) },\n ],\n [\n { icon: 'undo', label: l.value.undo, action: () => editor.chain().focus().undo().run() },\n { icon: 'redo', label: l.value.redo, action: () => editor.chain().focus().redo().run() },\n ],\n ]\n\n onBeforeUnmount(() => editor.destroy())\n\n watch(() => props.modelValue, (val) => {\n if (editor.getHTML() !== val) editor.commands.setContent(val)\n })\n\n watch(() => props.disabled, (v) => editor.setEditable(!v))\n\n ready.value = true\n})\n\nconst linkDialogOpen = ref(false)\nconst linkUrl = ref('')\nconst imageDialogOpen = ref(false)\nconst imageUrl = ref('')\n\nconst headingLabel = computed(() => {\n const e = editorRef.value\n if (!e) return l.value.paragraph\n if (e.isActive('heading', { level: 1 })) return l.value.heading1\n if (e.isActive('heading', { level: 2 })) return l.value.heading2\n if (e.isActive('heading', { level: 3 })) return l.value.heading3\n return l.value.paragraph\n})\n\nfunction setHeading(level: 0 | 1 | 2 | 3) {\n if (level === 0) editorRef.value?.chain().focus().setParagraph().run()\n else editorRef.value?.chain().focus().toggleHeading({ level }).run()\n}\n\nfunction openLinkDialog() {\n linkUrl.value = ''\n linkDialogOpen.value = true\n}\n\nfunction confirmLink() {\n if (linkUrl.value) editorRef.value?.chain().focus().setLink({ href: linkUrl.value }).run()\n linkDialogOpen.value = false\n}\n\nfunction openImageDialog() {\n imageUrl.value = ''\n imageDialogOpen.value = true\n}\n\nfunction confirmImage() {\n if (imageUrl.value) editorRef.value?.chain().focus().setImage({ src: imageUrl.value }).run()\n imageDialogOpen.value = false\n}\n</script>\n\n<template>\n <div\n class=\"overflow-hidden rounded-lg border transition-colors duration-150\"\n :class=\"disabled ? 'border-outline-variant/50 opacity-60' : 'border-outline-variant focus-within:border-primary'\"\n >\n <!-- Toolbar -->\n <div v-if=\"ready\" class=\"flex flex-wrap items-center gap-0.5 border-b border-outline-variant bg-surface-container px-2 py-1.5\">\n <!-- Heading menu -->\n <MMenu align=\"left\">\n <template #trigger>\n <button\n type=\"button\"\n class=\"flex h-8 cursor-pointer items-center gap-1 rounded px-2 text-label-large text-on-surface-variant hover:bg-on-surface/8\"\n >\n {{ headingLabel }}\n <MIcon name=\"arrow_drop_down\" :size=\"20\" />\n </button>\n </template>\n <MMenuItem @click=\"setHeading(0)\">{{ l.paragraph }}</MMenuItem>\n <MMenuItem @click=\"setHeading(1)\">{{ l.heading1 }}</MMenuItem>\n <MMenuItem @click=\"setHeading(2)\">{{ l.heading2 }}</MMenuItem>\n <MMenuItem @click=\"setHeading(3)\">{{ l.heading3 }}</MMenuItem>\n </MMenu>\n\n <div class=\"mx-1 h-6 w-px bg-outline-variant\" />\n\n <template v-for=\"(group, gi) in toolGroups\" :key=\"gi\">\n <button\n v-for=\"btn in group\"\n :key=\"btn.icon\"\n type=\"button\"\n :title=\"btn.label\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded transition-colors duration-100\"\n :class=\"btn.active?.() ? 'bg-secondary-container text-on-secondary-container' : 'text-on-surface-variant hover:bg-on-surface/8'\"\n @click=\"btn.action\"\n >\n <MIcon :name=\"btn.icon\" :size=\"20\" />\n </button>\n <div v-if=\"gi < toolGroups.length - 1\" class=\"mx-1 h-6 w-px bg-outline-variant\" />\n </template>\n\n <div class=\"mx-1 h-6 w-px bg-outline-variant\" />\n\n <button\n type=\"button\"\n :title=\"l.link\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8\"\n @click=\"openLinkDialog\"\n >\n <MIcon name=\"link\" :size=\"20\" />\n </button>\n <button\n type=\"button\"\n :title=\"l.image\"\n class=\"flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8\"\n @click=\"openImageDialog\"\n >\n <MIcon name=\"image\" :size=\"20\" />\n </button>\n </div>\n\n <!-- Editor content -->\n <div\n ref=\"editorContainer\"\n class=\"rte-content bg-surface px-4 py-3 text-body-large text-on-surface\"\n :style=\"{ minHeight: minHeight }\"\n />\n\n <!-- Link dialog -->\n <MDialog v-model=\"linkDialogOpen\" :title=\"l.insertLink\">\n <MTextField v-model=\"linkUrl\" label=\"URL\" placeholder=\" \" @keydown.enter=\"confirmLink\" />\n <template #actions>\n <MButton variant=\"text\" @click=\"linkDialogOpen = false\">{{ l.cancel }}</MButton>\n <MButton @click=\"confirmLink\">{{ l.insert }}</MButton>\n </template>\n </MDialog>\n\n <!-- Image dialog -->\n <MDialog v-model=\"imageDialogOpen\" :title=\"l.insertImage\">\n <MTextField v-model=\"imageUrl\" :label=\"l.imageUrlLabel\" placeholder=\" \" @keydown.enter=\"confirmImage\" />\n <template #actions>\n <MButton variant=\"text\" @click=\"imageDialogOpen = false\">{{ l.cancel }}</MButton>\n <MButton @click=\"confirmImage\">{{ l.insert }}</MButton>\n </template>\n </MDialog>\n </div>\n</template>\n\n<style scoped>\n.rte-content :deep(.tiptap) {\n outline: none;\n min-height: inherit;\n}\n\n.rte-content :deep(.tiptap p.is-editor-empty:first-child::before) {\n content: attr(data-placeholder);\n float: left;\n color: var(--color-on-surface-variant);\n opacity: 0.5;\n pointer-events: none;\n height: 0;\n}\n\n.rte-content :deep(h1) { font-size: var(--text-headline-large); line-height: var(--text-headline-large--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(h2) { font-size: var(--text-headline-medium); line-height: var(--text-headline-medium--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(h3) { font-size: var(--text-headline-small); line-height: var(--text-headline-small--line-height); font-weight: 600; margin: 0.75em 0 0.25em; }\n.rte-content :deep(p) { margin: 0.5em 0; }\n.rte-content :deep(ul) { list-style-type: disc; padding-left: 1.5em; margin: 0.5em 0; }\n.rte-content :deep(ol) { list-style-type: decimal; padding-left: 1.5em; margin: 0.5em 0; }\n.rte-content :deep(blockquote) { border-left: 3px solid var(--color-primary); padding-left: 1em; margin: 0.5em 0; color: var(--color-on-surface-variant); }\n.rte-content :deep(code) { background: var(--color-surface-container-highest); padding: 0.15em 0.4em; border-radius: 4px; font-size: 0.875em; }\n.rte-content :deep(pre) { background: var(--color-surface-container-highest); padding: 1em; border-radius: 8px; overflow-x: auto; margin: 0.5em 0; }\n.rte-content :deep(pre code) { background: none; padding: 0; }\n.rte-content :deep(a) { color: var(--color-primary); text-decoration: underline; }\n.rte-content :deep(mark) { background: var(--color-tertiary-container); color: var(--color-on-tertiary-container); padding: 0.1em 0.2em; border-radius: 2px; }\n.rte-content :deep(img) { max-width: 100%; height: auto; border-radius: 8px; margin: 0.5em 0; }\n</style>\n"],"mappings":"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"}
|