File drop
canonThe one surface for choosing a file: drop zone with a glyph, label, accepted formats, upload progress and an inline error.
Owner approved v2 on 3 Oct 2026 (acrm !4548): replaced Import .drop, the identity image .idimg-pick and the Documents step-1 zone. Import on dev = approved design, 0 px difference (1440 and 390). Canon since 4 Oct 2026: also used by step 1 of the Documents form-less dialog (acrm !4574), checked on dev at 1440 and 390.
Used in 3 files · 3 areas · 3× — components/IdentityImageDialog, components/evidence, pages/ImportPage
Default
Přetáhni libovolný CSV sem nebo vyber soubor.csv / .txt · max 10 MB
export const Default = () => (
<div style={W}>
<FileDrop
accept=".csv,.txt,.xls,.xlsx"
label="Přetáhni libovolný CSV sem nebo vyber soubor"
formats=".csv / .txt · max 10 MB"
onFile={noop}
/>
</div>
);States
restdrag-over (mouse only — touch has no drag)uploading — canonical Progress in place of the words, surface inertPDF, JPG nebo PNGerror — host text inline under the surface, aria-livedisabled — the host reports its state elsewhere (dialog header)
Přetáhni soubor sem nebo klikni pro výběrPDF, JPG nebo PNG
Přetáhni soubor sem nebo klikni pro výběrPDF, JPG nebo PNG
AI čte dokument…
Přetáhni soubor sem nebo klikni pro výběrPDF, JPG nebo PNG
Nahrání se nepodařilo. Zkus to znovu.
Přetáhni sem obrázek nebo klikni pro výběrPNG, JPG · max 2 MB
export const States = () => (
<div style={{ display: 'grid', gap: 'var(--sp-5)', ...W }}>
<span style={label}>rest</span>
<FileDrop
label="Přetáhni soubor sem nebo klikni pro výběr"
formats="PDF, JPG nebo PNG"
onFile={noop}
/>
<span style={label}>drag-over (mouse only — touch has no drag)</span>
<Forced cls="over" />
<span style={label}>uploading — canonical Progress in place of the words, surface inert</span>
<FileDrop
label="Přetáhni soubor sem nebo klikni pro výběr"
formats="PDF, JPG nebo PNG"
uploading={{ label: 'AI čte dokument…', value: 40, ariaLabel: 'Nahrávání' }}
onFile={noop}
/>
<span style={label}>error — host text inline under the surface, aria-live</span>
<FileDrop
label="Přetáhni soubor sem nebo klikni pro výběr"
formats="PDF, JPG nebo PNG"
error="Nahrání se nepodařilo. Zkus to znovu."
onFile={noop}
/>
<span style={label}>disabled — the host reports its state elsewhere (dialog header)</span>
<FileDrop
label="Přetáhni sem obrázek nebo klikni pro výběr"
formats="PNG, JPG · max 2 MB"
disabled
onFile={noop}
/>
</div>
);Composition
ACPřetáhni sem obrázek nebo klikni pro výběrPNG, JPG · max 2 MB
no file yet
export const Composition = () => {
const input = useRef<HTMLInputElement>(null);
const [name, setName] = useState<string | null>(null);
return (
<div style={{ display: 'grid', gap: 'var(--sp-4)', ...W }}>
<FileDrop
media={
<span
style={{
width: 96,
height: 96,
display: 'grid',
placeItems: 'center',
borderRadius: 'var(--radius-md)',
background: 'var(--surface-100)',
border: '1px solid var(--border)',
font: 'var(--h1)',
color: 'var(--fg-secondary)',
}}
>
AC
</span>
}
accept="image/png,image/jpeg"
label="Přetáhni sem obrázek nebo klikni pro výběr"
formats="PNG, JPG · max 2 MB"
wrongTypeText="Nahrát lze jen obrázek"
inputRef={input}
onFile={(f) => setName(f.name)}
/>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={label}>{name ?? 'no file yet'}</span>
<Button variant="default" onClick={() => input.current?.click()}>
<Icon name="upload" />
Nahrát logo
</Button>
</div>
</div>
);
};