Перетаскиваемый элемент в пользовательском блоке Гутенберга

Вопрос или проблема

Я разрабатываю некоторые пользовательские блоки в новом редакторе Gutenberg, и мне трудно понять, как использовать некоторые встроенные компоненты, в основном компоненты Draggable.

Что я хотел бы достичь, так это список элементов (скажем, много li в ul) и я хочу, чтобы их можно было упорядочивать с помощью функции перетаскивания.

Вот мой код:

import { __ } from '@wordpress/i18n';
import { registerBlockType } from '@wordpress/blocks';
import { Draggable, Dashicon } from '@wordpress/components';

import './style.scss';
import './editor.scss';

registerBlockType( 'namespace/my-custom-block', 
{
    title: __( 'Пользовательский блок', 'namespace'),
    description: __( 'Описание пользовательского блока', 'namespace' ),
    category: 'common',
    icon: 'clipboard',
    keywords: [
    __( 'список', 'namespace' ),
    __( 'элемент', 'namespace' ),
    __( 'порядок', 'namespace' )
    ],
    supports: {
    html: false,
    multiple: false,
    },
    attributes: {
        items: {
            type: 'array',
            default: [ 'Один' ,'Два' ,'Три' ,'Четыре' ,'Пять' ,'Шесть' ,'Семь' ,'Восемь' ,'Девять' ,'Десять' ]
        }
    },
    edit: props => {
    return (
        <ul>
        { props.attributes.items.map( (itemLabel, id) => (
            <li id={ `li_${id}` } draggable>
            <Draggable
                elementId={ `li_${id}` }
                transferData={ {} }>
                {
                ({ onDraggableStart, onDraggableEnd }) => (
                    <Dashicon
                    icon="move"
                    onDragStart={ onDraggableStart }
                    onDragEnd={ onDraggableEnd }
                    draggable
                    />
                )
                }
            </Draggable>
            { itemLabel }
            </li>
        ))
        }
        </ul>
    )
    },
    save: () => {
    // Вернуть null, чтобы он рендерился на сервере
    return null;
    }
}
)

На стороне сервера он правильно отображается, но элементы не поддаются перетаскиванию

введите описание изображения здесь

К сожалению, справочник разработчика Gutenberg не дает много информации
https://wordpress.org/gutenberg/handbook/designers-developers/developers/components/draggable/ и я не вижу, как это сделать.

Спасибо и всего хорошего

Если вам нужно сделать что-то перетаскиваемое, что появляется внутри вашего блока в основной области контента, то вам следует использовать дочерние блоки для реализации этого, и компонент <InnerBlocks/>. Затем вы можете заставить внутренние блоки быть только вашим новым типом дочернего блока.

Например, у нас может быть блок kuuak/my-custom-block, и каждый перетаскиваемый элемент будет блоком kuuak/my-custom-block-item. Затем вы можете использовать это, чтобы позволить элементам вставляться и сортироваться, но только блок вашего элемента, ничего другого:

const ALLOWED_BLOCKS = [ 'kuuak/my-custom-block-item' ];
//...
<InnerBlocks allowedBlocks={ ALLOWED_BLOCKS } />;

Вы также можете заставить так, чтобы блоки элементов не использовались нигде больше, когда их регистрируете:

"parent": [ "kuuak/my-custom-block" ],

Этот паттерн используется во многих блоках ядра WordPress, например, в блоке колонок, который может содержать только блоки “колонка”, новые галерейные блоки, которые действуют как контейнеры для отдельных изображений, каруселей и т.д.

Дополнительное чтение о вложенных/внутренних блоках: https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/nested-blocks-inner-blocks/

Используйте react-sortable-hoc
Draggable не имеет достаточной документации, и у меня не было времени углубляться в это.
Но вышеприведенное подходит вам.
Я использовал его для создания боковой панели Entry Content/Primary Sidebar – использовалась для переупорядочивания контента/боковой панели моей темы!
2

Ответ или решение

Создание перетаскиваемых элементов в кастомных блоках Гутенберга: Пошаговое руководство

Разработка кастомных блоков в редакторе Гутенберг предоставляет мощные возможности для управления контентом. Однако работа с компонентами перетаскивания может вызывать затруднения, особенно если документация недостаточно полна. В этом руководстве мы рассмотрим, как создать упорядочиваемый список элементов (li) внутри блока (ul), используя дополнительный блок для каждого элемента списка.

Проблема

Ваш код корректно отображает элементы на сервере, однако функция перетаскивания не работает. Проблема заключается в том, что элементы, которые нужно перетаскивать, не могут быть реализованы напрямую через компонент Draggable, поскольку он требует более сложной логики управления состоянием.

Подход с использованием InnerBlocks

Для достижения желаемого поведения рекомендуется использовать внутренние блоки (InnerBlocks). Это позволит вам создать родительский блок, который будет содержать ваши элементы в качестве дочерних блоков.
Вот шаги, которые необходимо выполнить:

  1. Создание родительского блока:

    Начнем с регистрации вашего кастомного блока, который будет содержать внутренние блоки.

    import { registerBlockType } from '@wordpress/blocks';
    import { InnerBlocks } from '@wordpress/block-editor';
    import { __ } from '@wordpress/i18n';
    
    registerBlockType('namespace/my-custom-block', {
       title: __('Custom List Block', 'namespace'),
       icon: 'list-view',
       category: 'common',
       supports: {
           html: false,
       },
       edit: () => {
           const ALLOWED_BLOCKS = ['namespace/my-custom-item'];
           return (
               <div>
                   <InnerBlocks allowedBlocks={ALLOWED_BLOCKS} />
               </div>
           );
       },
       save: () => {
           return <InnerBlocks.Content />;
       }
    });
  2. Создание дочернего блока для элементов списка:

    Теперь создайте новый блок для каждого элемента списка, который будет перетаскиваемым.

    registerBlockType('namespace/my-custom-item', {
       title: __('List Item', 'namespace'),
       parent: 'namespace/my-custom-block',
       edit: (props) => {
           return (
               <div className="list-item">
                   <textarea 
                       value={props.attributes.content} 
                       onChange={(e) => props.setAttributes({ content: e.target.value })} 
                   />
               </div>
           );
       },
       save: () => {
           return <div className="list-item">{content}</div>;
       },
       attributes: {
           content: {
               type: 'string',
               default: 'New item',
           },
       },
    });
  3. Использование библиотеки для сортировки:

    В качестве альтернативы встроенным компонентам, вы можете использовать библиотеку, такую как react-sortable-hoc для реализации функции перетаскивания. Пример использования:

    import SortableContainer from 'react-sortable-hoc';
    
    const SortableList = SortableContainer(({ items }) => {
       return (
           <ul>
               {items.map((value, index) => (
                   <SortableItem key={`item-${index}`} index={index} value={value} />
               ))}
           </ul>
       );
    });
    
    const SortableItem = SortableElement(({ value }) => <li>{value}</li>);
    
    const onSortEnd = ({ oldIndex, newIndex }) => {
       // управление порядком элементов после завершения перетаскивания
    };

Заключение

Использование InnerBlocks для организации ваших элементов и дополнительных библиотек для перетаскивания значительно упрощает вашу задачу. Это решение позволит вам создавать интерактивные и удобные для пользователя блоки в редакторе Гутенберг.

Однако интеграция сторонних библиотек требует дополнительной работы по управлению состоянием и обновлению UI. В этом контексте следует оценить и документы, которые предоставляют библиотеки, поскольку они могут облегчить реализацию необходимых функций.

Таким образом, создание перетаскиваемых элементов внутри Гутенберга — это не только реализация функционала, но и возможность улучшить UX вашего сайта через реализацию интуитивно понятного интерфейса.

Оцените материал
Добавить комментарий

Капча загружается...