Skip to content

LayrzFileInput

Kenny Mochizuki Escalona edited this page Aug 20, 2026 · 3 revisions

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.


⚠️ IMPORTANT: Specification Status

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.


Overview

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.

Composition

LayrzFileInput is a thin wrapper over LayrzTextInput configured as read-only. It follows the input family pattern (see Input Contract).


Conformance

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.


Value Type and Selection Surface

Value Type

// 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:

  1. Base64 data URI"data:{mimeType};base64,{base64Content}" for immediate use in web contexts.
  2. Raw bytesList<int> for lower-level processing (encryption, checksums, etc.).

Both are provided in the onChanged callback simultaneously.

Selection Surface

Type: System file picker (native platform dialog)
Filters: Configurable file type restrictions (see acceptedTypes below)

When the user taps the field:

  1. The native file picker opens (behavior varies by platform).
  2. The user selects a file.
  3. The file is read and converted to base64 and bytes.
  4. onChanged is invoked with both representations.
  5. The field displays the filename.

Deltas from Base Contract

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;

  // ...
}

Reference: layrz_theme API

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 LayrzTextInput contract 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+).

Behavior

Suffix Icon Affordance

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.

Filename Display

When a file is selected, the field displays the filename (not the full path). The base64 content is stored internally and available via value.


Dependencies

  • 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.

Implementation Notes

Base64 and Data URI Format

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.

Mime Type Detection

How should {mimeType} be determined?

  • From the file extension (fragile, e.g., .txttext/plain)?
  • From the file's binary signature (magic bytes)?
  • From the file_picker package's detection?

Recommend: Use file_picker's detection if available, fall back to extension-based detection.

Platform Differences

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.


Open Questions

  • 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 ThemedFilePicker allows allowMultiple: false only. 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 onChanged fire 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.paperclip and eraser is MdiIcons.eraser (from flutter_material_design_icons).


Design Reference Gap

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

Clone this wiki locally