-
Notifications
You must be signed in to change notification settings - Fork 0
LayrzFileInput
A file selection field that composes LayrzTextInput and opens a system file picker to select and upload a file, returning both base64-encoded and raw byte representations.
Metadata
Mirrors: ThemedFilePicker (layrz_theme)
Phase: M4 (Pickers)
Domain: Pickers
Primitive: file_picker 10.3.10 (verified clean, no Material coupling)
Status: Derived from layrz_theme. Not yet team-confirmed.
This page is derived from analysis of ThemedFilePicker in layrz_theme and represents planning assumptions only. The specification has not been reviewed or confirmed by the team. Implementation details, parameter names, and behavior may change during the M4 design phase.
All details below are subject to revision.
LayrzFileInput renders a read-only LayrzTextInput with a paperclip icon in the suffix slot. Tapping the field opens the system file picker (native Android, iOS, Windows, macOS, or web file browser). When a file is selected, the field displays the filename and invokes onChanged with both the base64-encoded content and raw bytes.
LayrzFileInput is a thin wrapper over LayrzTextInput configured as read-only. It follows the input family pattern (see Input Contract).
LayrzFileInput conforms to the Layrz*Input family contract defined in Input Contract. Inherited parameters:
- labelText (String) — the only label representation.
- placeholder — shown inside the field when no file is selected.
- prefixIcon / prefixWidget / onPrefixTap — mutually exclusive icon or widget in the leading slot.
- suffixIcon / suffixWidget / onSuffixTap — mutually exclusive icon or widget in the trailing slot.
- helpTitleText / helpContentText — help affordance (tooltip).
- onTap — callback when the field is tapped (opens the file picker).
-
readOnly — always true for
LayrzFileInput. - focusNode / controller — standard lifecycle management.
- padding — customizable per-field; defaults to M1 spacing tokens.
See the input contract for the complete shared API and disposal guarantees.
// Design sketch — illustrative only
class LayrzFileInput extends LayrzTextInput {
/// The currently selected file.
///
/// If null or empty, no file is selected.
/// Stored as base64 data URI (e.g., "data:image/png;base64,iVBORw0KG...").
final String? value;
// ...
}Stores the selected file in two representations:
-
Base64 data URI —
"data:{mimeType};base64,{base64Content}"for immediate use in web contexts. -
Raw bytes —
List<int>for lower-level processing (encryption, checksums, etc.).
Both are provided in the onChanged callback simultaneously.
Type: System file picker (native platform dialog)
Filters: Configurable file type restrictions (see acceptedTypes below)
When the user taps the field:
- The native file picker opens (behavior varies by platform).
- The user selects a file.
- The file is read and converted to base64 and bytes.
-
onChangedis invoked with both representations. - The field displays the filename.
LayrzFileInput adds the following to the base LayrzTextInput contract:
// Design sketch — illustrative only
class LayrzFileInput extends LayrzTextInput {
/// The currently selected file, encoded as a data URI.
///
/// Null or empty if no file is selected.
/// Format: "data:{mimeType};base64,{base64Content}"
final String? value;
/// Callback invoked when the user selects a file.
///
/// First parameter: base64 data URI string.
/// Second parameter: raw bytes (List<int>).
/// Both are provided for convenience; use whichever fits your use case.
final void Function(String, List<int>)? onChanged;
/// File type filter for the picker.
///
/// Constrains which files the user can select. Options include:
/// - FileType.any (all files)
/// - FileType.image (image files only)
/// - FileType.audio (audio files only)
/// - FileType.video (video files only)
/// - FileType.media (audio + video)
/// - FileType.custom (requires [allowedExtensions])
///
/// Defaults to FileType.any.
final FileType acceptedTypes;
/// Allowed file extensions when [acceptedTypes] is FileType.custom.
///
/// Example: ['pdf', 'doc', 'docx'].
/// Ignored if [acceptedTypes] is not FileType.custom.
final List<String>? allowedExtensions;
// ...
}ThemedFilePicker exposes these parameters (simplified):
class ThemedFilePicker extends StatefulWidget {
final String? labelText;
final Widget? label;
final String? value; // base64 data URI
final void Function(String, List<int>)? onChanged;
final bool disabled;
final List<String> errors;
final bool hideDetails;
final bool isRequired;
final FileType acceptedTypes;
final List<String>? allowedExtensions;
final EdgeInsets? padding;
final Widget? customChild;
// ... Material-specific color/focus/splash parameters
}Differences for layrz_ui:
- Remove all Material-specific color/focus/splash parameters.
- Inherit from base
LayrzTextInputcontract rather than re-declare shared parameters. - Remove
customChild(M1 foundation does not support arbitrary wrapping). - Remove
isRequired(validation and required markers are not part of the M4 scope; integrate as needed in M5+).
The suffix icon changes to indicate state:
- No file selected: Paperclip icon (upload affordance).
- File selected: Eraser or delete icon (indicates tapping will clear the selection).
Tapping the suffix when a file is selected clears the selection and invokes onChanged with empty string and empty bytes.
When a file is selected, the field displays the filename (not the full path). The base64 content is stored internally and available via value.
-
M1 Theme System (
LayrzTheme,LayrzThemeData) — colors and text styling. -
M2 Tooltip Component (
LayrzTooltip) — for help affordance. - M3 LayrzTextInput — base field chrome and behavior.
- file_picker 10.3.10 (verified clean) — system file picker integration.
layrz_theme returns the file content as "data:{mimeType};base64,{base64Content}". Verify that layrz_ui adopts the same format for consistency. This format is directly embeddable in HTML <img> tags and is a web standard.
How should {mimeType} be determined?
- From the file extension (fragile, e.g.,
.txt→text/plain)? - From the file's binary signature (magic bytes)?
- From the
file_pickerpackage's detection?
Recommend: Use file_picker's detection if available, fall back to extension-based detection.
The system file picker behaves differently on different platforms:
- Android/iOS: System file browsers (Google Files, iOS Files app).
- Desktop (Windows/macOS/Linux): Native file open dialogs.
-
Web: Browser's
<input type="file">dialog.
layrz_ui should test on each platform to ensure consistent UX.
-
File size limits: Should there be a maximum file size? If the user selects a 1 GB file, does layrz_ui load it into memory?
-
Multiple files: layrz_theme's
ThemedFilePickerallowsallowMultiple: falseonly. Should layrz_ui support multiple file selection, or is single-file-only correct? -
Folder access: Should the picker allow selecting folders, or files only? layrz_theme appears to be files-only.
-
File clearing behavior: When a file is selected and the user taps the suffix (delete icon), does
onChangedfire with empty values, or does the caller need to detect the state and handle clearing manually? -
Filename truncation: If a filename is very long (> 50 characters), should it be truncated with ellipsis in the display?
-
Icon choice: The paperclip icon is
MdiIcons.paperclipand eraser isMdiIcons.eraser(from flutter_material_design_icons).
Critical path item: A design reference (Figma, spec, or annotated screenshot) must be provided before M4 implementation begins, specifying:
- File field chrome (padding, icon placement).
- Filename display (truncation, font).
- Empty state icon and placeholder text.
- Selected state icon (eraser or delete).
- Interaction flow (tap to open picker, suffix tap to clear).
- Light and dark theme variants.
- Error display (related to help affordance in
[Input Contract](Input-Contract)).
Last updated: 2026-08-13
Related documents: Input Contract, Dependencies, Design Tokens, Architecture, Roadmap
Made with ❤️ by Golden M, Inc.
- LayrzTextInput
- LayrzSelectableAction
- LayrzSelectionToolbar
- LayrzTextSelectionControls
- LayrzSelectionMagnifier
- LayrzSelectionHandlePainter
- LayrzTextAreaInput
- LayrzComboBoxInput
- LayrzNumberInput
- LayrzPasswordInput
- LayrzCheckboxInput
- LayrzRadioInput
- LayrzSelectInput
- LayrzMultiSelectInput
- LayrzSearchInput
- LayrzDualListInput
- LayrzDurationInput