bkey_uikit

Pub Version Flutter Dart License

A shared Flutter UI component library for Bkey products, built on top of the BMoni design system.

bkey_uikit provides design tokens, typography, theming, and reusable UI primitives that are used across Bkey Flutter apps. It has no dependency on any specific app's business logic, state management, routing, or localisation framework.


๐Ÿ“‹ What's Inside

Layer Contents
Design Tokens BMoniColors โ€” full colour palette + semantic light/dark tokens
BMoniTextStyles โ€” complete type scale (display, heading, body, label)
BMoniTheme โ€” Flutter ThemeData factory + TextTheme wiring
Enums Button, text-field, display, and status enums shared by all components
Components Buttons, text fields, text widgets, avatars, toasts, bottom sheets, empty states, loaders, layout primitives, and wallet cards
Fonts Rethink Sans (400โ€“800, regular + italic) bundled in assets/fonts/
Wallet Assets Default wallet background art (USD/NGN/EUR/GBP/CAD/MXN/consolidated) plus 6 colour variants per currency, and shared SVG icons (logo_alt, info, eye_alt, eye_closed) bundled in assets/images/wallets/ and assets/svgs/

๐Ÿš€ Installation

Add bkey_uikit as a dependency in your pubspec.yaml:

dependencies:
  bkey_uikit: ^0.0.1

(Note: Adjust the installation instructions based on whether the package is published publicly or via a private git repository/path).


๐Ÿ› ๏ธ Setup

Wrap your app with BMoniTheme.darkTheme() (or the appropriate theme) to apply the full design system:

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

void main() {
  runApp(
    MaterialApp(
      theme: BMoniTheme.darkTheme(),
      home: const MyHomePage(),
    ),
  );
}

Import everything from a single barrel file:

import 'package:bkey_uikit/bkey_uikit.dart';

๐ŸŽจ Design Tokens

Colours

Container(color: BMoniColors.brand500)
Container(color: context.colors.bg.greySubtle) // theme-aware extension

Typography

Text('Hello', style: BMoniTextStyles.h4Semibold)
Text('Body', style: BMoniTextStyles.p2Regular)

๐Ÿงฉ Components Reference

Every component below is exported from the single package:bkey_uikit/bkey_uikit.dart barrel.

Buttons & Actions

BMoniButton

Primary action button with four visual variants and five sizes. Supports leading/trailing icons, loading state, and per-instance colour overrides. Triggers a light haptic on press.

BMoniButton(
  onPressed: () {},
  text: 'Confirm',
  variant: BMoniButtonVariant.primary,   // primary | secondary | outline | ghost
  size: BMoniButtonSize.large,            // extraSmall | small | medium | large | custom
  icon: Icons.check,
  iconPosition: BMoniButtonIconPosition.leading,
  isLoading: false,
  isDisabled: false,
)

// Convenience factories
BMoniButton.primary(onPressed: () {}, text: 'Save')
BMoniButton.secondary(onPressed: () {}, text: 'Edit')
BMoniButton.outline(onPressed: () {}, text: 'Cancel')
BMoniButton.ghost(onPressed: () {}, text: 'Skip')

UtilityButton

Square icon-only button used for compact toolbar actions.

UtilityButton(
  onTap: () {},
  size: 36,
  backgroundColor: BMoniColors.brand600,
  icon: const Icon(Icons.add, color: Colors.white, size: 24),
)

SwipeableActionRow

Row that reveals an action button when swiped left. A shared ValueNotifier<String?> ensures only one row is open at a time within a list.

final openItemId = ValueNotifier<String?>(null);

SwipeableActionRow(
  itemId: 'item-1',
  openItemId: openItemId,
  actionWidth: 72,
  actionColor: Colors.red,
  actionIcon: const Icon(Icons.delete, color: Colors.white),
  onActionPressed: () {/* delete */},
  onTap: () {/* open detail */},
  child: ListTile(title: Text('Swipe me left')),
)

Text & Typography

Helper widgets that wrap Text with the BMoni type scale.

DisplayText('Welcome', level: 2, weight: DisplayWeight.bold)
HeadingText('Page title', level: 3, weight: HeadingWeight.semibold)
BodyText('Lorem ipsum', size: BodySize.medium, weight: BodyWeight.regular)
LabelText('Caption', size: LabelSize.small, weight: LabelWeight.medium)

// Domain-specific helpers
AmountText(1234.56, currency: r'$', decimalPlaces: 2)
StatusText('Pending', status: StatusType.warning)

ReadMoreText

Collapsible text widget with length- or line-based trimming, custom toggle labels, RegExp-based annotations, and rich-text support.

ReadMoreText(
  longString,
  trimMode: TrimMode.line,
  trimLines: 3,
  trimCollapsedText: 'read more',
  trimExpandedText: 'show less',
  onExpandChanged: (isExpanded) {},
)

Inputs & Forms

BMoniTextFormField

Form field with two variants (filled and outlined), three sizes, label/helper/error slots, and prefix/suffix widgets.

BMoniTextFormField.filled(
  label: 'Email',
  hintText: 'you@example.com',
  keyboardType: TextInputType.emailAddress,
  size: BMoniTextFieldSize.medium,
  prefixIcon: const Icon(Icons.mail_outline),
  validator: (value) => value!.isEmpty ? 'Required' : null,
)

BMoniTextFormField.outlined(
  label: 'Reference',
  hintText: 'INV-001',
)

BMoniTextAreaField

Multiline note input with a built-in grapheme-aware character counter.

BMoniTextAreaField(
  controller: _noteController,
  label: 'Add a note',
  hintText: 'Optional message',
  maxLength: 120,
  maxLines: 4,
)

FileUploadWidget

Dotted-border upload area. Switches between placeholder, loading, and uploaded states.

FileUploadWidget(
  fileBytes: bytes,
  fileName: 'invoice.pdf',
  isLoading: false,
  onTap: pickFile,
  onRemove: () => setState(() => bytes = null),
  errorMessage: validationError,
)

Avatars & Images

ProfileAvatar & ChatAvatar

ProfileAvatar(imageUrl: user.avatarUrl, name: user.fullName, size: 48)

ChatAvatar(
  imageUrl: null,
  name: 'Alice Doe',
  userId: 'u_123',
  size: 40,
)

ProfileImageWidget

Tap-aware profile image that supports network URLs, asset paths, and local files. Caches network images.

ProfileImageWidget(
  imageUrl: profile.imageUrl,
  radius: 40,
  onTap: pickNewAvatar,
)

Layout & Containers

ActivitySectionCard & SectionHeader

ActivitySectionCard(
  header: const SectionHeader(
    title: 'Recent activity',
    trailing: Text('View all'),
  ),
  child: const Padding(
    padding: EdgeInsets.all(16),
    child: Text('Section content'),
  ),
  footer: const Divider(),
)

InfoCard

Inline informational/warning/tip card.

InfoCard(
  message: 'Your KYC is being reviewed.',
  title: 'In review',
  icon: Icons.info_outline,
)

CustomAppBar

Scaffold(
  appBar: CustomAppBar(
    title: 'Settings',
    showBackButton: true,
    actions: [IconButton(onPressed: () {}, icon: const Icon(Icons.help))],
  ),
)

Sheets & Overlays

BMoniBottomSheet.show & BMoniTitledBottomSheet

final result = await BMoniBottomSheet.show<String>(
  context: context,
  child: const BMoniTitledBottomSheet(
    title: 'Choose option',
    children: [/* ... */],
  ),
);

BMoniOptionsBottomSheet

BMoniOptionsBottomSheet(
  title: 'More actions',
  options: [
    BMoniBottomSheetOption(icon: 'assets/svgs/edit.svg', title: 'Edit', onTap: () {}),
    BMoniBottomSheetOption(icon: 'assets/svgs/delete.svg', title: 'Delete', onTap: () {}),
  ],
)

SelectorBottomSheet<T> & SearchableSelectorBottomSheet<T>

final picked = await BMoniBottomSheet.show<Currency>(
  context: context,
  child: SelectorBottomSheet<Currency>(
    items: currencies,
    selected: current,
    title: 'Choose currency',
    label: (c) => c.name,
    value: (c) => c.code,
    icon: (c) => c.flagAsset,
    showIcon: true,
  ),
);

Feedback & Status

BMoniToast and BMoniToastOverlay

BMoniToastOverlay.showSuccess(
  context: context,
  message: 'Payment sent!',
  title: 'Success',
);

BMoniToastOverlay.showError(context: context, message: 'Network error');

EmptyState, FailureWidget, & InProgressWidget

EmptyState(
  svgAsset: 'assets/svgs/empty_box.svg',
  message: 'No transactions yet',
  subtitle: 'Send or receive funds to get started',
  buttonText: 'Add money',
  onButtonPressed: () {},
)

Loaders

const ProgressLoaderWidget() // Square branded loading container
const ChasingDots() // Three small white dots animating

Wallet Cards

BMoniWalletCard

A 250px-tall card with a configurable background, a top-left logo slot, an optional bottom-right info button, a centred balance slot, and a built-in scale-down press animation.

BMoniWalletCard(
  background: const BMoniWalletCardBackground.type(BMoniWalletType.usd),
  onInfoTap: () => showWalletDetails(),
  reserveBottomSpaceForPageIndicator: hasMultiplePages,
  balanceChild: BMoniWalletCardBalance(
    wholePart: r'$1,234',
    decimalPart: '.56',
    isHidden: isBalanceHidden,
    onToggleHidden: toggleHideBalance,
  ),
)

๐Ÿงช Testing

Run the tests using the standard Flutter test command:

flutter test

๐Ÿ’ก Example

A complete component gallery lives in the example/ directory. It boots straight into a navigable list of every widget grouped by category (buttons, inputs, sheets, wallet cards, feedback, โ€ฆ) and is themed with BMoniTheme.darkTheme().

cd example
flutter pub get
flutter run

๐Ÿ“„ License

Copyright 2026 Bkey, Inc.

Licensed under the Apache License, Version 2.0 โ€” you may use, modify, and distribute the SDK (including in proprietary applications) provided you preserve the copyright and license notices and comply with the terms in the LICENSE file.

For commercial support or enterprise inquiries, contact developers@bkey.me.

Libraries

bkey_uikit
BKey UI Kit โ€” shared Flutter component library.