diff --git a/docs/guides/form-design.md b/docs/guides/form-design.md index 1b798e4..4e0a302 100644 --- a/docs/guides/form-design.md +++ b/docs/guides/form-design.md @@ -637,7 +637,7 @@ Records audio using device microphone. **Expected Schema:** ```json { - "type": "string", + "type": "object", "format": "audio", "title": "Voice Note" } @@ -670,7 +670,7 @@ Records video using device camera. **Expected Schema:** ```json { - "type": "string", + "type": "object", "format": "video", "title": "Instructional Video" } @@ -699,12 +699,12 @@ Records video using device camera. ### File Selection -Allows users to select files from device storage. +Allows users to pick an arbitrary file from device storage (documents, exports, etc.). Behaves like other **attachment** fields: the observation stores a **basename** (stable key under app `attachments/`) plus portable metadata; the binary syncs through the attachment pipeline separately from the observation JSON. **Expected Schema:** ```json { - "type": "string", + "type": "object", "format": "select_file", "title": "Upload Document" } @@ -719,15 +719,15 @@ Allows users to select files from device storage. ``` **Renderer Behavior:** -- Opens device file picker -- User selects file from storage -- Stores file reference and metadata -- File is uploaded as attachment +- Opens the system file picker +- Copies the file into **`attachments/draft/`** with a generated basename (mobile) +- Persists **`filename`** (basename), **`timestamp`**, and **`metadata`** (`mimeType`, `size`, `extension`, optional **`originalFileName`** for display) +- Shows **only the display filename** in the form (no thumbnail or inline preview) **Platform Constraints:** -- File type restrictions depend on platform -- Large files may take time to upload -- Storage permissions required +- Allowed file types depend on OS picker and Formulus configuration +- Large files affect sync time and storage +- Storage / privacy permissions depend on platform ### QR Code / Barcode Scanner @@ -1031,7 +1031,7 @@ Show field when boolean is true: ### Multimedia Capture -Forms can include fields for capturing photos, audio, and video. These are handled as attachments and synchronized separately from observation metadata. +Forms can include fields for capturing photos, audio, and video, and for attaching generic files (`select_file`). These binaries are handled as **attachments** and synchronized separately from observation metadata (observation JSON holds basename + metadata). ### Location Capture diff --git a/docs/reference/form-specifications.md b/docs/reference/form-specifications.md index 5261159..07145e4 100644 --- a/docs/reference/form-specifications.md +++ b/docs/reference/form-specifications.md @@ -282,9 +282,11 @@ See the full schema options and examples in [Custom Extensions](../guides/custom #### File Selection +Generic attachment via document picker. Use **`type: object`** with **`format: select_file`** (Formplayer stores basename + portable metadata; no inline preview). + ```json { - "type": "string", + "type": "object", "format": "select_file", "title": "Upload Document" } diff --git a/docs/reference/formplayer-contract.md b/docs/reference/formplayer-contract.md index 62d5836..4271dc2 100644 --- a/docs/reference/formplayer-contract.md +++ b/docs/reference/formplayer-contract.md @@ -558,13 +558,13 @@ All custom formats are registered in Ajv and have corresponding custom renderers | `gps` | `string` or `object` | `GPSQuestionRenderer` | GPS coordinates | | `signature` | `object` | `SignatureQuestionRenderer` | Signature pad | | `qrcode` | `string` or `object` | `QrcodeQuestionRenderer` | Barcode scanner | -| `audio` | `string` or `object` | `AudioQuestionRenderer` | Audio recording | -| `video` | `string` or `object` | `VideoQuestionRenderer` | Video recording | -| `select_file` | `string` or `object` | `FileQuestionRenderer` | File picker | +| `audio` | `object` | `AudioQuestionRenderer` | Audio recording | +| `video` | `object` | `VideoQuestionRenderer` | Video recording | +| `select_file` | `object` | `FileQuestionRenderer` | Generic file attachment (picker) | ### Format Registration -**Ajv Registration** (App.tsx:544-551): +**Ajv Registration** (App.tsx): ```typescript ajv.addFormat('photo', () => true); // Accepts any value ajv.addFormat('qrcode', () => true); @@ -608,6 +608,27 @@ export const customRenderers = [ } ``` +**File (`select_file`):** + +Use `type: object` with `format: select_file`. The Formplayer stores **basename-only** attachment keys and portable metadata (mime type, size, extension, optional original picker display name). The native app copies the picked file into **`attachments/draft/`** (same layout as photos). The UI shows the **filename only**—there is no embedded preview. + +```json +// Schema +{ + "supporting_doc": { + "type": "object", + "format": "select_file", + "title": "Supporting document" + } +} + +// UI Schema +{ + "type": "Control", + "scope": "#/properties/supporting_doc" +} +``` + **GPS:** ```json // Schema (string format) @@ -638,7 +659,7 @@ export const customRenderers = [ **Key Points:** - ✅ No special UI schema required (standard `Control` is sufficient) - ✅ Format must be specified in schema -- ✅ Type can be `string` or `object` (depends on format) +- ✅ Attachment-backed builtins (**`photo`**, **`audio`**, **`video`**, **`select_file`**) use **`type: object`** in current Formplayer (match JSON Forms testers in `App.tsx`). Other formats may accept `string` or `object` (e.g. **`gps`**, **`qrcode`**). - ✅ Custom renderer handles all UI and interaction --- diff --git a/docs/reference/formplayer.md b/docs/reference/formplayer.md index 66c7c42..3d40272 100644 --- a/docs/reference/formplayer.md +++ b/docs/reference/formplayer.md @@ -439,7 +439,7 @@ Formplayer includes core question type renderers: - `SignatureQuestionRenderer`: Digital signature - `AudioQuestionRenderer`: Voice recording - `VideoQuestionRenderer`: Video recording -- `FileQuestionRenderer`: File attachment +- `FileQuestionRenderer`: Generic file attachment (`format: select_file`, `type: object`) — document picker, basename persistence like photos; **filename-only** UI (no preview) - `SubObservationQuestionRenderer`: Embedded sub-observation repeats (`format: sub-observation`) — nested `openFormplayer` with `subObservationMode` ### Custom Renderers