@milkdown/plugin-upload 7.5.0 → 7.5.9

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 +1 @@
1
- {"version":3,"file":"default-uploader.d.ts","sourceRoot":"","sources":["../src/default-uploader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAGxC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAenF;AAID,eAAO,MAAM,eAAe,EAAE,QAqB7B,CAAA"}
1
+ {"version":3,"file":"default-uploader.d.ts","sourceRoot":"","sources":["../src/default-uploader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAGxC,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,GACT,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAevC;AAID,eAAO,MAAM,eAAe,EAAE,QAkB7B,CAAA"}
package/lib/index.es.js CHANGED
@@ -25,17 +25,19 @@ const A = async (n, s) => {
25
25
  e && e.type.includes("image") && r.push(e);
26
26
  }
27
27
  const { image: l } = s.nodes;
28
- if (!l)
29
- throw F("image");
28
+ if (!l) throw F("image");
30
29
  return (await Promise.all(r.map((t) => w(t)))).map(({ alt: t, src: e }) => l.createAndFill({ src: e, alt: t }));
31
- }, c = b({
32
- uploader: A,
33
- enableHtmlFileUploader: !1,
34
- uploadWidgetFactory: (n, s) => {
35
- const r = document.createElement("span");
36
- return r.textContent = "Upload in progress...", k.widget(n, r, s);
37
- }
38
- }, "uploadConfig");
30
+ }, c = b(
31
+ {
32
+ uploader: A,
33
+ enableHtmlFileUploader: !1,
34
+ uploadWidgetFactory: (n, s) => {
35
+ const r = document.createElement("span");
36
+ return r.textContent = "Upload in progress...", k.widget(n, r, s);
37
+ }
38
+ },
39
+ "uploadConfig"
40
+ );
39
41
  c.meta = {
40
42
  package: "@milkdown/plugin-upload",
41
43
  displayName: "Ctx<uploadConfig>"
@@ -44,14 +46,16 @@ const f = U((n) => {
44
46
  const s = new D("MILKDOWN_UPLOAD"), r = (o, t) => {
45
47
  var i;
46
48
  const e = s.getState(o);
47
- if (!e)
48
- return -1;
49
- const a = e.find(void 0, void 0, (d) => d.id === t);
49
+ if (!e) return -1;
50
+ const a = e.find(
51
+ void 0,
52
+ void 0,
53
+ (d) => d.id === t
54
+ );
50
55
  return a.length ? ((i = a[0]) == null ? void 0 : i.from) ?? -1 : -1;
51
56
  }, l = (o, t, e) => {
52
57
  var m;
53
- if (!e || e.length <= 0)
54
- return !1;
58
+ if (!e || e.length <= 0) return !1;
55
59
  const a = Symbol("upload symbol"), i = n.get(y), { tr: d } = o.state, g = t instanceof DragEvent ? ((m = o.posAtCoords({ left: t.clientX, top: t.clientY })) == null ? void 0 : m.pos) ?? d.selection.from : d.selection.from;
56
60
  o.dispatch(d.setMeta(s, { add: { id: a, pos: g } }));
57
61
  const { uploader: h } = n.get(c.key);
@@ -72,14 +76,19 @@ const f = U((n) => {
72
76
  },
73
77
  apply(o, t) {
74
78
  const e = t.map(o.mapping, o.doc), a = o.getMeta(this);
75
- if (!a)
76
- return e;
79
+ if (!a) return e;
77
80
  if (a.add) {
78
- const { uploadWidgetFactory: i } = n.get(c.key), d = i(a.add.pos, { id: a.add.id });
81
+ const { uploadWidgetFactory: i } = n.get(c.key), d = i(a.add.pos, {
82
+ id: a.add.id
83
+ });
79
84
  return e.add(o.doc, [d]);
80
85
  }
81
86
  if (a.remove) {
82
- const i = e.find(void 0, void 0, (d) => d.id === a.remove.id);
87
+ const i = e.find(
88
+ void 0,
89
+ void 0,
90
+ (d) => d.id === a.remove.id
91
+ );
83
92
  return e.remove(i);
84
93
  }
85
94
  return e;
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../src/default-uploader.ts","../src/upload.ts","../src/index.ts"],"sourcesContent":["import { missingNodeInSchema } from '@milkdown/exception'\nimport type { Node } from '@milkdown/prose/model'\n\nimport type { Uploader } from './upload'\n\n/// Read the image file as base64.\nexport function 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\n/// The default uploader.\n/// It will upload transform images to base64.\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","import { 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\n/// @internal\nexport type Uploader = UploadOptions['uploader']\ninterface Spec { id: symbol, pos: number }\n\n/// The configuration for upload.\nexport interface UploadOptions {\n /// The uploader for upload plugin.\n /// It takes the files and schema as parameters.\n /// It should return a `Promise` of Prosemirror `Fragment` or `Node` or `Node[]`.\n uploader: (files: FileList, schema: Schema) => Promise<Fragment | Node | Node[]>\n /// Whether to enable the html file uploader.\n /// When paste files from html (for example copy images by right click context menu),\n /// this option will make the plugin to upload the image copied instead of using the original link.\n enableHtmlFileUploader: boolean\n /// The factory for upload widget.\n /// The widget will be displayed when the file is uploading.\n /// It takes the position and spec as parameters.\n /// It should return a `Decoration` of Prosemirror.\n /// By default, it will return `<span>Upload in progress...</span>`.\n uploadWidgetFactory: (pos: number, spec: Parameters<typeof Decoration.widget>[2]) => Decoration\n}\n\n/// A slice that contains the configuration for upload.\n/// It should be typed of `UploadConfig`.\nexport const uploadConfig = $ctx<UploadOptions, '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\nuploadConfig.meta = {\n package: '@milkdown/plugin-upload',\n displayName: 'Ctx<uploadConfig>',\n}\n\n/// The prosemirror plugin for upload.\nexport const uploadPlugin = $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\nuploadPlugin.meta = {\n package: '@milkdown/plugin-upload',\n displayName: 'Prose<upload>',\n}\n","import type { MilkdownPlugin } from '@milkdown/ctx'\nimport { uploadConfig, uploadPlugin } from './upload'\n\nexport * from './upload'\nexport * from './default-uploader'\n\n/// All plugins exported by this package.\nexport const upload: MilkdownPlugin[] = [uploadConfig, uploadPlugin]\n"],"names":["readImageAsBase64","file","resolve","reader","defaultUploader","files","schema","imgs","i","image","missingNodeInSchema","img","alt","src","uploadConfig","$ctx","pos","spec","widgetDOM","Decoration","uploadPlugin","$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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"}
1
+ {"version":3,"file":"index.es.js","sources":["../src/default-uploader.ts","../src/upload.ts","../src/index.ts"],"sourcesContent":["import { missingNodeInSchema } from '@milkdown/exception'\nimport type { Node } from '@milkdown/prose/model'\n\nimport type { Uploader } from './upload'\n\n/// Read the image file as base64.\nexport function readImageAsBase64(\n file: File\n): 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\n/// The default uploader.\n/// It will upload transform images to base64.\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) continue\n\n if (!file.type.includes('image')) continue\n\n imgs.push(file)\n }\n\n const { image } = schema.nodes\n if (!image) 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","import { 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\n/// @internal\nexport type Uploader = UploadOptions['uploader']\ninterface Spec {\n id: symbol\n pos: number\n}\n\n/// The configuration for upload.\nexport interface UploadOptions {\n /// The uploader for upload plugin.\n /// It takes the files and schema as parameters.\n /// It should return a `Promise` of Prosemirror `Fragment` or `Node` or `Node[]`.\n uploader: (\n files: FileList,\n schema: Schema\n ) => Promise<Fragment | Node | Node[]>\n /// Whether to enable the html file uploader.\n /// When paste files from html (for example copy images by right click context menu),\n /// this option will make the plugin to upload the image copied instead of using the original link.\n enableHtmlFileUploader: boolean\n /// The factory for upload widget.\n /// The widget will be displayed when the file is uploading.\n /// It takes the position and spec as parameters.\n /// It should return a `Decoration` of Prosemirror.\n /// By default, it will return `<span>Upload in progress...</span>`.\n uploadWidgetFactory: (\n pos: number,\n spec: Parameters<typeof Decoration.widget>[2]\n ) => Decoration\n}\n\n/// A slice that contains the configuration for upload.\n/// It should be typed of `UploadConfig`.\nexport const uploadConfig = $ctx<UploadOptions, 'uploadConfig'>(\n {\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 },\n 'uploadConfig'\n)\n\nuploadConfig.meta = {\n package: '@milkdown/plugin-upload',\n displayName: 'Ctx<uploadConfig>',\n}\n\n/// The prosemirror plugin for upload.\nexport const uploadPlugin = $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) return -1\n const found = decorations.find(\n undefined,\n undefined,\n (spec: Spec) => spec.id === id\n )\n if (!found.length) return -1\n return found[0]?.from ?? -1\n }\n\n const handleUpload = (\n view: EditorView,\n event: DragEvent | ClipboardEvent,\n files: FileList | undefined\n ) => {\n if (!files || files.length <= 0) return false\n\n const id = Symbol('upload symbol')\n const schema = ctx.get(schemaCtx)\n const { tr } = view.state\n const insertPos =\n event instanceof DragEvent\n ? (view.posAtCoords({ left: event.clientX, top: event.clientY })?.pos ??\n 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) 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 // eslint-disable-next-line no-console\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) return _set\n\n if (action.add) {\n const { uploadWidgetFactory } = ctx.get(uploadConfig.key)\n\n const decoration = uploadWidgetFactory(action.add.pos, {\n id: action.add.id,\n })\n return _set.add(tr.doc, [decoration])\n }\n if (action.remove) {\n const target = _set.find(\n undefined,\n undefined,\n (spec: Spec) => spec.id === action.remove.id\n )\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)) return false\n\n if (\n !enableHtmlFileUploader &&\n event.clipboardData?.getData('text/html')\n )\n return false\n\n return handleUpload(view, event, event.clipboardData?.files)\n },\n handleDrop: (view, event) => {\n if (!(event instanceof DragEvent)) return false\n\n return handleUpload(view, event, event.dataTransfer?.files)\n },\n },\n })\n})\n\nuploadPlugin.meta = {\n package: '@milkdown/plugin-upload',\n displayName: 'Prose<upload>',\n}\n","import type { MilkdownPlugin } from '@milkdown/ctx'\nimport { uploadConfig, uploadPlugin } from './upload'\n\nexport * from './upload'\nexport * from './default-uploader'\n\n/// All plugins exported by this package.\nexport const upload: MilkdownPlugin[] = [uploadConfig, uploadPlugin]\n"],"names":["readImageAsBase64","file","resolve","reader","defaultUploader","files","schema","imgs","i","image","missingNodeInSchema","img","alt","src","uploadConfig","$ctx","pos","spec","widgetDOM","Decoration","uploadPlugin","$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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAInE,OAAO,EAAE,UAAU,EAAiB,MAAM,sBAAsB,CAAA;AAMhE,MAAM,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,CAAA;AAIhD,MAAM,WAAW,aAAa;IAI5B,QAAQ,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAA;IAIhF,sBAAsB,EAAE,OAAO,CAAA;IAM/B,mBAAmB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAA;CAChG;AAID,eAAO,MAAM,YAAY,+DAQP,CAAA;AAQlB,eAAO,MAAM,YAAY,kCA4FvB,CAAA"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAInE,OAAO,EAAE,UAAU,EAAiB,MAAM,sBAAsB,CAAA;AAMhE,MAAM,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,CAAA;AAOhD,MAAM,WAAW,aAAa;IAI5B,QAAQ,EAAE,CACR,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,MAAM,KACX,OAAO,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAA;IAItC,sBAAsB,EAAE,OAAO,CAAA;IAM/B,mBAAmB,EAAE,CACnB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAC1C,UAAU,CAAA;CAChB;AAID,eAAO,MAAM,YAAY,+DAWxB,CAAA;AAQD,eAAO,MAAM,YAAY,kCAyGvB,CAAA"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@milkdown/plugin-upload",
3
3
  "type": "module",
4
- "version": "7.5.0",
4
+ "version": "7.5.9",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -31,13 +31,13 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "tslib": "^2.5.0",
34
- "@milkdown/exception": "7.5.0",
35
- "@milkdown/utils": "7.5.0"
34
+ "@milkdown/exception": "7.5.9",
35
+ "@milkdown/utils": "7.5.9"
36
36
  },
37
37
  "devDependencies": {
38
- "@milkdown/core": "7.5.0",
39
- "@milkdown/ctx": "7.5.0",
40
- "@milkdown/prose": "7.5.0"
38
+ "@milkdown/core": "7.5.9",
39
+ "@milkdown/ctx": "7.5.9",
40
+ "@milkdown/prose": "7.5.9"
41
41
  },
42
42
  "nx": {
43
43
  "targets": {
@@ -4,7 +4,9 @@ import type { Node } from '@milkdown/prose/model'
4
4
  import type { Uploader } from './upload'
5
5
 
6
6
  /// Read the image file as base64.
7
- export function readImageAsBase64(file: File): Promise<{ alt: string, src: string }> {
7
+ export function readImageAsBase64(
8
+ file: File
9
+ ): Promise<{ alt: string; src: string }> {
8
10
  return new Promise((resolve) => {
9
11
  const reader = new FileReader()
10
12
  reader.addEventListener(
@@ -15,7 +17,7 @@ export function readImageAsBase64(file: File): Promise<{ alt: string, src: strin
15
17
  src: reader.result as string,
16
18
  })
17
19
  },
18
- false,
20
+ false
19
21
  )
20
22
  reader.readAsDataURL(file)
21
23
  })
@@ -28,20 +30,17 @@ export const defaultUploader: Uploader = async (files, schema) => {
28
30
 
29
31
  for (let i = 0; i < files.length; i++) {
30
32
  const file = files.item(i)
31
- if (!file)
32
- continue
33
+ if (!file) continue
33
34
 
34
- if (!file.type.includes('image'))
35
- continue
35
+ if (!file.type.includes('image')) continue
36
36
 
37
37
  imgs.push(file)
38
38
  }
39
39
 
40
40
  const { image } = schema.nodes
41
- if (!image)
42
- throw missingNodeInSchema('image')
41
+ if (!image) throw missingNodeInSchema('image')
43
42
 
44
- const data = await Promise.all(imgs.map(img => readImageAsBase64(img)))
43
+ const data = await Promise.all(imgs.map((img) => readImageAsBase64(img)))
45
44
 
46
45
  return data.map(({ alt, src }) => image.createAndFill({ src, alt }) as Node)
47
46
  }
package/src/upload.ts CHANGED
@@ -10,14 +10,20 @@ import { defaultUploader } from './default-uploader'
10
10
 
11
11
  /// @internal
12
12
  export type Uploader = UploadOptions['uploader']
13
- interface Spec { id: symbol, pos: number }
13
+ interface Spec {
14
+ id: symbol
15
+ pos: number
16
+ }
14
17
 
15
18
  /// The configuration for upload.
16
19
  export interface UploadOptions {
17
20
  /// The uploader for upload plugin.
18
21
  /// It takes the files and schema as parameters.
19
22
  /// It should return a `Promise` of Prosemirror `Fragment` or `Node` or `Node[]`.
20
- uploader: (files: FileList, schema: Schema) => Promise<Fragment | Node | Node[]>
23
+ uploader: (
24
+ files: FileList,
25
+ schema: Schema
26
+ ) => Promise<Fragment | Node | Node[]>
21
27
  /// Whether to enable the html file uploader.
22
28
  /// When paste files from html (for example copy images by right click context menu),
23
29
  /// this option will make the plugin to upload the image copied instead of using the original link.
@@ -27,20 +33,26 @@ export interface UploadOptions {
27
33
  /// It takes the position and spec as parameters.
28
34
  /// It should return a `Decoration` of Prosemirror.
29
35
  /// By default, it will return `<span>Upload in progress...</span>`.
30
- uploadWidgetFactory: (pos: number, spec: Parameters<typeof Decoration.widget>[2]) => Decoration
36
+ uploadWidgetFactory: (
37
+ pos: number,
38
+ spec: Parameters<typeof Decoration.widget>[2]
39
+ ) => Decoration
31
40
  }
32
41
 
33
42
  /// A slice that contains the configuration for upload.
34
43
  /// It should be typed of `UploadConfig`.
35
- export const uploadConfig = $ctx<UploadOptions, 'uploadConfig'>({
36
- uploader: defaultUploader,
37
- enableHtmlFileUploader: false,
38
- uploadWidgetFactory: (pos, spec) => {
39
- const widgetDOM = document.createElement('span')
40
- widgetDOM.textContent = 'Upload in progress...'
41
- return Decoration.widget(pos, widgetDOM, spec)
44
+ export const uploadConfig = $ctx<UploadOptions, 'uploadConfig'>(
45
+ {
46
+ uploader: defaultUploader,
47
+ enableHtmlFileUploader: false,
48
+ uploadWidgetFactory: (pos, spec) => {
49
+ const widgetDOM = document.createElement('span')
50
+ widgetDOM.textContent = 'Upload in progress...'
51
+ return Decoration.widget(pos, widgetDOM, spec)
52
+ },
42
53
  },
43
- }, 'uploadConfig')
54
+ 'uploadConfig'
55
+ )
44
56
 
45
57
  uploadConfig.meta = {
46
58
  package: '@milkdown/plugin-upload',
@@ -53,40 +65,47 @@ export const uploadPlugin = $prose((ctx) => {
53
65
 
54
66
  const findPlaceholder = (state: EditorState, id: symbol): number => {
55
67
  const decorations = pluginKey.getState(state)
56
- if (!decorations)
57
- return -1
58
- const found = decorations.find(undefined, undefined, (spec: Spec) => spec.id === id)
59
- if (!found.length)
60
- return -1
68
+ if (!decorations) return -1
69
+ const found = decorations.find(
70
+ undefined,
71
+ undefined,
72
+ (spec: Spec) => spec.id === id
73
+ )
74
+ if (!found.length) return -1
61
75
  return found[0]?.from ?? -1
62
76
  }
63
77
 
64
- const handleUpload = (view: EditorView, event: DragEvent | ClipboardEvent, files: FileList | undefined) => {
65
- if (!files || files.length <= 0)
66
- return false
78
+ const handleUpload = (
79
+ view: EditorView,
80
+ event: DragEvent | ClipboardEvent,
81
+ files: FileList | undefined
82
+ ) => {
83
+ if (!files || files.length <= 0) return false
67
84
 
68
85
  const id = Symbol('upload symbol')
69
86
  const schema = ctx.get(schemaCtx)
70
87
  const { tr } = view.state
71
- const insertPos = event instanceof DragEvent
72
- ? view.posAtCoords({ left: event.clientX, top: event.clientY })?.pos ?? tr.selection.from
73
- : tr.selection.from
88
+ const insertPos =
89
+ event instanceof DragEvent
90
+ ? (view.posAtCoords({ left: event.clientX, top: event.clientY })?.pos ??
91
+ tr.selection.from)
92
+ : tr.selection.from
74
93
  view.dispatch(tr.setMeta(pluginKey, { add: { id, pos: insertPos } }))
75
94
 
76
95
  const { uploader } = ctx.get(uploadConfig.key)
77
96
  uploader(files, schema)
78
97
  .then((fragment) => {
79
98
  const pos = findPlaceholder(view.state, id)
80
- if (pos < 0)
81
- return
99
+ if (pos < 0) return
82
100
 
83
101
  view.dispatch(
84
102
  view.state.tr
85
103
  .replaceWith(pos, pos, fragment)
86
- .setMeta(pluginKey, { remove: { id } }),
104
+ .setMeta(pluginKey, { remove: { id } })
87
105
  )
88
106
  })
89
107
  .catch((e) => {
108
+ // eslint-disable-next-line no-console
90
109
  console.error(e)
91
110
  })
92
111
  return true
@@ -101,17 +120,22 @@ export const uploadPlugin = $prose((ctx) => {
101
120
  apply(this: Plugin, tr, set) {
102
121
  const _set = set.map(tr.mapping, tr.doc)
103
122
  const action = tr.getMeta(this)
104
- if (!action)
105
- return _set
123
+ if (!action) return _set
106
124
 
107
125
  if (action.add) {
108
126
  const { uploadWidgetFactory } = ctx.get(uploadConfig.key)
109
127
 
110
- const decoration = uploadWidgetFactory(action.add.pos, { id: action.add.id })
128
+ const decoration = uploadWidgetFactory(action.add.pos, {
129
+ id: action.add.id,
130
+ })
111
131
  return _set.add(tr.doc, [decoration])
112
132
  }
113
133
  if (action.remove) {
114
- const target = _set.find(undefined, undefined, (spec: Spec) => spec.id === action.remove.id)
134
+ const target = _set.find(
135
+ undefined,
136
+ undefined,
137
+ (spec: Spec) => spec.id === action.remove.id
138
+ )
115
139
  return _set.remove(target)
116
140
  }
117
141
 
@@ -124,17 +148,18 @@ export const uploadPlugin = $prose((ctx) => {
124
148
  },
125
149
  handlePaste: (view, event) => {
126
150
  const { enableHtmlFileUploader } = ctx.get(uploadConfig.key)
127
- if (!(event instanceof ClipboardEvent))
128
- return false
151
+ if (!(event instanceof ClipboardEvent)) return false
129
152
 
130
- if (!enableHtmlFileUploader && event.clipboardData?.getData('text/html'))
153
+ if (
154
+ !enableHtmlFileUploader &&
155
+ event.clipboardData?.getData('text/html')
156
+ )
131
157
  return false
132
158
 
133
159
  return handleUpload(view, event, event.clipboardData?.files)
134
160
  },
135
161
  handleDrop: (view, event) => {
136
- if (!(event instanceof DragEvent))
137
- return false
162
+ if (!(event instanceof DragEvent)) return false
138
163
 
139
164
  return handleUpload(view, event, event.dataTransfer?.files)
140
165
  },