UNPKG

@edifice.io/tiptap-extensions

Version:
176 lines (175 loc) • 5.78 kB
import { ImageResizer } from "@edifice.io/utilities"; import { nodeInputRule, mergeAttributes } from "@tiptap/core"; import TiptapImage from "@tiptap/extension-image"; import { Plugin } from "prosemirror-state"; const IMAGE_INPUT_REGEX = /(?:^|\s)(!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\))$/, Image = TiptapImage.extend({ name: "custom-image", draggable: !0, selectable: !0, addOptions() { var _a; return { ...(_a = this.parent) == null ? void 0 : _a.call(this), inline: !0, content: "inline*", sizes: ["small", "medium", "large"], HTMLAttributes: { class: "custom-image" }, uploadFile: () => Promise.resolve(null) }; }, addAttributes() { var _a; return { ...(_a = this.parent) == null ? void 0 : _a.call(this), size: { default: "medium", rendered: !1 }, alt: { renderHTML: (attributes) => ({ alt: attributes.alt }), parseHTML: (element) => element.getAttribute("alt") }, title: { renderHTML: (attributes) => ({ title: attributes.title }), parseHTML: (element) => element.getAttribute("title") }, width: { default: "350", renderHTML: (attributes) => attributes.width !== null && attributes.width !== void 0 && !Number.isNaN(attributes.width) ? { width: parseInt(attributes.width) } : {}, parseHTML: (element) => element.getAttribute("width") }, height: { renderHTML: (attributes) => attributes.height !== null && attributes.height !== void 0 && !Number.isNaN(attributes.height) ? { height: parseInt(attributes.height) } : {}, parseHTML: (element) => element.getAttribute("height") }, style: { renderHTML: (attributes) => attributes.style ? { style: attributes.style } : {}, parseHTML: (element) => null } }; }, parseHTML() { return [ { tag: 'img[src]:not([src^="data:"])', getAttrs: (el) => { var _a, _b, _c; const attr = { src: el.getAttribute("src") }; return (_a = el.parentElement) != null && _a.className.includes("image-container") && (_b = el.parentElement.style) != null && _b.width && (attr.width = el.parentElement.style.width), (_c = el.style) != null && _c.width && (attr.width = el.style.width), [ "happy", "proud", "dreamy", "love", "tired", "angry", "worried", "sick", "joker", "sad" ].filter((smiley) => attr.src.includes(smiley + ".png")).length > 0 && (attr.style = { width: "1.5em", height: "1.5em", fontSize: "16px" }, attr.width = "null", attr.height = "null"), attr; } } ]; }, renderHTML({ HTMLAttributes }) { return [ "img", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes) ]; }, addInputRules() { return [ nodeInputRule({ find: IMAGE_INPUT_REGEX, type: this.type, getAttributes: (match) => { const [, , alt, src, title] = match; return { src, alt, title }; } }) ]; }, addCommands() { return { setNewImage: (attrs) => ({ tr, dispatch }) => { const { selection } = tr, node = this.type.create(attrs); return dispatch && tr.replaceRangeWith(selection.from, selection.to, node), !0; }, setAttributes: (attributes) => ({ tr, dispatch }) => { const { selection } = tr, options = { ...tr.doc.nodeAt(tr.selection.from).attrs, ...attributes }, node = this.type.create(options); return dispatch && tr.replaceRangeWith(selection.from, selection.to, node), !0; } }; }, addProseMirrorPlugins() { const uploadNode = async (file) => { const resizedImage = await ImageResizer.resizeImageFile(file), image = await this.options.uploadFile(resizedImage), imageUrl = `/workspace/${image.public ? "pub/" : ""}document/${image._id}?timestamp=${(/* @__PURE__ */ new Date()).getTime()}`; return this.type.create({ src: imageUrl, alt: image.alt, title: image.title }); }, getFilteredFiles = (files) => Array.from(files).filter( (file) => /image\/(png|jpeg|jpg|gif|webp|heic|avif)/.test(file.type) ), handleImageInsert = async (editor, file, position) => { const node = await uploadNode(file); if (!node) return; const transaction = position !== void 0 ? editor.state.tr.insert(position, node) : editor.state.tr.replaceSelectionWith(node); editor.dispatch(transaction); }; return [ new Plugin({ props: { handlePaste: (editor, e) => { var _a; const files = getFilteredFiles((_a = e.clipboardData) == null ? void 0 : _a.files); if (files.length === 0) return !1; for (const file of files) handleImageInsert(editor, file); return !0; }, handleDrop: (editor, e, _s, moved) => { if (moved) return !1; const files = getFilteredFiles(e.dataTransfer.files); if (files.length === 0) return !1; const { pos: position } = editor.posAtCoords({ left: e.clientX, top: e.clientY }); for (const file of files) handleImageInsert(editor, file, position); return !0; } } }) ]; } }); export { IMAGE_INPUT_REGEX, Image }; //# sourceMappingURL=image.js.map