sstur / react-rte

Pure React rich text WYSIWYG editor based on draft-js.
https://react-rte.org
ISC License
2.86k stars 430 forks source link

Question: how to use customControls (with or without toolbarConfig)? #319

Open kwhitejr opened 5 years ago

kwhitejr commented 5 years ago

RTE is great! This is a usage question, not an issue. My goal is to customize the toolbar components with, e.g., material ui react components. Reading through the react-rte docs, I think that there are two styling hooks:

  1. toolbarConfig for CSS (link); and
  2. customControls for completely overriding components (as seen in demo).

I believe that my use case calls for customControls, but from the provided demo I was not able to understand how to hook the custom components back into rte's functionality. For example, if I render a custom button component for BOLD, how does this button get the default functionality that would have gone to the default button provided by toolbarConfig?

In fact, it'd be wild if toolbarConfig offered an optional component attribute for each button type. For example:

INLINE_STYLE_BUTTONS: [
    { label: "Bold", style: "BOLD", component: MyBoldButtonComponent },
]

This would marry the best aspects of the toolbarConfig and customControls.

flotos commented 4 years ago

I am also interested in documentation about this. My use case is to add a way for the user to insert custom html tags in the input, so I want to add a button for that. However I struggle to understand the whole "CustControlFunc" type.

nadavhames commented 3 years ago

Just did a bit of snooping around, and managed to get bold and italic working in CustControlFunc.

Other actions like align, ol, ul, links etc. are contained within the rte library and not draft.js. Maybe they can be implemented with some careful copy pasting, although it would be nice if all the toggle functions and other states could be exposed in some way into CustControlFunc or another way.

On that subject, I have no idea if SetControlState and GetControlState give access to anything or if so to how to use them.

Here is roughly what I did: Note: I am using one CustControlFunc to render my whole toolbar at once, so customControls={[myCustomToolbar]} instead of customControls={[function1, function2]}.

import RichTextEditor, { EditorValue } from "react-rte";
import {RichUtils, EditorState} from "draft-js";

// typescript types for reference
type GetControlState = (key: string) => string | undefined;
type SetControlState = (key: string, value: string) => void;

const myCustomToolbar = (set: SetControlState, get: GetControlState, state: EditorState): ReactNode =>
    {
        // this uses the Draft.js EditorState to toggle changes, instead of rte's EditorValue. All functions I use here can be found in the draft.js docs
        const activeInlineStyles = state.getCurrentInlineStyle();
        const handleStyleToggle = (e: Event, style: string) => 
        {   
            e?.preventDefault();  // you need to use onMouseDown for button clicks to prevent default focus, otherwise onClick will lose focus on the editor and the action will not happen
            setEditorValue(EditorValue.createFromState(RichUtils.toggleInlineStyle(state, style)));  // set your react-rte EditorValue state, I am using a useState outside of this function
        };

        return (
            ...your custom styled toolbar here...
            <div>
                <button active={activeInlineStyles.has("BOLD")} onMouseDown={(e: Event) => handleStyleToggle(e, "BOLD")} />
                <button active={activeInlineStyles.has("ITALIC")} onMouseDown={(e: Event) => handleStyleToggle(e, "ITALIC")} />
            </div>
        );
    }