vasx_ui 0.0.2 copy "vasx_ui: ^0.0.2" to clipboard
vasx_ui: ^0.0.2 copied to clipboard

vasX UI — a collection of beautiful, reusable Flutter widgets including smart dropdowns, date pickers, multi-step wizards, animated popup menus, and responsive data tables. Built for production-grade [...]

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:vasx_ui/vasx_ui.dart';

void main() {
  runApp(const VasxUiExampleApp());
}

class VasxUiExampleApp extends StatelessWidget {
  const VasxUiExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'vasX UI Examples',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorSchemeSeed: VasxColors.primary,
        useMaterial3: true,
      ),
      home: const ExampleHomePage(),
    );
  }
}

// ─────────────────────────────────────────────
// Home Page — widget gallery navigation
// ─────────────────────────────────────────────
class ExampleHomePage extends StatelessWidget {
  const ExampleHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    final sections = [
      _GalleryItem('AppPopupMenu', Icons.more_vert,
          const AppPopupMenuExample()),
      _GalleryItem(
          'CustomTable', Icons.table_chart_outlined, const CustomTableExample()),
      _GalleryItem('VerticalWizardShell', Icons.linear_scale,
          const VerticalWizardExample()),
      _GalleryItem('ScrollableWizardShell', Icons.view_stream_outlined,
          const ScrollableWizardExample()),
      _GalleryItem('SearchableDropdown', Icons.search,
          const SearchableDropdownExample()),
      _GalleryItem('MultiSelectDropdown', Icons.checklist,
          const MultiSelectDropdownExample()),
      _GalleryItem(
          'CreatableDropdown', Icons.add_box_outlined, const CreatableDropdownExample()),
      _GalleryItem('DropdownDatePicker', Icons.calendar_month_outlined,
          const DropdownDatePickerExample()),
      _GalleryItem('DateRangePicker', Icons.date_range,
          const DateRangePickerExample()),
    ];

    return Scaffold(
      backgroundColor: VasxColors.surface,
      appBar: AppBar(
        title: const Text('vasX UI Widget Gallery'),
        backgroundColor: VasxColors.primary,
        foregroundColor: Colors.white,
      ),
      body: ListView.builder(
        padding: const EdgeInsets.all(20),
        itemCount: sections.length,
        itemBuilder: (context, index) {
          final item = sections[index];
          return Card(
            margin: const EdgeInsets.only(bottom: 12),
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(12)),
            child: ListTile(
              leading: Icon(item.icon, color: VasxColors.primary),
              title: Text(item.title,
                  style: const TextStyle(
                      fontWeight: FontWeight.w600,
                      color: VasxColors.textPrimary)),
              trailing:
                  const Icon(Icons.arrow_forward_ios, size: 16),
              onTap: () => Navigator.push(
                context,
                MaterialPageRoute(builder: (_) => item.page),
              ),
            ),
          );
        },
      ),
    );
  }
}

class _GalleryItem {
  final String title;
  final IconData icon;
  final Widget page;
  const _GalleryItem(this.title, this.icon, this.page);
}

// ─────────────────────────────────────────────
// AppPopupMenu Example
// ─────────────────────────────────────────────
class AppPopupMenuExample extends StatefulWidget {
  const AppPopupMenuExample({super.key});

  @override
  State<AppPopupMenuExample> createState() => _AppPopupMenuExampleState();
}

class _AppPopupMenuExampleState extends State<AppPopupMenuExample> {
  String _lastAction = 'No action yet';

  void _showMenu(BuildContext context) {
    final overlay = Overlay.of(context);
    late OverlayEntry entry;
    entry = OverlayEntry(
      builder: (_) => Positioned(
        top: 120,
        right: 24,
        child: AppPopupMenu(
          onClose: () => entry.remove(),
          items: [
            AppPopupMenuItem(
              label: 'Edit',
              icon: Icons.edit_outlined,
              onTap: () => setState(() => _lastAction = 'Edit tapped'),
            ),
            AppPopupMenuItem(
              label: 'Duplicate',
              icon: Icons.copy_outlined,
              onTap: () => setState(() => _lastAction = 'Duplicate tapped'),
            ),
            AppPopupMenuItem(
              label: 'Delete',
              icon: Icons.delete_outline,
              isDestructive: true,
              onTap: () => setState(() => _lastAction = 'Delete tapped'),
            ),
          ],
        ),
      ),
    );
    overlay.insert(entry);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('AppPopupMenu')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton.icon(
              onPressed: () => _showMenu(context),
              icon: const Icon(Icons.more_vert),
              label: const Text('Show Popup Menu'),
            ),
            const SizedBox(height: 24),
            Text('Last: $_lastAction',
                style: const TextStyle(fontSize: 16)),
          ],
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────
// CustomTable Example
// ─────────────────────────────────────────────
class CustomTableExample extends StatelessWidget {
  const CustomTableExample({super.key});

  @override
  Widget build(BuildContext context) {
    final data = [
      ['Alice Johnson', 'Class 10-A', 'alice@school.com'],
      ['Bob Smith', 'Class 9-B', 'bob@school.com'],
      ['Carol White', 'Class 11-C', 'carol@school.com'],
    ];

    return Scaffold(
      appBar: AppBar(title: const Text('CustomTable')),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: CustomTable(
          columns: const [
            CustomTableColumn(label: 'Name', flex: 2),
            CustomTableColumn(label: 'Class'),
            CustomTableColumn(label: 'Email', flex: 2),
          ],
          itemCount: data.length,
          minWidth: 600,
          rowBuilder: (context, index) => [
            Text(data[index][0]),
            Text(data[index][1]),
            Text(data[index][2]),
          ],
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────
// VerticalWizardShell Example
// ─────────────────────────────────────────────
class VerticalWizardExample extends StatefulWidget {
  const VerticalWizardExample({super.key});

  @override
  State<VerticalWizardExample> createState() =>
      _VerticalWizardExampleState();
}

class _VerticalWizardExampleState extends State<VerticalWizardExample> {
  int _step = 0;

  static const _steps = [
    WizardStepConfig(
      icon: Icons.person_outline_rounded,
      label: 'Personal Info',
      mobileLabel: 'Personal',
      subtitle: 'Name & contact',
    ),
    WizardStepConfig(
      icon: Icons.location_on_outlined,
      label: 'Address',
      mobileLabel: 'Address',
      subtitle: 'Current address',
    ),
    WizardStepConfig(
      icon: Icons.check_circle_outline,
      label: 'Review',
      mobileLabel: 'Review',
      subtitle: 'Confirm details',
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return VerticalWizardShell(
      steps: _steps,
      currentStep: _step,
      title: 'Registration Wizard',
      formContent: Padding(
        padding: const EdgeInsets.all(8),
        child: Text(
          'Step ${_step + 1} form content goes here.',
          style: const TextStyle(fontSize: 16),
        ),
      ),
      onBack: _step > 0
          ? () => setState(() => _step--)
          : null,
      onNext: _step < _steps.length - 1
          ? () => setState(() => _step++)
          : () {
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(content: Text('Wizard complete!')),
              );
              Navigator.pop(context);
            },
      nextLabel: _step == _steps.length - 1 ? 'Finish' : 'Next',
      onCancel: () => Navigator.pop(context),
    );
  }
}

// ─────────────────────────────────────────────
// ScrollableWizardShell Example
// ─────────────────────────────────────────────
class ScrollableWizardExample extends StatefulWidget {
  const ScrollableWizardExample({super.key});

  @override
  State<ScrollableWizardExample> createState() =>
      _ScrollableWizardExampleState();
}

class _ScrollableWizardExampleState
    extends State<ScrollableWizardExample> {
  bool _saving = false;

  static const _steps = [
    WizardStepConfig(
      icon: Icons.person_outline_rounded,
      label: 'Core Details',
      mobileLabel: 'Core',
      subtitle: 'Name & roll number',
    ),
    WizardStepConfig(
      icon: Icons.description_outlined,
      label: 'Basic Details',
      mobileLabel: 'Basic',
      subtitle: 'Class & contact info',
    ),
    WizardStepConfig(
      icon: Icons.location_on_outlined,
      label: 'Address',
      mobileLabel: 'Address',
      subtitle: 'Current address',
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return ScrollableWizardShell(
      steps: _steps,
      title: 'Create Student',
      sectionContents: List.generate(
        _steps.length,
        (i) => Padding(
          padding: const EdgeInsets.all(8),
          child: Text(
            'Section ${i + 1} — ${_steps[i].label}.\nAdd your form fields here.',
            style: const TextStyle(fontSize: 15),
          ),
        ),
      ),
      saving: _saving,
      onSave: () async {
        setState(() => _saving = true);
        await Future.delayed(const Duration(seconds: 2));
        if (mounted) {
          setState(() => _saving = false);
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Saved!')),
          );
        }
      },
      onCancel: () => Navigator.pop(context),
    );
  }
}

// ─────────────────────────────────────────────
// SearchableDropdown Example
// ─────────────────────────────────────────────
class SearchableDropdownExample extends StatefulWidget {
  const SearchableDropdownExample({super.key});

  @override
  State<SearchableDropdownExample> createState() =>
      _SearchableDropdownExampleState();
}

class _SearchableDropdownExampleState
    extends State<SearchableDropdownExample> {
  String? _selected;

  static const _countries = [
    'India', 'United States', 'United Kingdom', 'Canada',
    'Australia', 'Germany', 'France', 'Japan', 'Brazil', 'South Africa',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('SearchableDropdown')),
      body: Padding(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            SearchableDropdown(
              label: 'Country',
              value: _selected,
              hint: 'Select a country',
              items: _countries,
              onChanged: (val) => setState(() => _selected = val),
            ),
            const SizedBox(height: 24),
            if (_selected != null)
              Text('Selected: $_selected',
                  style: const TextStyle(
                      fontSize: 16, color: VasxColors.primary)),
          ],
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────
// MultiSelectSearchableDropdown Example
// ─────────────────────────────────────────────
class MultiSelectDropdownExample extends StatefulWidget {
  const MultiSelectDropdownExample({super.key});

  @override
  State<MultiSelectDropdownExample> createState() =>
      _MultiSelectDropdownExampleState();
}

class _MultiSelectDropdownExampleState
    extends State<MultiSelectDropdownExample> {
  List<String> _selected = [];

  static const _subjects = [
    'Mathematics', 'Physics', 'Chemistry', 'Biology',
    'English', 'History', 'Geography', 'Computer Science',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('MultiSelectSearchableDropdown')),
      body: Padding(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            MultiSelectSearchableDropdown(
              label: 'Subjects',
              values: _selected,
              hint: 'Pick subjects',
              items: _subjects,
              onChanged: (vals) => setState(() => _selected = vals),
            ),
            const SizedBox(height: 24),
            if (_selected.isNotEmpty)
              Text('Selected: ${_selected.join(', ')}',
                  style: const TextStyle(fontSize: 14)),
          ],
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────
// CreatableDropdown Example
// ─────────────────────────────────────────────
class CreatableDropdownExample extends StatefulWidget {
  const CreatableDropdownExample({super.key});

  @override
  State<CreatableDropdownExample> createState() =>
      _CreatableDropdownExampleState();
}

class _CreatableDropdownExampleState
    extends State<CreatableDropdownExample> {
  List<String> _classes = ['Class 10-A', 'Class 10-B', 'Class 11-A'];
  String _selected = 'Class 10-A';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('CreatableDropdown')),
      body: Padding(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Class', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500)),
            const SizedBox(height: 8),
            CreatableDropdown(
              value: _selected,
              items: _classes,
              onChanged: (val) => setState(() => _selected = val),
              onAddItem: (newClass) =>
                  setState(() {
                    _classes.add(newClass);
                    _selected = newClass;
                  }),
              onRemoveItem: (cls) => setState(() {
                _classes.remove(cls);
                if (_selected == cls) _selected = _classes.first;
              }),
            ),
            const SizedBox(height: 24),
            Text('Selected: $_selected',
                style: const TextStyle(fontSize: 14)),
          ],
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────
// DropdownDatePicker Example
// ─────────────────────────────────────────────
class DropdownDatePickerExample extends StatefulWidget {
  const DropdownDatePickerExample({super.key});

  @override
  State<DropdownDatePickerExample> createState() =>
      _DropdownDatePickerExampleState();
}

class _DropdownDatePickerExampleState
    extends State<DropdownDatePickerExample> {
  final _dobController = TextEditingController();

  @override
  void dispose() {
    _dobController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('DropdownDatePicker')),
      body: Padding(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            DropdownDatePicker(
              controller: _dobController,
              label: 'Date of Birth',
              startYear: 1950,
              endYear: 2010,
              showExtendYears: true,
            ),
            const SizedBox(height: 24),
            ValueListenableBuilder(
              valueListenable: _dobController,
              builder: (_, val, __) => Text(
                'Controller value: ${val.text.isEmpty ? "—" : val.text}',
                style: const TextStyle(fontSize: 14),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────
// DateRangePicker Example
// ─────────────────────────────────────────────
class DateRangePickerExample extends StatefulWidget {
  const DateRangePickerExample({super.key});

  @override
  State<DateRangePickerExample> createState() =>
      _DateRangePickerExampleState();
}

class _DateRangePickerExampleState
    extends State<DateRangePickerExample> {
  DateTimeRange? _range;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('CustomDateRangePicker')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton.icon(
              icon: const Icon(Icons.date_range),
              label: const Text('Pick Date Range'),
              onPressed: () async {
                final result = await showCustomDateRangePicker(
                  context: context,
                  initialDateRange: _range,
                );
                if (result != null) setState(() => _range = result);
              },
            ),
            const SizedBox(height: 24),
            if (_range != null)
              Text(
                'From: ${_range!.start.toLocal().toString().split(' ').first}\n'
                'To:   ${_range!.end.toLocal().toString().split(' ').first}',
                textAlign: TextAlign.center,
                style: const TextStyle(fontSize: 16),
              ),
          ],
        ),
      ),
    );
  }
}
2
likes
115
points
82
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

vasX UI — a collection of beautiful, reusable Flutter widgets including smart dropdowns, date pickers, multi-step wizards, animated popup menus, and responsive data tables. Built for production-grade Flutter apps.

License

MIT (license)

Dependencies

fl_chart, flutter, intl

More

Packages that depend on vasx_ui