Flutter · colveor_ui
Widgets
Every widget is styled by your theme. Import each group from package:colveor_ui/widgets/<group>.dart.
Buttons
widgets/buttons.dart
VoButton(label: 'Continue', onPressed: submit);
VoButton(label: 'Delete', variant: VoButtonVariant.danger, onPressed: delete);
VoButton(label: 'Saving', isLoading: true, onPressed: null);
VoIconButton(icon: const Icon(Icons.share), label: 'Share', onPressed: share);| Name | Description |
|---|---|
VoButton | label, onPressed, variant (primary, secondary, outline, text, danger), isLoading, isFullWidth (default true), prefixIcon, suffixIcon, height, colors, margin. |
VoIconButton | icon, onPressed, optional label underneath, tooltip, color, size. |
Inputs
widgets/inputs.dart
Text inputs share a VoFieldOptions object (label, hint, helper and error text, icons, keyboard type, input action, max lines/length, enabled, read-only, and labelBehavior: auto, floating, external or none).
VoInputField(
options: const VoFieldOptions(label: 'Email', keyboardType: TextInputType.emailAddress),
validator: VoValidators.email,
controller: emailController,
);
VoPasswordField(
options: const VoFieldOptions(label: 'Password'),
validator: VoValidators.password,
);
VoSearchField(onChanged: (query) => search(query)); // debounced, 400msVoPhoneInput
VoPhoneInput(
layout: VoPhoneInputLayout.integrated, // or split, stacked
initialCountryCode: 'NG',
onChanged: (country, phone, parsed) {
final e164 = parsed?.fullNumber;
},
)A country picker plus digit-only number field. It parses the number as you type (passing a PhoneParseResult), accepts a full number as initialValue, and writes the composed number into controller. The country list comes from VoConfig.initialCountryCode and favoriteCountries.
VoPinInput & VoKeyboard
VoPinInput(
length: 6,
errorText: error,
isLoading: verifying,
onCompleted: (code) => verify(code),
);
VoKeyboard(maxLength: 4, controller: pinController, onSubmit: confirmPin);VoKeyboard is an on-screen number pad (1–9, an optional action key, 0 and backspace).
VoSelectField
VoSelectField<String, String>(
options: const VoFieldOptions(label: 'Fruit'),
overlayOptions: VoOverlayOptions.singleSelect(
title: 'Pick a fruit',
items: ['Apple', 'Banana', 'Cherry'],
),
onChanged: (fruit) => setState(() => selected = fruit),
)Opens an overlay on tap. Use VoOverlayOptions.multiSelect for List<T> results.
Form helpers
VoFormGroup and VoFormControl keep a map of controls (label, hint, validator, keyboard type, password flag, initial value) with their own controllers: initState(), getControl(key), setValue, updateControl and dispose().
Display
widgets/display.dart
VoText(
'By continuing you agree to our [Terms] and [Privacy Policy].',
onTap: (index, text) => index == 0 ? openTerms() : openPrivacy(),
);| Name | Description |
|---|---|
VoText | Rich text where each [bracketed] span is a tappable link. Styled with VoTextStyle. |
VoAvatar | Network image or initials, with an optional online dot. |
VoCounterBadge | A count badge over any icon (maxCount 99, showZero). |
VoCounterText | A number that animates when it changes. |
VoCountryFlag | A flag by country code: circle, roundedRect or rect. |
VoDivider | Dashed or solid divider, optionally with a text label. |
Feedback
widgets/feedback.dart
Toasts
VoToast.error(context: context, message: 'Something went wrong');
VoToast.banner(message: 'You are offline', type: VoToastType.warning);
final id = VoToast.show(
message: 'Uploading…',
title: 'Please wait',
style: VoToastStyle.snackBar,
position: VoToastPosition.top,
);
VoToast.dismissById(id);Toasts stack (up to three) and work without a context by falling back to the root navigator. Helpers: success, error, warning, info, banner, show, and dismissById / dismissFirst / dismissLast / dismissAll. Reusing a toastId replaces that toast. Inside screens, prefer the showSuccessToast-style helpers from base screens.
VoFeedbackView
VoFeedbackView.empty('No orders yet', 'Orders you place will show up here.');
VoFeedbackView.offline('You are offline', 'Check your connection and try again.');
VoFeedbackView.custom(
title: 'Almost there',
description: 'Verify your email to continue.',
icon: const Icon(Icons.mail_outline),
actionBuilder: VoButton(label: 'Resend email', onPressed: resend),
);Full-area states: error, offline, noResults, empty, unauthorized, forbidden, maintenance, notFound and custom.
VoCountdownAction
VoCountdownAction(
prefixText: "Didn't receive a code?",
actionText: 'Resend',
countdownPrefixText: 'Resend in',
duration: const Duration(seconds: 30),
onPressed: () async => resendOtp(),
)Restart it through a GlobalKey<VoCountdownActionState> and restart().
Layout
widgets/layout.dart
| Name | Description |
|---|---|
VoScaffold | Scaffold with themed body padding (sizes.md by default) and a VoScaffoldStyle for colors, drawers and system UI overlay style. |
VoAppBar.fromStyle | Builds an AppBar from a VoAppBarStyle, with title, leading and actions. |
VoScrollableForm | A scrollable column that fills the viewport, with header, footer, spacing and keyboard dismissal on drag. |
VoTileView / VoTile | Lists or rows of selectable tiles with active-state styling (VoTileStyle, VoRowTileStyle). |
VoScaffold(
appBar: VoAppBar.fromStyle(const VoAppBarStyle(), title: 'Sign in'),
body: VoScrollableForm(
footer: VoButton(label: 'Continue', onPressed: submit),
children: [emailField, passwordField],
),
)Overlays
widgets/overlay.dart
final fruit = await showVoOverlay<String, String>(
context,
type: VoOverlayType.dialog, // bottomSheet (default), dialog or modal
options: VoOverlayOptions.singleSelect(
title: 'Pick one',
items: ['Apple', 'Banana'],
itemTile: VoOverlayTile(title: (s) => s),
onSearch: (query, items) => items
.where((i) => i.toLowerCase().contains(query.toLowerCase()))
.toList(),
),
);| Name | Description |
|---|---|
VoOverlayOptions.builder | Any custom content, with optional title, heading and footer. |
VoOverlayOptions.singleSelect | A searchable list that returns the tapped item. Supports favoriteItems, itemsAsStream and selectedItem. |
VoOverlayOptions.multiSelect | Returns List<T> on confirm. Options: selectedItems, minSelection, maxSelection, confirmLabel, clearLabel. |
VoOverlayTile | How each item renders: title, subtitle, or leading / title / trailing builders. |
VoBottomSheetOptions | initialChildSize 0.5, minChildSize 0.25, maxChildSize 0.9, canFullHeight. |
Search appears only when onSearch is set; favorites are listed first.
Page flow
widgets/page_flow.dart
A multi-step flow inside one screen, with its own history and animated transitions.
final flow = VoPageFlowController(initialPageKey: 'phone');
VoPageFlowView(
controller: flow,
theme: const VoPageFlowTheme(transition: VoPageFlowTransition.slideFade),
pages: [
VoPage(key: 'phone', builder: (_) => PhoneStep(onNext: () => flow.goToPage('otp'))),
VoPage(key: 'otp', builder: (_) => const OtpStep(), canLeave: () => !verifying),
],
);| Name | Description |
|---|---|
Controller | goToPage, replace, back, reset; currentKey, history, canGoBack. Each call returns success, alreadyCurrent, blocked or pageNotFound. |
VoPage | key, builder, canLeave (return false to block), onEnter, onExit. |
Transitions | none, fade, scale, slide, slideFade — or a custom transitionBuilder. |
VoPageFlowScope.of(context) | The controller, from inside a page. |
Dashboard
widgets/dashboard.dart
The signed-in shell: app bar, bottom dock, drawer and end drawer, with its own pane history and back handling.
VoDashboard(
initialPaneKey: 'home',
dockPanes: [
VoDashboardPane.dock(
key: 'home',
title: 'Home',
iconData: Icons.home_outlined,
builder: (context, pane) => const HomePane(),
),
VoDashboardPane.spacer(),
VoDashboardPane.dock(
key: 'explore',
title: 'Explore',
iconData: Icons.explore_outlined,
builder: (context, pane) => const ExplorePane(),
),
],
drawerPanes: [
VoDashboardPane.divider(title: 'Account'),
VoDashboardPane.drawer(
key: 'profile',
title: 'Profile',
iconData: Icons.person_outline,
builder: (context, pane) => const ProfilePane(),
),
VoDashboardPane.stickyBottom(
key: 'sign-out',
title: 'Sign out',
iconData: Icons.logout,
onPressed: (context, pane) => signOut(),
),
],
onPaneChanged: (key) => analytics.screen(key),
)| Name | Description |
|---|---|
Pane types | dock, drawer, endDrawer, stickyBottom (pinned at the drawer bottom), divider and spacer. |
Per-pane options | showAppBar, showDock, showDrawer, showEndDrawer, showFloatingActionButton, floatingActionButtonBuilder, appBarActionsBuilder, appBarLeadingBuilder, onPressed (replaces navigation). |
context.dashboardScope | goTo(key), openDrawer / closeDrawer, openEndDrawer / closeEndDrawer, handleBack. |
Back button | Closes an open drawer, then goes back through pane history, then pops the route. |
Styling | VoDashboardTheme via componentTheme.dashboard or the style parameter. |