ui-ux-consultant-cli 1.0.0-beta.1
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.
- package/assets/ui-ux-consultant/SKILL.md +844 -0
- package/assets/ui-ux-consultant/references/accessibility.md +175 -0
- package/assets/ui-ux-consultant/references/alt-libraries.md +90 -0
- package/assets/ui-ux-consultant/references/animations.md +448 -0
- package/assets/ui-ux-consultant/references/catalog/colors.md +91 -0
- package/assets/ui-ux-consultant/references/catalog/fonts.md +363 -0
- package/assets/ui-ux-consultant/references/catalog/products.md +340 -0
- package/assets/ui-ux-consultant/references/catalog/styles.md +165 -0
- package/assets/ui-ux-consultant/references/components.md +1116 -0
- package/assets/ui-ux-consultant/references/patterns.md +600 -0
- package/assets/ui-ux-consultant/references/performance.md +198 -0
- package/assets/ui-ux-consultant/references/stacks/astro.md +382 -0
- package/assets/ui-ux-consultant/references/stacks/flutter.md +308 -0
- package/assets/ui-ux-consultant/references/stacks/html-tailwind.md +415 -0
- package/assets/ui-ux-consultant/references/stacks/jetpack-compose.md +333 -0
- package/assets/ui-ux-consultant/references/stacks/laravel.md +521 -0
- package/assets/ui-ux-consultant/references/stacks/nextjs.md +275 -0
- package/assets/ui-ux-consultant/references/stacks/nuxt-ui.md +384 -0
- package/assets/ui-ux-consultant/references/stacks/nuxtjs.md +264 -0
- package/assets/ui-ux-consultant/references/stacks/react-native.md +346 -0
- package/assets/ui-ux-consultant/references/stacks/react.md +268 -0
- package/assets/ui-ux-consultant/references/stacks/shadcn.md +485 -0
- package/assets/ui-ux-consultant/references/stacks/svelte.md +429 -0
- package/assets/ui-ux-consultant/references/stacks/swiftui.md +336 -0
- package/assets/ui-ux-consultant/references/stacks/threejs.md +366 -0
- package/assets/ui-ux-consultant/references/stacks/vue.md +272 -0
- package/assets/ui-ux-consultant/references/theming.md +701 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +130 -0
- package/package.json +51 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Flutter Reference
|
|
2
|
+
|
|
3
|
+
## When to Read
|
|
4
|
+
Read this file when building Flutter (Dart) apps — widgets, state management, navigation, theming, lists, animation, or accessibility.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Recommended Libraries
|
|
9
|
+
|
|
10
|
+
| Library | Purpose | Install |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Riverpod | Async state, testability | `flutter pub add flutter_riverpod` |
|
|
13
|
+
| GoRouter | Declarative navigation | `flutter pub add go_router` |
|
|
14
|
+
| Freezed | Immutable data classes | `flutter pub add freezed` |
|
|
15
|
+
| Dio | HTTP client | `flutter pub add dio` |
|
|
16
|
+
| Hive / Isar | Local storage | `flutter pub add hive_flutter` |
|
|
17
|
+
| flutter_hooks | React-hooks-style utilities | `flutter pub add flutter_hooks` |
|
|
18
|
+
| cached_network_image | Image caching | `flutter pub add cached_network_image` |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Style Recommendations
|
|
23
|
+
|
|
24
|
+
- Material 3 (`useMaterial3: true`) for all new projects — M2 is legacy
|
|
25
|
+
- Use `ColorScheme.fromSeed` — never hardcode color roles
|
|
26
|
+
- `Inter` or `Plus Jakarta Sans` for modern sans-serif feel
|
|
27
|
+
- 8dp grid for spacing constants
|
|
28
|
+
- Avoid deeply nested `Padding`/`SizedBox` trees — extract sub-widgets
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## State Management Options
|
|
33
|
+
|
|
34
|
+
| Approach | Best for |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `setState` | Simple local state |
|
|
37
|
+
| Provider | App-wide state, medium complexity |
|
|
38
|
+
| Riverpod | Complex async state, testability |
|
|
39
|
+
| Bloc | Enterprise, strict unidirectional flow |
|
|
40
|
+
| GetX | Simple + routing (avoid in large apps) |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Top UX Patterns (with Code)
|
|
45
|
+
|
|
46
|
+
### Stateless widget with const constructor
|
|
47
|
+
```dart
|
|
48
|
+
class UserCard extends StatelessWidget {
|
|
49
|
+
const UserCard({ super.key, required this.user });
|
|
50
|
+
final User user;
|
|
51
|
+
|
|
52
|
+
@override
|
|
53
|
+
Widget build(BuildContext context) {
|
|
54
|
+
return Card(
|
|
55
|
+
child: ListTile(
|
|
56
|
+
leading: CircleAvatar(child: Text(user.initials)),
|
|
57
|
+
title: Text(user.name),
|
|
58
|
+
subtitle: Text(user.email),
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Riverpod async data
|
|
66
|
+
```dart
|
|
67
|
+
final usersProvider = FutureProvider<List<User>>(
|
|
68
|
+
(ref) => ref.watch(apiProvider).getUsers(),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// In widget:
|
|
72
|
+
final users = ref.watch(usersProvider);
|
|
73
|
+
return users.when(
|
|
74
|
+
data: (list) => ListView.builder(
|
|
75
|
+
itemCount: list.length,
|
|
76
|
+
itemBuilder: (_, i) => UserCard(user: list[i]),
|
|
77
|
+
),
|
|
78
|
+
loading: () => const CircularProgressIndicator(),
|
|
79
|
+
error: (e, _) => Text('Error: $e'),
|
|
80
|
+
);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Responsive layout
|
|
84
|
+
```dart
|
|
85
|
+
LayoutBuilder(
|
|
86
|
+
builder: (context, constraints) {
|
|
87
|
+
if (constraints.maxWidth > 600) {
|
|
88
|
+
return Row(children: [Sidebar(), Expanded(child: Content())]);
|
|
89
|
+
}
|
|
90
|
+
return Column(children: [Content()]);
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### ListView.builder (lazy — always for lists > 20 items)
|
|
96
|
+
```dart
|
|
97
|
+
ListView.builder(
|
|
98
|
+
itemCount: items.length,
|
|
99
|
+
itemBuilder: (context, index) => ItemTile(item: items[index]),
|
|
100
|
+
)
|
|
101
|
+
// NOT: ListView(children: items.map(...).toList())
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### const constructors (prevents unnecessary rebuilds)
|
|
105
|
+
```dart
|
|
106
|
+
const Icon(Icons.star, color: Colors.amber)
|
|
107
|
+
const SizedBox(height: 16)
|
|
108
|
+
const Text('Static label')
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Navigation with GoRouter
|
|
112
|
+
```dart
|
|
113
|
+
final router = GoRouter(routes: [
|
|
114
|
+
GoRoute(
|
|
115
|
+
path: '/',
|
|
116
|
+
builder: (ctx, state) => const HomeScreen(),
|
|
117
|
+
),
|
|
118
|
+
GoRoute(
|
|
119
|
+
path: '/users/:id',
|
|
120
|
+
builder: (ctx, state) => UserScreen(
|
|
121
|
+
id: state.pathParameters['id']!,
|
|
122
|
+
),
|
|
123
|
+
),
|
|
124
|
+
]);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Material 3 theming
|
|
128
|
+
```dart
|
|
129
|
+
MaterialApp.router(
|
|
130
|
+
theme: ThemeData(
|
|
131
|
+
useMaterial3: true,
|
|
132
|
+
colorScheme: ColorScheme.fromSeed(
|
|
133
|
+
seedColor: const Color(0xFF2563EB),
|
|
134
|
+
),
|
|
135
|
+
fontFamily: 'Inter',
|
|
136
|
+
),
|
|
137
|
+
darkTheme: ThemeData(
|
|
138
|
+
useMaterial3: true,
|
|
139
|
+
colorScheme: ColorScheme.fromSeed(
|
|
140
|
+
seedColor: const Color(0xFF2563EB),
|
|
141
|
+
brightness: Brightness.dark,
|
|
142
|
+
),
|
|
143
|
+
),
|
|
144
|
+
routerConfig: router,
|
|
145
|
+
)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Accessible icon button
|
|
149
|
+
```dart
|
|
150
|
+
Semantics(
|
|
151
|
+
label: 'Delete item',
|
|
152
|
+
button: true,
|
|
153
|
+
child: IconButton(
|
|
154
|
+
icon: const Icon(Icons.delete),
|
|
155
|
+
onPressed: onDelete,
|
|
156
|
+
),
|
|
157
|
+
)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### StatefulWidget with controller disposal
|
|
161
|
+
```dart
|
|
162
|
+
class SearchField extends StatefulWidget {
|
|
163
|
+
const SearchField({super.key});
|
|
164
|
+
|
|
165
|
+
@override
|
|
166
|
+
State<SearchField> createState() => _SearchFieldState();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
class _SearchFieldState extends State<SearchField> {
|
|
170
|
+
final _controller = TextEditingController();
|
|
171
|
+
|
|
172
|
+
@override
|
|
173
|
+
void dispose() {
|
|
174
|
+
_controller.dispose(); // always dispose
|
|
175
|
+
super.dispose();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@override
|
|
179
|
+
Widget build(BuildContext context) {
|
|
180
|
+
return TextField(controller: _controller);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Animation with dispose
|
|
186
|
+
```dart
|
|
187
|
+
class FadeInWidget extends StatefulWidget {
|
|
188
|
+
const FadeInWidget({super.key, required this.child});
|
|
189
|
+
final Widget child;
|
|
190
|
+
|
|
191
|
+
@override
|
|
192
|
+
State<FadeInWidget> createState() => _FadeInWidgetState();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
class _FadeInWidgetState extends State<FadeInWidget>
|
|
196
|
+
with SingleTickerProviderStateMixin {
|
|
197
|
+
late final AnimationController _controller = AnimationController(
|
|
198
|
+
vsync: this,
|
|
199
|
+
duration: const Duration(milliseconds: 300),
|
|
200
|
+
)..forward();
|
|
201
|
+
|
|
202
|
+
@override
|
|
203
|
+
void dispose() {
|
|
204
|
+
_controller.dispose();
|
|
205
|
+
super.dispose();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
@override
|
|
209
|
+
Widget build(BuildContext context) {
|
|
210
|
+
return FadeTransition(
|
|
211
|
+
opacity: _controller,
|
|
212
|
+
child: widget.child,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### RepaintBoundary for heavy widgets
|
|
219
|
+
```dart
|
|
220
|
+
RepaintBoundary(
|
|
221
|
+
child: HeavyAnimatedChart(),
|
|
222
|
+
)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Best Practices by Category
|
|
228
|
+
|
|
229
|
+
### Widgets
|
|
230
|
+
- Prefer `StatelessWidget`; reach for `StatefulWidget` only when local mutation is needed
|
|
231
|
+
- Always provide `super.key` in constructors
|
|
232
|
+
- Extract widgets into separate classes — not methods — for proper rebuild isolation
|
|
233
|
+
- Use `const` on every widget that doesn't reference mutable state
|
|
234
|
+
- Prefer `Column`/`Row` + `Expanded` over `Stack` for linear layouts
|
|
235
|
+
|
|
236
|
+
### State
|
|
237
|
+
- `setState` only for local UI state (toggle, text input)
|
|
238
|
+
- Lift state with Riverpod providers when 2+ widgets share it
|
|
239
|
+
- Avoid `setState` inside `initState` — schedule with `WidgetsBinding.instance.addPostFrameCallback`
|
|
240
|
+
- Keep Riverpod providers small and single-responsibility
|
|
241
|
+
- Use `ref.invalidate(provider)` to force refresh
|
|
242
|
+
|
|
243
|
+
### Layout & Sizing
|
|
244
|
+
- Use `MediaQuery.of(context).size` for screen dimensions
|
|
245
|
+
- `LayoutBuilder` for component-relative sizing
|
|
246
|
+
- 8dp spacing scale: 4, 8, 12, 16, 24, 32, 48
|
|
247
|
+
- Avoid hardcoded pixel sizes for text — use `Theme.of(context).textTheme`
|
|
248
|
+
- `SafeArea` wraps all top-level screens
|
|
249
|
+
|
|
250
|
+
### Lists
|
|
251
|
+
- `ListView.builder` for any list that might exceed ~20 items
|
|
252
|
+
- `SliverList` inside `CustomScrollView` for complex scrollable layouts
|
|
253
|
+
- `pageStorageKey` to preserve scroll position across tab switches
|
|
254
|
+
- `CachedNetworkImage` for list item images (caches aggressively)
|
|
255
|
+
|
|
256
|
+
### Navigation
|
|
257
|
+
- GoRouter for all routing — supports deep links and web
|
|
258
|
+
- Pass typed objects via `extra` parameter, not raw strings where possible
|
|
259
|
+
- `context.go()` replaces stack; `context.push()` adds to stack
|
|
260
|
+
- Handle `GoRouter.errorBuilder` for 404 screens
|
|
261
|
+
|
|
262
|
+
### Animation
|
|
263
|
+
- `AnimatedContainer`, `AnimatedOpacity` for simple implicit animations
|
|
264
|
+
- `AnimationController` + `AnimatedBuilder` for explicit control
|
|
265
|
+
- Always call `_controller.dispose()` in `dispose()`
|
|
266
|
+
- Use `Curves.easeInOut` as default — avoid linear for UI animations
|
|
267
|
+
- `Hero` for shared element transitions between routes
|
|
268
|
+
|
|
269
|
+
### Theming
|
|
270
|
+
- Never use raw `Color(0xFF...)` in widgets — use `colorScheme.primary` etc.
|
|
271
|
+
- `Theme.of(context).textTheme.bodyLarge` not hardcoded font sizes
|
|
272
|
+
- Define custom extensions on `ThemeData` for brand tokens
|
|
273
|
+
|
|
274
|
+
### Accessibility
|
|
275
|
+
- `Semantics` wrapper on any icon-only interactive element
|
|
276
|
+
- `excludeFromSemantics: true` on decorative images
|
|
277
|
+
- `MergeSemantics` to group related widgets for screen readers
|
|
278
|
+
- Support system font scaling — no `textScaleFactor` overrides
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Common Anti-Patterns
|
|
283
|
+
|
|
284
|
+
1. `ListView(children: longList.map(...).toList())` — renders all at once; use `ListView.builder`
|
|
285
|
+
2. Non-const constructors for static widgets — unnecessary rebuilds every parent rebuild
|
|
286
|
+
3. `setState` for deeply nested or shared state — prop drilling; use Provider/Riverpod
|
|
287
|
+
4. No `dispose()` for controllers, animations, streams — memory leaks accumulate over time
|
|
288
|
+
5. Hardcoded sizes without `MediaQuery` — breaks on different screen densities and tablets
|
|
289
|
+
6. Missing `Semantics` on icon buttons — invisible to screen readers; VoiceOver announces nothing
|
|
290
|
+
7. Logic inside `build()` — move to computed getters or provider selectors
|
|
291
|
+
8. `print()` in production — use a proper logger (`logger` package)
|
|
292
|
+
9. Catching `Exception` broadly without logging — hides bugs silently
|
|
293
|
+
10. Multiple `Scaffold` in a widget tree — only one per route
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Performance Checklist
|
|
298
|
+
|
|
299
|
+
- [ ] `const` on all widgets that don't depend on state
|
|
300
|
+
- [ ] `ListView.builder` (never `ListView` with full `children` list for long content)
|
|
301
|
+
- [ ] `dispose()` all `AnimationController`, `ScrollController`, `StreamSubscription`, `TextEditingController`
|
|
302
|
+
- [ ] `RepaintBoundary` around heavy animated widgets
|
|
303
|
+
- [ ] `useMaterial3: true` in ThemeData
|
|
304
|
+
- [ ] `flutter build apk --split-per-abi` for smaller Android bundles
|
|
305
|
+
- [ ] `cached_network_image` for remote images in lists
|
|
306
|
+
- [ ] Profile in `flutter run --profile` mode — never trust debug mode performance
|
|
307
|
+
- [ ] `const` constructors defined on all custom widgets
|
|
308
|
+
- [ ] `LayoutBuilder` not `MediaQuery` for responsive components inside flex layouts
|