@kungal/editor-vue 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @kungal/editor-vue
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4968c96: P3 (complete) — replace the source-mode `<textarea>` with a CodeMirror editor.
8
+
9
+ The "Markdown" tab is now a real CodeMirror editor with markdown syntax
10
+ highlighting, reusing the code block's `kunCM` theme (from
11
+ `@kungal/editor-core`) so the source view and code blocks match. Edits sync back
12
+ through `v-model` to the WYSIWYG view; the view is mounted on demand (CodeMirror
13
+ measures poorly while hidden).
14
+
15
+ Adds `@codemirror/lang-markdown` alongside the CodeMirror packages the editor
16
+ already needs (declared as optional peers; externalized from the build so the
17
+ host dedupes them). This finishes the P3 dual-view editor: WYSIWYG + toolbar +
18
+ @mention dropdown + sticker/emoji picker + CodeMirror source.
19
+
20
+ ### Patch Changes
21
+
22
+ - @kungal/editor-core@0.7.0
23
+
3
24
  ## 0.6.0
4
25
 
5
26
  ### Minor Changes
package/README.md CHANGED
@@ -48,11 +48,11 @@ Enable optional plugins by also installing their peers: `katex` (LaTeX),
48
48
 
49
49
  ## Status
50
50
 
51
- **P3 in progress.** `<KunEditor>` now renders a **real Milkdown dual-view
52
- editor**: a WYSIWYG view built from `@kungal/editor-core/preset`
53
- (`createKunEditorPlugins` — spoiler / katex / code-block / mention / upload /
54
- …), plus a markdown-source view, over one `v-model`. The prop/emit surface
55
- (`v-model`, `adapters`, `features`, `locale`, `readonly`) is stable.
51
+ **P3 complete.** `<KunEditor>` is a **real Milkdown dual-view editor**: a WYSIWYG
52
+ view built from `@kungal/editor-core/preset` (`createKunEditorPlugins` — spoiler /
53
+ katex / code-block / mention / upload / …) and a CodeMirror markdown-source view,
54
+ over one `v-model`. The prop/emit surface (`v-model`, `adapters`, `features`,
55
+ `locale`, `readonly`) is stable.
56
56
 
57
57
  A **formatting toolbar** is wired: bold / italic / strikethrough / inline code,
58
58
  H1–H3, bullet & ordered lists, blockquote, code block, divider, spoiler, LaTeX —
@@ -70,8 +70,12 @@ The **sticker / emoji picker** is a toolbar popover: a built-in emoji tab
70
70
  host supplies `stickerSource`, inserting each sticker as an image node. Turn the
71
71
  whole picker off with `features.sticker: false`.
72
72
 
73
- Still to come in P3: the CodeMirror markdown-source view (currently a
74
- `<textarea>`). See
73
+ The **markdown-source view** (the "Markdown" tab) is a CodeMirror editor with
74
+ markdown highlighting, sharing the code block's `kunCM` theme. Edits sync back
75
+ through `v-model` to the WYSIWYG view.
76
+
77
+ Next: **P4** — adopt in the forum, replacing its in-repo `components/kun/milkdown`
78
+ with real adapters. See
75
79
  [`../../docs/architecture.md`](../../docs/architecture.md) § migration.
76
80
 
77
81
  ## Build
@@ -1 +1 @@
1
- {"version":3,"file":"KunEditor.vue.d.ts","sourceRoot":"","sources":["../../src/components/KunEditor.vue"],"names":[],"mappings":"AAoNA,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EAChB,MAAM,qBAAqB,CAAA;AAK5B,KAAK,WAAW,GAAG;IACf,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,qDAAqD;IACrD,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAC;AA+LJ,QAAA,MAAM,YAAY;;;;;cAtMH,iBAAiB;cAEjB,iBAAiB;YAEnB,eAAe;cAEb,OAAO;6EAoMpB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"KunEditor.vue.d.ts","sourceRoot":"","sources":["../../src/components/KunEditor.vue"],"names":[],"mappings":"AAuMA,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EAChB,MAAM,qBAAqB,CAAA;AAM5B,KAAK,WAAW,GAAG;IACf,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,qDAAqD;IACrD,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAC;AAuMJ,QAAA,MAAM,YAAY;;;;;cA9MH,iBAAiB;cAEjB,iBAAiB;YAEnB,eAAe;cAEb,OAAO;6EA4MpB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -0,0 +1,12 @@
1
+ type __VLS_Props = {
2
+ modelValue: string;
3
+ readonly: boolean;
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
6
+ "update:modelValue": (markdown: string) => any;
7
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
8
+ "onUpdate:modelValue"?: ((markdown: string) => any) | undefined;
9
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
12
+ //# sourceMappingURL=MarkdownSource.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkdownSource.vue.d.ts","sourceRoot":"","sources":["../../src/components/MarkdownSource.vue"],"names":[],"mappings":"AAkGA,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;CAClB,CAAC;AA2EF,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
package/dist/index.js CHANGED
@@ -5,28 +5,32 @@ import { Editor as k, defaultValueCtx as A, editorViewCtx as j, editorViewOption
5
5
  import { listenerCtx as P } from "@milkdown/kit/plugin/listener";
6
6
  import { SlashProvider as ee, slashFactory as F } from "@milkdown/kit/plugin/slash";
7
7
  import { callCommand as I, replaceAll as L } from "@milkdown/kit/utils";
8
- import { createKunEditorPlugins as te, insertKunSpoilerCommand as R, mentionId as ne, toggleLatexCommand as re } from "@kungal/editor-core/preset";
9
- import { TextSelection as ie } from "@milkdown/kit/prose/state";
10
- import { createCodeBlockCommand as ae, insertHrCommand as oe, insertImageCommand as z, toggleEmphasisCommand as B, toggleInlineCodeCommand as V, toggleStrongCommand as H, wrapInBlockquoteCommand as U, wrapInBulletListCommand as W, wrapInHeadingCommand as G, wrapInOrderedListCommand as K } from "@milkdown/kit/preset/commonmark";
11
- import { toggleStrikethroughCommand as q } from "@milkdown/kit/preset/gfm";
8
+ import { createKunEditorPlugins as R, insertKunSpoilerCommand as te, kunCM as ne, mentionId as re, toggleLatexCommand as ie } from "@kungal/editor-core/preset";
9
+ import { TextSelection as ae } from "@milkdown/kit/prose/state";
10
+ import { createCodeBlockCommand as oe, insertHrCommand as se, insertImageCommand as z, toggleEmphasisCommand as B, toggleInlineCodeCommand as V, toggleStrongCommand as H, wrapInBlockquoteCommand as U, wrapInBulletListCommand as W, wrapInHeadingCommand as G, wrapInOrderedListCommand as K } from "@milkdown/kit/preset/commonmark";
11
+ import { toggleStrikethroughCommand as ce } from "@milkdown/kit/preset/gfm";
12
+ import { EditorState as le } from "@codemirror/state";
13
+ import { EditorView as q } from "@codemirror/view";
14
+ import { markdown as ue } from "@codemirror/lang-markdown";
15
+ import { basicSetup as de } from "codemirror";
12
16
  //#region src/context.ts
13
- var J = Symbol("kun-editor-context"), se = [
17
+ var J = Symbol("kun-editor-context"), fe = [
14
18
  "data-active",
15
19
  "onMousedown",
16
20
  "onMouseenter"
17
- ], ce = ["src", "alt"], le = {
21
+ ], pe = ["src", "alt"], me = {
18
22
  key: 1,
19
23
  class: "kun-mention-dropdown__avatar kun-mention-dropdown__avatar--fallback"
20
- }, ue = { class: "kun-mention-dropdown__name" }, de = {
24
+ }, he = { class: "kun-mention-dropdown__name" }, ge = {
21
25
  key: 1,
22
26
  class: "kun-mention-dropdown__hint"
23
- }, fe = {
27
+ }, _e = {
24
28
  key: 2,
25
29
  class: "kun-mention-dropdown__hint"
26
- }, pe = {
30
+ }, ve = {
27
31
  key: 3,
28
32
  class: "kun-mention-dropdown__hint"
29
- }, me = /* @__PURE__ */ s({
33
+ }, ye = /* @__PURE__ */ s({
30
34
  __name: "MentionDropdown",
31
35
  setup(n) {
32
36
  let r = /(?:^|\s)@([^\s@]{0,30})$/, o = c(J), s = o?.adapters.searchMentionUsers, f = t(() => (o?.locale ?? "zh-cn").toLowerCase().startsWith("en")), g = t(() => f.value ? {
@@ -69,13 +73,13 @@ var J = Symbol("kun-editor-context"), se = [
69
73
  }, I = (e) => {
70
74
  let t = _.value;
71
75
  if (!t || !k) return;
72
- let n = t.state.schema.nodes[ne];
76
+ let n = t.state.schema.nodes[re];
73
77
  if (!n) return;
74
78
  let r = n.create({
75
79
  userId: e.id,
76
80
  name: e.name
77
81
  }), { from: i, to: a } = k, o = t.state.tr.replaceWith(i, a, r), s = i + r.nodeSize;
78
- o.insertText(" ", s), o.setSelection(ie.create(o.doc, s + 1)), t.dispatch(o.scrollIntoView()), t.focus(), S.hide();
82
+ o.insertText(" ", s), o.setSelection(ae.create(o.doc, s + 1)), t.dispatch(o.scrollIntoView()), t.focus(), S.hide();
79
83
  }, L = (e) => {
80
84
  if (!C.value || !T.value.length) {
81
85
  C.value && e.key === "Escape" && (e.preventDefault(), S.hide());
@@ -132,9 +136,9 @@ var J = Symbol("kun-editor-context"), se = [
132
136
  src: e.avatar,
133
137
  alt: e.name,
134
138
  class: "kun-mention-dropdown__avatar"
135
- }, null, 8, ce)) : (d(), i("span", le, h(e.name.charAt(0)), 1)), a("span", ue, h(e.name), 1)], 40, se))), 128)) : O.value ? (d(), i("div", de, h(g.value.searching), 1)) : w.value ? (d(), i("div", fe, h(g.value.empty), 1)) : (d(), i("div", pe, h(g.value.prompt), 1))], 512));
139
+ }, null, 8, pe)) : (d(), i("span", me, h(e.name.charAt(0)), 1)), a("span", he, h(e.name), 1)], 40, fe))), 128)) : O.value ? (d(), i("div", ge, h(g.value.searching), 1)) : w.value ? (d(), i("div", _e, h(g.value.empty), 1)) : (d(), i("div", ve, h(g.value.prompt), 1))], 512));
136
140
  }
137
- }), he = /* @__PURE__ */ s({
141
+ }), be = /* @__PURE__ */ s({
138
142
  __name: "MilkdownEditor",
139
143
  props: {
140
144
  modelValue: {},
@@ -152,8 +156,8 @@ var J = Symbol("kun-editor-context"), se = [
152
156
  }), t.update(M, (e) => ({
153
157
  ...e,
154
158
  editable: () => !r.readonly
155
- })), c && t.set(s.key, { view: o({ component: me }) });
156
- }).use(te(r.adapters, r.features, { locale: r.locale }));
159
+ })), c && t.set(s.key, { view: o({ component: ye }) });
160
+ }).use(R(r.adapters, r.features, { locale: r.locale }));
157
161
  return c && t.use(s), t;
158
162
  });
159
163
  return v(() => r.modelValue, (e) => {
@@ -177,21 +181,21 @@ var J = Symbol("kun-editor-context"), se = [
177
181
  spoiler: Y("<path d=\"M9.9 4.24A9.1 9.1 0 0 1 12 4c7 0 10 8 10 8a13.2 13.2 0 0 1-1.67 2.68\"/><path d=\"M6.6 6.6A13.5 13.5 0 0 0 2 12s3 8 10 8a9.7 9.7 0 0 0 5.4-1.6\"/><line x1=\"2\" y1=\"2\" x2=\"22\" y2=\"22\"/>"),
178
182
  latex: X("Σ", 15),
179
183
  smile: Y("<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M8 14s1.5 2 4 2 4-2 4-2\"/><line x1=\"9\" y1=\"9\" x2=\"9.01\" y2=\"9\"/><line x1=\"15\" y1=\"9\" x2=\"15.01\" y2=\"9\"/>")
180
- }, ge = /* @__PURE__ */ "😀.😃.😄.😁.😆.😅.🤣.😂.🙂.🙃.😉.😊.😇.🥰.😍.🤩.😘.😗.😚.😋.😛.😜.🤪.😝.🤗.🤭.🤔.🤐.😐.😑.😶.😏.😒.🙄.😬.😌.😔.😪.🤤.😴.😷.🤒.🤕.🥵.🥶.🥴.😵.🤯.🤠.🥳.😎.🤓.🧐.😕.😟.🙁.😮.😯.😲.😳.🥺.😦.😧.😨.😰.😥.😢.😭.😱.😖.😣.😞.😓.😩.😫.🥱.😤.😡.😠.🤬.😈.👿.💀.💩.🤡.👻.👽.🤖.😺.😸.👍.👎.👌.🤌.🤏.✌️.🤞.🤟.🤘.👋.🤚.🖐️.✋.👏.🙌.🤝.🙏.💪.👀.👁️.❤️.🧡.💛.💚.💙.💜.🖤.🤍.💔.💕.💞.💓.💗.💖.💘.💝.💯.✨.⭐.🌟.🔥.💥.💫.⚡.☀️.🌈.🎉.🎊.🎁.🏆.🐶.🐱.🐭.🦊.🐻.🐼.🐨.🦄.🐢.🐳.🍎.🍑.🍓.🍉.🍰.🍺.🍵.☕.🍜.🍙.✅.❌.❓.❗.💤.👑.🎮.🎵.📌.🔖".split("."), _e = [
184
+ }, xe = /* @__PURE__ */ "😀.😃.😄.😁.😆.😅.🤣.😂.🙂.🙃.😉.😊.😇.🥰.😍.🤩.😘.😗.😚.😋.😛.😜.🤪.😝.🤗.🤭.🤔.🤐.😐.😑.😶.😏.😒.🙄.😬.😌.😔.😪.🤤.😴.😷.🤒.🤕.🥵.🥶.🥴.😵.🤯.🤠.🥳.😎.🤓.🧐.😕.😟.🙁.😮.😯.😲.😳.🥺.😦.😧.😨.😰.😥.😢.😭.😱.😖.😣.😞.😓.😩.😫.🥱.😤.😡.😠.🤬.😈.👿.💀.💩.🤡.👻.👽.🤖.😺.😸.👍.👎.👌.🤌.🤏.✌️.🤞.🤟.🤘.👋.🤚.🖐️.✋.👏.🙌.🤝.🙏.💪.👀.👁️.❤️.🧡.💛.💚.💙.💜.🖤.🤍.💔.💕.💞.💓.💗.💖.💘.💝.💯.✨.⭐.🌟.🔥.💥.💫.⚡.☀️.🌈.🎉.🎊.🎁.🏆.🐶.🐱.🐭.🦊.🐻.🐼.🐨.🦄.🐢.🐳.🍎.🍑.🍓.🍉.🍰.🍺.🍵.☕.🍜.🍙.✅.❌.❓.❗.💤.👑.🎮.🎵.📌.🔖".split("."), Se = [
181
185
  "title",
182
186
  "aria-label",
183
187
  "aria-expanded"
184
- ], ve = ["innerHTML"], Q = { class: "kun-editor__picker-panel" }, ye = {
188
+ ], Ce = ["innerHTML"], we = { class: "kun-editor__picker-panel" }, Te = {
185
189
  key: 0,
186
190
  class: "kun-editor__picker-tabs",
187
191
  role: "tablist"
188
- }, be = ["data-active"], xe = ["data-active"], Se = { class: "kun-editor__emoji-grid" }, Ce = ["onClick"], we = {
192
+ }, Ee = ["data-active"], De = ["data-active"], Oe = { class: "kun-editor__emoji-grid" }, ke = ["onClick"], Ae = {
189
193
  key: 1,
190
194
  class: "kun-editor__sticker-body"
191
- }, Te = { class: "kun-editor__pack-name" }, Ee = { class: "kun-editor__sticker-grid" }, De = ["title", "onClick"], Oe = ["src", "alt"], ke = {
195
+ }, je = { class: "kun-editor__pack-name" }, Me = { class: "kun-editor__sticker-grid" }, Ne = ["title", "onClick"], Pe = ["src", "alt"], Fe = {
192
196
  key: 1,
193
197
  class: "kun-editor__picker-hint"
194
- }, Ae = /* @__PURE__ */ s({
198
+ }, Ie = /* @__PURE__ */ s({
195
199
  __name: "StickerPicker",
196
200
  setup(n) {
197
201
  let [, o] = T(), s = c(J), f = s?.adapters.stickerSource, v = !!f, y = t(() => (s?.locale ?? "zh-cn").toLowerCase().startsWith("en")), x = t(() => y.value ? {
@@ -247,28 +251,28 @@ var J = Symbol("kun-editor-context"), se = [
247
251
  }, [a("span", {
248
252
  class: "kun-editor__icon",
249
253
  innerHTML: g(Z).smile
250
- }, null, 8, ve)], 8, _e), b(a("div", Q, [
251
- v ? (d(), i("div", ye, [a("button", {
254
+ }, null, 8, Ce)], 8, Se), b(a("div", we, [
255
+ v ? (d(), i("div", Te, [a("button", {
252
256
  type: "button",
253
257
  class: "kun-editor__picker-tab",
254
258
  "data-active": w.value === "emoji",
255
259
  onClick: n[0] ||= (e) => w.value = "emoji"
256
- }, h(x.value.emoji), 9, be), a("button", {
260
+ }, h(x.value.emoji), 9, Ee), a("button", {
257
261
  type: "button",
258
262
  class: "kun-editor__picker-tab",
259
263
  "data-active": w.value === "sticker",
260
264
  onClick: n[1] ||= (e) => w.value = "sticker"
261
- }, h(x.value.sticker), 9, xe)])) : r("", !0),
262
- b(a("div", Se, [(d(!0), i(e, null, m(g(ge), (e, t) => (d(), i("button", {
265
+ }, h(x.value.sticker), 9, De)])) : r("", !0),
266
+ b(a("div", Oe, [(d(!0), i(e, null, m(g(xe), (e, t) => (d(), i("button", {
263
267
  key: t,
264
268
  type: "button",
265
269
  class: "kun-editor__emoji",
266
270
  onClick: (t) => N(e)
267
- }, h(e), 9, Ce))), 128))], 512), [[_, !v || w.value === "emoji"]]),
268
- v ? b((d(), i("div", we, [E.value.length ? (d(!0), i(e, { key: 0 }, m(E.value, (t) => (d(), i("div", {
271
+ }, h(e), 9, ke))), 128))], 512), [[_, !v || w.value === "emoji"]]),
272
+ v ? b((d(), i("div", Ae, [E.value.length ? (d(!0), i(e, { key: 0 }, m(E.value, (t) => (d(), i("div", {
269
273
  key: t.name,
270
274
  class: "kun-editor__pack"
271
- }, [a("div", Te, h(t.name), 1), a("div", Ee, [(d(!0), i(e, null, m(t.stickers, (e, t) => (d(), i("button", {
275
+ }, [a("div", je, h(t.name), 1), a("div", Me, [(d(!0), i(e, null, m(t.stickers, (e, t) => (d(), i("button", {
272
276
  key: t,
273
277
  type: "button",
274
278
  class: "kun-editor__sticker",
@@ -278,21 +282,21 @@ var J = Symbol("kun-editor-context"), se = [
278
282
  src: e.src,
279
283
  alt: e.name,
280
284
  loading: "lazy"
281
- }, null, 8, Oe)], 8, De))), 128))])]))), 128)) : (d(), i("div", ke, h(O.value ? x.value.failed : x.value.empty), 1))], 512)), [[_, w.value === "sticker"]]) : r("", !0)
285
+ }, null, 8, Pe)], 8, Ne))), 128))])]))), 128)) : (d(), i("div", Fe, h(O.value ? x.value.failed : x.value.empty), 1))], 512)), [[_, w.value === "sticker"]]) : r("", !0)
282
286
  ], 512), [[_, S.value]])], 512));
283
287
  }
284
- }), je = {
288
+ }), Le = {
285
289
  class: "kun-editor__format-toolbar",
286
290
  role: "toolbar"
287
- }, Me = {
291
+ }, Re = {
288
292
  key: 0,
289
293
  class: "kun-editor__toolbar-divider",
290
294
  "aria-hidden": "true"
291
- }, Ne = [
295
+ }, ze = [
292
296
  "title",
293
297
  "aria-label",
294
298
  "onClick"
295
- ], Pe = ["innerHTML"], Fe = ["title", "aria-label"], Ie = ["innerHTML"], Le = /* @__PURE__ */ s({
299
+ ], Be = ["innerHTML"], Ve = ["title", "aria-label"], He = ["innerHTML"], Q = /* @__PURE__ */ s({
296
300
  __name: "EditorToolbar",
297
301
  setup(n) {
298
302
  let [, s] = T(), l = c(J), u = t(() => l?.adapters.uploadImage), f = () => l?.adapters.notify, h = t(() => l?.features.sticker !== !1), _ = t(() => (l?.locale ?? "zh-cn").toLowerCase().startsWith("en")), v = (e, t) => {
@@ -331,7 +335,7 @@ var J = Symbol("kun-editor-context"), se = [
331
335
  {
332
336
  svg: Z.strike,
333
337
  title: y.value.strike,
334
- run: () => v(q.key)
338
+ run: () => v(ce.key)
335
339
  },
336
340
  {
337
341
  svg: Z.code,
@@ -375,22 +379,22 @@ var J = Symbol("kun-editor-context"), se = [
375
379
  {
376
380
  svg: Z.codeBlock,
377
381
  title: y.value.codeBlock,
378
- run: () => v(ae.key, "")
382
+ run: () => v(oe.key, "")
379
383
  },
380
384
  {
381
385
  svg: Z.hr,
382
386
  title: y.value.hr,
383
- run: () => v(oe.key)
387
+ run: () => v(se.key)
384
388
  }
385
389
  ],
386
390
  [{
387
391
  svg: Z.spoiler,
388
392
  title: y.value.spoiler,
389
- run: () => v(R.key)
393
+ run: () => v(te.key)
390
394
  }, {
391
395
  svg: Z.latex,
392
396
  title: y.value.latex,
393
- run: () => v(re.key)
397
+ run: () => v(ie.key)
394
398
  }]
395
399
  ]), x = p(null), S = () => x.value?.click(), C = async (e) => {
396
400
  let t = e.target, n = t.files?.[0];
@@ -407,8 +411,8 @@ var J = Symbol("kun-editor-context"), se = [
407
411
  f()?.(_.value ? "Image upload failed" : "图片上传失败", "error");
408
412
  }
409
413
  };
410
- return (t, n) => (d(), i("div", je, [
411
- (d(!0), i(e, null, m(b.value, (t, n) => (d(), i(e, { key: n }, [n > 0 ? (d(), i("span", Me)) : r("", !0), (d(!0), i(e, null, m(t, (e, t) => (d(), i("button", {
414
+ return (t, n) => (d(), i("div", Le, [
415
+ (d(!0), i(e, null, m(b.value, (t, n) => (d(), i(e, { key: n }, [n > 0 ? (d(), i("span", Re)) : r("", !0), (d(!0), i(e, null, m(t, (e, t) => (d(), i("button", {
412
416
  key: t,
413
417
  type: "button",
414
418
  class: "kun-editor__tool",
@@ -418,7 +422,7 @@ var J = Symbol("kun-editor-context"), se = [
418
422
  }, [a("span", {
419
423
  class: "kun-editor__icon",
420
424
  innerHTML: e.svg
421
- }, null, 8, Pe)], 8, Ne))), 128))], 64))), 128)),
425
+ }, null, 8, Be)], 8, ze))), 128))], 64))), 128)),
422
426
  u.value ? (d(), i(e, { key: 0 }, [
423
427
  n[0] ||= a("span", {
424
428
  class: "kun-editor__toolbar-divider",
@@ -433,7 +437,7 @@ var J = Symbol("kun-editor-context"), se = [
433
437
  }, [a("span", {
434
438
  class: "kun-editor__icon",
435
439
  innerHTML: g(Z).image
436
- }, null, 8, Ie)], 8, Fe),
440
+ }, null, 8, He)], 8, Ve),
437
441
  a("input", {
438
442
  ref_key: "fileInput",
439
443
  ref: x,
@@ -446,20 +450,52 @@ var J = Symbol("kun-editor-context"), se = [
446
450
  h.value ? (d(), i(e, { key: 1 }, [n[1] ||= a("span", {
447
451
  class: "kun-editor__toolbar-divider",
448
452
  "aria-hidden": "true"
449
- }, null, -1), o(Ae)], 64)) : r("", !0)
453
+ }, null, -1), o(Ie)], 64)) : r("", !0)
450
454
  ]));
451
455
  }
452
- }), Re = {
456
+ }), Ue = /* @__PURE__ */ s({
457
+ __name: "MarkdownSource",
458
+ props: {
459
+ modelValue: {},
460
+ readonly: { type: Boolean }
461
+ },
462
+ emits: ["update:modelValue"],
463
+ setup(e, { emit: t }) {
464
+ let n = e, r = t, a = p(null), o = null, s = (e) => le.create({
465
+ doc: e,
466
+ extensions: [
467
+ ne(),
468
+ q.lineWrapping,
469
+ de,
470
+ ue(),
471
+ q.editable.of(!n.readonly),
472
+ q.updateListener.of((e) => {
473
+ e.docChanged && r("update:modelValue", e.state.doc.toString());
474
+ })
475
+ ]
476
+ });
477
+ return u(() => {
478
+ a.value && (o = new q({
479
+ state: s(n.modelValue),
480
+ parent: a.value
481
+ }));
482
+ }), l(() => {
483
+ o?.destroy(), o = null;
484
+ }), v(() => n.modelValue, (e) => {
485
+ o && o.state.doc.toString() !== e && o.setState(s(e));
486
+ }), (e, t) => (d(), i("div", {
487
+ ref_key: "host",
488
+ ref: a,
489
+ class: "kun-editor__source"
490
+ }, null, 512));
491
+ }
492
+ }), We = {
453
493
  class: "kun-editor",
454
494
  "data-kun-editor": ""
455
- }, ze = {
495
+ }, Ge = {
456
496
  class: "kun-editor__toolbar",
457
497
  role: "tablist"
458
- }, Be = ["aria-selected", "data-active"], Ve = ["aria-selected", "data-active"], He = { class: "kun-editor__wysiwyg" }, Ue = [
459
- "value",
460
- "readonly",
461
- "lang"
462
- ], $ = /* @__PURE__ */ s({
498
+ }, Ke = ["aria-selected", "data-active"], qe = ["aria-selected", "data-active"], Je = { class: "kun-editor__wysiwyg" }, $ = /* @__PURE__ */ s({
463
499
  __name: "KunEditor",
464
500
  props: {
465
501
  modelValue: {},
@@ -472,72 +508,70 @@ var J = Symbol("kun-editor-context"), se = [
472
508
  }
473
509
  },
474
510
  emits: ["update:modelValue"],
475
- setup(e, { emit: n }) {
476
- let r = e, s = n;
511
+ setup(e, { emit: s }) {
512
+ let c = e, l = s;
477
513
  f(J, {
478
514
  get adapters() {
479
- return r.adapters;
515
+ return c.adapters;
480
516
  },
481
517
  get features() {
482
- return r.features;
518
+ return c.features;
483
519
  },
484
520
  get locale() {
485
- return r.locale;
521
+ return c.locale;
486
522
  }
487
523
  });
488
- let c = p("wysiwyg"), l = t(() => r.locale.toLowerCase().startsWith("en")), u = t(() => l.value ? {
524
+ let u = p("wysiwyg"), m = t(() => c.locale.toLowerCase().startsWith("en")), v = t(() => m.value ? {
489
525
  wysiwyg: "Preview",
490
526
  source: "Markdown"
491
527
  } : {
492
528
  wysiwyg: "预览",
493
529
  source: "Markdown"
494
- }), m = (e) => s("update:modelValue", e), v = (e) => s("update:modelValue", e.target.value);
495
- return (t, n) => (d(), i("div", Re, [
496
- a("div", ze, [a("button", {
530
+ }), x = (e) => l("update:modelValue", e);
531
+ return (t, s) => (d(), i("div", We, [
532
+ a("div", Ge, [a("button", {
497
533
  type: "button",
498
534
  class: "kun-editor__tab",
499
- "aria-selected": c.value === "wysiwyg",
500
- "data-active": c.value === "wysiwyg",
501
- onClick: n[0] ||= (e) => c.value = "wysiwyg"
502
- }, h(u.value.wysiwyg), 9, Be), a("button", {
535
+ "aria-selected": u.value === "wysiwyg",
536
+ "data-active": u.value === "wysiwyg",
537
+ onClick: s[0] ||= (e) => u.value = "wysiwyg"
538
+ }, h(v.value.wysiwyg), 9, Ke), a("button", {
503
539
  type: "button",
504
540
  class: "kun-editor__tab",
505
- "aria-selected": c.value === "source",
506
- "data-active": c.value === "source",
507
- onClick: n[1] ||= (e) => c.value = "source"
508
- }, h(u.value.source), 9, Ve)]),
541
+ "aria-selected": u.value === "source",
542
+ "data-active": u.value === "source",
543
+ onClick: s[1] ||= (e) => u.value = "source"
544
+ }, h(v.value.source), 9, qe)]),
509
545
  o(g(C), null, {
510
546
  default: y(() => [o(g(E), null, {
511
- default: y(() => [b(o(Le, null, null, 512), [[_, c.value === "wysiwyg" && !e.readonly]]), b(a("div", He, [o(he, {
547
+ default: y(() => [b(o(Q, null, null, 512), [[_, u.value === "wysiwyg" && !e.readonly]]), b(a("div", Je, [o(be, {
512
548
  "model-value": e.modelValue,
513
549
  adapters: e.adapters,
514
550
  features: e.features,
515
551
  locale: e.locale,
516
552
  readonly: e.readonly,
517
- "onUpdate:modelValue": m
553
+ "onUpdate:modelValue": x
518
554
  }, null, 8, [
519
555
  "model-value",
520
556
  "adapters",
521
557
  "features",
522
558
  "locale",
523
559
  "readonly"
524
- ])], 512), [[_, c.value === "wysiwyg"]])]),
560
+ ])], 512), [[_, u.value === "wysiwyg"]])]),
525
561
  _: 1
526
562
  })]),
527
563
  _: 1
528
564
  }),
529
- b(a("textarea", {
530
- class: "kun-editor__source",
531
- value: e.modelValue,
565
+ u.value === "source" ? (d(), n(Ue, {
566
+ key: 0,
567
+ "model-value": e.modelValue,
532
568
  readonly: e.readonly,
533
- lang: e.locale,
534
- spellcheck: "false",
535
- onInput: v
536
- }, null, 40, Ue), [[_, c.value === "source"]])
569
+ "onUpdate:modelValue": x
570
+ }, null, 8, ["model-value", "readonly"])) : r("", !0)
537
571
  ]));
538
572
  }
539
- }), We = { install(e) {
573
+ }), Ye = { install(e) {
540
574
  e.component("KunEditor", $);
541
575
  } };
542
576
  //#endregion
543
- export { $ as KunEditor, We as KunEditorPlugin };
577
+ export { $ as KunEditor, Ye as KunEditorPlugin };
package/dist/style.css CHANGED
@@ -1,2 +1,2 @@
1
- .kun-mention-dropdown{z-index:30;background:var(--color-background,#fff);border:1px solid var(--color-default-200,#e4e4e7);border-radius:.5rem;min-width:12rem;max-width:20rem;max-height:16rem;padding:.25rem;display:none;position:absolute;overflow-y:auto;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.kun-mention-dropdown[data-show=true]{display:block}.kun-mention-dropdown__item{width:100%;font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:.375rem;align-items:center;gap:.5rem;padding:.375rem .5rem;display:flex}.kun-mention-dropdown__item:hover,.kun-mention-dropdown__item[data-active=true]{background:var(--color-default-100,#f4f4f5)}.kun-mention-dropdown__avatar{object-fit:cover;border-radius:9999px;flex-shrink:0;width:1.5rem;height:1.5rem}.kun-mention-dropdown__avatar--fallback{background:var(--color-default-200,#e4e4e7);color:var(--color-default-600,#52525b);justify-content:center;align-items:center;font-size:.75rem;display:flex}.kun-mention-dropdown__name{text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;overflow:hidden}.kun-mention-dropdown__hint{color:var(--color-default-400,#a1a1aa);padding:.375rem .5rem;font-size:.875rem}.kun-editor__picker{display:inline-flex;position:relative}.kun-editor__picker-panel{z-index:30;background:var(--color-background,#fff);border:1px solid var(--color-default-200,#e4e4e7);border-radius:.5rem;width:18rem;padding:.5rem;position:absolute;top:calc(100% + .25rem);left:0;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.kun-editor__picker-tabs{gap:.25rem;margin-bottom:.5rem;display:flex}.kun-editor__picker-tab{font:inherit;cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;flex:1;padding:.25rem .5rem}.kun-editor__picker-tab[data-active=true]{border-bottom-color:var(--color-primary,#006fee);color:var(--color-primary,#006fee)}.kun-editor__emoji-grid{grid-template-columns:repeat(8,1fr);gap:.125rem;max-height:16rem;display:grid;overflow-y:auto}.kun-editor__emoji{aspect-ratio:1;cursor:pointer;background:0 0;border:none;border-radius:.375rem;font-size:1.25rem;line-height:1}.kun-editor__emoji:hover{background:var(--color-default-100,#f4f4f5)}.kun-editor__sticker-body{max-height:16rem;overflow-y:auto}.kun-editor__pack-name{color:var(--color-default-500,#71717a);padding:.25rem .125rem;font-size:.75rem}.kun-editor__sticker-grid{grid-template-columns:repeat(5,1fr);gap:.25rem;display:grid}.kun-editor__sticker{aspect-ratio:1;cursor:pointer;background:0 0;border:none;border-radius:.375rem;padding:.125rem}.kun-editor__sticker:hover{background:var(--color-default-100,#f4f4f5)}.kun-editor__sticker img{object-fit:contain;width:100%;height:100%}.kun-editor__picker-hint{color:var(--color-default-400,#a1a1aa);text-align:center;padding:1rem;font-size:.875rem}.kun-editor__format-toolbar{flex-wrap:wrap;align-items:center;gap:.125rem;display:flex}.kun-editor__toolbar-divider{background:var(--color-default-200,#e4e4e7);align-self:stretch;width:1px;margin:.25rem}.kun-editor__tool{width:1.75rem;height:1.75rem;color:var(--color-foreground,#27272a);cursor:pointer;background:0 0;border:none;border-radius:.375rem;justify-content:center;align-items:center;padding:0;display:inline-flex}.kun-editor__tool:hover{background:var(--color-default-100,#f4f4f5)}.kun-editor__icon{display:inline-flex}.kun-editor{flex-direction:column;gap:.5rem;display:flex}.kun-editor__toolbar{gap:.25rem;display:flex}.kun-editor__tab{border:1px solid var(--color-default-200,#e4e4e7);font:inherit;cursor:pointer;background:0 0;border-radius:.5rem;padding:.25rem .75rem}.kun-editor__tab[data-active=true]{background:var(--color-primary,#006fee);border-color:var(--color-primary,#006fee);color:#fff}.kun-editor__wysiwyg .milkdown{outline:none}.kun-editor__wysiwyg .ProseMirror{border:1px solid var(--color-default-200,#e4e4e7);white-space:pre-wrap;word-wrap:break-word;border-radius:.5rem;outline:none;min-height:8rem;padding:.75rem}.kun-editor__source{border:1px solid var(--color-default-200,#e4e4e7);resize:vertical;border-radius:.5rem;width:100%;min-height:8rem;padding:.75rem;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.875rem}
1
+ .kun-mention-dropdown{z-index:30;background:var(--color-background,#fff);border:1px solid var(--color-default-200,#e4e4e7);border-radius:.5rem;min-width:12rem;max-width:20rem;max-height:16rem;padding:.25rem;display:none;position:absolute;overflow-y:auto;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.kun-mention-dropdown[data-show=true]{display:block}.kun-mention-dropdown__item{width:100%;font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:.375rem;align-items:center;gap:.5rem;padding:.375rem .5rem;display:flex}.kun-mention-dropdown__item:hover,.kun-mention-dropdown__item[data-active=true]{background:var(--color-default-100,#f4f4f5)}.kun-mention-dropdown__avatar{object-fit:cover;border-radius:9999px;flex-shrink:0;width:1.5rem;height:1.5rem}.kun-mention-dropdown__avatar--fallback{background:var(--color-default-200,#e4e4e7);color:var(--color-default-600,#52525b);justify-content:center;align-items:center;font-size:.75rem;display:flex}.kun-mention-dropdown__name{text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;overflow:hidden}.kun-mention-dropdown__hint{color:var(--color-default-400,#a1a1aa);padding:.375rem .5rem;font-size:.875rem}.kun-editor__picker{display:inline-flex;position:relative}.kun-editor__picker-panel{z-index:30;background:var(--color-background,#fff);border:1px solid var(--color-default-200,#e4e4e7);border-radius:.5rem;width:18rem;padding:.5rem;position:absolute;top:calc(100% + .25rem);left:0;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.kun-editor__picker-tabs{gap:.25rem;margin-bottom:.5rem;display:flex}.kun-editor__picker-tab{font:inherit;cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;flex:1;padding:.25rem .5rem}.kun-editor__picker-tab[data-active=true]{border-bottom-color:var(--color-primary,#006fee);color:var(--color-primary,#006fee)}.kun-editor__emoji-grid{grid-template-columns:repeat(8,1fr);gap:.125rem;max-height:16rem;display:grid;overflow-y:auto}.kun-editor__emoji{aspect-ratio:1;cursor:pointer;background:0 0;border:none;border-radius:.375rem;font-size:1.25rem;line-height:1}.kun-editor__emoji:hover{background:var(--color-default-100,#f4f4f5)}.kun-editor__sticker-body{max-height:16rem;overflow-y:auto}.kun-editor__pack-name{color:var(--color-default-500,#71717a);padding:.25rem .125rem;font-size:.75rem}.kun-editor__sticker-grid{grid-template-columns:repeat(5,1fr);gap:.25rem;display:grid}.kun-editor__sticker{aspect-ratio:1;cursor:pointer;background:0 0;border:none;border-radius:.375rem;padding:.125rem}.kun-editor__sticker:hover{background:var(--color-default-100,#f4f4f5)}.kun-editor__sticker img{object-fit:contain;width:100%;height:100%}.kun-editor__picker-hint{color:var(--color-default-400,#a1a1aa);text-align:center;padding:1rem;font-size:.875rem}.kun-editor__format-toolbar{flex-wrap:wrap;align-items:center;gap:.125rem;display:flex}.kun-editor__toolbar-divider{background:var(--color-default-200,#e4e4e7);align-self:stretch;width:1px;margin:.25rem}.kun-editor__tool{width:1.75rem;height:1.75rem;color:var(--color-foreground,#27272a);cursor:pointer;background:0 0;border:none;border-radius:.375rem;justify-content:center;align-items:center;padding:0;display:inline-flex}.kun-editor__tool:hover{background:var(--color-default-100,#f4f4f5)}.kun-editor__icon{display:inline-flex}.kun-editor__source .cm-editor{border:1px solid var(--color-default-200,#e4e4e7);border-radius:.5rem;overflow:hidden}.kun-editor{flex-direction:column;gap:.5rem;display:flex}.kun-editor__toolbar{gap:.25rem;display:flex}.kun-editor__tab{border:1px solid var(--color-default-200,#e4e4e7);font:inherit;cursor:pointer;background:0 0;border-radius:.5rem;padding:.25rem .75rem}.kun-editor__tab[data-active=true]{background:var(--color-primary,#006fee);border-color:var(--color-primary,#006fee);color:#fff}.kun-editor__wysiwyg .milkdown{outline:none}.kun-editor__wysiwyg .ProseMirror{border:1px solid var(--color-default-200,#e4e4e7);white-space:pre-wrap;word-wrap:break-word;border-radius:.5rem;outline:none;min-height:8rem;padding:.75rem}
2
2
  /*$vite$:1*/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kungal/editor-vue",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "KunEditor Vue 3 layer — the <KunEditor> component (dual WYSIWYG / markdown-source), toolbar and plugin views. Consumes @kungal/editor-core; pairs with @kungal/ui-vue.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -44,26 +44,48 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@prosemirror-adapter/vue": "^0.4.6",
47
- "@kungal/editor-core": "0.6.0"
47
+ "@kungal/editor-core": "0.7.0"
48
48
  },
49
49
  "peerDependencies": {
50
+ "@codemirror/lang-markdown": "^6.0.0",
51
+ "@codemirror/state": "^6.0.0",
52
+ "@codemirror/view": "^6.0.0",
50
53
  "@kungal/ui-vue": "^2.7.0",
51
54
  "@milkdown/kit": "^7.21.2",
52
55
  "@milkdown/prose": "^7.21.2",
53
56
  "@milkdown/vue": "^7.21.2",
57
+ "codemirror": "^6.0.0",
54
58
  "vue": "^3.5.0"
55
59
  },
60
+ "peerDependenciesMeta": {
61
+ "@codemirror/lang-markdown": {
62
+ "optional": true
63
+ },
64
+ "@codemirror/state": {
65
+ "optional": true
66
+ },
67
+ "@codemirror/view": {
68
+ "optional": true
69
+ },
70
+ "codemirror": {
71
+ "optional": true
72
+ }
73
+ },
56
74
  "devDependencies": {
75
+ "@codemirror/lang-markdown": "^6.5.0",
76
+ "@codemirror/state": "^6.5.2",
77
+ "@codemirror/view": "^6.39.4",
57
78
  "@milkdown/kit": "^7.21.2",
58
79
  "@milkdown/prose": "^7.21.2",
59
80
  "@milkdown/vue": "7.21.2",
60
81
  "@types/node": "^22.10.0",
61
82
  "@vitejs/plugin-vue": "^6.0.7",
83
+ "codemirror": "^6.0.2",
62
84
  "typescript": "^5.7.0",
63
85
  "vite": "^8.0.16",
64
86
  "vue": "^3.5.35",
65
87
  "vue-tsc": "^3.3.3",
66
- "@kungal/editor-core": "0.6.0"
88
+ "@kungal/editor-core": "0.7.0"
67
89
  },
68
90
  "scripts": {
69
91
  "build": "vite build && vue-tsc -p tsconfig.build.json",