Called with the accepted files from a drop or the browse picker.
accept
string[]
n/a
Allowed extensions / MIME globs (e.g. .ts, image/*). Anything else is rejected with a reason.
multiple
boolean
true
Allow selecting more than one file at a time.
maxSize
number
n/a
Per-file byte cap. Over-size files render the rejected treatment (⚠ + reason), never silently dropped.
onReject
(file: File, reason: string) => void
n/a
Called for each file that fails the accept / maxSize checks.
disabled
boolean
false
Inert + clearly-seen dropzone (never faded to invisible). Browse + drop are blocked.
The shipped app uses the platform photo picker (PickMultipleVisualMedia), an
image-only attach, not a file dropzone. The parameters below are that
launcher’s real surface; the dropzone / size / per-file progress are web-only for
now (see the drift note).
Parameter
Type
Default
Description
contract *
ActivityResultContract
n/a
PickMultipleVisualMedia(maxItems) for a multi-image pick, or PickVisualMedia() for one.
onResult *
(List<Uri>) -> Unit
n/a
Callback with the picked content URIs (empty if the user cancels).
maxItems
Int
system max
Upper bound on the multi-select count, passed to the contract.
mediaType
VisualMediaType
ImageOnly
Passed in the PickVisualMediaRequest: ImageOnly, VideoOnly, or ImageAndVideo.
Not shipped in Nockerl Voice. The table is the intended native API: SwiftUI’s
.fileImporter plus a .dropDestination on the recessed dropzone surface.
Style
Type
Default
Description
isPresented *
Binding<Bool>
n/a
Drives the system file importer open/closed.
allowedContentTypes *
[UTType]
n/a
The accepted uniform type identifiers (e.g. .plainText, .json, .image).
allowsMultipleSelection
Bool
false
Permit selecting several files in the importer.
onCompletion *
Result<[URL], Error>
n/a
Picked file URLs, or the error if the import failed / was cancelled.
.dropDestination
for: URL.self
n/a
The drag-and-drop sink on the dropzone; returns true when the drop is accepted.
Cross-platform drift (tracked for reconciliation)
The dropzone, file list, per-file progress, and success / error / rejected states
are web-only today, designed originally from the laws + the Button / TextField
/ progress vocabulary, since the apps don’t ship them:
Android attaches images only through the system photo picker
(PickMultipleVisualMedia) and shows dismissable thumbnail chips (an X in the
error color). No generic files, no size, no drag-drop, no per-file progress.
Voice (macOS) ships no file affordance at all; the Swift code/params
above are the intended .fileImporter + .dropDestination API.
The signature dropzone reuses the recessed-well + dashed-border look from the
text field; the progress bar reuses the gauge track; browse/upload reuse
the button ladder, so when the apps adopt it, it already matches.