UNPKG

@medalsocial/meda

Version:

Shared Meda UI shell and runtime package.

67 lines (66 loc) 3.39 kB
'use client'; import { jsx as _jsx } from "react/jsx-runtime"; import { useDndMonitor, useDroppable } from '@dnd-kit/core'; import { useState } from 'react'; import { cn } from '../lib/utils.js'; export function RailDropSlot({ id, accepts, disabled, children, render, className, ariaLabel, ref, }) { const { isOver, active, setNodeRef } = useDroppable({ id, disabled, data: { type: 'rail-drop-slot' }, }); const [globalDragActive, setGlobalDragActive] = useState(false); /* v8 ignore next — useDndMonitor: callbacks are never invoked in jsdom (no pointer events) */ useDndMonitor({ onDragStart: () => setGlobalDragActive(true), onDragEnd: () => setGlobalDragActive(false), onDragCancel: () => setGlobalDragActive(false), }); /* v8 ignore next — active?.id: active is always null in jsdom (no pointer events) */ const wouldAccept = !disabled && (!accepts || (active?.id != null && accepts(String(active.id)))); let state; /* v8 ignore next — isOver: always false in jsdom (no DnD pointer events) */ if (isOver && wouldAccept) { state = 'over'; /* v8 ignore next — isOver: always false in jsdom */ } else if (isOver && !wouldAccept) { state = 'rejected'; /* v8 ignore next — globalDragActive: always false in jsdom */ } else if (globalDragActive && disabled) { state = 'rejected'; /* v8 ignore next — globalDragActive: always false in jsdom */ } else if (globalDragActive && wouldAccept) { state = 'active'; } else { state = 'idle'; } // Legacy boolean aliases kept for backward-compat data attributes const showHover = state === 'over'; const showRejected = state === 'rejected'; return (_jsx("section", { ref: (el) => { setNodeRef(el); if (typeof ref === 'function') ref(el); else if (ref) ref.current = el; }, "data-slot-id": id, "data-state": state, "aria-label": ariaLabel, "aria-disabled": disabled || undefined, className: cn('relative rounded-lg border border-border bg-card transition-all duration-150', state === 'idle' && '', /* v8 ignore next — active state only reachable when drag is in progress (pointer events) */ state === 'active' && 'border-dashed border-primary/60 bg-primary/5', /* v8 ignore next 2 — over state only reachable when dragging over this slot */ state === 'over' && 'border-primary bg-primary/5 ring-2 ring-primary/30 shadow-[0_0_0_4px_hsl(var(--primary)/0.1)]', /* v8 ignore next — rejected state only reachable when drag is active */ state === 'rejected' && 'border-destructive/40 opacity-60', // Legacy classes — keep working for consumers using data-state selectors /* v8 ignore next — showHover is always false in jsdom (no drag pointer events) */ showHover && '', /* v8 ignore next — showRejected is always false in jsdom (no drag pointer events) */ showRejected && '', /* v8 ignore next — disabled+idle combination: disabled prop not exercised with drag-active state */ disabled && state === 'idle' && 'opacity-60', className), children: render ? render(state) : children })); } RailDropSlot.displayName = 'RailDropSlot';