Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Produces a Slate error on image paste #37

Open
scythargon opened this issue Dec 13, 2018 · 10 comments
Open

Produces a Slate error on image paste #37

scythargon opened this issue Dec 13, 2018 · 10 comments

Comments

@scythargon
Copy link

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:
image
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:)

@thedrew12
Copy link

I'm getting the same thing.

@scythargon
Copy link
Author

@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

@thedrew12
Copy link

thedrew12 commented Dec 15, 2018

@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",

@scythargon
Copy link
Author

@thedrew12 What happens if you comment out the onPasteattribute? 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

@thedrew12
Copy link

thedrew12 commented Dec 15, 2018

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.

@thedrew12
Copy link

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.

@jorgeavaldez
Copy link

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.

@gregoryforel
Copy link

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.

@gregoryforel gregoryforel mentioned this issue Apr 18, 2019
@mittermayr
Copy link

mittermayr commented Jul 30, 2019

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.

@Sulkar
Copy link

Sulkar commented Oct 20, 2020

Hello,
is there an updated version of this plugin for the current slate.js? Version 0.59
Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants