(file: File, view: EditorView, pos: number)
| 56 | } |
| 57 | |
| 58 | export function startImageUpload(file: File, view: EditorView, pos: number) { |
| 59 | // check if the file is an image |
| 60 | if (!file.type.includes("image/")) { |
| 61 | toast.error("File type not supported."); |
| 62 | return; |
| 63 | |
| 64 | // check if the file size is less than 20MB |
| 65 | } else if (file.size / 1024 / 1024 > 20) { |
| 66 | toast.error("File size too big (max 20MB)."); |
| 67 | return; |
| 68 | } |
| 69 | |
| 70 | // A fresh object to act as the ID for this upload |
| 71 | const id = {}; |
| 72 | |
| 73 | // Replace the selection with a placeholder |
| 74 | const tr = view.state.tr; |
| 75 | if (!tr.selection.empty) tr.deleteSelection(); |
| 76 | |
| 77 | const reader = new FileReader(); |
| 78 | reader.readAsDataURL(file); |
| 79 | reader.onload = () => { |
| 80 | tr.setMeta(uploadKey, { |
| 81 | add: { |
| 82 | id, |
| 83 | pos, |
| 84 | src: reader.result, |
| 85 | }, |
| 86 | }); |
| 87 | view.dispatch(tr); |
| 88 | }; |
| 89 | |
| 90 | handleImageUpload(file).then((src) => { |
| 91 | const { schema } = view.state; |
| 92 | |
| 93 | let pos = findPlaceholder(view.state, id); |
| 94 | // If the content around the placeholder has been deleted, drop |
| 95 | // the image |
| 96 | if (pos == null) return; |
| 97 | |
| 98 | // Otherwise, insert it at the placeholder's position, and remove |
| 99 | // the placeholder |
| 100 | |
| 101 | // When BLOB_READ_WRITE_TOKEN is not valid or unavailable, read |
| 102 | // the image locally |
| 103 | const imageSrc = typeof src === "object" ? reader.result : src; |
| 104 | |
| 105 | const node = schema.nodes.image.create({ src: imageSrc }); |
| 106 | const transaction = view.state.tr |
| 107 | .replaceWith(pos, pos, node) |
| 108 | .setMeta(uploadKey, { remove: { id } }); |
| 109 | view.dispatch(transaction); |
| 110 | }); |
| 111 | } |
| 112 | |
| 113 | export const handleImageUpload = (file: File) => { |
| 114 | // upload to Vercel Blob |
no test coverage detected