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

Support custom components for toolbar options #419

Open
kylekirkby opened this issue Jul 28, 2022 · 13 comments
Open

Support custom components for toolbar options #419

kylekirkby opened this issue Jul 28, 2022 · 13 comments

Comments

@kylekirkby
Copy link

Hi @jaywcjlove,

Can we please add support for using a custom component for the toolbar buttons?

I'm trying to add Material UI styling. With MUI 5, you cannot generate a class name for a button?! If we can provide a styled component to override the button element, that would be awesome :)

We'll need to update this section:

https://github.com/uiwjs/react-md-editor/blob/master/core/src/components/Toolbar/index.tsx#L90

to allow custom components to be provided.

Thoughts?

Cheers,

Kyle

@jaywcjlove
Copy link
Member

@kylekirkby See if this meets your needs.

const title2 = {
  name: 'title3',
  keyCommand: 'title3',
  render: (command, disabled, executeCommand) => {
    return (
      <button 
        aria-label="Insert title3"
        disabled={disabled}
        onClick={(evn) => {
          evn.stopPropagation();
          executeCommand(command, command.groupName)
        }}
      >
        <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>
      </button>
    )
  },
  execute: (state, api) => {
    let modifyText = `## ${state.selectedText}\n`;
    if (!state.selectedText) {
      modifyText = `## `;
    }
    api.replaceSelection(modifyText);
  },
}

@jaywcjlove
Copy link
Member

@kylekirkby Upgrade v3.16.0

@jaywcjlove
Copy link
Member

const title2 = {
  name: 'title3',
  keyCommand: 'title3',
+  render: (command, disabled, executeCommand) => {
+    return (
+      <button 
+        aria-label="Insert title3"
+        disabled={disabled}
+        onClick={(evn) => {
+          evn.stopPropagation();
+          executeCommand(command, command.groupName)
+        }}
+      >
+        btn
+      </button>
+    )
+  },
  execute: (state, api) => {
    let modifyText = `## ${state.selectedText}\n`;
    if (!state.selectedText) {
      modifyText = `## `;
    }
    api.replaceSelection(modifyText);
  },
}

@kylekirkby
Copy link
Author

@jaywcjlove - this is great! I'm now able to render a Material UI Button / IconButton component. However, it may be easier for developers if we could override the components without having to copy the action functionality in the execute method. Unless I'm missing something, I'd need to copy the implementation for each command in order to get this working?

Maybe a higher level component feature would be better?

			<MDEditor
				{...props}
				components={{
					button: Button,
					toolbar: Toolbar,
					textarea: TextArea,
				}}
/>

Thoughts?

@kylekirkby
Copy link
Author

@jaywcjlove - alternatively, a way to simply use the functionality of an existing command would also work? I thought that was what the keyCommand property would do.

@jaywcjlove
Copy link
Member

@kylekirkby Oh nice idea, actually we already have the renderTextarea props.

command[]. render Try adding a commandRender?

<MDEditor
  commandRender={(
    command: ICommand<T>,
    disabled: boolean,
    executeCommand: (command: ICommand<T>, name?: string) => void,
    index: number,
  ) => {

  }}
/>

@kylekirkby
Copy link
Author

@jaywcjlove - does this functionality already exist? That seems like a good solution potentially? It would be nice though, to use the default setup and simply "plug in" some custom components 🤔

@jaywcjlove
Copy link
Member

Now to customize the commands style, the commands must be retyped. Add a commandRender props, it will be more convenient.

@kylekirkby Use your idea and add component props.

@kylekirkby
Copy link
Author

@jaywcjlove - yh I definitely think that the component prop would be super useful!

@jaywcjlove
Copy link
Member

import React from "react";
import MDEditor, { commands } from '@uiw/react-md-editor';

export default function App() {
  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 === 'code') {
              return (
                <button 
                  aria-label="Insert code"
                  disabled={disabled}
                  onClick={(evn) => {
                    evn.stopPropagation();
                    executeCommand(command, command.groupName)
                  }}
                >
                  Code
                </button>
              )
            }
          }
        }}
      />
    </div>
  );
}
/**
 * Use div to replace TextArea or re-render TextArea
 * @deprecated Please use ~~`renderTextarea`~~ -> `components`
 */
renderTextarea?: ITextAreaProps['renderTextarea'];
/**
 * re-render element
 */
components?: {
  /** Use div to replace TextArea or re-render TextArea */
  textarea?: ITextAreaProps['renderTextarea'];
  /**
   * Override the default command element
   * _`toolbar`_ < _`command[].render`_
   */
  toolbar?: ICommand['render'];
};

jaywcjlove added a commit that referenced this issue Jul 29, 2022
jaywcjlove added a commit that referenced this issue Jul 29, 2022
@kylekirkby
Copy link
Author

Hi @jaywcjlove,

Thanks for this! This seems promising. However, it appears that after upgrading to 3.17.0, I've lost all styling. 🤔 Any ideas? It was working fine before the upgrade.

components={{
					toolbar: (command, disabled, executeCommand) => {
						console.log('Command:', command);
						if (command.keyCommand === 'code') {
							return (
								<Button
									aria-label="Insert code"
									disabled={disabled}
									onClick={(evn) => {
										evn.stopPropagation();
										executeCommand(command, command.groupName);
									}}
								>
									Code
								</Button>
							);
						}
					},
				}}

image

@jaywcjlove
Copy link
Member

@kylekirkby The test was fine: https://codesandbox.io/embed/markdown-editor-for-react-izdd6?fontsize=14&hidenavigation=1&theme=dark

Do you need to restart the service or clean up dependencies?

@jaywcjlove
Copy link
Member

@kylekirkby https://codesandbox.io/embed/markdown-editor-for-react-forked-xxdosy?fontsize=14&hidenavigation=1&theme=dark

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

2 participants