bloom_ui 0.2.0
bloom_ui: ^0.2.0 copied to clipboard
Reusable, accessible, token-driven Flutter UI primitives inspired by shadcn/ui with zero runtime dependencies.
import 'package:bloom_ui/bloom_ui.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const BloomUiExampleApp());
}
class BloomUiExampleApp extends StatefulWidget {
const BloomUiExampleApp({super.key});
@override
State<BloomUiExampleApp> createState() => _BloomUiExampleAppState();
}
class _BloomUiExampleAppState extends State<BloomUiExampleApp> {
ThemeMode _themeMode = ThemeMode.light;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bloom UI Showcase',
debugShowCheckedModeBanner: false,
themeMode: _themeMode,
theme: ThemeData(
brightness: Brightness.light,
scaffoldBackgroundColor: const Color(0xFFFAFAFA),
extensions: const [BloomTheme.light],
),
darkTheme: ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: const Color(0xFF030509),
extensions: const [BloomTheme.dark],
),
home: ShowcaseScreen(
isDark: _themeMode == ThemeMode.dark,
onToggleTheme: () {
setState(() {
_themeMode = _themeMode == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark;
});
},
),
);
}
}
class ShowcaseScreen extends StatefulWidget {
final bool isDark;
final VoidCallback onToggleTheme;
const ShowcaseScreen({
super.key,
required this.isDark,
required this.onToggleTheme,
});
@override
State<ShowcaseScreen> createState() => _ShowcaseScreenState();
}
class _ShowcaseScreenState extends State<ShowcaseScreen> {
bool _switchVal = true;
bool? _checkVal = true;
double _sliderVal = 0.45;
String _selectVal = 'nova';
@override
Widget build(BuildContext context) {
final colors = context.bloomColors;
return Scaffold(
appBar: AppBar(
title: const Row(
children: [
Text('🌸 Bloom UI', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
SizedBox(width: 8),
BloomBadge(
variant: BloomBadgeVariant.secondary,
size: BloomBadgeSize.sm,
child: Text('v0.1.0'),
),
],
),
actions: [
IconButton(
icon: Icon(widget.isDark ? Icons.light_mode : Icons.dark_mode),
onPressed: widget.onToggleTheme,
),
const SizedBox(width: 8),
],
elevation: 0,
backgroundColor: Colors.transparent,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 800),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Cards & Forms
BloomCard(
header: const BloomCardHeader(
title: BloomCardTitle('Interactive Primitives'),
description: BloomCardDescription('Zero-dependency Flutter widgets styled with shadcn base-nova.'),
),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Wrap(
spacing: 8,
runSpacing: 8,
children: [
BloomButton(
variant: BloomButtonVariant.defaultVariant,
onPressed: () {
BloomSonner.success(context, 'Primary action clicked!');
},
child: const Text('Default'),
),
BloomButton(
variant: BloomButtonVariant.secondary,
onPressed: () {},
child: const Text('Secondary'),
),
BloomButton(
variant: BloomButtonVariant.outline,
onPressed: () {},
child: const Text('Outline'),
),
BloomButton(
variant: BloomButtonVariant.ghost,
onPressed: () {},
child: const Text('Ghost'),
),
BloomButton(
variant: BloomButtonVariant.destructive,
onPressed: () {
BloomSonner.error(context, 'Destructive event triggered.');
},
child: const Text('Destructive'),
),
],
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: BloomInput(
placeholder: 'Search components...',
leading: const Icon(Icons.search, size: 16),
),
),
const SizedBox(width: 8),
BloomSelect<String>(
value: _selectVal,
items: const [
BloomSelectItem(value: 'nova', label: 'Nova'),
BloomSelectItem(value: 'vega', label: 'Vega'),
BloomSelectItem(value: 'lyra', label: 'Lyra'),
],
onChanged: (v) => setState(() => _selectVal = v!),
),
],
),
const SizedBox(height: 16),
Row(
children: [
BloomCheckbox(
checked: _checkVal,
label: const Text('Enabled'),
onChanged: (v) => setState(() => _checkVal = v),
),
const SizedBox(width: 16),
BloomSwitch(
checked: _switchVal,
label: const Text('Notifications'),
onChanged: (v) => setState(() => _switchVal = v),
),
],
),
const SizedBox(height: 16),
BloomSlider(
value: _sliderVal,
onChanged: (v) => setState(() => _sliderVal = v),
),
],
),
footer: BloomCardFooter(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
BloomButton(
variant: BloomButtonVariant.outline,
size: BloomButtonSize.sm,
onPressed: () {},
child: const Text('Reset'),
),
const SizedBox(width: 8),
BloomButton(
size: BloomButtonSize.sm,
onPressed: () {
BloomSonner.success(context, 'Saved preferences!');
},
child: const Text('Save Changes'),
),
],
),
),
),
const SizedBox(height: 24),
// Charts demo
BloomCard(
header: const BloomCardHeader(
title: BloomCardTitle('Pure Dart Charts'),
description: BloomCardDescription('Responsive area and bar charts with drag tooltip tracking.'),
),
content: BloomChart(
type: BloomChartType.area,
height: 220,
data: BloomChartData(
labels: const ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
series: [
BloomChartSeries(
name: 'Desktop',
values: const [186, 305, 237, 73, 209, 214],
color: colors.primary,
),
BloomChartSeries(
name: 'Mobile',
values: const [80, 200, 120, 190, 130, 140],
color: BloomColors.petalPink,
),
],
),
),
),
],
),
),
),
),
);
}
}