Block Draggable
plate/block-draggableFreeComponent
A block wrapper with a drag handle for moving editor blocks.
Live preview
live · rendered by the registry
Rendered by plate on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://platejs.org/r/block-draggable.jsonSource
1'use client';23import * as React from 'react';45import { DndPlugin, useDraggable, useDropLine } from '@platejs/dnd';6import { expandListItemsWithChildren } from '@platejs/list';7import { BlockSelectionPlugin } from '@platejs/selection/react';8import { GripVertical } from 'lucide-react';9import { type TElement, getPluginByType, isType, KEYS } from 'platejs';10import {11 type PlateEditor,12 type PlateElementProps,13 type RenderNodeWrapper,14 MemoizedChildren,15 useEditorRef,16 useElement,17 usePluginOption,18} from 'platejs/react';19import { useSelected } from 'platejs/react';2021import { Button } from '@/components/ui/button';22import {23 Tooltip,24 TooltipContent,25 TooltipTrigger,26} from '@/components/ui/tooltip';27import { cn } from '@/lib/utils';2829const UNDRAGGABLE_KEYS = [KEYS.column, KEYS.tr, KEYS.td];3031export const BlockDraggable: RenderNodeWrapper = (props) => {32 const { editor, element, path } = props;3334 const enabled = React.useMemo(() => {35 if (editor.dom.readOnly) return false;3637 if (path.length === 1 && !isType(editor, element, UNDRAGGABLE_KEYS)) {38 return true;39 }40 if (path.length === 3 && !isType(editor, element, UNDRAGGABLE_KEYS)) {41 const block = editor.api.some({42 at: path,43 match: {44 type: editor.getType(KEYS.column),45 },46 });4748 if (block) {49 return true;50 }51 }52 if (path.length === 4 && !isType(editor, element, UNDRAGGABLE_KEYS)) {53 const block = editor.api.some({54 at: path,55 match: {56 type: editor.getType(KEYS.table),57 },58 });5960 if (block) {61 return true;62 }63 }6465 return false;66 }, [editor, element, path]);6768 if (!enabled) return;6970 return (props) => <Draggable {...props} />;71};7273function Draggable(props: PlateElementProps) {74 const { children, editor, element, path } = props;75 const blockSelectionApi = editor.getApi(BlockSelectionPlugin).blockSelection;7677 const { isAboutToDrag, isDragging, nodeRef, previewRef, handleRef } =78 useDraggable({79 element,80 onDropHandler: (_, { dragItem }) => {81 const id = (dragItem as { id: string[] | string }).id;8283 if (blockSelectionApi) {84 blockSelectionApi.add(id);85 }86 resetPreview();87 },88 });8990 const isInColumn = path.length === 3;91 const isInTable = path.length === 4;9293 const [previewTop, setPreviewTop] = React.useState(0);9495 const resetPreview = () => {96 if (previewRef.current) {97// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from plate
All 324 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| ai-kitai-kit | plate | Components | Free | 1 dep | |
| AI Menuai-menu | plate | Components | Free | 5 deps · 2 files | |
| AI Leafai-node | plate | Components | Free | no deps | |
| AI Toolbar Buttonai-toolbar-button | plate | Components | Free | 1 dep | |
| align-base-kitalign-base-kit | plate | Components | Free | 1 dep | |
| align-kitalign-kit | plate | Components | Free | 1 dep | |
| Align Toolbar Buttonalign-toolbar-button | plate | Components | Free | 1 dep | |
| autoformat-classic-kitautoformat-classic-kit | plate | Components | Free | 2 deps |
