Replacing WYSIWYG in v4

This is my solution with TinyMCE, it supports media selection too:

  • generate a new plugin with “npx strapi generate
  • enable the plugin in config/plugin.js
  • npm install @tinymce/tinymce-react tinymce
  • in your plugin folder create the component admin/src/components/Editor.js and paste the following code
import React, { useState, useRef } from 'react'
import { Field, Stack, Flex, FieldLabel } from '@strapi/design-system';

import tinymce from 'tinymce';
import 'tinymce/icons/default';
import 'tinymce/themes/silver';
import 'tinymce/plugins/code';
import 'tinymce/plugins/colorpicker';
import 'tinymce/plugins/textcolor';
import 'tinymce/skins/ui/oxide/skin.css';
import { Editor as TinyMCE } from "@tinymce/tinymce-react";
import { useLibrary, prefixFileUrlWithBackendUrl } from '@strapi/helper-plugin';

export default function Editor({ name, value, onChange, ...props }) {

    const { components } = useLibrary();
    const editorRef = useRef(null);

    const [showMediaLibrary, setShowMediaLibrary] = useState(false)

    const MediaLibraryDialog = components['media-library'];

    const handleToggleMediaLib = () => {
        setShowMediaLibrary(!showMediaLibrary);
    }

    const handleSelectAssets = files => {
        const formattedFiles = files.map(f => ({
            alt: f.alternativeText || f.name,
            url: prefixFileUrlWithBackendUrl(f.url),
            mime: f.mime,
        }));

        const imgs = formattedFiles.map(img => `<img src='${img.url}' alt='${img.alt}'>`).join();
        onChange({
            target: {
                name: name,
                value: value + imgs
            }
        })
        handleToggleMediaLib();

    }

    const initEditor = {
        width: '100%',
        branding: false,
        height: '400px',
        toolbar: 'customInsertButton code',
        plugins: 'code ',
        setup: function (editor) {
            editor.ui.registry.addButton('customInsertButton', {
                text: 'Add Media',
                onAction: function (_) {
                    handleToggleMediaLib()
                }
            });
        }
    }

    return <Field name={name}>
        <Stack size={1}>
            <Flex cols="auto auto 1fr" gap={1}>
                <FieldLabel>{name}</FieldLabel>
            </Flex>

            <Flex>

                <TinyMCE init={initEditor} ref={editorRef} value={value} onEditorChange={
                    (editorContent) => onChange({
                        target: {
                            name: name,
                            value: editorContent
                        }
                    })
                } />
            </Flex>
        </Stack>
        {showMediaLibrary && <MediaLibraryDialog onClose={handleToggleMediaLib} onSelectAssets={handleSelectAssets} />}
    </Field>

}
  • in your plugin folder edit admin/src/index.js

import pluginPkg from '../../package.json';
import pluginId from './pluginId';
import Initializer from './components/Initializer';
import Editor from './components/Editor';
const name = pluginPkg.strapi.name;

export default {
  register(app) {
    
    app.registerPlugin({
      id: pluginId,
      initializer: Initializer,
      isReady: false,
      name,
    });

    app.addFields({type:'wysiwyg',Component:Editor})
  }
  
};

  • start strapi with yarn develop --watch-admin and you should be able to see the new editor
2 Likes