import type { CSSProperties, ReactElement, ReactNode } from 'react' import { useSortable } from '@dnd-kit/sortable' import { CSS } from '@dnd-kit/utilities' import { Box, IconButton } from '@mui/material' import { DragIndicator as DragIndicatorIcon } from '@mui/icons-material' import { Tooltip } from '../../../components/tooltip/tooltip' import { useLegendConfig } from '../../provider' import { toSortableId, type SortableKind } from './sortable-ids' import { styles } from './styles' /** What `SortableEntity` hands to its render callback. */ export interface SortableEntityRenderProps { /** Attach to the entity's existing root element. */ rootRef: (el: HTMLElement | null) => void /** Sort transform/transition for the root (inline, per-frame values). */ rootStyle: CSSProperties /** The original is dimmed in place while its overlay clone is dragged. */ dragging: boolean /** The drag handle — absolutely positioned, place anywhere in the header. */ handle: ReactNode } export interface SortableEntityProps { kind: SortableKind id: string render: (sortable: SortableEntityRenderProps) => ReactElement } /** * Sortable shell for a legend group/row. Render-prop (instead of a wrapper * element) so the entity keeps its own root — sibling CSS like the `& + &` * dividers keeps working. Hosts `useSortable` and builds the drag handle * (keyboard-activatable, labelled `labels.reorder`). * * @experimental This API is new and may change in a future release. */ export function SortableEntity({ kind, id, render }: SortableEntityProps) { const { labels } = useLegendConfig() const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging, } = useSortable({ id: toSortableId(kind, id) }) const rootStyle: CSSProperties = { // Vertical list: lock x so items only shift along the axis. transform: CSS.Transform.toString( transform ? { ...transform, x: 0 } : null, ), transition, } const handle = ( // Absolutely positioned (see styles.handleSlot) — no reserved flex slot, // so it never shifts the title/icon; the fade rules live on the // group/row root. Kind-scoped class so a group hover doesn't light up // its member rows' handles. ) return render({ rootRef: setNodeRef, rootStyle, dragging: isDragging, handle, }) }