kin_ui 1.3.0
kin_ui: ^1.3.0 copied to clipboard
A Native inspired Flutter design system. Tokens, primitives, components, adaptive shell, and templates out of the box.
example/main.dart
import 'package:flutter/material.dart';
import 'package:kin_ui/kin_ui.dart';
// ── Theme ────────────────────────────────────────────────────────
const _light = KinTheme(
primary: Color(0xFFE84141),
primaryContainer: Color(0xFFFBE8DA),
surface: Color(0xFFF2EEE8),
surfaceVariant: Color(0xFFFCF7F1),
onSurface: Color(0xFF231B15),
onSurfaceVariant: Color(0xFF655C54),
outline: Color(0xFFDCCFC4),
destructive: Color(0xFFFF453A),
);
const _dark = KinTheme(
primary: Color(0xFFE84141),
primaryContainer: Color(0xFF5C2222),
surface: Color(0xFF0A0A0A),
surfaceVariant: Color(0xFF1C1C1C),
onSurface: Color(0xFFF5F5F5),
onSurfaceVariant: Color(0xFF8E8E8E),
outline: Color(0xFF2C2C2C),
destructive: Color(0xFFFF453A),
);
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.light,
scaffoldBackgroundColor: _light.surface,
extensions: const [_light],
),
darkTheme: ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: _dark.surface,
extensions: const [_dark],
),
home: const KinApp(child: _Shell()),
);
}
}
// ── Shell with adaptive navigation ───────────────────────────────
class _Shell extends StatefulWidget {
const _Shell();
@override
State<_Shell> createState() => _ShellState();
}
class _ShellState extends State<_Shell> {
int _tab = 0;
static const _navItems = [
KinNavItem(icon: Icons.home_rounded, label: 'Home', activeIcon: Icons.home),
KinNavItem(icon: Icons.bar_chart_rounded, label: 'Stats'),
KinNavItem(icon: Icons.settings_rounded, label: 'Settings'),
];
@override
Widget build(BuildContext context) {
return KinScaffold(
navItems: _navItems,
currentIndex: _tab,
onIndexChanged: (i) => setState(() => _tab = i),
body: switch (_tab) {
0 => const _HomePage(),
1 => const _StatsPage(),
_ => const _SettingsPage(),
},
);
}
}
// ── Home ─────────────────────────────────────────────────────────
class _HomePage extends StatelessWidget {
const _HomePage();
@override
Widget build(BuildContext context) {
final theme = KinTheme.of(context);
return KinFeedTemplate(
title: 'Home',
children: [
// Buttons
Wrap(
spacing: KinSpacing.sm,
runSpacing: KinSpacing.sm,
children: [
KinButton(label: 'Primary', onTap: () {}),
KinButton(label: 'Secondary', variant: KinButtonVariant.secondary, onTap: () {}),
KinButton(label: 'Ghost', variant: KinButtonVariant.ghost, onTap: () {}),
],
),
const SizedBox(height: KinSpacing.lg),
// Cards
KinCard(
child: Padding(
padding: const EdgeInsets.all(KinSpacing.md),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
KinText.titleMedium('Welcome to KinUI', color: theme.onSurface),
const SizedBox(height: KinSpacing.xs),
KinText.bodyMedium(
'A warm, native-inspired design system for Flutter.',
color: theme.onSurfaceVariant,
),
],
),
),
),
const SizedBox(height: KinSpacing.md),
// Toggle & Slider
KinCard(
child: Padding(
padding: const EdgeInsets.all(KinSpacing.md),
child: Column(
children: [
_ToggleRow(),
const SizedBox(height: KinSpacing.md),
_SliderRow(),
],
),
),
),
const SizedBox(height: KinSpacing.md),
// Chips
Wrap(
spacing: KinSpacing.sm,
children: const [
KinChip(label: 'Flutter', isSelected: true),
KinChip(label: 'Dart'),
KinChip(label: 'Design'),
],
),
],
);
}
}
class _ToggleRow extends StatefulWidget {
@override
State<_ToggleRow> createState() => _ToggleRowState();
}
class _ToggleRowState extends State<_ToggleRow> {
bool _on = false;
@override
Widget build(BuildContext context) {
final theme = KinTheme.of(context);
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
KinText.bodyLarge('Notifications', color: theme.onSurface),
KinPremiumToggle(value: _on, onChanged: (v) => setState(() => _on = v)),
],
);
}
}
class _SliderRow extends StatefulWidget {
@override
State<_SliderRow> createState() => _SliderRowState();
}
class _SliderRowState extends State<_SliderRow> {
double _val = 0.5;
@override
Widget build(BuildContext context) {
final theme = KinTheme.of(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
KinText.bodyMedium('Volume', color: theme.onSurface),
KinText.bodyMedium('${(_val * 100).round()}%', color: theme.onSurfaceVariant),
],
),
const SizedBox(height: KinSpacing.sm),
KinSlider(value: _val, onChanged: (v) => setState(() => _val = v)),
],
);
}
}
// ── Stats ────────────────────────────────────────────────────────
class _StatsPage extends StatelessWidget {
const _StatsPage();
static const _entries = [
KinChartEntry(label: 'Mon', value: 40),
KinChartEntry(label: 'Tue', value: 70),
KinChartEntry(label: 'Wed', value: 55),
KinChartEntry(label: 'Thu', value: 90),
KinChartEntry(label: 'Fri', value: 65),
];
@override
Widget build(BuildContext context) {
return KinDashboardTemplate(
title: 'Stats',
stats: [
_StatCard(label: 'Users', value: '1.2k'),
_StatCard(label: 'Revenue', value: '\$8.4k'),
_StatCard(label: 'Growth', value: '+12%'),
],
feed: [
KinCard(
child: Padding(
padding: const EdgeInsets.all(KinSpacing.md),
child: KinChart.bar(entries: _entries, height: 180),
),
),
const SizedBox(height: KinSpacing.md),
KinCard(
child: Padding(
padding: const EdgeInsets.all(KinSpacing.md),
child: KinChart.line(
entries: _entries,
height: 160,
lineStyle: KinChartLineStyle.smooth,
),
),
),
],
);
}
}
class _StatCard extends StatelessWidget {
final String label;
final String value;
const _StatCard({required this.label, required this.value});
@override
Widget build(BuildContext context) {
final theme = KinTheme.of(context);
return KinCard(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: KinSpacing.lg,
vertical: KinSpacing.md,
),
child: Column(
children: [
KinText.labelSmall(label, color: theme.onSurfaceVariant),
const SizedBox(height: KinSpacing.xs),
KinText.titleLarge(value, color: theme.onSurface),
],
),
),
);
}
}
// ── Settings ─────────────────────────────────────────────────────
class _SettingsPage extends StatelessWidget {
const _SettingsPage();
@override
Widget build(BuildContext context) {
final theme = KinTheme.of(context);
return KinSettingsTemplate(
title: 'Settings',
sections: [
KinSettingsSection(
header: 'Account',
children: [
KinListTile(
title: 'Profile',
subtitle: 'Edit your personal info',
leading: Icon(Icons.person_rounded, color: theme.onSurfaceVariant),
trailing: Icon(Icons.chevron_right, color: theme.onSurfaceVariant),
onTap: () {},
),
KinListTile(
title: 'Privacy',
leading: Icon(Icons.lock_rounded, color: theme.onSurfaceVariant),
trailing: Icon(Icons.chevron_right, color: theme.onSurfaceVariant),
onTap: () {},
),
],
),
KinSettingsSection(
header: 'About',
children: [
KinListTile(
title: 'Version',
trailing: KinText.bodyMedium('1.2.0', color: theme.onSurfaceVariant),
),
],
),
],
);
}
}