cronixui 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +16 -27
  2. package/package.json +2 -1
  3. package/packages/flutter/lib/cronixui.dart +41 -0
  4. package/packages/flutter/lib/src/tokens/colors.dart +34 -0
  5. package/packages/flutter/lib/src/tokens/spacing.dart +54 -0
  6. package/packages/flutter/lib/src/tokens/theme.dart +174 -0
  7. package/packages/flutter/lib/src/widgets/cn_accordion.dart +254 -0
  8. package/packages/flutter/lib/src/widgets/cn_alert.dart +137 -0
  9. package/packages/flutter/lib/src/widgets/cn_avatar.dart +98 -0
  10. package/packages/flutter/lib/src/widgets/cn_badge.dart +80 -0
  11. package/packages/flutter/lib/src/widgets/cn_breadcrumb.dart +88 -0
  12. package/packages/flutter/lib/src/widgets/cn_button.dart +137 -0
  13. package/packages/flutter/lib/src/widgets/cn_card.dart +99 -0
  14. package/packages/flutter/lib/src/widgets/cn_checkbox.dart +77 -0
  15. package/packages/flutter/lib/src/widgets/cn_command_palette.dart +299 -0
  16. package/packages/flutter/lib/src/widgets/cn_container.dart +131 -0
  17. package/packages/flutter/lib/src/widgets/cn_dropdown.dart +149 -0
  18. package/packages/flutter/lib/src/widgets/cn_file_input.dart +113 -0
  19. package/packages/flutter/lib/src/widgets/cn_footer.dart +108 -0
  20. package/packages/flutter/lib/src/widgets/cn_header.dart +173 -0
  21. package/packages/flutter/lib/src/widgets/cn_input.dart +142 -0
  22. package/packages/flutter/lib/src/widgets/cn_list.dart +150 -0
  23. package/packages/flutter/lib/src/widgets/cn_modal.dart +213 -0
  24. package/packages/flutter/lib/src/widgets/cn_nav.dart +157 -0
  25. package/packages/flutter/lib/src/widgets/cn_pagination.dart +193 -0
  26. package/packages/flutter/lib/src/widgets/cn_progress.dart +146 -0
  27. package/packages/flutter/lib/src/widgets/cn_radio.dart +133 -0
  28. package/packages/flutter/lib/src/widgets/cn_search.dart +183 -0
  29. package/packages/flutter/lib/src/widgets/cn_select.dart +244 -0
  30. package/packages/flutter/lib/src/widgets/cn_sidebar.dart +207 -0
  31. package/packages/flutter/lib/src/widgets/cn_skeleton.dart +136 -0
  32. package/packages/flutter/lib/src/widgets/cn_slider.dart +141 -0
  33. package/packages/flutter/lib/src/widgets/cn_spinner.dart +85 -0
  34. package/packages/flutter/lib/src/widgets/cn_stat.dart +135 -0
  35. package/packages/flutter/lib/src/widgets/cn_table.dart +136 -0
  36. package/packages/flutter/lib/src/widgets/cn_tabs.dart +229 -0
  37. package/packages/flutter/lib/src/widgets/cn_tag.dart +185 -0
  38. package/packages/flutter/lib/src/widgets/cn_textarea.dart +143 -0
  39. package/packages/flutter/lib/src/widgets/cn_toast.dart +121 -0
  40. package/packages/flutter/lib/src/widgets/cn_toggle.dart +78 -0
  41. package/packages/flutter/lib/src/widgets/cn_tooltip.dart +118 -0
  42. package/packages/flutter/pubspec.yaml +20 -0
package/README.md CHANGED
@@ -10,36 +10,15 @@ A multi-platform, multi-language UI toolkit with a dark theme, crimson accents,
10
10
  npm install cronixui
11
11
  ```
12
12
 
13
- ### React
13
+ ### React, Vue, Svelte, Solid
14
14
 
15
15
  ```bash
16
16
  npm install @cronixui/react
17
- ```
18
-
19
- ### Vue
20
-
21
- ```bash
22
17
  npm install @cronixui/vue
23
- ```
24
-
25
- ### Svelte
26
-
27
- ```bash
28
18
  npm install @cronixui/svelte
29
- ```
30
-
31
- ### Solid
32
-
33
- ```bash
34
19
  npm install @cronixui/solid
35
20
  ```
36
21
 
37
- ### Flutter
38
-
39
- ```bash
40
- flutter pub add cronixui
41
- ```
42
-
43
22
  ### Python
44
23
 
45
24
  ```bash
@@ -56,14 +35,24 @@ go get github.com/CazyUndee/CronixUI/packages/go/cronixui
56
35
 
57
36
  ```toml
58
37
  [dependencies]
59
- cronixui = "1.1.0"
38
+ cronixui = "1.1.2"
39
+ ```
40
+
41
+ ### Flutter
42
+
43
+ ```yaml
44
+ dependencies:
45
+ cronixui:
46
+ git:
47
+ url: https://github.com/CazyUndee/CronixUI.git
48
+ path: packages/flutter
60
49
  ```
61
50
 
62
51
  ### CDN
63
52
 
64
53
  ```html
65
- <link rel="stylesheet" href="https://unpkg.com/cronixui@1.1.0/packages/web/dist/cronixui.css">
66
- <script src="https://unpkg.com/cronixui@1.1.0/packages/web/dist/cronixui.js"></script>
54
+ <link rel="stylesheet" href="https://unpkg.com/cronixui@1.1.2/packages/web/dist/cronixui.css">
55
+ <script src="https://unpkg.com/cronixui@1.1.2/packages/web/dist/cronixui.js"></script>
67
56
  ```
68
57
 
69
58
  ## Quick Start (Web)
@@ -75,14 +64,14 @@ cronixui = "1.1.0"
75
64
  <meta charset="UTF-8">
76
65
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
77
66
  <title>My App</title>
78
- <link rel="stylesheet" href="https://unpkg.com/cronixui@1.1.0/packages/web/dist/cronixui.css">
67
+ <link rel="stylesheet" href="https://unpkg.com/cronixui@1.1.2/packages/web/dist/cronixui.css">
79
68
  </head>
80
69
  <body>
81
70
  <div class="cn-container">
82
71
  <h1 class="cn-h1">Hello, CronixUI!</h1>
83
72
  <button class="cn-btn cn-btn-primary">Get Started</button>
84
73
  </div>
85
- <script src="https://unpkg.com/cronixui@1.1.0/packages/web/dist/cronixui.js"></script>
74
+ <script src="https://unpkg.com/cronixui@1.1.2/packages/web/dist/cronixui.js"></script>
86
75
  </body>
87
76
  </html>
88
77
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cronixui",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "CronixUI - A dark-themed UI toolkit with crimson accents and Outfit typography. Available for JavaScript, TypeScript, Python, Go, and Rust.",
5
5
  "keywords": [
6
6
  "ui",
@@ -52,6 +52,7 @@
52
52
  "packages/python/cronixui/",
53
53
  "packages/go/cronixui/",
54
54
  "packages/rust/cronixui/src/",
55
+ "packages/flutter/",
55
56
  "README.md"
56
57
  ],
57
58
  "scripts": {
@@ -0,0 +1,41 @@
1
+ library cronixui;
2
+
3
+ export 'src/tokens/colors.dart';
4
+ export 'src/tokens/spacing.dart';
5
+ export 'src/tokens/theme.dart';
6
+
7
+ export 'src/widgets/cn_button.dart';
8
+ export 'src/widgets/cn_card.dart';
9
+ export 'src/widgets/cn_badge.dart';
10
+ export 'src/widgets/cn_input.dart';
11
+ export 'src/widgets/cn_textarea.dart';
12
+ export 'src/widgets/cn_checkbox.dart';
13
+ export 'src/widgets/cn_radio.dart';
14
+ export 'src/widgets/cn_select.dart';
15
+ export 'src/widgets/cn_slider.dart';
16
+ export 'src/widgets/cn_toggle.dart';
17
+ export 'src/widgets/cn_file_input.dart';
18
+ export 'src/widgets/cn_avatar.dart';
19
+ export 'src/widgets/cn_alert.dart';
20
+ export 'src/widgets/cn_spinner.dart';
21
+ export 'src/widgets/cn_skeleton.dart';
22
+ export 'src/widgets/cn_progress.dart';
23
+ export 'src/widgets/cn_table.dart';
24
+ export 'src/widgets/cn_list.dart';
25
+ export 'src/widgets/cn_tooltip.dart';
26
+ export 'src/widgets/cn_stat.dart';
27
+ export 'src/widgets/cn_modal.dart';
28
+ export 'src/widgets/cn_dropdown.dart';
29
+ export 'src/widgets/cn_tabs.dart';
30
+ export 'src/widgets/cn_accordion.dart';
31
+ export 'src/widgets/cn_toast.dart';
32
+ export 'src/widgets/cn_pagination.dart';
33
+ export 'src/widgets/cn_search.dart';
34
+ export 'src/widgets/cn_command_palette.dart';
35
+ export 'src/widgets/cn_nav.dart';
36
+ export 'src/widgets/cn_breadcrumb.dart';
37
+ export 'src/widgets/cn_container.dart';
38
+ export 'src/widgets/cn_header.dart';
39
+ export 'src/widgets/cn_sidebar.dart';
40
+ export 'src/widgets/cn_footer.dart';
41
+ export 'src/widgets/cn_tag.dart';
@@ -0,0 +1,34 @@
1
+ import 'package:flutter/material.dart';
2
+
3
+ class CronixColors {
4
+ static const Color background = Color(0xFF0a0a0a);
5
+ static const Color text = Color(0xFFf0ede8);
6
+ static const Color accent = Color(0xFF6b2323);
7
+
8
+ static const Color backgroundLight = Color(0xFF1a1a1a);
9
+ static const Color backgroundDark = Color(0xFF050505);
10
+ static const Color surface = Color(0xFF141414);
11
+ static const Color surfaceLight = Color(0xFF1f1f1f);
12
+
13
+ static const Color textSecondary = Color(0xFFa0a0a0);
14
+ static const Color textMuted = Color(0xFF666666);
15
+
16
+ static const Color accentLight = Color(0xFF8b3333);
17
+ static const Color accentDark = Color(0xFF4b1a1a);
18
+
19
+ static const Color success = Color(0xFF22c55e);
20
+ static const Color successDark = Color(0xFF16a34a);
21
+ static const Color warning = Color(0xFFeab308);
22
+ static const Color warningDark = Color(0xFFca8a04);
23
+ static const Color error = Color(0xFFef4444);
24
+ static const Color errorDark = Color(0xFFdc2626);
25
+ static const Color info = Color(0xFF3b82f6);
26
+ static const Color infoDark = Color(0xFF2563eb);
27
+
28
+ static const Color border = Color(0xFF2a2a2a);
29
+ static const Color borderLight = Color(0xFF3a3a3a);
30
+ static const Color divider = Color(0xFF222222);
31
+
32
+ static const Color shimmerBase = Color(0xFF1a1a1a);
33
+ static const Color shimmerHighlight = Color(0xFF2a2a2a);
34
+ }
@@ -0,0 +1,54 @@
1
+ import 'package:flutter/material.dart';
2
+
3
+ class CronixSpacing {
4
+ static const double xxs = 2.0;
5
+ static const double xs = 4.0;
6
+ static const double sm = 8.0;
7
+ static const double md = 16.0;
8
+ static const double lg = 24.0;
9
+ static const double xl = 32.0;
10
+ static const double xxl = 48.0;
11
+ static const double xxxl = 64.0;
12
+
13
+ static const EdgeInsets paddingNone = EdgeInsets.zero;
14
+ static const EdgeInsets paddingXS = EdgeInsets.all(xs);
15
+ static const EdgeInsets paddingSM = EdgeInsets.all(sm);
16
+ static const EdgeInsets paddingMD = EdgeInsets.all(md);
17
+ static const EdgeInsets paddingLG = EdgeInsets.all(lg);
18
+ static const EdgeInsets paddingXL = EdgeInsets.all(xl);
19
+
20
+ static const EdgeInsets paddingHorizontalSM = EdgeInsets.symmetric(horizontal: sm);
21
+ static const EdgeInsets paddingHorizontalMD = EdgeInsets.symmetric(horizontal: md);
22
+ static const EdgeInsets paddingHorizontalLG = EdgeInsets.symmetric(horizontal: lg);
23
+
24
+ static const EdgeInsets paddingVerticalSM = EdgeInsets.symmetric(vertical: sm);
25
+ static const EdgeInsets paddingVerticalMD = EdgeInsets.symmetric(vertical: md);
26
+ static const EdgeInsets paddingVerticalLG = EdgeInsets.symmetric(vertical: lg);
27
+
28
+ static const SizedBox hXS = SizedBox(width: xs);
29
+ static const SizedBox hSM = SizedBox(width: sm);
30
+ static const SizedBox hMD = SizedBox(width: md);
31
+ static const SizedBox hLG = SizedBox(width: lg);
32
+ static const SizedBox hXL = SizedBox(width: xl);
33
+
34
+ static const SizedBox vXS = SizedBox(height: xs);
35
+ static const SizedBox vSM = SizedBox(height: sm);
36
+ static const SizedBox vMD = SizedBox(height: md);
37
+ static const SizedBox vLG = SizedBox(height: lg);
38
+ static const SizedBox vXL = SizedBox(height: xl);
39
+ }
40
+
41
+ class CronixRadius {
42
+ static const double none = 0;
43
+ static const double sm = 4.0;
44
+ static const double md = 8.0;
45
+ static const double lg = 12.0;
46
+ static const double xl = 16.0;
47
+ static const double full = 9999.0;
48
+
49
+ static const BorderRadius radiusSM = BorderRadius.all(Radius.circular(sm));
50
+ static const BorderRadius radiusMD = BorderRadius.all(Radius.circular(md));
51
+ static const BorderRadius radiusLG = BorderRadius.all(Radius.circular(lg));
52
+ static const BorderRadius radiusXL = BorderRadius.all(Radius.circular(xl));
53
+ static const BorderRadius radiusFull = BorderRadius.all(Radius.circular(full));
54
+ }
@@ -0,0 +1,174 @@
1
+ import 'package:flutter/material.dart';
2
+ import 'colors.dart';
3
+ import 'spacing.dart';
4
+
5
+ class CronixTheme {
6
+ static ThemeData get dark {
7
+ return ThemeData(
8
+ useMaterial3: true,
9
+ brightness: Brightness.dark,
10
+ scaffoldBackgroundColor: CronixColors.background,
11
+ colorScheme: ColorScheme.dark(
12
+ primary: CronixColors.accent,
13
+ secondary: CronixColors.accentLight,
14
+ surface: CronixColors.surface,
15
+ error: CronixColors.error,
16
+ onPrimary: CronixColors.text,
17
+ onSecondary: CronixColors.text,
18
+ onSurface: CronixColors.text,
19
+ onError: CronixColors.text,
20
+ ),
21
+ textTheme: _buildTextTheme(),
22
+ appBarTheme: AppBarTheme(
23
+ backgroundColor: CronixColors.background,
24
+ foregroundColor: CronixColors.text,
25
+ elevation: 0,
26
+ scrolledUnderElevation: 1,
27
+ ),
28
+ cardTheme: CardTheme(
29
+ color: CronixColors.surface,
30
+ elevation: 0,
31
+ shape: RoundedRectangleBorder(
32
+ borderRadius: CronixRadius.radiusMD,
33
+ side: const BorderSide(color: CronixColors.border),
34
+ ),
35
+ ),
36
+ elevatedButtonTheme: ElevatedButtonThemeData(
37
+ style: ElevatedButton.styleFrom(
38
+ backgroundColor: CronixColors.accent,
39
+ foregroundColor: CronixColors.text,
40
+ shape: RoundedRectangleBorder(
41
+ borderRadius: CronixRadius.radiusMD,
42
+ ),
43
+ padding: CronixSpacing.paddingHorizontalMD.copyWith(
44
+ top: CronixSpacing.sm,
45
+ bottom: CronixSpacing.sm,
46
+ ),
47
+ ),
48
+ ),
49
+ inputDecorationTheme: InputDecorationTheme(
50
+ filled: true,
51
+ fillColor: CronixColors.surface,
52
+ border: OutlineInputBorder(
53
+ borderRadius: CronixRadius.radiusMD,
54
+ borderSide: const BorderSide(color: CronixColors.border),
55
+ ),
56
+ enabledBorder: OutlineInputBorder(
57
+ borderRadius: CronixRadius.radiusMD,
58
+ borderSide: const BorderSide(color: CronixColors.border),
59
+ ),
60
+ focusedBorder: OutlineInputBorder(
61
+ borderRadius: CronixRadius.radiusMD,
62
+ borderSide: const BorderSide(color: CronixColors.accent, width: 2),
63
+ ),
64
+ contentPadding: CronixSpacing.paddingSM,
65
+ ),
66
+ dividerTheme: const DividerThemeData(
67
+ color: CronixColors.divider,
68
+ thickness: 1,
69
+ ),
70
+ dialogTheme: DialogTheme(
71
+ backgroundColor: CronixColors.surface,
72
+ shape: RoundedRectangleBorder(
73
+ borderRadius: CronixRadius.radiusLG,
74
+ ),
75
+ ),
76
+ snackBarTheme: SnackBarThemeData(
77
+ backgroundColor: CronixColors.surfaceLight,
78
+ contentTextStyle: TextStyle(color: CronixColors.text),
79
+ shape: RoundedRectangleBorder(
80
+ borderRadius: CronixRadius.radiusMD,
81
+ ),
82
+ ),
83
+ );
84
+ }
85
+
86
+ static TextTheme _buildTextTheme() {
87
+ return TextTheme(
88
+ displayLarge: TextStyle(
89
+ fontSize: 57,
90
+ fontWeight: FontWeight.w400,
91
+ color: CronixColors.text,
92
+ letterSpacing: -0.25,
93
+ ),
94
+ displayMedium: TextStyle(
95
+ fontSize: 45,
96
+ fontWeight: FontWeight.w400,
97
+ color: CronixColors.text,
98
+ ),
99
+ displaySmall: TextStyle(
100
+ fontSize: 36,
101
+ fontWeight: FontWeight.w400,
102
+ color: CronixColors.text,
103
+ ),
104
+ headlineLarge: TextStyle(
105
+ fontSize: 32,
106
+ fontWeight: FontWeight.w600,
107
+ color: CronixColors.text,
108
+ ),
109
+ headlineMedium: TextStyle(
110
+ fontSize: 28,
111
+ fontWeight: FontWeight.w600,
112
+ color: CronixColors.text,
113
+ ),
114
+ headlineSmall: TextStyle(
115
+ fontSize: 24,
116
+ fontWeight: FontWeight.w600,
117
+ color: CronixColors.text,
118
+ ),
119
+ titleLarge: TextStyle(
120
+ fontSize: 22,
121
+ fontWeight: FontWeight.w500,
122
+ color: CronixColors.text,
123
+ ),
124
+ titleMedium: TextStyle(
125
+ fontSize: 16,
126
+ fontWeight: FontWeight.w500,
127
+ color: CronixColors.text,
128
+ letterSpacing: 0.15,
129
+ ),
130
+ titleSmall: TextStyle(
131
+ fontSize: 14,
132
+ fontWeight: FontWeight.w500,
133
+ color: CronixColors.text,
134
+ letterSpacing: 0.1,
135
+ ),
136
+ bodyLarge: TextStyle(
137
+ fontSize: 16,
138
+ fontWeight: FontWeight.w400,
139
+ color: CronixColors.text,
140
+ letterSpacing: 0.5,
141
+ ),
142
+ bodyMedium: TextStyle(
143
+ fontSize: 14,
144
+ fontWeight: FontWeight.w400,
145
+ color: CronixColors.text,
146
+ letterSpacing: 0.25,
147
+ ),
148
+ bodySmall: TextStyle(
149
+ fontSize: 12,
150
+ fontWeight: FontWeight.w400,
151
+ color: CronixColors.textSecondary,
152
+ letterSpacing: 0.4,
153
+ ),
154
+ labelLarge: TextStyle(
155
+ fontSize: 14,
156
+ fontWeight: FontWeight.w500,
157
+ color: CronixColors.text,
158
+ letterSpacing: 0.1,
159
+ ),
160
+ labelMedium: TextStyle(
161
+ fontSize: 12,
162
+ fontWeight: FontWeight.w500,
163
+ color: CronixColors.text,
164
+ letterSpacing: 0.5,
165
+ ),
166
+ labelSmall: TextStyle(
167
+ fontSize: 11,
168
+ fontWeight: FontWeight.w500,
169
+ color: CronixColors.textSecondary,
170
+ letterSpacing: 0.5,
171
+ ),
172
+ );
173
+ }
174
+ }
@@ -0,0 +1,254 @@
1
+ import 'package:flutter/material.dart';
2
+ import '../tokens/colors.dart';
3
+ import '../tokens/spacing.dart';
4
+
5
+ class CnAccordionItem {
6
+ final String title;
7
+ final Widget content;
8
+ final IconData? leadingIcon;
9
+ final bool initiallyExpanded;
10
+
11
+ const CnAccordionItem({
12
+ required this.title,
13
+ required this.content,
14
+ this.leadingIcon,
15
+ this.initiallyExpanded = false,
16
+ });
17
+ }
18
+
19
+ class CnAccordion extends StatelessWidget {
20
+ final List<CnAccordionItem> items;
21
+ final bool allowMultiple;
22
+ final Color? backgroundColor;
23
+ final Color? headerBackgroundColor;
24
+
25
+ const CnAccordion({
26
+ super.key,
27
+ required this.items,
28
+ this.allowMultiple = false,
29
+ this.backgroundColor,
30
+ this.headerBackgroundColor,
31
+ });
32
+
33
+ @override
34
+ Widget build(BuildContext context) {
35
+ if (allowMultiple) {
36
+ return Column(
37
+ children: items.asMap().entries.map((entry) {
38
+ return Padding(
39
+ padding: EdgeInsets.only(
40
+ bottom: entry.key < items.length - 1 ? 1 : 0,
41
+ ),
42
+ child: _CnAccordionItem(
43
+ item: entry.value,
44
+ backgroundColor: backgroundColor,
45
+ headerBackgroundColor: headerBackgroundColor,
46
+ ),
47
+ );
48
+ }).toList(),
49
+ );
50
+ }
51
+
52
+ return _CnAccordionGroup(
53
+ items: items,
54
+ backgroundColor: backgroundColor,
55
+ headerBackgroundColor: headerBackgroundColor,
56
+ );
57
+ }
58
+ }
59
+
60
+ class _CnAccordionGroup extends StatefulWidget {
61
+ final List<CnAccordionItem> items;
62
+ final Color? backgroundColor;
63
+ final Color? headerBackgroundColor;
64
+
65
+ const _CnAccordionGroup({
66
+ required this.items,
67
+ this.backgroundColor,
68
+ this.headerBackgroundColor,
69
+ });
70
+
71
+ @override
72
+ State<_CnAccordionGroup> createState() => _CnAccordionGroupState();
73
+ }
74
+
75
+ class _CnAccordionGroupState extends State<_CnAccordionGroup> {
76
+ int? _expandedIndex;
77
+
78
+ @override
79
+ void initState() {
80
+ super.initState();
81
+ for (int i = 0; i < widget.items.length; i++) {
82
+ if (widget.items[i].initiallyExpanded) {
83
+ _expandedIndex = i;
84
+ break;
85
+ }
86
+ }
87
+ }
88
+
89
+ @override
90
+ Widget build(BuildContext context) {
91
+ return Column(
92
+ children: widget.items.asMap().entries.map((entry) {
93
+ final index = entry.key;
94
+ final item = entry.value;
95
+ final isExpanded = _expandedIndex == index;
96
+
97
+ return Padding(
98
+ padding: EdgeInsets.only(
99
+ bottom: index < widget.items.length - 1 ? 1 : 0,
100
+ ),
101
+ child: Container(
102
+ decoration: BoxDecoration(
103
+ color: widget.backgroundColor ?? CronixColors.surface,
104
+ border: Border.all(color: CronixColors.border),
105
+ borderRadius: CronixRadius.radiusMD,
106
+ ),
107
+ child: Column(
108
+ children: [
109
+ InkWell(
110
+ onTap: () {
111
+ setState(() {
112
+ _expandedIndex = isExpanded ? null : index;
113
+ });
114
+ },
115
+ child: Container(
116
+ padding: const EdgeInsets.all(16),
117
+ child: Row(
118
+ children: [
119
+ if (item.leadingIcon != null) ...[
120
+ Icon(
121
+ item.leadingIcon,
122
+ size: 20,
123
+ color: CronixColors.textSecondary,
124
+ ),
125
+ const SizedBox(width: 12),
126
+ ],
127
+ Expanded(
128
+ child: Text(
129
+ item.title,
130
+ style: const TextStyle(
131
+ color: CronixColors.text,
132
+ fontSize: 14,
133
+ fontWeight: FontWeight.w500,
134
+ ),
135
+ ),
136
+ ),
137
+ Icon(
138
+ isExpanded
139
+ ? Icons.keyboard_arrow_up
140
+ : Icons.keyboard_arrow_down,
141
+ color: CronixColors.textSecondary,
142
+ ),
143
+ ],
144
+ ),
145
+ ),
146
+ ),
147
+ AnimatedCrossFade(
148
+ firstChild: const SizedBox.shrink(),
149
+ secondChild: Container(
150
+ width: double.infinity,
151
+ padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
152
+ child: item.content,
153
+ ),
154
+ crossFadeState: isExpanded
155
+ ? CrossFadeState.showSecond
156
+ : CrossFadeState.showFirst,
157
+ duration: const Duration(milliseconds: 200),
158
+ ),
159
+ ],
160
+ ),
161
+ ),
162
+ );
163
+ }).toList(),
164
+ );
165
+ }
166
+ }
167
+
168
+ class _CnAccordionItem extends StatefulWidget {
169
+ final CnAccordionItem item;
170
+ final Color? backgroundColor;
171
+ final Color? headerBackgroundColor;
172
+
173
+ const _CnAccordionItem({
174
+ required this.item,
175
+ this.backgroundColor,
176
+ this.headerBackgroundColor,
177
+ });
178
+
179
+ @override
180
+ State<_CnAccordionItem> createState() => _CnAccordionItemState();
181
+ }
182
+
183
+ class _CnAccordionItemState extends State<_CnAccordionItem> {
184
+ bool _isExpanded = false;
185
+
186
+ @override
187
+ void initState() {
188
+ super.initState();
189
+ _isExpanded = widget.item.initiallyExpanded;
190
+ }
191
+
192
+ @override
193
+ Widget build(BuildContext context) {
194
+ return Container(
195
+ decoration: BoxDecoration(
196
+ color: widget.backgroundColor ?? CronixColors.surface,
197
+ border: Border.all(color: CronixColors.border),
198
+ borderRadius: CronixRadius.radiusMD,
199
+ ),
200
+ child: Column(
201
+ children: [
202
+ InkWell(
203
+ onTap: () {
204
+ setState(() => _isExpanded = !_isExpanded);
205
+ },
206
+ child: Container(
207
+ padding: const EdgeInsets.all(16),
208
+ child: Row(
209
+ children: [
210
+ if (widget.item.leadingIcon != null) ...[
211
+ Icon(
212
+ widget.item.leadingIcon,
213
+ size: 20,
214
+ color: CronixColors.textSecondary,
215
+ ),
216
+ const SizedBox(width: 12),
217
+ ],
218
+ Expanded(
219
+ child: Text(
220
+ widget.item.title,
221
+ style: const TextStyle(
222
+ color: CronixColors.text,
223
+ fontSize: 14,
224
+ fontWeight: FontWeight.w500,
225
+ ),
226
+ ),
227
+ ),
228
+ Icon(
229
+ _isExpanded
230
+ ? Icons.keyboard_arrow_up
231
+ : Icons.keyboard_arrow_down,
232
+ color: CronixColors.textSecondary,
233
+ ),
234
+ ],
235
+ ),
236
+ ),
237
+ ),
238
+ AnimatedCrossFade(
239
+ firstChild: const SizedBox.shrink(),
240
+ secondChild: Container(
241
+ width: double.infinity,
242
+ padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
243
+ child: widget.item.content,
244
+ ),
245
+ crossFadeState: _isExpanded
246
+ ? CrossFadeState.showSecond
247
+ : CrossFadeState.showFirst,
248
+ duration: const Duration(milliseconds: 200),
249
+ ),
250
+ ],
251
+ ),
252
+ );
253
+ }
254
+ }