@edifice.io/tiptap-extensions
Version:
Edifice Rich Text Editor Extensions
176 lines (175 loc) • 5.78 kB
JavaScript
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