Produces a Slate error on image paste
scythargon opened this issue · 10 comments
Do you want to request a feature or report a bug?
bug
What's the current behavior?
I clone this repo locally, install dependencies, run it and open the page in my Chrome browser, select "Drop/Paste images" tab, paste an image from clipboard, and see the error in the browser's console:
The worst thing comes that when in my project i use Nextjs with server-side rendering - this error crashes the page completely.
What's the expected behavior?
There is no error:)
I'm getting the same thing.
@thedrew12 It turned out we need to define a schema for the editor to make this work.
https://stackoverflow.com/questions/52575301/image-insertion-at-cursor-in-editor-using-slatejs
my schema - https://pastebin.com/HjzFcNq8
@scythargon Do you mind sharing the rest of your code? I took your schema and added it
<Editor schema={schema} value={inputValue} plugins={plugins} onChange={this.onChange} onPaste={this.onPaste} renderNode={this.renderNode} />
But now I can't copy and paste images or drag and drop, no errors but nothing happens. I'm just trying to get a running example of text and images. I'm using the slate-drop-or-paste-images
plugin.
"slate": "0.42.2",
"slate-drop-or-paste-images": "^0.9.1",
"slate-react": "0.19.2",
@thedrew12 What happens if you comment out the onPaste
attribute? I've disabled it for me now because there was a conflict with the url pasting example and I haven't adapted it to support images yet
This is what I have right now:
const schema = {
document: {
nodes: [
{
match: [{ type: "paragraph" }, { type: "image" }]
}
]
},
blocks: {
paragraph: {
nodes: [
{
match: { object: "text" }
}
]
},
image: {
isVoid: true,
data: {
src: v => v
}
}
}
};
const plugins = [
DropOrPasteImages({
insertImage: (transform, file) => {
return transform.insertBlock({
isVoid: true,
type: "image",
data: { src: file }
});
}
})
];
/**
* Image node renderer.
*
* @type {Component}
*/
class Image extends React.Component<any, any> {
state = {
src: null
};
componentDidMount() {
const { node } = this.props;
const { data } = node;
const file = data.get("src");
this.load(file);
}
load(file: any) {
const reader = new FileReader();
reader.addEventListener("load", () => this.setState({ src: reader.result }));
reader.readAsDataURL(file);
}
render() {
const { attributes, imageKey } = this.props;
const { src } = this.state;
return src ? (
// <div style={{ position: "relative" }}>
<img
style={{
maxHeight: "20rem",
maxWidth: "20rem"
}}
src={src}
{...attributes}
data-key={imageKey || attributes["data-key"]}
/>
) : (
// </div>
<div {...attributes} data-key={imageKey || attributes["data-key"]}>
Loading...
</div>
);
}
}
/**
* Example.
*
* @type {Component}
*/
class RequestDetailEditor extends React.Component<any, any> {
state = {
didPaste: false,
inputValue: Value.fromJSON({
document: {
nodes: [
{
object: "block",
type: "paragraph",
nodes: [
{
object: "text",
leaves: [
{
text: this.props.value
}
]
}
]
}
]
}
})
};
componentDidUpdate(prevProps: any) {
if (prevProps.value !== this.props.value) {
this.setState({
inputValue: Value.fromJSON({
document: {
nodes: [
{
object: "block",
type: "paragraph",
nodes: [
{
object: "text",
leaves: [
{
text: this.props.value
}
]
}
]
}
]
}
})
});
}
}
onChange = ({ value }) => {
this.setState({ inputValue: value });
};
render() {
const { inputValue } = this.state;
return (
<Editor schema={schema} value={inputValue} plugins={plugins} onChange={this.onChange} onPaste={this.onPaste} renderNode={this.renderNode} />
);
}
onPaste = (e: any, editor: any, next: any) => {
this.setState({ didPaste: true });
next();
};
renderNode = (props: any, next: any) => {
switch (props.node.type) {
case "image":
// if (this.state.didPaste) {
// // hack here, for some reason when you paste in an image the data-key to select the img element is one less than what the package is doing
// // drag and drop works fine through
// return <Image {...props} imageKey={`${Number(props.key) + 1}`} />;
// }
return <Image {...props} />;
default:
return next();
}
};
}
Very similar to the example in the repo. There are some commmented out hacks. The onPaste doesn't really do anything, just a passthrough.
Actually its kind of working, pasting and dragging and dropping. Something I've run into though if you paste an image at the very bottom of the editor there is no way to create a text block after the image, maybe its my schema.
I was having the same issue, but it looked like it was happening as a result of transform.insertBlock
passing children as props that the Editor was then expecting to find.
I solved it by doing the following, rendering the children prop:
<React.Fragment>
<img {...props.attributes} src={typeof src === File ? URL.createObjectURL(src) : src} />
{props.children}
</React.Fragment>
The problem I'm getting now is that, when pasting an image link, src
is a reference to the Editor, and so I'm not sure how exactly to get the link text to pass in as the src
attribute of the image tag.
I made a react / typescript repository if anyone's interested in seeing the full solution work. It's in working progress, so it might end up being much more than just an image paste example.
Just wanted to add to @thedrew12's comment on being unable to create new text after an image was inserted, it drove me crazy but the solution was as simple as it gets:
last: { type: 'paragraph' },
was missing in my schema definition. You can find it here put into some more context.
Hello,
is there an updated version of this plugin for the current slate.js? Version 0.59
Thank you