Jungwoo-An / react-editor-js

⚛️📝The unofficial editor-js component for React
https://codesandbox.io/s/react-editor-js-v2-34bfl
MIT License
954 stars 77 forks source link

Remix - SSR additional 'tools' - window of undefined #185

Closed ldmsh closed 2 years ago

ldmsh commented 2 years ago

Environment

Remix / SSR

Describe

Unable to implement tools as suggested in documentation and issue #58

Tried all suggested fixes above (bar next/dynamic obviously).

Any suggestions on how to implement tools similar to your default @editorjs/paragraph, which works as expected. When declaring additional tools i.e. tools={{ header: Header }} - this returnes window of undefined error.

Implementation:

// Editor.tsx

import { useCallback, useRef } from "react";
import { createReactEditorJS } from "react-editor-js";
import { ClientOnly } from "remix-utils";
import { EDITOR_JS_TOOLS } from "./Editor/constants";

const Editor = () => {
  const ReactEditorJS = createReactEditorJS();

  const editorJS = useRef(null);

  const handleInitialize = useCallback((instance) => {
    editorJS.current = instance;
  }, []);

  const handleSave = useCallback(async () => {
    const savedData = await editorJS.current.save();
  }, []);

  return (
    <ClientOnly>
      <ReactEditorJS tools={EDITOR_JS_TOOLS} holder="ssrHolder" onInitialize={handleInitialize} />
    </ClientOnly>
  )
};

export default Editor;
stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Jungwoo-An commented 2 years ago

@exponent42 Hi! First of all, thanks for your interest! 👋

I'm sorry for the late response. What tool are you using?

Thanks!

Moikapy commented 2 years ago

I'm having this issue as well using NextJS, I use the Dynamic api they provide and it removes the error, but the tools are in the inline editor/editor

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

kalebheitzman commented 1 year ago

I'm new to Remix but was able to get it working using the following structure:

The editor service: ~/services/editor.client.tsx

import EditorJS, { type OutputData } from "@editorjs/editorjs";

import Header from "@editorjs/header";
// @ts-ignore
// import Paragraph from "@editorjs/paragraph";
// @ts-ignore
import List from "@editorjs/list";
// @ts-ignore
// import LinkTool from "@editorjs/link";
import Embed from "@editorjs/embed";

// export * from "@editorjs/paragraph";

let EDITOR_TOOLS = {
  header: {
    class: Header,
    inlineToolbar: ["link"],
  },
  list: {
    class: List,
    inlineToolbar: true,
  },
  embed: {
    class: Embed,
  },
};

export { EDITOR_TOOLS, type OutputData };

export default EditorJS;

The HOC Editor component which uses Remix ClientOnly ~/components/editor.tsx

// import types
import type { OutputData } from "~/services/editor.client";

// import libs
import { useState } from "react";
import { ClientOnly } from "remix-utils";
import { EditorBlock } from "./editor-block";

export const Editor = ({ holder }: { holder: string }) => {
  const [data, setData] = useState<OutputData>();

  return (
    <ClientOnly fallback={null}>
      {() => <EditorBlock data={data} onChange={setData} holder={holder} />}
    </ClientOnly>
  );
};

The Editor Component itself. It's not quite right because I have a dependency error in my useEffect hook but it works. ~/components/editor-block.tsx

import { memo, useEffect, useRef } from "react";

import EditorJS, {
  type OutputData,
  EDITOR_TOOLS,
} from "~/services/editor.client";

export const EditorComponent = ({
  data,
  onChange,
  holder,
}: {
  data?: OutputData;
  onChange(val: OutputData): void;
  holder: string;
}) => {
  const editorRef = useRef<EditorJS>();

  useEffect(() => {
    console.log(data);
  }, [data]);

  useEffect(() => {
    if (!editorRef.current) {
      const editor = new EditorJS({
        holder: holder,
        // @ts-ignore
        tools: EDITOR_TOOLS,
        data,
        async onChange(api, event) {
          const data = await api.saver.save();
          onChange(data);
        },
      });
      editorRef.current = editor;
    }

    //add a return function handle cleanup
    return () => {
      if (editorRef.current && editorRef.current.destroy) {
        editorRef.current.destroy();
      }
    };
  }, [holder]);

  return (
    <>
      <label className="label">Editor</label>
      <div id={holder} className="prose border rounded-lg px-10 py-3 w-full" />
    </>
  );
};

export const EditorBlock = memo(EditorComponent);

All code adapted from https://reacthustle.com/blog/ultimate-guide-on-how-to-setup-editorjs-with-nextjs-12-typescript