kin_ui 1.7.1
kin_ui: ^1.7.1 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 ────────────────────────────────────────────────────────
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
final lightTheme = KinTheme.inkLight;
final darkTheme = KinTheme.inkDark;
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
brightness: Brightness.light,
scaffoldBackgroundColor: lightTheme.surface,
colorScheme: ColorScheme.light(
primary: lightTheme.primary,
surface: lightTheme.surface,
onSurface: lightTheme.onSurface,
outline: lightTheme.outline,
error: lightTheme.destructive,
),
extensions: [lightTheme],
),
darkTheme: ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
scaffoldBackgroundColor: darkTheme.surface,
colorScheme: ColorScheme.dark(
primary: darkTheme.primary,
surface: darkTheme.surface,
onSurface: darkTheme.onSurface,
outline: darkTheme.outline,
error: darkTheme.destructive,
),
extensions: [darkTheme],
),
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,
),
),
],
),
],
);
}
}