@m3ui-vue/m3ui-vue 0.1.0 → 0.1.2

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 (64) hide show
  1. package/README.md +80 -23
  2. package/dist/MIcon-CaEooCmZ.js +20 -0
  3. package/dist/MIcon-CaEooCmZ.js.map +1 -0
  4. package/dist/_plugin-vue_export-helper-B3ysoDQm.js +8 -0
  5. package/dist/chart.d.ts +1 -0
  6. package/dist/chart.js +141 -0
  7. package/dist/chart.js.map +1 -0
  8. package/dist/code-editor.d.ts +2 -0
  9. package/dist/code-editor.js +379 -0
  10. package/dist/code-editor.js.map +1 -0
  11. package/dist/components/MButton.vue.d.ts +1 -1
  12. package/dist/components/MCalendar.vue.d.ts +1 -1
  13. package/dist/components/MChart.vue.d.ts +2 -3
  14. package/dist/components/MCodeEditor.vue.d.ts +3 -1
  15. package/dist/components/MContainer.vue.d.ts +1 -1
  16. package/dist/components/MDataTable.vue.d.ts +1 -1
  17. package/dist/components/MFab.vue.d.ts +0 -2
  18. package/dist/components/MIconButton.vue.d.ts +1 -1
  19. package/dist/components/MMultiSelect.vue.d.ts +1 -1
  20. package/dist/components/MProgressBar.vue.d.ts +1 -1
  21. package/dist/components/MRichTextEditor.vue.d.ts +1 -1
  22. package/dist/components/MScheduler.vue.d.ts +1 -1
  23. package/dist/components/MSelect.vue.d.ts +1 -1
  24. package/dist/components/MSkeleton.vue.d.ts +1 -1
  25. package/dist/components/MSpotlightSearch.vue.d.ts +1 -1
  26. package/dist/components/MStack.vue.d.ts +2 -2
  27. package/dist/components/MTerminal.vue.d.ts +6 -6
  28. package/dist/components/MTextField.vue.d.ts +1 -1
  29. package/dist/components/MTooltip.vue.d.ts +1 -1
  30. package/dist/dist-Dsrzt6J5.js +1192 -0
  31. package/dist/dist-Dsrzt6J5.js.map +1 -0
  32. package/dist/index.d.ts +0 -6
  33. package/dist/m3ui-vue.css +2 -0
  34. package/dist/m3ui.js +2738 -3367
  35. package/dist/m3ui.js.map +1 -1
  36. package/dist/markdown.d.ts +1 -0
  37. package/dist/markdown.js +41 -0
  38. package/dist/markdown.js.map +1 -0
  39. package/dist/rich-text-editor.d.ts +1 -0
  40. package/dist/rich-text-editor.js +215 -0
  41. package/dist/rich-text-editor.js.map +1 -0
  42. package/dist/styles/theme.css +3 -0
  43. package/dist/styles.css +2 -0
  44. package/dist/terminal.d.ts +1 -0
  45. package/dist/terminal.js +97 -0
  46. package/dist/terminal.js.map +1 -0
  47. package/package.json +28 -2
  48. package/src/chart.ts +1 -0
  49. package/src/code-editor.ts +2 -0
  50. package/src/components/MAlert.vue +1 -1
  51. package/src/components/MChart.vue +54 -47
  52. package/src/components/MCodeEditor.vue +149 -44
  53. package/src/components/MFab.vue +64 -48
  54. package/src/components/MMarkdown.vue +24 -17
  55. package/src/components/MMultiSelect.vue +3 -2
  56. package/src/components/MRichTextEditor.vue +101 -67
  57. package/src/components/MTerminal.vue +10 -8
  58. package/src/components/MTooltip.vue +8 -1
  59. package/src/index.ts +6 -6
  60. package/src/markdown.ts +1 -0
  61. package/src/rich-text-editor.ts +1 -0
  62. package/src/styles/theme.css +3 -0
  63. package/src/terminal.ts +1 -0
  64. package/dist/m3ui.css +0 -2
@@ -0,0 +1 @@
1
+ export { default as MMarkdown } from './components/MMarkdown.vue';
@@ -0,0 +1,41 @@
1
+ import { t as e } from "./_plugin-vue_export-helper-B3ysoDQm.js";
2
+ import { computed as t, createElementBlock as n, defineComponent as r, onMounted as i, openBlock as a, ref as o } from "vue";
3
+ //#region src/components/MMarkdown.vue?vue&type=script&setup=true&lang.ts
4
+ var s = ["innerHTML"], c = /*#__PURE__*/ e(/* @__PURE__ */ r({
5
+ __name: "MMarkdown",
6
+ props: {
7
+ source: {},
8
+ breaks: {
9
+ type: Boolean,
10
+ default: !0
11
+ },
12
+ linkify: {
13
+ type: Boolean,
14
+ default: !0
15
+ }
16
+ },
17
+ setup(e) {
18
+ let r = e, c = o(null);
19
+ i(async () => {
20
+ let { default: e } = await import("markdown-it"), t = new e({
21
+ html: !1,
22
+ breaks: r.breaks,
23
+ linkify: r.linkify,
24
+ typographer: !0
25
+ });
26
+ t.renderer.rules.link_open = (e, t, n, r, i) => {
27
+ let a = e[t];
28
+ return a && (a.attrSet("target", "_blank"), a.attrSet("rel", "noopener noreferrer")), i.renderToken(e, t, n);
29
+ }, c.value = t;
30
+ });
31
+ let l = t(() => c.value ? c.value.render(r.source) : "");
32
+ return (e, t) => (a(), n("div", {
33
+ class: "m3-markdown text-body-large text-on-surface",
34
+ innerHTML: l.value
35
+ }, null, 8, s));
36
+ }
37
+ }), [["__scopeId", "data-v-6e4dc2b6"]]);
38
+ //#endregion
39
+ export { c as MMarkdown };
40
+
41
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","names":[],"sources":["../src/components/MMarkdown.vue","../src/components/MMarkdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, onMounted } from 'vue'\n\nconst props = withDefaults(\n defineProps<{\n source: string\n breaks?: boolean\n linkify?: boolean\n }>(),\n { breaks: true, linkify: true },\n)\n\nconst md = ref<any>(null)\n\nonMounted(async () => {\n const { default: MarkdownIt } = await import('markdown-it')\n\n const instance = new MarkdownIt({\n html: false,\n breaks: props.breaks,\n linkify: props.linkify,\n typographer: true,\n })\n\n instance.renderer.rules.link_open = (tokens: any, idx: number, options: any, _env: any, self: any) => {\n const token = tokens[idx]\n if (token) {\n token.attrSet('target', '_blank')\n token.attrSet('rel', 'noopener noreferrer')\n }\n return self.renderToken(tokens, idx, options)\n }\n\n md.value = instance\n})\n\nconst rendered = computed(() => md.value ? md.value.render(props.source) : '')\n</script>\n\n<template>\n <div class=\"m3-markdown text-body-large text-on-surface\" v-html=\"rendered\" />\n</template>\n\n<style scoped>\n.m3-markdown :deep(h1) { font-size: var(--text-headline-large); line-height: var(--text-headline-large--line-height); font-weight: 600; margin: 1em 0 0.5em; color: var(--color-on-surface); }\n.m3-markdown :deep(h2) { font-size: var(--text-headline-medium); line-height: var(--text-headline-medium--line-height); font-weight: 600; margin: 1em 0 0.5em; color: var(--color-on-surface); }\n.m3-markdown :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; color: var(--color-on-surface); }\n.m3-markdown :deep(h4) { font-size: var(--text-title-large); line-height: var(--text-title-large--line-height); font-weight: 600; margin: 0.75em 0 0.25em; color: var(--color-on-surface); }\n\n.m3-markdown :deep(p) { margin: 0.5em 0; }\n\n.m3-markdown :deep(a) {\n color: var(--color-primary);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.m3-markdown :deep(a:hover) { opacity: 0.8; }\n\n.m3-markdown :deep(strong) { font-weight: 600; color: var(--color-on-surface); }\n.m3-markdown :deep(em) { font-style: italic; }\n\n.m3-markdown :deep(ul),\n.m3-markdown :deep(ol) { padding-left: 1.5em; margin: 0.5em 0; }\n.m3-markdown :deep(li) { margin: 0.25em 0; }\n.m3-markdown :deep(li::marker) { color: var(--color-on-surface-variant); }\n\n.m3-markdown :deep(blockquote) {\n border-left: 3px solid var(--color-primary);\n padding: 0.5em 1em;\n margin: 0.75em 0;\n background: var(--color-surface-container);\n border-radius: 0 8px 8px 0;\n color: var(--color-on-surface-variant);\n}\n\n.m3-markdown :deep(code) {\n background: var(--color-surface-container-highest);\n padding: 0.15em 0.4em;\n border-radius: 4px;\n font-family: 'JetBrains Mono', 'Fira Code', monospace;\n font-size: 0.875em;\n color: var(--color-primary);\n}\n\n.m3-markdown :deep(pre) {\n background: var(--color-surface-container-highest);\n padding: 1em;\n border-radius: 12px;\n overflow-x: auto;\n margin: 0.75em 0;\n border: 1px solid var(--color-outline-variant);\n}\n.m3-markdown :deep(pre code) {\n background: none;\n padding: 0;\n color: var(--color-on-surface);\n}\n\n.m3-markdown :deep(hr) {\n border: none;\n border-top: 1px solid var(--color-outline-variant);\n margin: 1.5em 0;\n}\n\n.m3-markdown :deep(table) {\n width: 100%;\n border-collapse: collapse;\n margin: 0.75em 0;\n}\n.m3-markdown :deep(th) {\n background: var(--color-surface-container);\n font-weight: 600;\n text-align: left;\n padding: 0.5em 0.75em;\n border-bottom: 2px solid var(--color-outline-variant);\n font-size: var(--text-label-large);\n color: var(--color-on-surface);\n}\n.m3-markdown :deep(td) {\n padding: 0.5em 0.75em;\n border-bottom: 1px solid var(--color-outline-variant);\n}\n\n.m3-markdown :deep(img) {\n max-width: 100%;\n height: auto;\n border-radius: 12px;\n margin: 0.5em 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref, onMounted } from 'vue'\n\nconst props = withDefaults(\n defineProps<{\n source: string\n breaks?: boolean\n linkify?: boolean\n }>(),\n { breaks: true, linkify: true },\n)\n\nconst md = ref<any>(null)\n\nonMounted(async () => {\n const { default: MarkdownIt } = await import('markdown-it')\n\n const instance = new MarkdownIt({\n html: false,\n breaks: props.breaks,\n linkify: props.linkify,\n typographer: true,\n })\n\n instance.renderer.rules.link_open = (tokens: any, idx: number, options: any, _env: any, self: any) => {\n const token = tokens[idx]\n if (token) {\n token.attrSet('target', '_blank')\n token.attrSet('rel', 'noopener noreferrer')\n }\n return self.renderToken(tokens, idx, options)\n }\n\n md.value = instance\n})\n\nconst rendered = computed(() => md.value ? md.value.render(props.source) : '')\n</script>\n\n<template>\n <div class=\"m3-markdown text-body-large text-on-surface\" v-html=\"rendered\" />\n</template>\n\n<style scoped>\n.m3-markdown :deep(h1) { font-size: var(--text-headline-large); line-height: var(--text-headline-large--line-height); font-weight: 600; margin: 1em 0 0.5em; color: var(--color-on-surface); }\n.m3-markdown :deep(h2) { font-size: var(--text-headline-medium); line-height: var(--text-headline-medium--line-height); font-weight: 600; margin: 1em 0 0.5em; color: var(--color-on-surface); }\n.m3-markdown :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; color: var(--color-on-surface); }\n.m3-markdown :deep(h4) { font-size: var(--text-title-large); line-height: var(--text-title-large--line-height); font-weight: 600; margin: 0.75em 0 0.25em; color: var(--color-on-surface); }\n\n.m3-markdown :deep(p) { margin: 0.5em 0; }\n\n.m3-markdown :deep(a) {\n color: var(--color-primary);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.m3-markdown :deep(a:hover) { opacity: 0.8; }\n\n.m3-markdown :deep(strong) { font-weight: 600; color: var(--color-on-surface); }\n.m3-markdown :deep(em) { font-style: italic; }\n\n.m3-markdown :deep(ul),\n.m3-markdown :deep(ol) { padding-left: 1.5em; margin: 0.5em 0; }\n.m3-markdown :deep(li) { margin: 0.25em 0; }\n.m3-markdown :deep(li::marker) { color: var(--color-on-surface-variant); }\n\n.m3-markdown :deep(blockquote) {\n border-left: 3px solid var(--color-primary);\n padding: 0.5em 1em;\n margin: 0.75em 0;\n background: var(--color-surface-container);\n border-radius: 0 8px 8px 0;\n color: var(--color-on-surface-variant);\n}\n\n.m3-markdown :deep(code) {\n background: var(--color-surface-container-highest);\n padding: 0.15em 0.4em;\n border-radius: 4px;\n font-family: 'JetBrains Mono', 'Fira Code', monospace;\n font-size: 0.875em;\n color: var(--color-primary);\n}\n\n.m3-markdown :deep(pre) {\n background: var(--color-surface-container-highest);\n padding: 1em;\n border-radius: 12px;\n overflow-x: auto;\n margin: 0.75em 0;\n border: 1px solid var(--color-outline-variant);\n}\n.m3-markdown :deep(pre code) {\n background: none;\n padding: 0;\n color: var(--color-on-surface);\n}\n\n.m3-markdown :deep(hr) {\n border: none;\n border-top: 1px solid var(--color-outline-variant);\n margin: 1.5em 0;\n}\n\n.m3-markdown :deep(table) {\n width: 100%;\n border-collapse: collapse;\n margin: 0.75em 0;\n}\n.m3-markdown :deep(th) {\n background: var(--color-surface-container);\n font-weight: 600;\n text-align: left;\n padding: 0.5em 0.75em;\n border-bottom: 2px solid var(--color-outline-variant);\n font-size: var(--text-label-large);\n color: var(--color-on-surface);\n}\n.m3-markdown :deep(td) {\n padding: 0.5em 0.75em;\n border-bottom: 1px solid var(--color-outline-variant);\n}\n\n.m3-markdown :deep(img) {\n max-width: 100%;\n height: auto;\n border-radius: 12px;\n margin: 0.5em 0;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;EAGA,IAAM,IAAQ,GASR,IAAK,EAAS,IAAI;EAExB,EAAU,YAAY;GACpB,IAAM,EAAE,SAAS,MAAe,MAAM,OAAO,gBAEvC,IAAW,IAAI,EAAW;IAC9B,MAAM;IACN,QAAQ,EAAM;IACd,SAAS,EAAM;IACf,aAAa;GACf,CAAC;GAWD,AATA,EAAS,SAAS,MAAM,aAAa,GAAa,GAAa,GAAc,GAAW,MAAc;IACpG,IAAM,IAAQ,EAAO;IAKrB,OAJI,MACF,EAAM,QAAQ,UAAU,QAAQ,GAChC,EAAM,QAAQ,OAAO,qBAAqB,IAErC,EAAK,YAAY,GAAQ,GAAK,CAAO;GAC9C,GAEA,EAAG,QAAQ;EACb,CAAC;EAED,IAAM,IAAW,QAAe,EAAG,QAAQ,EAAG,MAAM,OAAO,EAAM,MAAM,IAAI,EAAE;yBAI3E,EAA6E,OAAA;GAAxE,OAAM;GAA8C,WAAQ,EAAA"}
@@ -0,0 +1 @@
1
+ export { default as MRichTextEditor } from './components/MRichTextEditor.vue';
@@ -0,0 +1,215 @@
1
+ import { t as e } from "./MIcon-CaEooCmZ.js";
2
+ import { t } from "./_plugin-vue_export-helper-B3ysoDQm.js";
3
+ import { Fragment as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createVNode as o, defineComponent as s, normalizeClass as c, normalizeStyle as l, onBeforeUnmount as u, onMounted as d, openBlock as f, ref as p, renderList as m, shallowRef as h, watch as g } from "vue";
4
+ //#region src/components/MRichTextEditor.vue?vue&type=script&setup=true&lang.ts
5
+ var _ = {
6
+ key: 0,
7
+ class: "flex flex-wrap items-center gap-0.5 border-b border-outline-variant bg-surface-container px-2 py-1.5"
8
+ }, v = ["value"], y = ["title", "onClick"], b = {
9
+ key: 0,
10
+ class: "mx-1 h-6 w-px bg-outline-variant"
11
+ }, x = /*#__PURE__*/ t(/* @__PURE__ */ s({
12
+ __name: "MRichTextEditor",
13
+ props: {
14
+ modelValue: {},
15
+ placeholder: { default: "Escribe aquí..." },
16
+ disabled: {
17
+ type: Boolean,
18
+ default: !1
19
+ },
20
+ minHeight: { default: "200px" }
21
+ },
22
+ emits: ["update:modelValue"],
23
+ setup(t, { emit: s }) {
24
+ let x = t, S = s, C = p(!1), w = h(null), T = p(null), E = p([]);
25
+ d(async () => {
26
+ let [{ useEditor: e, EditorContent: t }, { default: n }, { default: r }, { default: i }, { default: a }, { default: o }, { default: s }, { default: c }, { TextStyle: l }, { default: d }] = await Promise.all([
27
+ import("@tiptap/vue-3"),
28
+ import("@tiptap/starter-kit"),
29
+ import("@tiptap/extension-underline"),
30
+ import("@tiptap/extension-text-align"),
31
+ import("@tiptap/extension-link"),
32
+ import("@tiptap/extension-image"),
33
+ import("@tiptap/extension-highlight"),
34
+ import("@tiptap/extension-placeholder"),
35
+ import("@tiptap/extension-text-style"),
36
+ import("@tiptap/extension-color")
37
+ ]), f = e({
38
+ content: x.modelValue,
39
+ editable: !x.disabled,
40
+ extensions: [
41
+ n,
42
+ r,
43
+ i.configure({ types: ["heading", "paragraph"] }),
44
+ a.configure({ openOnClick: !1 }),
45
+ o,
46
+ s.configure({ multicolor: !0 }),
47
+ c.configure({ placeholder: x.placeholder }),
48
+ l,
49
+ d
50
+ ],
51
+ onUpdate: ({ editor: e }) => S("update:modelValue", e.getHTML())
52
+ });
53
+ if (w.value = f, E.value = [
54
+ [
55
+ {
56
+ icon: "format_bold",
57
+ label: "Negrita",
58
+ action: () => f.value?.chain().focus().toggleBold().run(),
59
+ active: () => !!f.value?.isActive("bold")
60
+ },
61
+ {
62
+ icon: "format_italic",
63
+ label: "Cursiva",
64
+ action: () => f.value?.chain().focus().toggleItalic().run(),
65
+ active: () => !!f.value?.isActive("italic")
66
+ },
67
+ {
68
+ icon: "format_underlined",
69
+ label: "Subrayado",
70
+ action: () => f.value?.chain().focus().toggleUnderline().run(),
71
+ active: () => !!f.value?.isActive("underline")
72
+ },
73
+ {
74
+ icon: "format_strikethrough",
75
+ label: "Tachado",
76
+ action: () => f.value?.chain().focus().toggleStrike().run(),
77
+ active: () => !!f.value?.isActive("strike")
78
+ },
79
+ {
80
+ icon: "ink_highlighter",
81
+ label: "Resaltar",
82
+ action: () => f.value?.chain().focus().toggleHighlight().run(),
83
+ active: () => !!f.value?.isActive("highlight")
84
+ }
85
+ ],
86
+ [
87
+ {
88
+ icon: "format_list_bulleted",
89
+ label: "Lista",
90
+ action: () => f.value?.chain().focus().toggleBulletList().run(),
91
+ active: () => !!f.value?.isActive("bulletList")
92
+ },
93
+ {
94
+ icon: "format_list_numbered",
95
+ label: "Lista numerada",
96
+ action: () => f.value?.chain().focus().toggleOrderedList().run(),
97
+ active: () => !!f.value?.isActive("orderedList")
98
+ },
99
+ {
100
+ icon: "format_quote",
101
+ label: "Cita",
102
+ action: () => f.value?.chain().focus().toggleBlockquote().run(),
103
+ active: () => !!f.value?.isActive("blockquote")
104
+ },
105
+ {
106
+ icon: "code",
107
+ label: "Código",
108
+ action: () => f.value?.chain().focus().toggleCode().run(),
109
+ active: () => !!f.value?.isActive("code")
110
+ }
111
+ ],
112
+ [
113
+ {
114
+ icon: "format_align_left",
115
+ label: "Izquierda",
116
+ action: () => f.value?.chain().focus().setTextAlign("left").run(),
117
+ active: () => !!f.value?.isActive({ textAlign: "left" })
118
+ },
119
+ {
120
+ icon: "format_align_center",
121
+ label: "Centro",
122
+ action: () => f.value?.chain().focus().setTextAlign("center").run(),
123
+ active: () => !!f.value?.isActive({ textAlign: "center" })
124
+ },
125
+ {
126
+ icon: "format_align_right",
127
+ label: "Derecha",
128
+ action: () => f.value?.chain().focus().setTextAlign("right").run(),
129
+ active: () => !!f.value?.isActive({ textAlign: "right" })
130
+ }
131
+ ],
132
+ [{
133
+ icon: "undo",
134
+ label: "Deshacer",
135
+ action: () => f.value?.chain().focus().undo().run()
136
+ }, {
137
+ icon: "redo",
138
+ label: "Rehacer",
139
+ action: () => f.value?.chain().focus().redo().run()
140
+ }]
141
+ ], T.value) {
142
+ let e = (await import("vue")).createApp(t, { editor: f.value });
143
+ e.mount(T.value), u(() => e.unmount());
144
+ }
145
+ g(() => x.modelValue, (e) => {
146
+ f.value && f.value.getHTML() !== e && f.value.commands.setContent(e);
147
+ }), g(() => x.disabled, (e) => f.value?.setEditable(!e)), C.value = !0;
148
+ });
149
+ function D() {
150
+ let e = window.prompt("URL del enlace:");
151
+ e && w.value?.value?.chain().focus().setLink({ href: e }).run();
152
+ }
153
+ function O() {
154
+ let e = window.prompt("URL de la imagen:");
155
+ e && w.value?.value?.chain().focus().setImage({ src: e }).run();
156
+ }
157
+ function k(e) {
158
+ w.value?.value?.chain().focus().toggleHeading({ level: e }).run();
159
+ }
160
+ return (s, u) => (f(), i("div", { class: c(["overflow-hidden rounded-lg border transition-colors duration-150", t.disabled ? "border-outline-variant/50 opacity-60" : "border-outline-variant focus-within:border-primary"]) }, [C.value ? (f(), i("div", _, [
161
+ a("select", {
162
+ class: "h-8 cursor-pointer rounded bg-transparent px-2 text-label-large text-on-surface-variant outline-none hover:bg-on-surface/8",
163
+ value: w.value?.value?.isActive("heading", { level: 1 }) ? "1" : w.value?.value?.isActive("heading", { level: 2 }) ? "2" : w.value?.value?.isActive("heading", { level: 3 }) ? "3" : "0",
164
+ onChange: u[0] ||= (e) => {
165
+ let t = e.target.value;
166
+ t === "0" ? w.value?.value?.chain().focus().setParagraph().run() : k(Number(t));
167
+ }
168
+ }, [...u[1] ||= [
169
+ a("option", { value: "0" }, "Párrafo", -1),
170
+ a("option", { value: "1" }, "Título 1", -1),
171
+ a("option", { value: "2" }, "Título 2", -1),
172
+ a("option", { value: "3" }, "Título 3", -1)
173
+ ]], 40, v),
174
+ u[2] ||= a("div", { class: "mx-1 h-6 w-px bg-outline-variant" }, null, -1),
175
+ (f(!0), i(n, null, m(E.value, (t, a) => (f(), i(n, { key: a }, [(f(!0), i(n, null, m(t, (t) => (f(), i("button", {
176
+ key: t.icon,
177
+ type: "button",
178
+ title: t.label,
179
+ class: c(["flex h-8 w-8 cursor-pointer items-center justify-center rounded transition-colors duration-100", t.active?.() ? "bg-secondary-container text-on-secondary-container" : "text-on-surface-variant hover:bg-on-surface/8"]),
180
+ onClick: t.action
181
+ }, [o(e, {
182
+ name: t.icon,
183
+ size: 20
184
+ }, null, 8, ["name"])], 10, y))), 128)), a < E.value.length - 1 ? (f(), i("div", b)) : r("", !0)], 64))), 128)),
185
+ u[3] ||= a("div", { class: "mx-1 h-6 w-px bg-outline-variant" }, null, -1),
186
+ a("button", {
187
+ type: "button",
188
+ title: "Enlace",
189
+ class: "flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8",
190
+ onClick: D
191
+ }, [o(e, {
192
+ name: "link",
193
+ size: 20
194
+ })]),
195
+ a("button", {
196
+ type: "button",
197
+ title: "Imagen",
198
+ class: "flex h-8 w-8 cursor-pointer items-center justify-center rounded text-on-surface-variant transition-colors hover:bg-on-surface/8",
199
+ onClick: O
200
+ }, [o(e, {
201
+ name: "image",
202
+ size: 20
203
+ })])
204
+ ])) : r("", !0), a("div", {
205
+ ref_key: "editorContainer",
206
+ ref: T,
207
+ class: "rte-content bg-surface px-4 py-3 text-body-large text-on-surface",
208
+ style: l({ minHeight: t.minHeight })
209
+ }, null, 4)], 2));
210
+ }
211
+ }), [["__scopeId", "data-v-89c08c83"]]);
212
+ //#endregion
213
+ export { x as MRichTextEditor };
214
+
215
+ //# sourceMappingURL=rich-text-editor.js.map
@@ -0,0 +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 } from 'vue'\nimport MIcon from './MIcon.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 { useEditor, EditorContent },\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 = useEditor({\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.value?.chain().focus().toggleBold().run(), active: () => !!editor.value?.isActive('bold') },\n { icon: 'format_italic', label: 'Cursiva', action: () => editor.value?.chain().focus().toggleItalic().run(), active: () => !!editor.value?.isActive('italic') },\n { icon: 'format_underlined', label: 'Subrayado', action: () => editor.value?.chain().focus().toggleUnderline().run(), active: () => !!editor.value?.isActive('underline') },\n { icon: 'format_strikethrough', label: 'Tachado', action: () => editor.value?.chain().focus().toggleStrike().run(), active: () => !!editor.value?.isActive('strike') },\n { icon: 'ink_highlighter', label: 'Resaltar', action: () => editor.value?.chain().focus().toggleHighlight().run(), active: () => !!editor.value?.isActive('highlight') },\n ],\n [\n { icon: 'format_list_bulleted', label: 'Lista', action: () => editor.value?.chain().focus().toggleBulletList().run(), active: () => !!editor.value?.isActive('bulletList') },\n { icon: 'format_list_numbered', label: 'Lista numerada', action: () => editor.value?.chain().focus().toggleOrderedList().run(), active: () => !!editor.value?.isActive('orderedList') },\n { icon: 'format_quote', label: 'Cita', action: () => editor.value?.chain().focus().toggleBlockquote().run(), active: () => !!editor.value?.isActive('blockquote') },\n { icon: 'code', label: 'Código', action: () => editor.value?.chain().focus().toggleCode().run(), active: () => !!editor.value?.isActive('code') },\n ],\n [\n { icon: 'format_align_left', label: 'Izquierda', action: () => editor.value?.chain().focus().setTextAlign('left').run(), active: () => !!editor.value?.isActive({ textAlign: 'left' }) },\n { icon: 'format_align_center', label: 'Centro', action: () => editor.value?.chain().focus().setTextAlign('center').run(), active: () => !!editor.value?.isActive({ textAlign: 'center' }) },\n { icon: 'format_align_right', label: 'Derecha', action: () => editor.value?.chain().focus().setTextAlign('right').run(), active: () => !!editor.value?.isActive({ textAlign: 'right' }) },\n ],\n [\n { icon: 'undo', label: 'Deshacer', action: () => editor.value?.chain().focus().undo().run() },\n { icon: 'redo', label: 'Rehacer', action: () => editor.value?.chain().focus().redo().run() },\n ],\n ]\n\n // Mount EditorContent manually since we can't use the component from dynamic import in template\n if (editorContainer.value) {\n const app = await import('vue')\n const editorApp = app.createApp(EditorContent, { editor: editor.value })\n editorApp.mount(editorContainer.value)\n onBeforeUnmount(() => editorApp.unmount())\n }\n\n watch(() => props.modelValue, (val) => {\n if (editor.value && editor.value.getHTML() !== val) editor.value.commands.setContent(val)\n })\n\n watch(() => props.disabled, (v) => editor.value?.setEditable(!v))\n\n ready.value = true\n})\n\nfunction insertLink() {\n const url = window.prompt('URL del enlace:')\n if (url) editorRef.value?.value?.chain().focus().setLink({ href: url }).run()\n}\n\nfunction insertImage() {\n const url = window.prompt('URL de la imagen:')\n if (url) editorRef.value?.value?.chain().focus().setImage({ src: url }).run()\n}\n\nfunction setHeading(level: 1 | 2 | 3) {\n editorRef.value?.value?.chain().focus().toggleHeading({ level }).run()\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 select -->\n <select\n class=\"h-8 cursor-pointer rounded bg-transparent px-2 text-label-large text-on-surface-variant outline-none hover:bg-on-surface/8\"\n :value=\"\n editorRef?.value?.isActive('heading', { level: 1 }) ? '1'\n : editorRef?.value?.isActive('heading', { level: 2 }) ? '2'\n : editorRef?.value?.isActive('heading', { level: 3 }) ? '3'\n : '0'\n \"\n @change=\"(e: Event) => {\n const v = (e.target as HTMLSelectElement).value\n if (v === '0') editorRef?.value?.chain().focus().setParagraph().run()\n else setHeading(Number(v) as 1 | 2 | 3)\n }\"\n >\n <option value=\"0\">Párrafo</option>\n <option value=\"1\">Título 1</option>\n <option value=\"2\">Título 2</option>\n <option value=\"3\">Título 3</option>\n </select>\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=\"insertLink\"\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=\"insertImage\"\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 </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),\n.rte-content :deep(ol) { 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 } from 'vue'\nimport MIcon from './MIcon.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 { useEditor, EditorContent },\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 = useEditor({\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.value?.chain().focus().toggleBold().run(), active: () => !!editor.value?.isActive('bold') },\n { icon: 'format_italic', label: 'Cursiva', action: () => editor.value?.chain().focus().toggleItalic().run(), active: () => !!editor.value?.isActive('italic') },\n { icon: 'format_underlined', label: 'Subrayado', action: () => editor.value?.chain().focus().toggleUnderline().run(), active: () => !!editor.value?.isActive('underline') },\n { icon: 'format_strikethrough', label: 'Tachado', action: () => editor.value?.chain().focus().toggleStrike().run(), active: () => !!editor.value?.isActive('strike') },\n { icon: 'ink_highlighter', label: 'Resaltar', action: () => editor.value?.chain().focus().toggleHighlight().run(), active: () => !!editor.value?.isActive('highlight') },\n ],\n [\n { icon: 'format_list_bulleted', label: 'Lista', action: () => editor.value?.chain().focus().toggleBulletList().run(), active: () => !!editor.value?.isActive('bulletList') },\n { icon: 'format_list_numbered', label: 'Lista numerada', action: () => editor.value?.chain().focus().toggleOrderedList().run(), active: () => !!editor.value?.isActive('orderedList') },\n { icon: 'format_quote', label: 'Cita', action: () => editor.value?.chain().focus().toggleBlockquote().run(), active: () => !!editor.value?.isActive('blockquote') },\n { icon: 'code', label: 'Código', action: () => editor.value?.chain().focus().toggleCode().run(), active: () => !!editor.value?.isActive('code') },\n ],\n [\n { icon: 'format_align_left', label: 'Izquierda', action: () => editor.value?.chain().focus().setTextAlign('left').run(), active: () => !!editor.value?.isActive({ textAlign: 'left' }) },\n { icon: 'format_align_center', label: 'Centro', action: () => editor.value?.chain().focus().setTextAlign('center').run(), active: () => !!editor.value?.isActive({ textAlign: 'center' }) },\n { icon: 'format_align_right', label: 'Derecha', action: () => editor.value?.chain().focus().setTextAlign('right').run(), active: () => !!editor.value?.isActive({ textAlign: 'right' }) },\n ],\n [\n { icon: 'undo', label: 'Deshacer', action: () => editor.value?.chain().focus().undo().run() },\n { icon: 'redo', label: 'Rehacer', action: () => editor.value?.chain().focus().redo().run() },\n ],\n ]\n\n // Mount EditorContent manually since we can't use the component from dynamic import in template\n if (editorContainer.value) {\n const app = await import('vue')\n const editorApp = app.createApp(EditorContent, { editor: editor.value })\n editorApp.mount(editorContainer.value)\n onBeforeUnmount(() => editorApp.unmount())\n }\n\n watch(() => props.modelValue, (val) => {\n if (editor.value && editor.value.getHTML() !== val) editor.value.commands.setContent(val)\n })\n\n watch(() => props.disabled, (v) => editor.value?.setEditable(!v))\n\n ready.value = true\n})\n\nfunction insertLink() {\n const url = window.prompt('URL del enlace:')\n if (url) editorRef.value?.value?.chain().focus().setLink({ href: url }).run()\n}\n\nfunction insertImage() {\n const url = window.prompt('URL de la imagen:')\n if (url) editorRef.value?.value?.chain().focus().setImage({ src: url }).run()\n}\n\nfunction setHeading(level: 1 | 2 | 3) {\n editorRef.value?.value?.chain().focus().toggleHeading({ level }).run()\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 select -->\n <select\n class=\"h-8 cursor-pointer rounded bg-transparent px-2 text-label-large text-on-surface-variant outline-none hover:bg-on-surface/8\"\n :value=\"\n editorRef?.value?.isActive('heading', { level: 1 }) ? '1'\n : editorRef?.value?.isActive('heading', { level: 2 }) ? '2'\n : editorRef?.value?.isActive('heading', { level: 3 }) ? '3'\n : '0'\n \"\n @change=\"(e: Event) => {\n const v = (e.target as HTMLSelectElement).value\n if (v === '0') editorRef?.value?.chain().focus().setParagraph().run()\n else setHeading(Number(v) as 1 | 2 | 3)\n }\"\n >\n <option value=\"0\">Párrafo</option>\n <option value=\"1\">Título 1</option>\n <option value=\"2\">Título 2</option>\n <option value=\"3\">Título 3</option>\n </select>\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=\"insertLink\"\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=\"insertImage\"\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 </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),\n.rte-content :deep(ol) { 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,3 +1,6 @@
1
+ /* Scan the library's components so Tailwind generates the needed utilities */
2
+ @source '..';
3
+
1
4
  /* Enable class-based dark mode for Tailwind v4 */
2
5
  @custom-variant dark (&:where(.dark, .dark *));
3
6
 
@@ -0,0 +1,2 @@
1
+ .code-editor-container[data-v-b0a66a4b] .cm-editor{height:100%;min-height:inherit;font-family:Roboto Mono,Fira Code,Consolas,monospace;font-size:.8125rem;line-height:1.6}.code-editor-container[data-v-b0a66a4b] .cm-editor.cm-focused{outline:none}.code-editor-container[data-v-b0a66a4b] .cm-scroller{min-height:inherit}.code-editor-container[data-v-b0a66a4b] .cm-content{padding:12px 0}.code-editor-container[data-v-b0a66a4b] .cm-line{padding:0 16px}.code-editor-container[data-v-b0a66a4b] .cm-gutters{background:var(--color-surface-container);border-right:1px solid var(--color-outline-variant);color:var(--color-outline);padding:0 4px;font-size:.75rem}.code-editor-container[data-v-b0a66a4b] .cm-activeLineGutter{background:var(--color-surface-container-high);color:var(--color-on-surface-variant)}.code-editor-container[data-v-b0a66a4b] .cm-activeLine{background:var(--color-surface-container-lowest)}.code-editor-container[data-v-b0a66a4b] .cm-selectionBackground{background:var(--color-primary-container)!important}.code-editor-container[data-v-b0a66a4b] .cm-cursor{border-left-color:var(--color-primary);border-left-width:2px}.code-editor-container[data-v-b0a66a4b] .cm-matchingBracket{background:var(--color-tertiary-container);color:var(--color-on-tertiary-container);border-radius:2px}.code-editor-container[data-v-b0a66a4b] .cm-foldGutter span{color:var(--color-on-surface-variant)}.bs-scrim[data-v-941a89e7]{transition:opacity .3s}.bs-enter-from .bs-scrim[data-v-941a89e7],.bs-leave-to .bs-scrim[data-v-941a89e7]{opacity:0}.bs-panel[data-v-941a89e7]{transition:transform .32s cubic-bezier(.2,0,0,1),opacity .24s}.bs-enter-from .bs-panel[data-v-941a89e7]{opacity:0;transform:translateY(40%)}.bs-leave-to .bs-panel[data-v-941a89e7]{opacity:0;transform:translateY(100%)!important}@keyframes m3-wavy-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes m3-wavy-travel{0%{stroke-dashoffset:0}to{stroke-dashoffset:calc(var(--m3-wave-len) * -1px)}}@media (prefers-reduced-motion:reduce){.animate-\[m3-wavy-spin_2\.8s_linear_infinite\]{animation:2.8s linear infinite m3-wavy-spin}.animate-\[m3-wavy-travel_2s_linear_infinite\]{animation:none!important}}.hue-slider[data-v-9ee0043f]{background:linear-gradient(90deg,red 0%,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}.hue-slider[data-v-9ee0043f]::-webkit-slider-thumb{-webkit-appearance:none;cursor:pointer;background:#fff;border-radius:50%;width:16px;height:16px;box-shadow:0 1px 3px #0006}.hue-slider[data-v-9ee0043f]::-moz-range-thumb{cursor:pointer;background:#fff;border:none;border-radius:50%;width:16px;height:16px;box-shadow:0 1px 3px #0006}.m3-cmd-enter-active[data-v-da578f14],.m3-cmd-leave-active[data-v-da578f14]{transition:opacity .15s}.m3-cmd-enter-from[data-v-da578f14],.m3-cmd-leave-to[data-v-da578f14]{opacity:0}.m3-cmd-enter-active .cmd-box[data-v-da578f14],.m3-cmd-leave-active .cmd-box[data-v-da578f14]{transition:transform .15s}.m3-cmd-enter-from .cmd-box[data-v-da578f14],.m3-cmd-leave-to .cmd-box[data-v-da578f14]{transform:scale(.95)translateY(-10px)}.m3-dialog-enter-active[data-v-e7dfca29],.m3-dialog-leave-active[data-v-e7dfca29]{transition:opacity .15s}.m3-dialog-enter-from[data-v-e7dfca29],.m3-dialog-leave-to[data-v-e7dfca29]{opacity:0}.m3-dialog-enter-active .dialog-box[data-v-e7dfca29],.m3-dialog-leave-active .dialog-box[data-v-e7dfca29]{transition:transform .15s}.m3-dialog-enter-from .dialog-box[data-v-e7dfca29],.m3-dialog-leave-to .dialog-box[data-v-e7dfca29]{transform:scale(.95)}.expand-grid[data-v-89e4475b]{grid-template-rows:1fr;display:grid}.expand-body[data-v-89e4475b]{min-height:0;overflow:hidden}.expand-enter-active[data-v-89e4475b]{transition:grid-template-rows .28s cubic-bezier(.2,0,0,1)}.expand-enter-active>.expand-body[data-v-89e4475b]{transition:opacity .22s}.expand-enter-from[data-v-89e4475b]{grid-template-rows:0fr}.expand-enter-from>.expand-body[data-v-89e4475b]{opacity:0}.expand-leave-active[data-v-89e4475b]{transition:grid-template-rows .22s cubic-bezier(.4,0,1,1)}.expand-leave-active>.expand-body[data-v-89e4475b]{transition:opacity .15s}.expand-leave-to[data-v-89e4475b]{grid-template-rows:0fr}.expand-leave-to>.expand-body[data-v-89e4475b]{opacity:0}.m3-file-enter-active[data-v-34a862f0],.m3-file-leave-active[data-v-34a862f0]{transition:all .2s}.m3-file-enter-from[data-v-34a862f0],.m3-file-leave-to[data-v-34a862f0]{opacity:0;transform:translateY(-8px)}.nd-scrim[data-v-98c11a62]{transition:opacity .28s}.nd-enter-from .nd-scrim[data-v-98c11a62],.nd-leave-to .nd-scrim[data-v-98c11a62]{opacity:0}.nd-panel[data-v-98c11a62]{transition:transform .3s cubic-bezier(.2,0,0,1)}.nd-enter-from .nd-panel[data-v-98c11a62],.nd-leave-to .nd-panel[data-v-98c11a62]{transform:translate(-100%)}@keyframes m3-wave-flow{0%{transform:translate(0)}to{transform:translate(-20px)}}@keyframes m3-progress-indeterminate{0%{left:-40%}to{left:100%}}@media (prefers-reduced-motion:reduce){.animate-\[m3-wave-flow_1\.2s_linear_infinite\],.animate-\[m3-wave-flow_0\.9s_linear_infinite\],.animate-\[m3-progress-indeterminate_1\.6s_ease-in-out_infinite\]{animation:none!important}}.m3-radio-dot[data-v-cdb650b5]{transform-box:fill-box;transform-origin:50%;transition:transform .15s;transform:scale(0)}.m3-radio-dot.is-checked[data-v-cdb650b5]{transform:scale(1)}.ss-scrim[data-v-f8751672]{transition:opacity .28s}.ss-enter-from .ss-scrim[data-v-f8751672],.ss-leave-to .ss-scrim[data-v-f8751672]{opacity:0}.ss-panel[data-v-f8751672]{transition:transform .32s cubic-bezier(.2,0,0,1),opacity .24s}.ss-enter-from .ss-panel[data-v-f8751672]{opacity:0;transform:translate(40%)}.ss-leave-to .ss-panel[data-v-f8751672]{opacity:0;transform:translate(100%)!important}@keyframes skeleton-wave-move-32ecf05b{0%{transform:translate(-100%)}60%{transform:translate(100%)}to{transform:translate(100%)}}.skeleton-wave[data-v-32ecf05b]{position:relative;overflow:hidden}.skeleton-wave[data-v-32ecf05b]:after{content:"";background:linear-gradient(90deg, transparent 0%, var(--color-on-surface) 50%, transparent 100%);opacity:.06;animation:1.8s ease-in-out infinite skeleton-wave-move-32ecf05b;position:absolute;inset:0}.toast-row[data-v-e83a5c10]{grid-template-rows:1fr;padding-bottom:8px;display:grid}.toast-row>.toast-inner[data-v-e83a5c10]{min-height:0}.m3-toast-bot-enter-active[data-v-e83a5c10]{transition:grid-template-rows .22s cubic-bezier(.2,0,0,1),padding-bottom .22s cubic-bezier(.2,0,0,1);overflow:hidden}.m3-toast-bot-enter-active>.toast-inner[data-v-e83a5c10]{transition:opacity .18s,transform .22s cubic-bezier(.2,0,0,1)}.m3-toast-bot-enter-from[data-v-e83a5c10]{grid-template-rows:0fr;padding-bottom:0}.m3-toast-bot-enter-from>.toast-inner[data-v-e83a5c10]{opacity:0;transform:translateY(20px)scale(.94)}.m3-toast-bot-leave-active[data-v-e83a5c10]{transition:grid-template-rows .3s cubic-bezier(.2,0,0,1),padding-bottom .3s cubic-bezier(.2,0,0,1);overflow:hidden}.m3-toast-bot-leave-active>.toast-inner[data-v-e83a5c10]{transition:opacity .18s,transform .18s}.m3-toast-bot-leave-to[data-v-e83a5c10]{grid-template-rows:0fr;padding-bottom:0}.m3-toast-bot-leave-to>.toast-inner[data-v-e83a5c10]{opacity:0;transform:scale(.92)}.m3-toast-top-enter-active[data-v-e83a5c10]{transition:grid-template-rows .22s cubic-bezier(.2,0,0,1),padding-bottom .22s cubic-bezier(.2,0,0,1);overflow:hidden}.m3-toast-top-enter-active>.toast-inner[data-v-e83a5c10]{transition:opacity .18s,transform .22s cubic-bezier(.2,0,0,1)}.m3-toast-top-enter-from[data-v-e83a5c10]{grid-template-rows:0fr;padding-bottom:0}.m3-toast-top-enter-from>.toast-inner[data-v-e83a5c10]{opacity:0;transform:translateY(-20px)scale(.94)}.m3-toast-top-leave-active[data-v-e83a5c10]{transition:grid-template-rows .3s cubic-bezier(.2,0,0,1),padding-bottom .3s cubic-bezier(.2,0,0,1);overflow:hidden}.m3-toast-top-leave-active>.toast-inner[data-v-e83a5c10]{transition:opacity .18s,transform .18s}.m3-toast-top-leave-to[data-v-e83a5c10]{grid-template-rows:0fr;padding-bottom:0}.m3-toast-top-leave-to>.toast-inner[data-v-e83a5c10]{opacity:0;transform:scale(.92)}@keyframes m3-toast-progress-e83a5c10{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.m3-spot-enter-active[data-v-51b103ff],.m3-spot-leave-active[data-v-51b103ff]{transition:opacity .15s}.m3-spot-enter-from[data-v-51b103ff],.m3-spot-leave-to[data-v-51b103ff]{opacity:0}.m3-spot-enter-active .spot-box[data-v-51b103ff],.m3-spot-leave-active .spot-box[data-v-51b103ff]{transition:transform .15s,opacity .15s}.m3-spot-enter-from .spot-box[data-v-51b103ff]{opacity:0;transform:scale(.96)translateY(-8px)}.m3-spot-leave-to .spot-box[data-v-51b103ff]{opacity:0;transform:scale(.98)}.m3-tour-highlight{box-shadow:0 0 0 4px var(--color-primary), 0 0 0 9999px #0006;border-radius:8px;position:relative;z-index:101!important}.m3-tour-enter-active,.m3-tour-leave-active{transition:opacity .2s}.m3-tour-enter-from,.m3-tour-leave-to{opacity:0}.m3-markdown[data-v-6e4dc2b6] h1{font-size:var(--text-headline-large);line-height:var(--text-headline-large--line-height);color:var(--color-on-surface);margin:1em 0 .5em;font-weight:600}.m3-markdown[data-v-6e4dc2b6] h2{font-size:var(--text-headline-medium);line-height:var(--text-headline-medium--line-height);color:var(--color-on-surface);margin:1em 0 .5em;font-weight:600}.m3-markdown[data-v-6e4dc2b6] h3{font-size:var(--text-headline-small);line-height:var(--text-headline-small--line-height);color:var(--color-on-surface);margin:.75em 0 .25em;font-weight:600}.m3-markdown[data-v-6e4dc2b6] h4{font-size:var(--text-title-large);line-height:var(--text-title-large--line-height);color:var(--color-on-surface);margin:.75em 0 .25em;font-weight:600}.m3-markdown[data-v-6e4dc2b6] p{margin:.5em 0}.m3-markdown[data-v-6e4dc2b6] a{color:var(--color-primary);text-underline-offset:2px;text-decoration:underline}.m3-markdown[data-v-6e4dc2b6] a:hover{opacity:.8}.m3-markdown[data-v-6e4dc2b6] strong{color:var(--color-on-surface);font-weight:600}.m3-markdown[data-v-6e4dc2b6] em{font-style:italic}.m3-markdown[data-v-6e4dc2b6] ul,.m3-markdown[data-v-6e4dc2b6] ol{margin:.5em 0;padding-left:1.5em}.m3-markdown[data-v-6e4dc2b6] li{margin:.25em 0}.m3-markdown[data-v-6e4dc2b6] li::marker{color:var(--color-on-surface-variant)}.m3-markdown[data-v-6e4dc2b6] blockquote{border-left:3px solid var(--color-primary);background:var(--color-surface-container);color:var(--color-on-surface-variant);border-radius:0 8px 8px 0;margin:.75em 0;padding:.5em 1em}.m3-markdown[data-v-6e4dc2b6] code{background:var(--color-surface-container-highest);color:var(--color-primary);border-radius:4px;padding:.15em .4em;font-family:JetBrains Mono,Fira Code,monospace;font-size:.875em}.m3-markdown[data-v-6e4dc2b6] pre{background:var(--color-surface-container-highest);border:1px solid var(--color-outline-variant);border-radius:12px;margin:.75em 0;padding:1em;overflow-x:auto}.m3-markdown[data-v-6e4dc2b6] pre code{color:var(--color-on-surface);background:0 0;padding:0}.m3-markdown[data-v-6e4dc2b6] hr{border:none;border-top:1px solid var(--color-outline-variant);margin:1.5em 0}.m3-markdown[data-v-6e4dc2b6] table{border-collapse:collapse;width:100%;margin:.75em 0}.m3-markdown[data-v-6e4dc2b6] th{background:var(--color-surface-container);text-align:left;border-bottom:2px solid var(--color-outline-variant);font-weight:600;font-size:var(--text-label-large);color:var(--color-on-surface);padding:.5em .75em}.m3-markdown[data-v-6e4dc2b6] td{border-bottom:1px solid var(--color-outline-variant);padding:.5em .75em}.m3-markdown[data-v-6e4dc2b6] img{border-radius:12px;max-width:100%;height:auto;margin:.5em 0}.rte-content[data-v-89c08c83] .tiptap{min-height:inherit;outline:none}.rte-content[data-v-89c08c83] .tiptap p.is-editor-empty:first-child:before{content:attr(data-placeholder);float:left;color:var(--color-on-surface-variant);opacity:.5;pointer-events:none;height:0}.rte-content[data-v-89c08c83] h1{font-size:var(--text-headline-large);line-height:var(--text-headline-large--line-height);margin:.75em 0 .25em;font-weight:600}.rte-content[data-v-89c08c83] h2{font-size:var(--text-headline-medium);line-height:var(--text-headline-medium--line-height);margin:.75em 0 .25em;font-weight:600}.rte-content[data-v-89c08c83] h3{font-size:var(--text-headline-small);line-height:var(--text-headline-small--line-height);margin:.75em 0 .25em;font-weight:600}.rte-content[data-v-89c08c83] p{margin:.5em 0}.rte-content[data-v-89c08c83] ul,.rte-content[data-v-89c08c83] ol{margin:.5em 0;padding-left:1.5em}.rte-content[data-v-89c08c83] blockquote{border-left:3px solid var(--color-primary);color:var(--color-on-surface-variant);margin:.5em 0;padding-left:1em}.rte-content[data-v-89c08c83] code{background:var(--color-surface-container-highest);border-radius:4px;padding:.15em .4em;font-size:.875em}.rte-content[data-v-89c08c83] pre{background:var(--color-surface-container-highest);border-radius:8px;margin:.5em 0;padding:1em;overflow-x:auto}.rte-content[data-v-89c08c83] pre code{background:0 0;padding:0}.rte-content[data-v-89c08c83] a{color:var(--color-primary);text-decoration:underline}.rte-content[data-v-89c08c83] mark{background:var(--color-tertiary-container);color:var(--color-on-tertiary-container);border-radius:2px;padding:.1em .2em}.rte-content[data-v-89c08c83] img{border-radius:8px;max-width:100%;height:auto;margin:.5em 0}
2
+ /*$vite$:1*/
@@ -0,0 +1 @@
1
+ export { default as MTerminal } from './components/MTerminal.vue';
@@ -0,0 +1,97 @@
1
+ import { t as e } from "./MIcon-CaEooCmZ.js";
2
+ import { createElementBlock as t, createElementVNode as n, createVNode as r, defineComponent as i, normalizeStyle as a, onBeforeUnmount as o, onMounted as s, openBlock as c, ref as l, toDisplayString as u, watch as d } from "vue";
3
+ //#region src/components/MTerminal.vue?vue&type=script&setup=true&lang.ts
4
+ var f = { class: "overflow-hidden rounded-lg border border-outline-variant" }, p = { class: "flex items-center gap-2 border-b border-outline-variant bg-surface-container px-4 py-2" }, m = { class: "flex-1 text-label-medium text-on-surface-variant" }, h = /* @__PURE__ */ i({
5
+ __name: "MTerminal",
6
+ props: {
7
+ lines: { default: () => [] },
8
+ readonly: {
9
+ type: Boolean,
10
+ default: !1
11
+ },
12
+ title: { default: "Terminal" },
13
+ minHeight: { default: "300px" }
14
+ },
15
+ emits: ["input", "line"],
16
+ setup(i, { expose: h, emit: g }) {
17
+ let _ = i, v = g, y = l(null), b = null, x = null, S = null, C = "";
18
+ function w() {
19
+ let e = getComputedStyle(document.documentElement);
20
+ return {
21
+ background: e.getPropertyValue("--color-surface-container-lowest").trim() || "#0f0d13",
22
+ foreground: e.getPropertyValue("--color-on-surface").trim() || "#e6e1e5",
23
+ cursor: e.getPropertyValue("--color-primary").trim() || "#d0bcff",
24
+ cursorAccent: e.getPropertyValue("--color-on-primary").trim() || "#381e72",
25
+ selectionBackground: e.getPropertyValue("--color-primary-container").trim() || "#4f378b"
26
+ };
27
+ }
28
+ return s(async () => {
29
+ if (!y.value) return;
30
+ let [e, t] = await Promise.all([import("@xterm/xterm"), import("@xterm/addon-fit")]);
31
+ try {
32
+ await import("@xterm/xterm/css/xterm.css");
33
+ } catch {}
34
+ let n = w();
35
+ b = new e.Terminal({
36
+ fontFamily: "'JetBrains Mono', 'Fira Code', 'Consolas', monospace",
37
+ fontSize: 14,
38
+ lineHeight: 1.4,
39
+ cursorBlink: !_.readonly,
40
+ disableStdin: _.readonly,
41
+ theme: {
42
+ background: n.background,
43
+ foreground: n.foreground,
44
+ cursor: n.cursor,
45
+ cursorAccent: n.cursorAccent,
46
+ selectionBackground: n.selectionBackground
47
+ },
48
+ scrollback: 1e3,
49
+ convertEol: !0
50
+ }), x = new t.FitAddon(), b.loadAddon(x), b.open(y.value);
51
+ try {
52
+ x.fit();
53
+ } catch {}
54
+ for (let e of _.lines) b.writeln(e);
55
+ _.readonly || b.onData((e) => {
56
+ v("input", e), e === "\r" ? (b.write("\r\n"), v("line", C), C = "") : e === "" ? C.length > 0 && (C = C.slice(0, -1), b.write("\b \b")) : (C += e, b.write(e));
57
+ }), S = new ResizeObserver(() => {
58
+ try {
59
+ x?.fit();
60
+ } catch {}
61
+ }), S.observe(y.value);
62
+ }), d(() => _.lines, (e) => {
63
+ if (b) {
64
+ b.clear();
65
+ for (let t of e) b.writeln(t);
66
+ }
67
+ }), o(() => {
68
+ S?.disconnect(), b?.dispose();
69
+ }), h({
70
+ write: (e) => b?.write(e),
71
+ writeln: (e) => b?.writeln(e),
72
+ clear: () => b?.clear(),
73
+ focus: () => b?.focus()
74
+ }), (o, s) => (c(), t("div", f, [n("div", p, [
75
+ r(e, {
76
+ name: "terminal",
77
+ size: 18,
78
+ class: "text-on-surface-variant"
79
+ }),
80
+ n("span", m, u(i.title), 1),
81
+ s[0] ||= n("div", { class: "flex gap-1.5" }, [
82
+ n("div", { class: "h-3 w-3 rounded-full bg-error/60" }),
83
+ n("div", { class: "h-3 w-3 rounded-full bg-tertiary-container" }),
84
+ n("div", { class: "h-3 w-3 rounded-full bg-success/60" })
85
+ ], -1)
86
+ ]), n("div", {
87
+ ref_key: "containerRef",
88
+ ref: y,
89
+ class: "bg-surface-container-lowest px-2 py-1",
90
+ style: a({ minHeight: i.minHeight })
91
+ }, null, 4)]));
92
+ }
93
+ });
94
+ //#endregion
95
+ export { h as MTerminal };
96
+
97
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","names":[],"sources":["../src/components/MTerminal.vue","../src/components/MTerminal.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, onMounted, onBeforeUnmount, watch } from 'vue'\nimport MIcon from './MIcon.vue'\n\nconst props = withDefaults(\n defineProps<{\n lines?: string[]\n readonly?: boolean\n title?: string\n minHeight?: string\n }>(),\n {\n lines: () => [],\n readonly: false,\n title: 'Terminal',\n minHeight: '300px',\n },\n)\n\nconst emit = defineEmits<{\n input: [string]\n line: [string]\n}>()\n\nconst containerRef = ref<HTMLElement | null>(null)\nlet terminal: any = null\nlet fitAddon: any = null\nlet resizeObserver: ResizeObserver | null = null\nlet lineBuffer = ''\n\nfunction getThemeColors() {\n const style = getComputedStyle(document.documentElement)\n return {\n background: style.getPropertyValue('--color-surface-container-lowest').trim() || '#0f0d13',\n foreground: style.getPropertyValue('--color-on-surface').trim() || '#e6e1e5',\n cursor: style.getPropertyValue('--color-primary').trim() || '#d0bcff',\n cursorAccent: style.getPropertyValue('--color-on-primary').trim() || '#381e72',\n selectionBackground: style.getPropertyValue('--color-primary-container').trim() || '#4f378b',\n }\n}\n\nonMounted(async () => {\n if (!containerRef.value) return\n\n const [xtermMod, fitMod] = await Promise.all([\n import('@xterm/xterm'),\n import('@xterm/addon-fit'),\n ])\n\n try { await import('@xterm/xterm/css/xterm.css') } catch { /* consumer will provide styles */ }\n\n const colors = getThemeColors()\n\n terminal = new xtermMod.Terminal({\n fontFamily: \"'JetBrains Mono', 'Fira Code', 'Consolas', monospace\",\n fontSize: 14,\n lineHeight: 1.4,\n cursorBlink: !props.readonly,\n disableStdin: props.readonly,\n theme: {\n background: colors.background,\n foreground: colors.foreground,\n cursor: colors.cursor,\n cursorAccent: colors.cursorAccent,\n selectionBackground: colors.selectionBackground,\n },\n scrollback: 1000,\n convertEol: true,\n })\n\n fitAddon = new fitMod.FitAddon()\n terminal.loadAddon(fitAddon)\n terminal.open(containerRef.value)\n\n try { fitAddon.fit() } catch { /* container might not be visible yet */ }\n\n for (const line of props.lines) {\n terminal.writeln(line)\n }\n\n if (!props.readonly) {\n terminal.onData((data: string) => {\n emit('input', data)\n\n if (data === '\\r') {\n terminal!.write('\\r\\n')\n emit('line', lineBuffer)\n lineBuffer = ''\n } else if (data === '\\x7f') {\n if (lineBuffer.length > 0) {\n lineBuffer = lineBuffer.slice(0, -1)\n terminal!.write('\\b \\b')\n }\n } else {\n lineBuffer += data\n terminal!.write(data)\n }\n })\n }\n\n resizeObserver = new ResizeObserver(() => {\n try { fitAddon?.fit() } catch { /* ignore */ }\n })\n resizeObserver.observe(containerRef.value)\n})\n\nwatch(() => props.lines, (newLines) => {\n if (!terminal) return\n terminal.clear()\n for (const line of newLines) {\n terminal.writeln(line)\n }\n})\n\nonBeforeUnmount(() => {\n resizeObserver?.disconnect()\n terminal?.dispose()\n})\n\ndefineExpose({\n write: (text: string) => terminal?.write(text),\n writeln: (text: string) => terminal?.writeln(text),\n clear: () => terminal?.clear(),\n focus: () => terminal?.focus(),\n})\n</script>\n\n<template>\n <div class=\"overflow-hidden rounded-lg border border-outline-variant\">\n <!-- Title bar -->\n <div class=\"flex items-center gap-2 border-b border-outline-variant bg-surface-container px-4 py-2\">\n <MIcon name=\"terminal\" :size=\"18\" class=\"text-on-surface-variant\" />\n <span class=\"flex-1 text-label-medium text-on-surface-variant\">{{ title }}</span>\n <div class=\"flex gap-1.5\">\n <div class=\"h-3 w-3 rounded-full bg-error/60\" />\n <div class=\"h-3 w-3 rounded-full bg-tertiary-container\" />\n <div class=\"h-3 w-3 rounded-full bg-success/60\" />\n </div>\n </div>\n\n <!-- Terminal container -->\n <div\n ref=\"containerRef\"\n class=\"bg-surface-container-lowest px-2 py-1\"\n :style=\"{ minHeight }\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { ref, onMounted, onBeforeUnmount, watch } from 'vue'\nimport MIcon from './MIcon.vue'\n\nconst props = withDefaults(\n defineProps<{\n lines?: string[]\n readonly?: boolean\n title?: string\n minHeight?: string\n }>(),\n {\n lines: () => [],\n readonly: false,\n title: 'Terminal',\n minHeight: '300px',\n },\n)\n\nconst emit = defineEmits<{\n input: [string]\n line: [string]\n}>()\n\nconst containerRef = ref<HTMLElement | null>(null)\nlet terminal: any = null\nlet fitAddon: any = null\nlet resizeObserver: ResizeObserver | null = null\nlet lineBuffer = ''\n\nfunction getThemeColors() {\n const style = getComputedStyle(document.documentElement)\n return {\n background: style.getPropertyValue('--color-surface-container-lowest').trim() || '#0f0d13',\n foreground: style.getPropertyValue('--color-on-surface').trim() || '#e6e1e5',\n cursor: style.getPropertyValue('--color-primary').trim() || '#d0bcff',\n cursorAccent: style.getPropertyValue('--color-on-primary').trim() || '#381e72',\n selectionBackground: style.getPropertyValue('--color-primary-container').trim() || '#4f378b',\n }\n}\n\nonMounted(async () => {\n if (!containerRef.value) return\n\n const [xtermMod, fitMod] = await Promise.all([\n import('@xterm/xterm'),\n import('@xterm/addon-fit'),\n ])\n\n try { await import('@xterm/xterm/css/xterm.css') } catch { /* consumer will provide styles */ }\n\n const colors = getThemeColors()\n\n terminal = new xtermMod.Terminal({\n fontFamily: \"'JetBrains Mono', 'Fira Code', 'Consolas', monospace\",\n fontSize: 14,\n lineHeight: 1.4,\n cursorBlink: !props.readonly,\n disableStdin: props.readonly,\n theme: {\n background: colors.background,\n foreground: colors.foreground,\n cursor: colors.cursor,\n cursorAccent: colors.cursorAccent,\n selectionBackground: colors.selectionBackground,\n },\n scrollback: 1000,\n convertEol: true,\n })\n\n fitAddon = new fitMod.FitAddon()\n terminal.loadAddon(fitAddon)\n terminal.open(containerRef.value)\n\n try { fitAddon.fit() } catch { /* container might not be visible yet */ }\n\n for (const line of props.lines) {\n terminal.writeln(line)\n }\n\n if (!props.readonly) {\n terminal.onData((data: string) => {\n emit('input', data)\n\n if (data === '\\r') {\n terminal!.write('\\r\\n')\n emit('line', lineBuffer)\n lineBuffer = ''\n } else if (data === '\\x7f') {\n if (lineBuffer.length > 0) {\n lineBuffer = lineBuffer.slice(0, -1)\n terminal!.write('\\b \\b')\n }\n } else {\n lineBuffer += data\n terminal!.write(data)\n }\n })\n }\n\n resizeObserver = new ResizeObserver(() => {\n try { fitAddon?.fit() } catch { /* ignore */ }\n })\n resizeObserver.observe(containerRef.value)\n})\n\nwatch(() => props.lines, (newLines) => {\n if (!terminal) return\n terminal.clear()\n for (const line of newLines) {\n terminal.writeln(line)\n }\n})\n\nonBeforeUnmount(() => {\n resizeObserver?.disconnect()\n terminal?.dispose()\n})\n\ndefineExpose({\n write: (text: string) => terminal?.write(text),\n writeln: (text: string) => terminal?.writeln(text),\n clear: () => terminal?.clear(),\n focus: () => terminal?.focus(),\n})\n</script>\n\n<template>\n <div class=\"overflow-hidden rounded-lg border border-outline-variant\">\n <!-- Title bar -->\n <div class=\"flex items-center gap-2 border-b border-outline-variant bg-surface-container px-4 py-2\">\n <MIcon name=\"terminal\" :size=\"18\" class=\"text-on-surface-variant\" />\n <span class=\"flex-1 text-label-medium text-on-surface-variant\">{{ title }}</span>\n <div class=\"flex gap-1.5\">\n <div class=\"h-3 w-3 rounded-full bg-error/60\" />\n <div class=\"h-3 w-3 rounded-full bg-tertiary-container\" />\n <div class=\"h-3 w-3 rounded-full bg-success/60\" />\n </div>\n </div>\n\n <!-- Terminal container -->\n <div\n ref=\"containerRef\"\n class=\"bg-surface-container-lowest px-2 py-1\"\n :style=\"{ minHeight }\"\n />\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;EAIA,IAAM,IAAQ,GAeR,IAAO,GAKP,IAAe,EAAwB,IAAI,GAC7C,IAAgB,MAChB,IAAgB,MAChB,IAAwC,MACxC,IAAa;EAEjB,SAAS,IAAiB;GACxB,IAAM,IAAQ,iBAAiB,SAAS,eAAe;GACvD,OAAO;IACL,YAAY,EAAM,iBAAiB,kCAAkC,EAAE,KAAK,KAAK;IACjF,YAAY,EAAM,iBAAiB,oBAAoB,EAAE,KAAK,KAAK;IACnE,QAAQ,EAAM,iBAAiB,iBAAiB,EAAE,KAAK,KAAK;IAC5D,cAAc,EAAM,iBAAiB,oBAAoB,EAAE,KAAK,KAAK;IACrE,qBAAqB,EAAM,iBAAiB,2BAA2B,EAAE,KAAK,KAAK;GACrF;EACF;SAEA,EAAU,YAAY;GACpB,IAAI,CAAC,EAAa,OAAO;GAEzB,IAAM,CAAC,GAAU,KAAU,MAAM,QAAQ,IAAI,CAC3C,OAAO,iBACP,OAAO,mBACT,CAAC;GAED,IAAI;IAAE,MAAM,OAAO;GAA8B,QAAQ,CAAqC;GAE9F,IAAM,IAAS,EAAe;GAqB9B,AAnBA,IAAW,IAAI,EAAS,SAAS;IAC/B,YAAY;IACZ,UAAU;IACV,YAAY;IACZ,aAAa,CAAC,EAAM;IACpB,cAAc,EAAM;IACpB,OAAO;KACL,YAAY,EAAO;KACnB,YAAY,EAAO;KACnB,QAAQ,EAAO;KACf,cAAc,EAAO;KACrB,qBAAqB,EAAO;IAC9B;IACA,YAAY;IACZ,YAAY;GACd,CAAC,GAED,IAAW,IAAI,EAAO,SAAS,GAC/B,EAAS,UAAU,CAAQ,GAC3B,EAAS,KAAK,EAAa,KAAK;GAEhC,IAAI;IAAE,EAAS,IAAI;GAAE,QAAQ,CAA2C;GAExE,KAAK,IAAM,KAAQ,EAAM,OACvB,EAAS,QAAQ,CAAI;GA0BvB,AAvBK,EAAM,YACT,EAAS,QAAQ,MAAiB;IAGhC,AAFA,EAAK,SAAS,CAAI,GAEd,MAAS,QACX,EAAU,MAAM,MAAM,GACtB,EAAK,QAAQ,CAAU,GACvB,IAAa,MACJ,MAAS,MACd,EAAW,SAAS,MACtB,IAAa,EAAW,MAAM,GAAG,EAAE,GACnC,EAAU,MAAM,OAAO,MAGzB,KAAc,GACd,EAAU,MAAM,CAAI;GAExB,CAAC,GAGH,IAAiB,IAAI,qBAAqB;IACxC,IAAI;KAAE,GAAU,IAAI;IAAE,QAAQ,CAAe;GAC/C,CAAC,GACD,EAAe,QAAQ,EAAa,KAAK;EAC3C,CAAC,GAED,QAAY,EAAM,QAAQ,MAAa;GAChC,OACL;MAAS,MAAM;IACf,KAAK,IAAM,KAAQ,GACjB,EAAS,QAAQ,CAAI;GAFR;EAIjB,CAAC,GAED,QAAsB;GAEpB,AADA,GAAgB,WAAW,GAC3B,GAAU,QAAQ;EACpB,CAAC,GAED,EAAa;GACX,QAAQ,MAAiB,GAAU,MAAM,CAAI;GAC7C,UAAU,MAAiB,GAAU,QAAQ,CAAI;GACjD,aAAa,GAAU,MAAM;GAC7B,aAAa,GAAU,MAAM;EAC/B,CAAC,mBAIC,EAkBM,OAlBN,GAkBM,CAhBJ,EAQM,OARN,GAQM;GAPJ,EAAoE,GAAA;IAA7D,MAAK;IAAY,MAAM;IAAI,OAAM;;GACxC,EAAiF,QAAjF,GAAiF,EAAf,EAAA,KAAK,GAAA,CAAA;YACvE,EAIM,OAAA,EAJD,OAAM,eAAc,GAAA;IACvB,EAAgD,OAAA,EAA3C,OAAM,mCAAkC,CAAA;IAC7C,EAA0D,OAAA,EAArD,OAAM,6CAA4C,CAAA;IACvD,EAAkD,OAAA,EAA7C,OAAM,qCAAoC,CAAA;;MAKnD,EAIE,OAAA;YAHI;GAAJ,KAAI;GACJ,OAAM;GACL,OAAK,EAAA,EAAA,WAAI,EAAA,UAAS,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m3ui-vue/m3ui-vue",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Material 3 component library for Vue 3 + Tailwind CSS v4",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -27,6 +27,27 @@
27
27
  "types": "./dist/index.d.ts",
28
28
  "import": "./dist/m3ui.js"
29
29
  },
30
+ "./chart": {
31
+ "types": "./dist/chart.d.ts",
32
+ "import": "./dist/chart.js"
33
+ },
34
+ "./code-editor": {
35
+ "types": "./dist/code-editor.d.ts",
36
+ "import": "./dist/code-editor.js"
37
+ },
38
+ "./markdown": {
39
+ "types": "./dist/markdown.d.ts",
40
+ "import": "./dist/markdown.js"
41
+ },
42
+ "./rich-text-editor": {
43
+ "types": "./dist/rich-text-editor.d.ts",
44
+ "import": "./dist/rich-text-editor.js"
45
+ },
46
+ "./terminal": {
47
+ "types": "./dist/terminal.d.ts",
48
+ "import": "./dist/terminal.js"
49
+ },
50
+ "./styles": "./dist/styles.css",
30
51
  "./theme": "./src/styles/theme.css",
31
52
  "./palettes": "./src/styles/palettes.css"
32
53
  },
@@ -36,7 +57,7 @@
36
57
  ],
37
58
  "scripts": {
38
59
  "build": "pnpm build:js && pnpm build:types && pnpm build:css",
39
- "build:js": "vite build",
60
+ "build:js": "vite build && cp dist/m3ui-vue.css dist/styles.css",
40
61
  "build:types": "vue-tsc -p tsconfig.build.json",
41
62
  "build:css": "cp -r src/styles dist/",
42
63
  "prepublishOnly": "pnpm build"
@@ -106,6 +127,9 @@
106
127
  "@codemirror/lang-python": {
107
128
  "optional": true
108
129
  },
130
+ "@codemirror/lang-vue": {
131
+ "optional": true
132
+ },
109
133
  "@codemirror/theme-one-dark": {
110
134
  "optional": true
111
135
  },
@@ -132,10 +156,12 @@
132
156
  "@codemirror/lang-javascript": "^6.2.5",
133
157
  "@codemirror/lang-json": "^6.0.2",
134
158
  "@codemirror/lang-python": "^6.2.1",
159
+ "@codemirror/lang-vue": "^0.1.3",
135
160
  "@codemirror/language": "^6.12.3",
136
161
  "@codemirror/state": "^6.6.0",
137
162
  "@codemirror/theme-one-dark": "^6.1.3",
138
163
  "@codemirror/view": "^6.43.1",
164
+ "@lezer/highlight": "^1.2.3",
139
165
  "@tiptap/extension-color": "^3.26.1",
140
166
  "@tiptap/extension-highlight": "^3.26.1",
141
167
  "@tiptap/extension-image": "^3.26.1",
package/src/chart.ts ADDED
@@ -0,0 +1 @@
1
+ export { default as MChart } from './components/MChart.vue'
@@ -0,0 +1,2 @@
1
+ export { default as MCodeEditor } from './components/MCodeEditor.vue'
2
+ export { default as MJsonEditor } from './components/MJsonEditor.vue'
@@ -59,7 +59,7 @@ const config = {
59
59
  <button
60
60
  v-if="closeable"
61
61
  type="button"
62
- class="shrink-0 cursor-pointer rounded-full p-1 transition-colors hover:bg-on-surface/8"
62
+ class="-mr-1 flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-full transition-colors hover:bg-on-surface/8"
63
63
  aria-label="Cerrar"
64
64
  @click="emit('close')"
65
65
  >