import { useUniqueId } from "@charcuterie/logic" import type { DragEvent, ReactNode } from "react" import { useRef, useState } from "react" import { toClassName } from "../toClassName.ts" export type FileDropZoneProps = { /** An `accept` list, passed straight to the input. */ accept?: string className?: string /** Secondary line — the formats taken, a size cap. */ description?: ReactNode isDisabled?: boolean isMultiple?: boolean /** The control's accessible name, and its visible prompt. */ label: string onDropFiles: (files: File[]) => void /** * Dropped text, when there is any. A browser hands over a dragged * link as `text/plain` and no files at all, which is what * gallery-downloader's page is built entirely around — it takes * `dataTransfer.getData("text")` and never looks at `.files`. */ onDropText?: (text: string) => void } /** * The one drag target in the fleet is gallery-downloader's, and it * gets the hard part right: `dragenter`/`dragleave` fire once per * *element* the pointer crosses, not once per zone, so a naive * implementation flickers over every child — and that page keeps a * `dragDepth` counter, which is the correct fix. It is reproduced * below with credit. * * What it has no answer for is the part that cannot be fixed by * counting: * * ### Dragging is pointer-only, so the zone is a label around an input * * There is **no keyboard gesture for drag-and-drop**. WCAG 2.5.7 * (AA since 2.2) requires a single-pointer alternative for any * dragging movement, and the honest one has existed since 1995: a * real ``. So this component is a `