File upload / dropzone
In reviewLive · web
Dropzone: tab to it (Enter / Space), click Browse, or toggle drag-over
Drag files hereor browse · TS, JSON, YAML, images · up to 10.0 MB each
- session-state.ts18 KB
- tokens.json6 KB
- facet-bg.png1.4 MB
- cluster-dump.bin40.3 MB
0 uploaded · 3 pending
Drag-over highlight: force the active state
// Web: React, consuming @dizyx/nockerl-tokens. (Web is the laggard platform. Spec + live demo,// not yet exported from @dizyx/nockerl-react; promotion is tracked.)
export function AttachPanel() { return ( <FileUpload accept={['.ts', '.json', '.yaml', 'image/*']} multiple maxSize={10 * 1024 * 1024} onFiles={(files) => files.forEach(uploadFile)} onReject={(file, reason) => toast(`${file.name}: ${reason}`)} /> );}// Android Jetpack Compose (canonical). The shipped app attaches IMAGES only via// the system photo picker; there is no dropzone / size / per-file progress yet.import androidx.activity.compose.rememberLauncherForActivityResultimport androidx.activity.result.PickVisualMediaRequestimport androidx.activity.result.contract.ActivityResultContracts
val picker = rememberLauncherForActivityResult( contract = ActivityResultContracts.PickMultipleVisualMedia(maxItems = 8),) { uris -> viewModel.attach(uris) }
NockerlIconButton( icon = Icons.Filled.AttachFile, contentDescription = "Attach", onClick = { picker.launch( PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly), ) },)// macOS SwiftUI (canonical). Nockerl Voice ships NO file affordance today; this// is the intended native API (the standard .fileImporter + a drop destination)..fileImporter( isPresented: $showImporter, allowedContentTypes: [.plainText, .json, .yaml, .image], allowsMultipleSelection: true,) { result in if case .success(let urls) = result { uploader.add(urls) }}.dropDestination(for: URL.self) { urls, _ in uploader.add(urls) return true}Parameters
Section titled “Parameters”| Prop | Type | Default | Description |
|---|---|---|---|
onFiles * | (files: File[]) => void | Called with the accepted files from a drop or the browse picker. | |
accept | string[] | 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 | Per-file byte cap. Over-size files render the rejected treatment (⚠ + reason), never silently dropped. | |
onReject | (file: File, reason: string) => void | 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 | PickMultipleVisualMedia(maxItems) for a multi-image pick, or PickVisualMedia() for one. | |
onResult * | (List<Uri>) -> Unit | 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> | Drives the system file importer open/closed. | |
allowedContentTypes * | [UTType] | The accepted uniform type identifiers (e.g. .plainText, .json, .image). | |
allowsMultipleSelection | Bool | false | Permit selecting several files in the importer. |
onCompletion * | Result<[URL], Error> | Picked file URLs, or the error if the import failed / was cancelled. | |
.dropDestination | for: URL.self | The drag-and-drop sink on the dropzone; returns true when the drop is accepted. |