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

About Custom Toolbar #443

Closed
psn417 opened this issue Oct 17, 2022 · 1 comment
Closed

About Custom Toolbar #443

psn417 opened this issue Oct 17, 2022 · 1 comment

Comments

@psn417
Copy link

psn417 commented Oct 17, 2022

Hello everyone I am a beginner to React. I am trying to modifiy the add image command. I want a Modal to appear on screen when I click the command, so that I can use the modal to upload the image to a server, then insert the url to the editor, as is shown below:

Screenshot 2022-10-17 221015

But I don't know what's the proper way to achieve this goal. Currently I use a parent component to manage an Editor and a Modal:

import * as React from "react";
import MDEditor from "@uiw/react-md-editor";
import UploadModal from "./UploadModal";

export default function Markdown() {
  const [api, setApi] = React.useState(null);
  const [showModal, setShowModal] = React.useState(false);

  let EditorRef = React.createRef();

  const img = {
    name: "img",
    keyCommand: "img",
    buttonProps: { "aria-label": "Insert img" },
    icon: (
      <svg width="12" height="12" viewBox="0 0 520 520">
        <path
          fill="currentColor"
          d="M15.7083333,468 C7.03242448,468 0,462.030833 0,454.666667 L0,421.333333 C0,413.969167 7.03242448,408 15.7083333,408 L361.291667,408 C369.967576,408 377,413.969167 377,421.333333 L377,454.666667 C377,462.030833 369.967576,468 361.291667,468 L15.7083333,468 Z M21.6666667,366 C9.69989583,366 0,359.831861 0,352.222222 L0,317.777778 C0,310.168139 9.69989583,304 21.6666667,304 L498.333333,304 C510.300104,304 520,310.168139 520,317.777778 L520,352.222222 C520,359.831861 510.300104,366 498.333333,366 L21.6666667,366 Z M136.835938,64 L136.835937,126 L107.25,126 L107.25,251 L40.75,251 L40.75,126 L-5.68434189e-14,126 L-5.68434189e-14,64 L136.835938,64 Z M212,64 L212,251 L161.648438,251 L161.648438,64 L212,64 Z M378,64 L378,126 L343.25,126 L343.25,251 L281.75,251 L281.75,126 L238,126 L238,64 L378,64 Z M449.047619,189.550781 L520,189.550781 L520,251 L405,251 L405,64 L449.047619,64 L449.047619,189.550781 Z"
        />
      </svg>
    ),
    execute: (state, api) => {
      setShowModal(true);
      setApi(api);
    },
  };

  const [value, setValue] = React.useState(
    "Hello Markdown! `Tab` key uses default behavior"
  );
  return (
    <div className="container">
      <MDEditor
        ref={EditorRef}
        value={value}
        onChange={setValue}
        commands={[
          // Custom Toolbars
          img,
        ]}
      />
      {showModal ? (
        <UploadModal
          onSubmit={(url) => {
            api.replaceSelection(`![description](${url})`);
          }}
          onExit={() => {
            setShowModal(false);
          }}
        />
      ) : null}
    </div>
  );
}

Here is the modal component:

import * as React from "react";
import Upload from "rc-upload";
import { Button, Image, Modal, ProgressBar } from "react-bootstrap";

export default function UploadModal(props) {
  const [showUploader, setShowUploader] = React.useState(true);
  const [showImage, setShowImage] = React.useState(false);
  const [showProcess, setShowProcess] = React.useState(false);
  const [process, setProcess] = React.useState(0);
  const [url, setUrl] = React.useState(null);

  const handleClose = () => {
    setShowUploader(true);
    setShowImage(false);
    setUrl(null);
    setProcess(0);
    setShowProcess(false);
    props.onExit();
  };

  const handleSubmit = () => {
    handleClose();
    props.onSubmit(url);
  };

  const uploaderProps = {
    action: "/upload",
    multiple: true,
    beforeUpload(file) {},
    onStart: (file) => {
      setShowProcess(true);
    },
    onSuccess(result) {
      setUrl(result.url);
      setShowImage(true);
      setShowUploader(false);
      setShowProcess(false);
    },
    onProgress(step) {
      setProcess(step.percent);
    },
    onError(err) {
      console.log("onError", err);
    },
  };

  return (
    <Modal show={true} onHide={handleClose}>
      <Modal.Header closeButton>
        <Modal.Title>Upload Image</Modal.Title>
      </Modal.Header>
      <Modal.Body className="d-flex justify-content-center">
        {showUploader ? (
          <Upload
            {...uploaderProps}
            className={
              "w-100 border border-3 border-secondary rounded bg-light"
            }
            component={"div"}
          >
            <br />
            <br />
            <p className="text-secondary text-center">
              Click or drag the image here to upload.
            </p>
            <br />
            <br />
          </Upload>
        ) : null}
        {showImage ? (
          <Image src={url} thumbnail="true" className="w-50" />
        ) : null}
        {showProcess ? <ProgressBar now={process} /> : null}
      </Modal.Body>
      <Modal.Footer>
        <Button variant="secondary" onClick={handleClose}>
          Close
        </Button>
        <Button variant="primary" onClick={handleSubmit}>
          OK
        </Button>
      </Modal.Footer>
    </Modal>
  );
}

These code can achieve exactly what I want. But I think they are very bad. It seems that the parent component needs to get the api of the editor, and I don't know how to do it.

Does anyone know how to do it properly?

@psn417
Copy link
Author

psn417 commented Oct 18, 2022

I render the image command to my custom element. It seems to be a good solution.

export default function Markdown() {
  const [value, setValue] = React.useState(
    "Hello Markdown! `Tab` key uses default behavior"
  );

  return (
    <div className="container">
      <MDEditor
        value={value}
        onChange={setValue}
        preview="edit"
        components={{
          toolbar: (command, disabled, executeCommand) => {
            if (command.keyCommand === "image") {
              return (
                <UploadModal
                  onClick={() => {
                    console.log(command);
                  }}
                  onSubmit={(url) => {
                    command.execute = (state, api) => {
                      api.replaceSelection(`![description](${url})`);
                    };
                    executeCommand(command, command.groupName);
                  }}
                />
              );
            }
          },
        }}
      />
    </div>
  );
}

@psn417 psn417 closed this as completed Nov 25, 2022
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

1 participant