leo_easy_ui_kit 0.2.0 copy "leo_easy_ui_kit: ^0.2.0" to clipboard
leo_easy_ui_kit: ^0.2.0 copied to clipboard

Leo Easy UI Kit: effortless yet powerful Flutter UI components.

leo_easy_ui_kit #

Effortless APIs. Production‑ready Flutter UI primitives for forms, selectors, tables, and HTML.

Pub Version Pub Points

leo_easy_ui_kit is a focused UI toolkit that gives you high‑level, type‑safe widgets for most input and selection patterns you build in Flutter apps:

  • one‑line easy*Of<T> helpers for the common cases, and
  • fully customizable widgets when you need to go deeper.

Every widget is generic (<T>), null‑safe, and designed to integrate cleanly with your existing state management (ValueNotifier, BLoC, Provider, etc.).


✨ Highlights #

  • Unified selection model – dropdowns, checkboxes, radios, switches, chips, segmented controls, lists, grids, menus, and data tables all share the same mental model: items + value/values + onChanged/onChangedMany.
  • Multi‑select built‑in – enable multi‑select with a single multiSelect: true flag on widgets that support it.
  • Powerful shortcutseasyDropdownOf, easyCheckboxOf, easyRadioOf, easySwitchOf, easyButtonGroupOf, easyChipsOf, easySegmentedOf, easyPopupSelectOf, easyBottomSheetSelectOf, easyTextFieldOf, easyIntFieldOf, easyDoubleFieldOf, easyTableOf, easyListOf, easySearchableListOf, easyGridOf, easySearchableGridOf, easyMenuOf, easySearchOf, easyHtml, easyHtmlFromUrl, easyTagInputOf, easyFilterBarOf, easyResponsiveScaffoldOf.
  • Rich data & content widgets – generic data table, selectable lists, grids, popup menus, and HTML rendering (from strings or URLs).
  • File & image pickers – well‑designed primitives that delegate to your own file_picker / image_picker integration via callbacks.
  • Composable base layerEasySelectionController, EasyValueNotifier, and EasyBloc give you predictable, testable state primitives under the hood.

🚀 Getting started #

  1. Add the dependency:
dependencies:
  leo_easy_ui_kit: ^0.1.0
  1. Import the library:
import 'package:leo_easy_ui_kit/leo_easy_ui_kit.dart';
  1. Start with the easy*Of helpers for simple cases. Drop down to the underlying widgets (EasyDropdown, EasyCheckbox, EasyTable, EasyHtml, etc.) when you need more control.

🧭 Example: full demo app #

This package ships with a full example app at example/lib/main.dart. It demonstrates four real‑world areas:

  • Forms – profile form with dropdowns, button groups, checkboxes, radio buttons, switches, numeric inputs, date picker, file picker, image picker, onboarding stepper, and tag input.
  • Selectors – chips, segmented controls, bottom‑sheet and dialog selectors, autocomplete search, and responsive layout shell.
  • Data & menus – selectable data table, filter bar, searchable lists, grids, and popup menu actions.
  • HTML – render inline HTML strings or remote pages with loading and error states.

To run it locally:

flutter run example/lib/main.dart

Below is a tour of the key pieces you will see in the example.


1. Forms – build a profile form in minutes #

1.1 Core inputs with easy*Of #

The Forms tab uses the one‑line helpers to wire up a complete profile form:

easyDropdownOf<String>(
  items: const ['Developer', 'Designer', 'Manager', 'Student'],
  value: role,
  onChanged: (value) => setState(() => role = value),
  label: (v) => v,
);

easyButtonGroupOf<String>(
  items: const ['Beginner', 'Intermediate', 'Advanced', 'Expert'],
  value: experienceLevel,
  onChanged: (value) => setState(() => experienceLevel = value),
);

easyCheckboxOf<String>(
  items: const ['Flutter', 'UI/UX', 'Backend', 'DevOps', 'Mobile', 'Web'],
  values: selectedInterests,
  onChangedMany: (values) => setState(() => selectedInterests = values),
  multiSelect: true,
);

easyRadioOf<String>(
  items: const ['Employed', 'Freelance', 'Student', 'Seeking'],
  value: employmentStatus,
  onChanged: (value) => setState(() => employmentStatus = value),
  label: (v) => v,
);

easySwitchOf<String>(
  items: const ['Enable Notifications'],
  value: receiveNotifications ? 'Enable Notifications' : null,
  onChanged: (value) =>
      setState(() => receiveNotifications = value != null),
  label: (v) => v,
);

// Type‑safe text fields

easyIntFieldOf(
  value: yearsExperience,
  onChanged: (value) => setState(() => yearsExperience = value),
  hintText: 'Years of experience',
);

easyDateFieldOf(
  value: startDate,
  onChanged: (value) => setState(() => startDate = value),
  label: (date) => '${date.year}-${date.month}-${date.day}',
  firstDate: DateTime(2000),
  lastDate: DateTime(2030),
);

What this gives you

  • Minimal boilerplate: no DropdownButton, FormField, or DataTable plumbing.
  • Strong typing: all helpers are generic (easyDropdownOf<String>, easyIntFieldOf, etc.).
  • Multi‑select behavior that is consistent across components.

1.2 File & image pickers #

The same form also demonstrates integrating file and image pickers. leo_easy_ui_kit does not force a particular plugin; instead, you provide the async callback that calls file_picker, image_picker, or any custom API:

EasyFilePicker<String>(
  label: 'Attach files',
  allowMultiple: true,
  values: uploadedFiles,
  onChangedMany: (files) => setState(() => uploadedFiles = files),
  onPick: (category, allowMultiple) async {
    // Plug in your own implementation here (file_picker, etc.).
    // The example app returns demo values to focus on UI wiring.
    return [
      '${category.label} sample ${uploadedFiles.length + 1}.txt',
    ];
  },
);

EasyImagePicker<String>(
  allowMultiple: true,
  values: profileImages,
  onChangedMany: (images) => setState(() => profileImages = images),
  onPick: (source, allowMultiple) async {
    // Plug in image_picker or any camera/gallery implementation.
    return [
      '${source.label} image ${profileImages.length + 1}',
    ];
  },
);

At the bottom of the tab, a summary card (_buildSummaryCard) aggregates the current selections into a compact profile overview so you can see the state flowing through all widgets.

1.3 Tag input #

The Forms/Selectors experience also showcases a tag input for free‑form values:

easyTagInputOf(
  tags: technologyTags,
  onChanged: (tags) => setState(() => technologyTags = tags),
);

Under the hood this uses EasyTagInput<T>, which exposes a parser and label builder so you can map arbitrary strings to strongly‑typed values (IDs, enums, etc.).


The Selectors tab highlights richer selection patterns.

2.1 Chips & segmented controls #

easyChipsOf<String>(
  items: const ['TypeScript', 'Dart', 'Python', 'Rust', 'Go', 'Swift'],
  values: selectedSkills,
  onChangedMany: (values) => setState(() => selectedSkills = values),
  multiSelect: true,
);

// Material 3 segmented control
easySegmentedOf<String>(
  items: const ['Day', 'Week', 'Month', 'Year'],
  value: 'Week',
  onChanged: (value) {
    // update state here
  },
  label: (v) => v,
);

2.2 Bottom sheet & dialog selectors #

// Bottom sheet selector for large lists
easyBottomSheetSelectOf<String>(
  items: const ['United States', 'Canada', 'United Kingdom', 'Germany', 'France'],
  value: country,
  onChanged: (value) => setState(() => country = value),
  label: (v) => v,
  sheetTitle: const Text('Select Country'),
);

// Dialog‑based selector
easyPopupSelectOf<String>(
  items: const ['Light Theme', 'Dark Theme', 'System Default', 'High Contrast'],
  value: 'System Default',
  onChanged: (value) {
    // apply theme
  },
  label: (v) => v,
  title: const Text('Select Theme'),
);

2.3 Search with autocomplete & remote results #

easySearchOf<String>(
  items: const [
    'Alice Johnson',
    'Bob Smith',
    'Charlie Brown',
    'Diana Prince',
    'Eve Davis',
  ],
  label: (v) => v,
  onSelected: (value) {
    // handle selection
  },
  hintText: 'Search for a person...',
  // Optional: integrate remote search
  // remoteSearch: (query) async => fetchUsersFromServer(query),
);

This gives you a ready‑made search bar with suggestion list, multi‑select support, and an escape‑hatch for server‑side filtering.


3. Data & menus – tables, lists, grids, and menus #

The Data tab shows how to present and select structured data.

3.1 Tables, lists and menus #

// Selectable data table
easyTableOf<Project>(
  items: projects,
  columns: const [
    DataColumn(label: Text('Project')),
    DataColumn(label: Text('Status')),
    DataColumn(label: Text('Progress')),
  ],
  cellBuilder: (context, project, colIndex, selected) {
    switch (colIndex) {
      case 0:
        return Text(project.name);
      case 1:
        return _StatusBadge(project.status);
      case 2:
        return Text('${project.progress}%');
      default:
        return const SizedBox.shrink();
    }
  },
  selectedValues: selectedProjects,
  onChangedMany: (values) => setState(() => selectedProjects = values),
  multiSelect: true,
);

// Simple one‑dimensional selectable list
easyListOf<String>(
  items: const ['Inbox', 'Starred', 'Sent', 'Drafts', 'Trash'],
  value: 'Inbox',
  onChanged: (value) {
    // navigate to mailbox
  },
  label: (v) => v,
  divided: true,
);

// Popup menu for actions
easyMenuOf<String>(
  items: const ['Profile', 'Settings', 'Help', 'Logout'],
  value: null,
  onChanged: (value) {
    // handle menu action
  },
  label: (v) => v,
  tooltip: 'Open menu',
);

3.2 Filter bar, searchable list & searchable grid #

// Filter bar wrapping status filters
easyFilterBarOf(
  leading: const Icon(Icons.filter_list),
  filters: [
    easyButtonGroupOf<String>(
      items: const ['All', 'Completed', 'In Progress', 'Planned'],
      value: projectStatusFilter,
      onChanged: (value) => setState(() {
        projectStatusFilter = value ?? 'All';
        tablePageIndex = 0;
      }),
    ),
  ],
);

// Searchable list
easySearchableListOf<String>(
  items: const ['Inbox', 'Starred', 'Sent', 'Drafts', 'Trash', 'Spam'],
  label: (v) => v,
  hintText: 'Search mailboxes...',
);

// Grid view
easyGridOf<Project>(
  items: _sampleProjects,
  values: selectedProjects,
  onChangedMany: (values) => setState(() => selectedProjects = values),
  multiSelect: true,
  label: (p) => p.name,
  crossAxisCount: 2,
  childAspectRatio: 4 / 3,
);

// Searchable grid with custom tiles
easySearchableGridOf<Project>(
  items: _sampleProjects,
  label: (p) => p.name,
  itemBuilder: (context, project, selected) => Card(
    elevation: selected ? 4 : 1,
    child: Padding(
      padding: const EdgeInsets.all(12),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(project.name),
          _StatusBadge(project.status),
          Text('${project.progress}% complete'),
        ],
      ),
    ),
  ),
  values: selectedProjects,
  onChangedMany: (values) => setState(() => selectedProjects = values),
  multiSelect: true,
  hintText: 'Search projects...',
  crossAxisCount: 2,
  childAspectRatio: 4 / 3,
);

4. HTML – render rich content from strings or URLs #

The HTML tab demonstrates both inline and remote HTML rendering.

// Inline HTML rendering
easyHtml(
  '''
  <h2 style="color: #6200EE;">Welcome to Leo Easy UI Kit</h2>
  <p>This is <strong>rendered HTML</strong> content.</p>
  ''',
  onTapUrl: (url) async {
    // Decide how to handle links (launch, track, etc.)
    return false; // prevent default behaviour
  },
);

// Fetch and render HTML from a URL
SizedBox(
  height: 400,
  child: easyHtmlFromUrl(
    'https://example.com',
    loading: const Center(child: CircularProgressIndicator()),
    errorBuilder: (context, error) => Text('Failed to load: $error'),
  ),
);

This is ideal for CMS content, documentation pages, terms & conditions, and any server‑driven HTML experience you want to surface in‑app.


🔌 State management & architecture #

Under the hood, most widgets are powered by a small set of primitives:

  • EasySelectionController<T> – centralizes single/multi‑select state.
  • EasyValueNotifier<T> – a ValueNotifier<T?> that stays in sync with an EasySelectionController.
  • EasyBloc<T> – a ready‑made bloc with EasyEvent/EasyState for when you prefer flutter_bloc.

You can:

  • Use the value / values + onChanged / onChangedMany pattern directly, or
  • Wrap widgets with your own BLoC/Provider/Riverpod and feed them via these base types.

The public surface is intentionally small and predictable; the example app keeps everything in a single StatefulWidget for clarity, but the same widgets work equally well in layered architectures.


🛠 Contributing #

Contributions are welcome:

  1. Fork & clone the repository.
  2. Run flutter pub get.
  3. Run flutter analyze and add or adjust tests.
  4. Open a pull request describing your changes.

Bug reports and feature requests are also appreciated via the issue tracker.

8
likes
0
points
123
downloads

Publisher

unverified uploader

Weekly Downloads

Leo Easy UI Kit: effortless yet powerful Flutter UI components.

Repository (GitHub)
View/report issues

Topics

#flutter #ui-kit #widget #form

License

unknown (license)

Dependencies

equatable, flutter, flutter_bloc, flutter_hooks, flutter_widget_from_html, http, provider

More

Packages that depend on leo_easy_ui_kit