import "./record_files.css"; import type * as React from "react"; import { useRender } from "@base-ui/react/use-render"; import type { DisplayFile } from "./file_thumbnail"; import { type RecordLabels } from "./locale"; import { type PendingUpload } from "./thumbnail_grid"; import { type StyleProps } from "./style_props"; export interface RecordFilesProps extends StyleProps { /** Everything the record holds, across every files field, in the order the * record reads them. */ files: readonly DisplayFile[]; /** WHAT THE PILE IS FOR, when the mimes do not say it. Read by MAJORITY * otherwise: a pile at least half pictures is photos-heavy; anything else is * documents-heavy, where the NAME is what tells a signed contract from a * draft. State it where the majority is a coincidence. */ lead?: "photos" | "documents"; /** The live add-queue, drawn in the same grid as the stored pile. */ uploads?: readonly PendingUpload[]; /** * HOW MANY FILES THIS SECTION IS OWED, and what ONE of them is. Every owed * slot the pile does not cover stands as a GHOST tile at the end of the strip * and GIVES WAY as a file lands; the queue counts, since an upload in flight * already has its tile. * * A GHOST STATES; IT DOES NOT ACT — the section's intake is the heading's verb * and the drop that covers the whole region. `label` is what one owed file IS * and names the tile; a count past what a placeholder can say draws what it * can ({@link waitingRows}). */ expected?: { count: number; label: string; }; /** * Receives files dropped anywhere over the section, and files picked in the * EMPTY state's well. The WHOLE section takes the drop at every size. * * **ONE NAMED DOOR, AND WHICH ONE IS DECIDED BY WHETHER THE SECTION HOLDS * ANYTHING.** Holding nothing, the door is the line this draws, and the * section's heading stands its verb down (`composition.md` § The add-placement * law). Holding something, the door is the heading's named verb * (`RecordSection.action`) and this draws none. */ onAdd?: (files: File[]) => void; /** Opens one of the record's files, with the whole pile it belongs to, so the * surface can put it in its own viewer. ABSENT, the section opens its own * `FileGalleryDialog` at that file. The same prop `RecordExpectedSet` takes. */ onOpenFile?: (file: DisplayFile, files: readonly DisplayFile[]) => void; /** Detaches one file from the record. Offered in the named rows' ⋯ and in the * viewer's toolbar — never on a tile — and confirmed either way. */ onRemove?: (file: DisplayFile) => void; labels?: Partial; testID?: string; ref?: React.Ref; render?: useRender.RenderProp; } /** * A RECORD'S FILES, PICTURES FIRST. The resting state is one row of thumbnails * at the container's width — product shots as pictures, documents as their typed * badge, media with its glyph — so a reader sees WHAT the record holds before * reading a name, and the row's own "+N" tile says how much did not fit. * * Pressing that tile REVEALS the rest, and what "the rest" looks like is the * pile's own question. A photos-heavy pile opens into the full grid; a * documents-heavy pile keeps the strip as its visual index and lists every file * beneath it by NAME, because a PDF badge is the same badge as the next one. * * The section owns ONE gallery, so the reader never has two lightboxes over one * set of files. */ export declare function RecordFiles(props: RecordFilesProps): React.ReactElement>;