Интеграция редактора Lexical в CMS сайта

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Интеграция редактора Lexical в CMS сайта
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Интеграция редактора Lexical в CMS сайта

Lexical — разработанный Meta редактор с акцентом на расширяемость и производительность. Написан на TypeScript, разработан с учётом опыта создания редактора Facebook. Headless, как Tiptap — весь UI строится разработчиком.

Установка

npm install lexical @lexical/react @lexical/rich-text @lexical/list @lexical/link
npm install @lexical/markdown @lexical/code @lexical/utils @lexical/selection

Базовая настройка

import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin';
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
import { ListPlugin } from '@lexical/react/LexicalListPlugin';
import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
import { HeadingNode, QuoteNode } from '@lexical/rich-text';
import { ListNode, ListItemNode } from '@lexical/list';
import { LinkNode, AutoLinkNode } from '@lexical/link';
import { CodeNode, CodeHighlightNode } from '@lexical/code';

const editorConfig = {
    namespace: 'cms-editor',
    theme: {
        paragraph: 'mb-3',
        heading: { h1: 'text-3xl font-bold', h2: 'text-2xl font-bold', h3: 'text-xl font-bold' },
        list: { ol: 'list-decimal ml-6', ul: 'list-disc ml-6' },
        text: { bold: 'font-bold', italic: 'italic', underline: 'underline' }
    },
    nodes: [HeadingNode, QuoteNode, ListNode, ListItemNode, LinkNode, AutoLinkNode, CodeNode, CodeHighlightNode],
    onError: console.error
};

function LexicalEditor({ initialState, onChange }) {
    return (
        <LexicalComposer initialConfig={{ ...editorConfig, editorState: initialState }}>
            <div className="relative border rounded-lg">
                <ToolbarPlugin />
                <div className="relative">
                    <RichTextPlugin
                        contentEditable={<ContentEditable className="outline-none p-4 min-h-96" />}
                        placeholder={<div className="absolute top-4 left-4 text-gray-400">Начните вводить...</div>}
                        ErrorBoundary={({ children }) => children}
                    />
                    <HistoryPlugin />
                    <AutoFocusPlugin />
                    <ListPlugin />
                    <LinkPlugin />
                    <OnChangePlugin onChange={(editorState) => {
                        editorState.read(() => {
                            const json = editorState.toJSON();
                            onChange(JSON.stringify(json));
                        });
                    }} />
                </div>
            </div>
        </LexicalComposer>
    );
}

Кастомный тулбар

import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { FORMAT_TEXT_COMMAND } from 'lexical';
import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list';

function ToolbarPlugin() {
    const [editor] = useLexicalComposerContext();
    const [isBold, setIsBold] = useState(false);

    useEffect(() => {
        return editor.registerUpdateListener(({ editorState }) => {
            editorState.read(() => {
                const selection = $getSelection();
                if ($isRangeSelection(selection)) {
                    setIsBold(selection.hasFormat('bold'));
                }
            });
        });
    }, [editor]);

    return (
        <div className="flex gap-1 p-2 border-b">
            <button
                onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold')}
                className={isBold ? 'bg-gray-200 rounded px-2' : 'px-2'}
            >
                B
            </button>
            <button onClick={() => editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined)}>
                List
            </button>
        </div>
    );
}

Кастомные ноды

import { DecoratorNode, SerializedLexicalNode } from 'lexical';

class ImageNode extends DecoratorNode<React.ReactElement> {
    static getType() { return 'image'; }
    static clone(node: ImageNode) { return new ImageNode(node.__src, node.__alt, node.__key); }

    constructor(private __src: string, private __alt: string, key?: string) {
        super(key);
    }

    createDOM() {
        return document.createElement('div');
    }

    decorate() {
        return <img src={this.__src} alt={this.__alt} className="max-w-full rounded" />;
    }

    exportJSON(): SerializedLexicalNode {
        return { type: 'image', src: this.__src, alt: this.__alt, version: 1 };
    }
}

Сохранение и загрузка состояния

// Сохранение
const jsonState = JSON.stringify(editor.getEditorState().toJSON());

// Загрузка
editor.update(() => {
    const state = editor.parseEditorState(savedJsonState);
    editor.setEditorState(state);
});

Срок интеграции: 2–4 дня для полноценного редактора с тулбаром, кастомными нодами и загрузкой медиа.