Coder Social home page Coder Social logo

How do I upload images? about react-md-editor HOT 13 CLOSED

uiwjs avatar uiwjs commented on May 24, 2024
How do I upload images?

from react-md-editor.

Comments (13)

dino3616 avatar dino3616 commented on May 24, 2024 29

Hi, I have tried to implement a way to upload an image by Drag&Drop directly into the editor or by Copy&Paste and display it in the preview.
It may not be a very pretty method, but I hope it will be useful to you.
Here's my EXAMPLE!

import MDEditor from '@uiw/react-md-editor';
import { useState } from 'react';
import onImagePasted from './utils/onImagePasted';
import '@uiw/react-md-editor/markdown-editor.css';
import '@uiw/react-markdown-preview/markdown.css';

const MdEditor = () => {
  const [markdown, setMarkdown] = useState<string | undefined>();

  return (
    <div data-color-mode="light">
      <MDEditor
        value={markdown}
        onChange={(value) => {
          setMarkdown(value);
        }}
        onPaste={async (event) => {
          await onImagePasted(event.clipboardData, setMarkdown);
        }}
        onDrop={async (event) => {
          await onImagePasted(event.dataTransfer, setMarkdown);
        }}
        height={440}
        textareaProps={{
          placeholder: 'Fill in your markdown for the coolest of the cool.',
        }}
        hideToolbar
      />
    </div>
  );
};

export default MdEditor;
import type { SetStateAction } from 'react';
import { fileUpload } from '../../../../../libs/firebase/storage';
import insertToTextArea from './insertToTextArea';

const onImagePasted = async (dataTransfer: DataTransfer, setMarkdown: (value: SetStateAction<string | undefined>) => void) => {
  const files: File[] = [];
  for (let index = 0; index < dataTransfer.items.length; index += 1) {
    const file = dataTransfer.files.item(index);

    if (file) {
      files.push(file);
    }
  }

  await Promise.all(
    files.map(async (file) => {
      const url = await fileUpload(file);
      const insertedMarkdown = insertToTextArea(`![](${url})`);
      if (!insertedMarkdown) {
        return;
      }
      setMarkdown(insertedMarkdown);
    }),
  );
};

export default onImagePasted;
const insertToTextArea = (intsertString: string) => {
  const textarea = document.querySelector('textarea');
  if (!textarea) {
    return null;
  }

  let sentence = textarea.value;
  const len = sentence.length;
  const pos = textarea.selectionStart;
  const end = textarea.selectionEnd;

  const front = sentence.slice(0, pos);
  const back = sentence.slice(pos, len);

  sentence = front + intsertString + back;

  textarea.value = sentence;
  textarea.selectionEnd = end + intsertString.length;

  return sentence;
};

export default insertToTextArea;

from react-md-editor.

jaywcjlove avatar jaywcjlove commented on May 24, 2024 6

@TheStarkor I need to expand this

image

Do you need such an effect?

from react-md-editor.

jaywcjlove avatar jaywcjlove commented on May 24, 2024 3

@TheStarkor Definition tool reference: #85

import React from "react";
import ReactDOM from "react-dom";
import MDEditor, { commands, ICommand, TextState, TextApi } from '@uiw/react-md-editor';

const title3: ICommand = {
  name: 'title3',
  keyCommand: 'title3',
  buttonProps: { 'aria-label': 'Insert title3' },
  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: TextState, api: TextApi) => {
    let modifyText = `### ${state.selectedText}\n`;
    if (!state.selectedText) {
      modifyText = `### `;
    }
    api.replaceSelection(modifyText);
  },
};

export default function App() {
  const [value, setValue] = React.useState("**Hello world!!!**");
  return (
    <div className="container">
      <MDEditor
        value="Hello Markdown!"
        commands={[
          commands.bold, commands.hr, commands.italic, commands.divider, commands.codeEdit, commands.codeLive, commands.codePreview, commands.divider,
          commands.fullscreen, 
          // Custom Toolbars
          title3,
        ]}
      />
    </div>
  );
}

from react-md-editor.

TheStarkor avatar TheStarkor commented on May 24, 2024 1

Thank you for answering @jaywcjlove.

What I need is

const image = {
  name: 'image',
  keyCommand: 'image',
  buttonProps: { 'aria-label': 'Insert image' },
  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: async (state, api) => {
    // OPEN my component. 

    // example
    // const [image, setImaeg] = React.useState('');
    // <ImageUploader value={image} onChange={setImage} />

    let image_url = await upload_image(image);

    let modifyText = `![](${image_url})\n`;
    api.replaceSelection(modifyText);
  },
};
  1. I click my custom button. (like title3)
  2. Show my component that can upload an image like the figure.
  3. Get image buffer and upload.
  4. Modify text.

Can I open a component below the button(commands)?

from react-md-editor.

jaywcjlove avatar jaywcjlove commented on May 24, 2024 1

@TheStarkor Example: https://codesandbox.io/s/dazzling-resonance-m08m7

from react-md-editor.

R3D-Z3R0 avatar R3D-Z3R0 commented on May 24, 2024 1

Hello @jaywcjlove the example is not working and we wanted to implement a small drag & drop it
2021-07-22 17_11_24-React Typescript - CodeSandbox
into our markdown

from react-md-editor.

killerbytes avatar killerbytes commented on May 24, 2024 1

How to implement with a custom component eg: Modal?

from react-md-editor.

TheStarkor avatar TheStarkor commented on May 24, 2024

Yes! That's what I want.

from react-md-editor.

jaywcjlove avatar jaywcjlove commented on May 24, 2024

import React from 'react';
import MDEditor, { commands, ICommand } from '../';
const ExampleCustomToolbar = () => {
const title: ICommand<string> = {
name: 'title3',
keyCommand: 'title3',
buttonProps: null,
icon: (
<span style={{ padding: '0 5px' }}>Custom Toolbar</span>
),
};
return (
<MDEditor
value="Hello Markdown!"
commands={[
title,
commands.group([commands.title1, commands.title2, commands.title3, commands.title4, commands.title5, commands.title6], {
name: 'title',
groupName: 'title',
buttonProps: { 'aria-label': 'Insert title'}
}),
// commands.bold, commands.hr, commands.italic, commands.divider,
commands.group([], {
name: 'update',
groupName: 'update',
icon: (
<svg viewBox="0 0 1024 1024" width="12" height="12">
<path fill="currentColor" d="M716.8 921.6a51.2 51.2 0 1 1 0 102.4H307.2a51.2 51.2 0 1 1 0-102.4h409.6zM475.8016 382.1568a51.2 51.2 0 0 1 72.3968 0l144.8448 144.8448a51.2 51.2 0 0 1-72.448 72.3968L563.2 541.952V768a51.2 51.2 0 0 1-45.2096 50.8416L512 819.2a51.2 51.2 0 0 1-51.2-51.2v-226.048l-57.3952 57.4464a51.2 51.2 0 0 1-67.584 4.2496l-4.864-4.2496a51.2 51.2 0 0 1 0-72.3968zM512 0c138.6496 0 253.4912 102.144 277.1456 236.288l10.752 0.3072C924.928 242.688 1024 348.0576 1024 476.5696 1024 608.9728 918.8352 716.8 788.48 716.8a51.2 51.2 0 1 1 0-102.4l8.3968-0.256C866.2016 609.6384 921.6 550.0416 921.6 476.5696c0-76.4416-59.904-137.8816-133.12-137.8816h-97.28v-51.2C691.2 184.9856 610.6624 102.4 512 102.4S332.8 184.9856 332.8 287.488v51.2H235.52c-73.216 0-133.12 61.44-133.12 137.8816C102.4 552.96 162.304 614.4 235.52 614.4l5.9904 0.3584A51.2 51.2 0 0 1 235.52 716.8C105.1648 716.8 0 608.9728 0 476.5696c0-132.1984 104.8064-239.872 234.8544-240.2816C258.5088 102.144 373.3504 0 512 0z" />
</svg>
),
children: (handle) => {
return (
<div style={{ width: 120, padding: 10 }}>
<div>My Custom Toolbar</div>
<button type="button" onClick={() => console.log('> execute: >>>>>', handle.getState!())}>State</button>
<button type="button" onClick={() => handle.close()}>Close</button>
<button type="button" onClick={() => handle.execute()}>Execute</button>
</div>
);
},
execute: (state: commands.TextState, api: commands.TextApi) => {
console.log('> execute: >>>>>', state)
},
buttonProps: { 'aria-label': 'Insert title'}
}),
// commands.divider,
// commands.codeEdit, commands.codeLive, commands.codePreview, commands.divider,
// commands.fullscreen,
]}
/>
)
}
export default ExampleCustomToolbar;

Upgrade + @uiw/[email protected]

from react-md-editor.

jmvalino avatar jmvalino commented on May 24, 2024

hi @jaywcjlove can you give more example on how to achieve this functionality ? Thanks

from react-md-editor.

dibasdauliya avatar dibasdauliya commented on May 24, 2024

@TheStarkor Example: https://codesandbox.io/s/dazzling-resonance-m08m7

getting TypeError: handle.getState is not a function error

from react-md-editor.

nguyenvietdung31 avatar nguyenvietdung31 commented on May 24, 2024

Thank you for answering @jaywcjlove.

What I need is

const image = {
  name: 'image',
  keyCommand: 'image',
  buttonProps: { 'aria-label': 'Insert image' },
  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: async (state, api) => {
    // OPEN my component. 

    // example
    // const [image, setImaeg] = React.useState('');
    // <ImageUploader value={image} onChange={setImage} />

    let image_url = await upload_image(image);

    let modifyText = `![](${image_url})\n`;
    api.replaceSelection(modifyText);
  },
};
  1. I click my custom button. (like title3)
  2. Show my component that can upload an image like the figure.
  3. Get image buffer and upload.
  4. Modify text.

Can I open a component below the button(commands)?

can you share the code that open your component (e.g a modal) ?

from react-md-editor.

BarrySong97 avatar BarrySong97 commented on May 24, 2024

Hi, I have tried to implement a way to upload an image by Drag&Drop directly into the editor or by Copy&Paste and display it in the preview. It may not be a very pretty method, but I hope it will be useful to you. Here's my EXAMPLE!

import MDEditor from '@uiw/react-md-editor';
import { useState } from 'react';
import onImagePasted from './utils/onImagePasted';
import '@uiw/react-md-editor/markdown-editor.css';
import '@uiw/react-markdown-preview/markdown.css';

const MdEditor = () => {
  const [markdown, setMarkdown] = useState<string | undefined>();

  return (
    <div data-color-mode="light">
      <MDEditor
        value={markdown}
        onChange={(value) => {
          setMarkdown(value);
        }}
        onPaste={async (event) => {
          await onImagePasted(event.clipboardData, setMarkdown);
        }}
        onDrop={async (event) => {
          await onImagePasted(event.dataTransfer, setMarkdown);
        }}
        height={440}
        textareaProps={{
          placeholder: 'Fill in your markdown for the coolest of the cool.',
        }}
        hideToolbar
      />
    </div>
  );
};

export default MdEditor;
import type { SetStateAction } from 'react';
import { fileUpload } from '../../../../../libs/firebase/storage';
import insertToTextArea from './insertToTextArea';

const onImagePasted = async (dataTransfer: DataTransfer, setMarkdown: (value: SetStateAction<string | undefined>) => void) => {
  const files: File[] = [];
  for (let index = 0; index < dataTransfer.items.length; index += 1) {
    const file = dataTransfer.files.item(index);

    if (file) {
      files.push(file);
    }
  }

  await Promise.all(
    files.map(async (file) => {
      const url = await fileUpload(file);
      const insertedMarkdown = insertToTextArea(`![](${url})`);
      if (!insertedMarkdown) {
        return;
      }
      setMarkdown(insertedMarkdown);
    }),
  );
};

export default onImagePasted;
const insertToTextArea = (intsertString: string) => {
  const textarea = document.querySelector('textarea');
  if (!textarea) {
    return null;
  }

  let sentence = textarea.value;
  const len = sentence.length;
  const pos = textarea.selectionStart;
  const end = textarea.selectionEnd;

  const front = sentence.slice(0, pos);
  const back = sentence.slice(pos, len);

  sentence = front + intsertString + back;

  textarea.value = sentence;
  textarea.selectionEnd = end + intsertString.length;

  return sentence;
};

export default insertToTextArea;

great job, my friend

from react-md-editor.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.