@milkdown/plugin-upload 6.5.4 → 7.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,7 @@
1
1
  import type { Uploader } from './upload';
2
+ export declare const readImageAsBase64: (file: File) => Promise<{
3
+ alt: string;
4
+ src: string;
5
+ }>;
2
6
  export declare const defaultUploader: Uploader;
3
7
  //# sourceMappingURL=default-uploader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"default-uploader.d.ts","sourceRoot":"","sources":["../src/default-uploader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAmBxC,eAAO,MAAM,eAAe,EAAE,QAqB7B,CAAA"}
1
+ {"version":3,"file":"default-uploader.d.ts","sourceRoot":"","sources":["../src/default-uploader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,eAAO,MAAM,iBAAiB,SAAU,IAAI,KAAG,QAAQ;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAelF,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,QAqB7B,CAAA"}
package/lib/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { AtomList } from '@milkdown/utils';
2
- export type { Uploader } from './upload';
3
- export { key, uploadPlugin } from './upload';
4
- export declare const upload: AtomList<import("@milkdown/utils").Metadata<import("@milkdown/utils").GetPlugin<string, import("./upload").Options>> & import("@milkdown/core").MilkdownPlugin>;
1
+ import type { MilkdownPlugin } from '@milkdown/ctx';
2
+ export * from './upload';
3
+ export * from './default-uploader';
4
+ export declare const upload: MilkdownPlugin[];
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAI1C,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C,eAAO,MAAM,MAAM,iKAAoC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAGnD,cAAc,UAAU,CAAA;AACxB,cAAc,oBAAoB,CAAA;AAElC,eAAO,MAAM,MAAM,EAAE,cAAc,EAAiC,CAAA"}
package/lib/index.es.js CHANGED
@@ -1,102 +1,103 @@
1
- import { createPlugin as I, AtomList as w } from "@milkdown/utils";
2
- import { schemaCtx as C, themeManagerCtx as E, ThemeIcon as L } from "@milkdown/core";
3
- import { missingNodeInSchema as M, missingIcon as S } from "@milkdown/exception";
4
- import { PluginKey as U, Plugin as D } from "@milkdown/prose/state";
5
- import { DecorationSet as _, Decoration as x } from "@milkdown/prose/view";
6
- const F = (l) => new Promise((o) => {
7
- const i = new FileReader();
8
- i.addEventListener(
1
+ import { schemaCtx as h } from "@milkdown/core";
2
+ import { PluginKey as y, Plugin as D } from "@milkdown/prose/state";
3
+ import { Decoration as P, DecorationSet as b } from "@milkdown/prose/view";
4
+ import { $ctx as U, $prose as C } from "@milkdown/utils";
5
+ import { missingNodeInSchema as F } from "@milkdown/exception";
6
+ const A = (a) => new Promise((i) => {
7
+ const r = new FileReader();
8
+ r.addEventListener(
9
9
  "load",
10
10
  () => {
11
- o({
12
- alt: l.name,
13
- src: i.result
11
+ i({
12
+ alt: a.name,
13
+ src: r.result
14
14
  });
15
15
  },
16
16
  !1
17
- ), i.readAsDataURL(l);
18
- }), K = async (l, o) => {
19
- const i = [];
20
- for (let s = 0; s < l.length; s++) {
21
- const d = l.item(s);
22
- !d || !d.type.includes("image") || i.push(d);
17
+ ), r.readAsDataURL(a);
18
+ }), E = async (a, i) => {
19
+ const r = [];
20
+ for (let t = 0; t < a.length; t++) {
21
+ const e = a.item(t);
22
+ !e || !e.type.includes("image") || r.push(e);
23
23
  }
24
- const { image: u } = o.nodes;
25
- if (!u)
26
- throw M("image");
27
- return (await Promise.all(i.map((s) => F(s)))).map(({ alt: s, src: d }) => u.createAndFill({ src: d, alt: s }));
28
- }, N = new U("MILKDOWN_UPLOAD"), O = I((l, o) => {
29
- var u;
30
- const i = (u = o == null ? void 0 : o.uploader) != null ? u : K;
31
- return {
32
- prosePlugins: (y, s) => {
33
- const d = s.get(C), p = new D({
34
- key: N,
35
- state: {
36
- init() {
37
- return _.empty;
38
- },
39
- apply(e, r) {
40
- const t = r.map(e.mapping, e.doc), a = e.getMeta(this);
41
- if (!a)
42
- return t;
43
- if (a.add) {
44
- const n = document.createElement("span"), c = s.get(E).get(L, "loading");
45
- if (!c)
46
- throw S("loading");
47
- n.appendChild(c.dom);
48
- const m = x.widget(a.add.pos, n, { id: a.add.id });
49
- return t.add(e.doc, [m]);
50
- }
51
- return a.remove ? t.remove(
52
- t.find(void 0, void 0, (n) => n.id === a.remove.id)
53
- ) : t;
54
- }
55
- },
56
- props: {
57
- decorations(e) {
58
- return this.getState(e);
59
- }
24
+ const { image: c } = i.nodes;
25
+ if (!c)
26
+ throw F("image");
27
+ return (await Promise.all(r.map((t) => A(t)))).map(({ alt: t, src: e }) => c.createAndFill({ src: e, alt: t }));
28
+ }, l = U({
29
+ uploader: E,
30
+ enableHtmlFileUploader: !1,
31
+ uploadWidgetFactory: (a, i) => {
32
+ const r = document.createElement("span");
33
+ return r.textContent = "Upload in progress...", P.widget(a, r, i);
34
+ }
35
+ }, "uploadConfig"), M = C((a) => {
36
+ const i = new y("MILKDOWN_UPLOAD"), r = (o, t) => {
37
+ var s;
38
+ const e = i.getState(o);
39
+ if (!e)
40
+ return -1;
41
+ const n = e.find(void 0, void 0, (d) => d.id === t);
42
+ return n.length ? ((s = n[0]) == null ? void 0 : s.from) ?? -1 : -1;
43
+ }, c = (o, t, e) => {
44
+ var m;
45
+ if (!e || e.length <= 0)
46
+ return !1;
47
+ const n = Symbol("upload symbol"), s = a.get(h), { tr: d } = o.state, f = t instanceof DragEvent ? ((m = o.posAtCoords({ left: t.clientX, top: t.clientY })) == null ? void 0 : m.pos) ?? d.selection.from : d.selection.from;
48
+ o.dispatch(d.setMeta(i, { add: { id: n, pos: f } }));
49
+ const { uploader: g } = a.get(l.key);
50
+ return g(e, s).then((p) => {
51
+ const u = r(o.state, n);
52
+ u < 0 || o.dispatch(
53
+ o.state.tr.replaceWith(u, u, p).setMeta(i, { remove: { id: n } })
54
+ );
55
+ }).catch((p) => {
56
+ console.error(p);
57
+ }), !0;
58
+ };
59
+ return new D({
60
+ key: i,
61
+ state: {
62
+ init() {
63
+ return b.empty;
64
+ },
65
+ apply(o, t) {
66
+ const e = t.map(o.mapping, o.doc), n = o.getMeta(this);
67
+ if (!n)
68
+ return e;
69
+ if (n.add) {
70
+ const { uploadWidgetFactory: s } = a.get(l.key), d = s(n.add.pos, { id: n.add.id });
71
+ return e.add(o.doc, [d]);
60
72
  }
61
- }), b = (e, r) => {
62
- var n, c;
63
- const t = p.getState(e);
64
- if (!t)
65
- return -1;
66
- const a = t.find(void 0, void 0, (m) => m.id === r);
67
- return a.length && (c = (n = a[0]) == null ? void 0 : n.from) != null ? c : -1;
68
- }, h = (e, r, t) => {
69
- var m, P;
70
- if (!t || t.length <= 0)
71
- return !1;
72
- const a = Symbol("upload symbol"), { tr: n } = e.state, c = r instanceof DragEvent && (P = (m = e.posAtCoords({ left: r.clientX, top: r.clientY })) == null ? void 0 : m.pos) != null ? P : n.selection.from;
73
- return e.dispatch(n.setMeta(p, { add: { id: a, pos: c } })), i(t, d).then((f) => {
74
- const g = b(e.state, a);
75
- g < 0 || e.dispatch(
76
- e.state.tr.replaceWith(g, g, f).setMeta(p, { remove: { id: a } })
77
- );
78
- }).catch((f) => {
79
- console.error(f);
80
- }), !0;
81
- }, A = new D({
82
- props: {
83
- handlePaste: (e, r) => {
84
- var t, a;
85
- return !(r instanceof ClipboardEvent) || !(o != null && o.enableHtmlFileUploader) && ((t = r.clipboardData) == null ? void 0 : t.getData("text/html")) ? !1 : h(e, r, (a = r.clipboardData) == null ? void 0 : a.files);
86
- },
87
- handleDrop: (e, r) => {
88
- var t;
89
- return r instanceof DragEvent ? h(e, r, (t = r.dataTransfer) == null ? void 0 : t.files) : !1;
90
- }
73
+ if (n.remove) {
74
+ const s = e.find(void 0, void 0, (d) => d.id === n.remove.id);
75
+ return e.remove(s);
91
76
  }
92
- });
93
- return [p, A];
77
+ return e;
78
+ }
79
+ },
80
+ props: {
81
+ decorations(o) {
82
+ return this.getState(o);
83
+ },
84
+ handlePaste: (o, t) => {
85
+ var n, s;
86
+ const { enableHtmlFileUploader: e } = a.get(l.key);
87
+ return !(t instanceof ClipboardEvent) || !e && ((n = t.clipboardData) == null ? void 0 : n.getData("text/html")) ? !1 : c(o, t, (s = t.clipboardData) == null ? void 0 : s.files);
88
+ },
89
+ handleDrop: (o, t) => {
90
+ var e;
91
+ return t instanceof DragEvent ? c(o, t, (e = t.dataTransfer) == null ? void 0 : e.files) : !1;
92
+ }
94
93
  }
95
- };
96
- }), H = w.create([O()]);
94
+ });
95
+ }), I = [l, M];
97
96
  export {
98
- N as key,
99
- H as upload,
100
- O as uploadPlugin
97
+ E as defaultUploader,
98
+ A as readImageAsBase64,
99
+ M as updatePlugin,
100
+ I as upload,
101
+ l as uploadConfig
101
102
  };
102
103
  //# sourceMappingURL=index.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../src/default-uploader.ts","../src/upload.ts","../src/index.ts"],"sourcesContent":["/* Copyright 2021, Milkdown by Mirone. */\nimport { missingNodeInSchema } from '@milkdown/exception'\nimport type { Node } from '@milkdown/prose/model'\n\nimport type { Uploader } from './upload'\n\nconst readImageAsBase64 = (file: File): Promise<{ alt: string; src: string }> => {\n return new Promise((resolve) => {\n const reader = new FileReader()\n reader.addEventListener(\n 'load',\n () => {\n resolve({\n alt: file.name,\n src: reader.result as string,\n })\n },\n false,\n )\n reader.readAsDataURL(file)\n })\n}\n\nexport const defaultUploader: Uploader = async (files, schema) => {\n const imgs: File[] = []\n\n for (let i = 0; i < files.length; i++) {\n const file = files.item(i)\n if (!file)\n continue\n\n if (!file.type.includes('image'))\n continue\n\n imgs.push(file)\n }\n\n const { image } = schema.nodes\n if (!image)\n throw missingNodeInSchema('image')\n\n const data = await Promise.all(imgs.map(img => readImageAsBase64(img)))\n\n return data.map(({ alt, src }) => image.createAndFill({ src, alt }) as Node)\n}\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { ThemeIcon, schemaCtx, themeManagerCtx } from '@milkdown/core'\nimport { missingIcon } from '@milkdown/exception'\nimport type { Fragment, Node, Schema } from '@milkdown/prose/model'\nimport type { EditorState } from '@milkdown/prose/state'\nimport { Plugin, PluginKey } from '@milkdown/prose/state'\nimport type { EditorView } from '@milkdown/prose/view'\nimport { Decoration, DecorationSet } from '@milkdown/prose/view'\nimport { createPlugin } from '@milkdown/utils'\n\nimport { defaultUploader } from './default-uploader'\n\nexport type Uploader = (files: FileList, schema: Schema) => Promise<Fragment | Node | Node[]>\ninterface Spec { id: symbol; pos: number }\nexport interface Options {\n uploader: Uploader\n enableHtmlFileUploader: boolean\n}\nexport const key = new PluginKey('MILKDOWN_UPLOAD')\n\nexport const uploadPlugin = createPlugin<string, Options>((_, options) => {\n const uploader = options?.uploader ?? defaultUploader\n\n return {\n prosePlugins: (_, ctx) => {\n const schema = ctx.get(schemaCtx)\n\n const placeholderPlugin = new Plugin({\n key,\n state: {\n init() {\n return DecorationSet.empty\n },\n apply(this: Plugin, tr, set) {\n const _set = set.map(tr.mapping, tr.doc)\n const action = tr.getMeta(this)\n if (!action)\n return _set\n\n if (action.add) {\n const widget = document.createElement('span')\n const loadingIcon = ctx.get(themeManagerCtx).get(ThemeIcon, 'loading')\n if (!loadingIcon)\n throw missingIcon('loading')\n\n widget.appendChild(loadingIcon.dom)\n\n const decoration = Decoration.widget(action.add.pos, widget, { id: action.add.id } as any)\n return _set.add(tr.doc, [decoration])\n }\n if (action.remove) {\n return _set.remove(\n _set.find(undefined, undefined, (spec: Spec) => spec.id === action.remove.id),\n )\n }\n\n return _set\n },\n },\n props: {\n decorations(this: Plugin, state) {\n return this.getState(state)\n },\n },\n })\n\n const findPlaceholder = (state: EditorState, id: symbol): number => {\n const decorations = placeholderPlugin.getState(state)\n if (!decorations)\n return -1\n const found = decorations.find(undefined, undefined, (spec: Spec) => spec.id === id)\n if (!found.length)\n return -1\n return found[0]?.from ?? -1\n }\n\n const handleUpload = (view: EditorView, event: DragEvent | ClipboardEvent, files: FileList | undefined) => {\n if (!files || files.length <= 0)\n return false\n\n const id = Symbol('upload symbol')\n const { tr } = view.state\n const insertPos\n = event instanceof DragEvent\n ? view.posAtCoords({ left: event.clientX, top: event.clientY })?.pos ?? tr.selection.from\n : tr.selection.from\n view.dispatch(tr.setMeta(placeholderPlugin, { add: { id, pos: insertPos } }))\n\n uploader(files, schema)\n .then((fragment) => {\n const pos = findPlaceholder(view.state, id)\n if (pos < 0)\n return\n\n view.dispatch(\n view.state.tr\n .replaceWith(pos, pos, fragment)\n .setMeta(placeholderPlugin, { remove: { id } }),\n )\n })\n .catch((e) => {\n console.error(e)\n })\n return true\n }\n\n const uploadPlugin = new Plugin({\n props: {\n handlePaste: (view, event) => {\n if (!(event instanceof ClipboardEvent))\n return false\n\n if (!options?.enableHtmlFileUploader && event.clipboardData?.getData('text/html'))\n return false\n\n return handleUpload(view, event, event.clipboardData?.files)\n },\n handleDrop: (view, event) => {\n if (!(event instanceof DragEvent))\n return false\n\n return handleUpload(view, event, event.dataTransfer?.files)\n },\n },\n })\n return [placeholderPlugin, uploadPlugin]\n },\n }\n})\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { AtomList } from '@milkdown/utils'\n\nimport { uploadPlugin } from './upload'\n\nexport type { Uploader } from './upload'\nexport { key, uploadPlugin } from './upload'\n\nexport const upload = AtomList.create([uploadPlugin()])\n"],"names":["readImageAsBase64","file","resolve","reader","defaultUploader","files","schema","imgs","i","image","missingNodeInSchema","img","alt","src","key","PluginKey","uploadPlugin","createPlugin","_","options","uploader","_a","ctx","schemaCtx","placeholderPlugin","Plugin","DecorationSet","tr","set","_set","action","widget","loadingIcon","themeManagerCtx","ThemeIcon","missingIcon","decoration","Decoration","spec","state","findPlaceholder","id","decorations","found","_b","handleUpload","view","event","insertPos","fragment","pos","e","upload","AtomList"],"mappings":";;;;;AAMA,MAAMA,IAAoB,CAACC,MAClB,IAAI,QAAQ,CAACC,MAAY;AACxB,QAAAC,IAAS,IAAI;AACZ,EAAAA,EAAA;AAAA,IACL;AAAA,IACA,MAAM;AACI,MAAAD,EAAA;AAAA,QACN,KAAKD,EAAK;AAAA,QACV,KAAKE,EAAO;AAAA,MAAA,CACb;AAAA,IACH;AAAA,IACA;AAAA,EAAA,GAEFA,EAAO,cAAcF,CAAI;AAAA,CAC1B,GAGUG,IAA4B,OAAOC,GAAOC,MAAW;AAChE,QAAMC,IAAe,CAAA;AAErB,WAASC,IAAI,GAAGA,IAAIH,EAAM,QAAQG,KAAK;AAC/B,UAAAP,IAAOI,EAAM,KAAKG,CAAC;AACzB,IAAI,CAACP,KAGD,CAACA,EAAK,KAAK,SAAS,OAAO,KAG/BM,EAAK,KAAKN,CAAI;AAAA,EAChB;AAEM,QAAA,EAAE,OAAAQ,EAAM,IAAIH,EAAO;AACzB,MAAI,CAACG;AACH,UAAMC,EAAoB,OAAO;AAInC,UAFa,MAAM,QAAQ,IAAIH,EAAK,IAAI,CAAOI,MAAAX,EAAkBW,CAAG,CAAC,CAAC,GAE1D,IAAI,CAAC,EAAE,KAAAC,GAAK,KAAAC,EAAA,MAAUJ,EAAM,cAAc,EAAE,KAAAI,GAAK,KAAAD,EAAA,CAAK,CAAS;AAC7E,GC1BaE,IAAM,IAAIC,EAAU,iBAAiB,GAErCC,IAAeC,EAA8B,CAACC,GAAGC,MAAY;;AAClE,QAAAC,KAAWC,IAAAF,KAAA,gBAAAA,EAAS,aAAT,OAAAE,IAAqBjB;AAE/B,SAAA;AAAA,IACL,cAAc,CAACc,GAAGI,MAAQ;AAClB,YAAAhB,IAASgB,EAAI,IAAIC,CAAS,GAE1BC,IAAoB,IAAIC,EAAO;AAAA,QACnC,KAAAX;AAAA,QACA,OAAO;AAAA,UACL,OAAO;AACL,mBAAOY,EAAc;AAAA,UACvB;AAAA,UACA,MAAoBC,GAAIC,GAAK;AAC3B,kBAAMC,IAAOD,EAAI,IAAID,EAAG,SAASA,EAAG,GAAG,GACjCG,IAASH,EAAG,QAAQ,IAAI;AAC9B,gBAAI,CAACG;AACI,qBAAAD;AAET,gBAAIC,EAAO,KAAK;AACR,oBAAAC,IAAS,SAAS,cAAc,MAAM,GACtCC,IAAcV,EAAI,IAAIW,CAAe,EAAE,IAAIC,GAAW,SAAS;AACrE,kBAAI,CAACF;AACH,sBAAMG,EAAY,SAAS;AAEtB,cAAAJ,EAAA,YAAYC,EAAY,GAAG;AAElC,oBAAMI,IAAaC,EAAW,OAAOP,EAAO,IAAI,KAAKC,GAAQ,EAAE,IAAID,EAAO,IAAI,GAAW,CAAA;AACzF,qBAAOD,EAAK,IAAIF,EAAG,KAAK,CAACS,CAAU,CAAC;AAAA,YACtC;AACA,mBAAIN,EAAO,SACFD,EAAK;AAAA,cACVA,EAAK,KAAK,QAAW,QAAW,CAACS,MAAeA,EAAK,OAAOR,EAAO,OAAO,EAAE;AAAA,YAAA,IAIzED;AAAA,UACT;AAAA,QACF;AAAA,QACA,OAAO;AAAA,UACL,YAA0BU,GAAO;AACxB,mBAAA,KAAK,SAASA,CAAK;AAAA,UAC5B;AAAA,QACF;AAAA,MAAA,CACD,GAEKC,IAAkB,CAACD,GAAoBE,MAAuB;;AAC5D,cAAAC,IAAclB,EAAkB,SAASe,CAAK;AACpD,YAAI,CAACG;AACI,iBAAA;AACH,cAAAC,IAAQD,EAAY,KAAK,QAAW,QAAW,CAACJ,MAAeA,EAAK,OAAOG,CAAE;AACnF,eAAKE,EAAM,WAEJC,KAAAvB,IAAAsB,EAAM,OAAN,gBAAAtB,EAAU,SAAV,OAAAuB,IADE;AAAA,MACgB,GAGrBC,IAAe,CAACC,GAAkBC,GAAmC1C,MAAgC;;AACrG,YAAA,CAACA,KAASA,EAAM,UAAU;AACrB,iBAAA;AAEH,cAAAoC,IAAK,OAAO,eAAe,GAC3B,EAAE,IAAAd,EAAG,IAAImB,EAAK,OACdE,IACQD,aAAiB,cACfH,KAAAvB,IAAAyB,EAAK,YAAY,EAAE,MAAMC,EAAM,SAAS,KAAKA,EAAM,QAAA,CAAS,MAA5D,gBAAA1B,EAA+D,QAA/D,OAAAuB,IACAjB,EAAG,UAAU;AAC7B,eAAAmB,EAAK,SAASnB,EAAG,QAAQH,GAAmB,EAAE,KAAK,EAAE,IAAAiB,GAAI,KAAKO,EAAY,EAAA,CAAC,CAAC,GAE5E5B,EAASf,GAAOC,CAAM,EACnB,KAAK,CAAC2C,MAAa;AAClB,gBAAMC,IAAMV,EAAgBM,EAAK,OAAOL,CAAE;AAC1C,UAAIS,IAAM,KAGLJ,EAAA;AAAA,YACHA,EAAK,MAAM,GACR,YAAYI,GAAKA,GAAKD,CAAQ,EAC9B,QAAQzB,GAAmB,EAAE,QAAQ,EAAE,IAAAiB,KAAM;AAAA,UAAA;AAAA,QAClD,CACD,EACA,MAAM,CAACU,MAAM;AACZ,kBAAQ,MAAMA,CAAC;AAAA,QAAA,CAChB,GACI;AAAA,MAAA,GAGHnC,IAAe,IAAIS,EAAO;AAAA,QAC9B,OAAO;AAAA,UACL,aAAa,CAACqB,GAAMC,MAAU;;AAI5B,mBAHI,EAAEA,aAAiB,mBAGnB,EAAC5B,KAAA,QAAAA,EAAS,6BAA0BE,IAAA0B,EAAM,kBAAN,gBAAA1B,EAAqB,QAAQ,gBAC5D,KAEFwB,EAAaC,GAAMC,IAAOH,IAAAG,EAAM,kBAAN,gBAAAH,EAAqB,KAAK;AAAA,UAC7D;AAAA,UACA,YAAY,CAACE,GAAMC,MAAU;;AAC3B,mBAAMA,aAAiB,YAGhBF,EAAaC,GAAMC,IAAO1B,IAAA0B,EAAM,iBAAN,gBAAA1B,EAAoB,KAAK,IAFjD;AAAA,UAGX;AAAA,QACF;AAAA,MAAA,CACD;AACM,aAAA,CAACG,GAAmBR,CAAY;AAAA,IACzC;AAAA,EAAA;AAEJ,CAAC,GCxHYoC,IAASC,EAAS,OAAO,CAACrC,EAAA,CAAc,CAAC;"}
1
+ {"version":3,"file":"index.es.js","sources":["../src/default-uploader.ts","../src/upload.ts","../src/index.ts"],"sourcesContent":["/* Copyright 2021, Milkdown by Mirone. */\nimport { missingNodeInSchema } from '@milkdown/exception'\nimport type { Node } from '@milkdown/prose/model'\n\nimport type { Uploader } from './upload'\n\nexport const readImageAsBase64 = (file: File): Promise<{ alt: string; src: string }> => {\n return new Promise((resolve) => {\n const reader = new FileReader()\n reader.addEventListener(\n 'load',\n () => {\n resolve({\n alt: file.name,\n src: reader.result as string,\n })\n },\n false,\n )\n reader.readAsDataURL(file)\n })\n}\n\nexport const defaultUploader: Uploader = async (files, schema) => {\n const imgs: File[] = []\n\n for (let i = 0; i < files.length; i++) {\n const file = files.item(i)\n if (!file)\n continue\n\n if (!file.type.includes('image'))\n continue\n\n imgs.push(file)\n }\n\n const { image } = schema.nodes\n if (!image)\n throw missingNodeInSchema('image')\n\n const data = await Promise.all(imgs.map(img => readImageAsBase64(img)))\n\n return data.map(({ alt, src }) => image.createAndFill({ src, alt }) as Node)\n}\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { schemaCtx } from '@milkdown/core'\nimport type { Fragment, Node, Schema } from '@milkdown/prose/model'\nimport type { EditorState } from '@milkdown/prose/state'\nimport { Plugin, PluginKey } from '@milkdown/prose/state'\nimport type { EditorView } from '@milkdown/prose/view'\nimport { Decoration, DecorationSet } from '@milkdown/prose/view'\nimport { $ctx, $prose } from '@milkdown/utils'\n\nimport { defaultUploader } from './default-uploader'\n\nexport type Uploader = (files: FileList, schema: Schema) => Promise<Fragment | Node | Node[]>\ninterface Spec { id: symbol; pos: number }\nexport interface UploadConfig {\n uploader: Uploader\n enableHtmlFileUploader: boolean\n uploadWidgetFactory: (pos: number, spec: Parameters<typeof Decoration.widget>[2]) => Decoration\n}\n\nexport const uploadConfig = $ctx<UploadConfig, 'uploadConfig'>({\n uploader: defaultUploader,\n enableHtmlFileUploader: false,\n uploadWidgetFactory: (pos, spec) => {\n const widgetDOM = document.createElement('span')\n widgetDOM.textContent = 'Upload in progress...'\n return Decoration.widget(pos, widgetDOM, spec)\n },\n}, 'uploadConfig')\n\nexport const updatePlugin = $prose((ctx) => {\n const pluginKey = new PluginKey('MILKDOWN_UPLOAD')\n\n const findPlaceholder = (state: EditorState, id: symbol): number => {\n const decorations = pluginKey.getState(state)\n if (!decorations)\n return -1\n const found = decorations.find(undefined, undefined, (spec: Spec) => spec.id === id)\n if (!found.length)\n return -1\n return found[0]?.from ?? -1\n }\n\n const handleUpload = (view: EditorView, event: DragEvent | ClipboardEvent, files: FileList | undefined) => {\n if (!files || files.length <= 0)\n return false\n\n const id = Symbol('upload symbol')\n const schema = ctx.get(schemaCtx)\n const { tr } = view.state\n const insertPos = event instanceof DragEvent\n ? view.posAtCoords({ left: event.clientX, top: event.clientY })?.pos ?? tr.selection.from\n : tr.selection.from\n view.dispatch(tr.setMeta(pluginKey, { add: { id, pos: insertPos } }))\n\n const { uploader } = ctx.get(uploadConfig.key)\n uploader(files, schema)\n .then((fragment) => {\n const pos = findPlaceholder(view.state, id)\n if (pos < 0)\n return\n\n view.dispatch(\n view.state.tr\n .replaceWith(pos, pos, fragment)\n .setMeta(pluginKey, { remove: { id } }),\n )\n })\n .catch((e) => {\n console.error(e)\n })\n return true\n }\n\n return new Plugin({\n key: pluginKey,\n state: {\n init() {\n return DecorationSet.empty\n },\n apply(this: Plugin, tr, set) {\n const _set = set.map(tr.mapping, tr.doc)\n const action = tr.getMeta(this)\n if (!action)\n return _set\n\n if (action.add) {\n const { uploadWidgetFactory } = ctx.get(uploadConfig.key)\n\n const decoration = uploadWidgetFactory(action.add.pos, { id: action.add.id })\n return _set.add(tr.doc, [decoration])\n }\n if (action.remove) {\n const target = _set.find(undefined, undefined, (spec: Spec) => spec.id === action.remove.id)\n return _set.remove(target)\n }\n\n return _set\n },\n },\n props: {\n decorations(this: Plugin, state) {\n return this.getState(state)\n },\n handlePaste: (view, event) => {\n const { enableHtmlFileUploader } = ctx.get(uploadConfig.key)\n if (!(event instanceof ClipboardEvent))\n return false\n\n if (!enableHtmlFileUploader && event.clipboardData?.getData('text/html'))\n return false\n\n return handleUpload(view, event, event.clipboardData?.files)\n },\n handleDrop: (view, event) => {\n if (!(event instanceof DragEvent))\n return false\n\n return handleUpload(view, event, event.dataTransfer?.files)\n },\n },\n })\n})\n","/* Copyright 2021, Milkdown by Mirone. */\nimport type { MilkdownPlugin } from '@milkdown/ctx'\nimport { updatePlugin, uploadConfig } from './upload'\n\nexport * from './upload'\nexport * from './default-uploader'\n\nexport const upload: MilkdownPlugin[] = [uploadConfig, updatePlugin]\n"],"names":["readImageAsBase64","file","resolve","reader","defaultUploader","files","schema","imgs","i","image","missingNodeInSchema","img","alt","src","uploadConfig","$ctx","pos","spec","widgetDOM","Decoration","updatePlugin","$prose","ctx","pluginKey","PluginKey","findPlaceholder","state","id","decorations","found","_a","handleUpload","view","event","schemaCtx","tr","insertPos","uploader","fragment","e","Plugin","DecorationSet","set","_set","action","uploadWidgetFactory","decoration","target","enableHtmlFileUploader","_b","upload"],"mappings":"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"}
package/lib/upload.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import type { Fragment, Node, Schema } from '@milkdown/prose/model';
2
- import { PluginKey } from '@milkdown/prose/state';
2
+ import { Decoration } from '@milkdown/prose/view';
3
3
  export type Uploader = (files: FileList, schema: Schema) => Promise<Fragment | Node | Node[]>;
4
- export interface Options {
4
+ export interface UploadConfig {
5
5
  uploader: Uploader;
6
6
  enableHtmlFileUploader: boolean;
7
+ uploadWidgetFactory: (pos: number, spec: Parameters<typeof Decoration.widget>[2]) => Decoration;
7
8
  }
8
- export declare const key: PluginKey<any>;
9
- export declare const uploadPlugin: import("@milkdown/utils").WithExtend<string, Options, import("@milkdown/utils").TypeMapping<string, string>, import("@milkdown/utils").PluginRest<string, string>>;
9
+ export declare const uploadConfig: import("@milkdown/utils").$Ctx<UploadConfig, "uploadConfig">;
10
+ export declare const updatePlugin: import("@milkdown/utils").$Prose;
10
11
  //# sourceMappingURL=upload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAEnE,OAAO,EAAU,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAOzD,MAAM,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAA;AAE7F,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,QAAQ,CAAA;IAClB,sBAAsB,EAAE,OAAO,CAAA;CAChC;AACD,eAAO,MAAM,GAAG,gBAAmC,CAAA;AAEnD,eAAO,MAAM,YAAY,oKA4GvB,CAAA"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAInE,OAAO,EAAE,UAAU,EAAiB,MAAM,sBAAsB,CAAA;AAKhE,MAAM,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAA;AAE7F,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,CAAA;IAClB,sBAAsB,EAAE,OAAO,CAAA;IAC/B,mBAAmB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAA;CAChG;AAED,eAAO,MAAM,YAAY,8DAQP,CAAA;AAElB,eAAO,MAAM,YAAY,kCA4FvB,CAAA"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@milkdown/plugin-upload",
3
3
  "type": "module",
4
- "version": "6.5.4",
4
+ "version": "7.0.0-next.0",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -20,17 +20,19 @@
20
20
  "src"
21
21
  ],
22
22
  "peerDependencies": {
23
- "@milkdown/core": "^6.0.1",
24
- "@milkdown/prose": "^6.0.1"
23
+ "@milkdown/core": "^7.0.0-next.0",
24
+ "@milkdown/ctx": "^7.0.0-next.0",
25
+ "@milkdown/prose": "^7.0.0-next.0"
25
26
  },
26
27
  "dependencies": {
27
28
  "tslib": "^2.4.0",
28
- "@milkdown/exception": "6.5.4",
29
- "@milkdown/utils": "6.5.4"
29
+ "@milkdown/exception": "7.0.0-next.0",
30
+ "@milkdown/utils": "7.0.0-next.0"
30
31
  },
31
32
  "devDependencies": {
32
- "@milkdown/core": "6.5.4",
33
- "@milkdown/prose": "6.5.4"
33
+ "@milkdown/core": "7.0.0-next.0",
34
+ "@milkdown/ctx": "7.0.0-next.0",
35
+ "@milkdown/prose": "7.0.0-next.0"
34
36
  },
35
37
  "nx": {
36
38
  "targets": {
@@ -4,7 +4,7 @@ import type { Node } from '@milkdown/prose/model'
4
4
 
5
5
  import type { Uploader } from './upload'
6
6
 
7
- const readImageAsBase64 = (file: File): Promise<{ alt: string; src: string }> => {
7
+ export const readImageAsBase64 = (file: File): Promise<{ alt: string; src: string }> => {
8
8
  return new Promise((resolve) => {
9
9
  const reader = new FileReader()
10
10
  reader.addEventListener(
package/src/index.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { AtomList } from '@milkdown/utils'
2
+ import type { MilkdownPlugin } from '@milkdown/ctx'
3
+ import { updatePlugin, uploadConfig } from './upload'
3
4
 
4
- import { uploadPlugin } from './upload'
5
+ export * from './upload'
6
+ export * from './default-uploader'
5
7
 
6
- export type { Uploader } from './upload'
7
- export { key, uploadPlugin } from './upload'
8
-
9
- export const upload = AtomList.create([uploadPlugin()])
8
+ export const upload: MilkdownPlugin[] = [uploadConfig, updatePlugin]
package/src/upload.ts CHANGED
@@ -1,129 +1,122 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { ThemeIcon, schemaCtx, themeManagerCtx } from '@milkdown/core'
3
- import { missingIcon } from '@milkdown/exception'
2
+ import { schemaCtx } from '@milkdown/core'
4
3
  import type { Fragment, Node, Schema } from '@milkdown/prose/model'
5
4
  import type { EditorState } from '@milkdown/prose/state'
6
5
  import { Plugin, PluginKey } from '@milkdown/prose/state'
7
6
  import type { EditorView } from '@milkdown/prose/view'
8
7
  import { Decoration, DecorationSet } from '@milkdown/prose/view'
9
- import { createPlugin } from '@milkdown/utils'
8
+ import { $ctx, $prose } from '@milkdown/utils'
10
9
 
11
10
  import { defaultUploader } from './default-uploader'
12
11
 
13
12
  export type Uploader = (files: FileList, schema: Schema) => Promise<Fragment | Node | Node[]>
14
13
  interface Spec { id: symbol; pos: number }
15
- export interface Options {
14
+ export interface UploadConfig {
16
15
  uploader: Uploader
17
16
  enableHtmlFileUploader: boolean
17
+ uploadWidgetFactory: (pos: number, spec: Parameters<typeof Decoration.widget>[2]) => Decoration
18
18
  }
19
- export const key = new PluginKey('MILKDOWN_UPLOAD')
20
-
21
- export const uploadPlugin = createPlugin<string, Options>((_, options) => {
22
- const uploader = options?.uploader ?? defaultUploader
23
-
24
- return {
25
- prosePlugins: (_, ctx) => {
26
- const schema = ctx.get(schemaCtx)
27
-
28
- const placeholderPlugin = new Plugin({
29
- key,
30
- state: {
31
- init() {
32
- return DecorationSet.empty
33
- },
34
- apply(this: Plugin, tr, set) {
35
- const _set = set.map(tr.mapping, tr.doc)
36
- const action = tr.getMeta(this)
37
- if (!action)
38
- return _set
39
-
40
- if (action.add) {
41
- const widget = document.createElement('span')
42
- const loadingIcon = ctx.get(themeManagerCtx).get(ThemeIcon, 'loading')
43
- if (!loadingIcon)
44
- throw missingIcon('loading')
45
-
46
- widget.appendChild(loadingIcon.dom)
47
-
48
- const decoration = Decoration.widget(action.add.pos, widget, { id: action.add.id } as any)
49
- return _set.add(tr.doc, [decoration])
50
- }
51
- if (action.remove) {
52
- return _set.remove(
53
- _set.find(undefined, undefined, (spec: Spec) => spec.id === action.remove.id),
54
- )
55
- }
56
-
57
- return _set
58
- },
59
- },
60
- props: {
61
- decorations(this: Plugin, state) {
62
- return this.getState(state)
63
- },
64
- },
19
+
20
+ export const uploadConfig = $ctx<UploadConfig, 'uploadConfig'>({
21
+ uploader: defaultUploader,
22
+ enableHtmlFileUploader: false,
23
+ uploadWidgetFactory: (pos, spec) => {
24
+ const widgetDOM = document.createElement('span')
25
+ widgetDOM.textContent = 'Upload in progress...'
26
+ return Decoration.widget(pos, widgetDOM, spec)
27
+ },
28
+ }, 'uploadConfig')
29
+
30
+ export const updatePlugin = $prose((ctx) => {
31
+ const pluginKey = new PluginKey('MILKDOWN_UPLOAD')
32
+
33
+ const findPlaceholder = (state: EditorState, id: symbol): number => {
34
+ const decorations = pluginKey.getState(state)
35
+ if (!decorations)
36
+ return -1
37
+ const found = decorations.find(undefined, undefined, (spec: Spec) => spec.id === id)
38
+ if (!found.length)
39
+ return -1
40
+ return found[0]?.from ?? -1
41
+ }
42
+
43
+ const handleUpload = (view: EditorView, event: DragEvent | ClipboardEvent, files: FileList | undefined) => {
44
+ if (!files || files.length <= 0)
45
+ return false
46
+
47
+ const id = Symbol('upload symbol')
48
+ const schema = ctx.get(schemaCtx)
49
+ const { tr } = view.state
50
+ const insertPos = event instanceof DragEvent
51
+ ? view.posAtCoords({ left: event.clientX, top: event.clientY })?.pos ?? tr.selection.from
52
+ : tr.selection.from
53
+ view.dispatch(tr.setMeta(pluginKey, { add: { id, pos: insertPos } }))
54
+
55
+ const { uploader } = ctx.get(uploadConfig.key)
56
+ uploader(files, schema)
57
+ .then((fragment) => {
58
+ const pos = findPlaceholder(view.state, id)
59
+ if (pos < 0)
60
+ return
61
+
62
+ view.dispatch(
63
+ view.state.tr
64
+ .replaceWith(pos, pos, fragment)
65
+ .setMeta(pluginKey, { remove: { id } }),
66
+ )
65
67
  })
68
+ .catch((e) => {
69
+ console.error(e)
70
+ })
71
+ return true
72
+ }
73
+
74
+ return new Plugin({
75
+ key: pluginKey,
76
+ state: {
77
+ init() {
78
+ return DecorationSet.empty
79
+ },
80
+ apply(this: Plugin, tr, set) {
81
+ const _set = set.map(tr.mapping, tr.doc)
82
+ const action = tr.getMeta(this)
83
+ if (!action)
84
+ return _set
85
+
86
+ if (action.add) {
87
+ const { uploadWidgetFactory } = ctx.get(uploadConfig.key)
88
+
89
+ const decoration = uploadWidgetFactory(action.add.pos, { id: action.add.id })
90
+ return _set.add(tr.doc, [decoration])
91
+ }
92
+ if (action.remove) {
93
+ const target = _set.find(undefined, undefined, (spec: Spec) => spec.id === action.remove.id)
94
+ return _set.remove(target)
95
+ }
96
+
97
+ return _set
98
+ },
99
+ },
100
+ props: {
101
+ decorations(this: Plugin, state) {
102
+ return this.getState(state)
103
+ },
104
+ handlePaste: (view, event) => {
105
+ const { enableHtmlFileUploader } = ctx.get(uploadConfig.key)
106
+ if (!(event instanceof ClipboardEvent))
107
+ return false
66
108
 
67
- const findPlaceholder = (state: EditorState, id: symbol): number => {
68
- const decorations = placeholderPlugin.getState(state)
69
- if (!decorations)
70
- return -1
71
- const found = decorations.find(undefined, undefined, (spec: Spec) => spec.id === id)
72
- if (!found.length)
73
- return -1
74
- return found[0]?.from ?? -1
75
- }
76
-
77
- const handleUpload = (view: EditorView, event: DragEvent | ClipboardEvent, files: FileList | undefined) => {
78
- if (!files || files.length <= 0)
109
+ if (!enableHtmlFileUploader && event.clipboardData?.getData('text/html'))
79
110
  return false
80
111
 
81
- const id = Symbol('upload symbol')
82
- const { tr } = view.state
83
- const insertPos
84
- = event instanceof DragEvent
85
- ? view.posAtCoords({ left: event.clientX, top: event.clientY })?.pos ?? tr.selection.from
86
- : tr.selection.from
87
- view.dispatch(tr.setMeta(placeholderPlugin, { add: { id, pos: insertPos } }))
88
-
89
- uploader(files, schema)
90
- .then((fragment) => {
91
- const pos = findPlaceholder(view.state, id)
92
- if (pos < 0)
93
- return
94
-
95
- view.dispatch(
96
- view.state.tr
97
- .replaceWith(pos, pos, fragment)
98
- .setMeta(placeholderPlugin, { remove: { id } }),
99
- )
100
- })
101
- .catch((e) => {
102
- console.error(e)
103
- })
104
- return true
105
- }
106
-
107
- const uploadPlugin = new Plugin({
108
- props: {
109
- handlePaste: (view, event) => {
110
- if (!(event instanceof ClipboardEvent))
111
- return false
112
-
113
- if (!options?.enableHtmlFileUploader && event.clipboardData?.getData('text/html'))
114
- return false
115
-
116
- return handleUpload(view, event, event.clipboardData?.files)
117
- },
118
- handleDrop: (view, event) => {
119
- if (!(event instanceof DragEvent))
120
- return false
121
-
122
- return handleUpload(view, event, event.dataTransfer?.files)
123
- },
124
- },
125
- })
126
- return [placeholderPlugin, uploadPlugin]
112
+ return handleUpload(view, event, event.clipboardData?.files)
113
+ },
114
+ handleDrop: (view, event) => {
115
+ if (!(event instanceof DragEvent))
116
+ return false
117
+
118
+ return handleUpload(view, event, event.dataTransfer?.files)
119
+ },
127
120
  },
128
- }
121
+ })
129
122
  })