@the-bearded-bear/claude-craft 8.8.1 → 8.8.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 (79) hide show
  1. package/Dev/i18n/de/Angular/commands/check-compliance.md +218 -168
  2. package/Dev/i18n/de/Common/agents/refactoring-specialist.md +146 -69
  3. package/Dev/i18n/de/Common/commands/add-technology.md +166 -68
  4. package/Dev/i18n/de/Common/commands/setup-ci.md +216 -33
  5. package/Dev/i18n/de/Laravel/commands/check-compliance.md +223 -115
  6. package/Dev/i18n/de/Python/checklists/new-feature.md +319 -44
  7. package/Dev/i18n/de/React/rules/02-architecture.md +483 -322
  8. package/Dev/i18n/de/React/rules/03-coding-standards.md +584 -368
  9. package/Dev/i18n/de/Symfony/commands/check-compliance.md +186 -114
  10. package/Dev/i18n/de/Symfony/rules/07-testing-symfony.md +679 -10
  11. package/Dev/i18n/de/UIUX/commands/a11y-component.md +284 -26
  12. package/Dev/i18n/de/UIUX/commands/design-tokens.md +199 -35
  13. package/Dev/i18n/de/UIUX/commands/user-flow.md +179 -16
  14. package/Dev/i18n/de/VueJS/commands/check-compliance.md +227 -102
  15. package/Dev/i18n/es/Angular/commands/check-compliance.md +217 -167
  16. package/Dev/i18n/es/Common/commands/add-technology.md +158 -60
  17. package/Dev/i18n/es/Laravel/commands/check-compliance.md +223 -115
  18. package/Dev/i18n/es/React/commands/check-testing.md +263 -169
  19. package/Dev/i18n/es/ReactNative/commands/check-testing.md +256 -198
  20. package/Dev/i18n/es/Symfony/commands/check-compliance.md +189 -117
  21. package/Dev/i18n/es/Symfony/commands/check-testing.md +301 -102
  22. package/Dev/i18n/es/Symfony/commands/migration-plan.md +267 -34
  23. package/Dev/i18n/es/UIUX/commands/a11y-component.md +274 -16
  24. package/Dev/i18n/es/UIUX/commands/design-tokens.md +186 -22
  25. package/Dev/i18n/es/UIUX/commands/user-flow.md +173 -10
  26. package/Dev/i18n/es/VueJS/commands/check-compliance.md +227 -102
  27. package/Dev/i18n/fr/Angular/commands/check-compliance.md +217 -167
  28. package/Dev/i18n/fr/Common/commands/ralph-run.md +138 -60
  29. package/Dev/i18n/fr/Laravel/commands/check-compliance.md +223 -115
  30. package/Dev/i18n/fr/React/commands/check-architecture.md +370 -53
  31. package/Dev/i18n/fr/React/commands/check-code-quality.md +454 -64
  32. package/Dev/i18n/fr/React/commands/check-testing.md +476 -102
  33. package/Dev/i18n/fr/Symfony/commands/check-compliance.md +188 -116
  34. package/Dev/i18n/fr/VueJS/commands/check-compliance.md +227 -102
  35. package/Dev/i18n/pt/Angular/commands/check-compliance.md +225 -175
  36. package/Dev/i18n/pt/Common/agents/ralph-conductor.md +211 -30
  37. package/Dev/i18n/pt/Common/commands/add-technology.md +149 -51
  38. package/Dev/i18n/pt/Common/commands/ralph-run.md +239 -35
  39. package/Dev/i18n/pt/Flutter/commands/analyze-performance.md +331 -46
  40. package/Dev/i18n/pt/Flutter/commands/check-compliance.md +234 -29
  41. package/Dev/i18n/pt/Flutter/commands/generate-feature.md +526 -51
  42. package/Dev/i18n/pt/Flutter/commands/generate-widget.md +515 -27
  43. package/Dev/i18n/pt/Flutter/commands/golden-update.md +322 -46
  44. package/Dev/i18n/pt/Flutter/commands/localization-check.md +278 -37
  45. package/Dev/i18n/pt/Laravel/commands/check-compliance.md +212 -104
  46. package/Dev/i18n/pt/React/commands/accessibility-check.md +151 -42
  47. package/Dev/i18n/pt/React/commands/bundle-analyze.md +300 -25
  48. package/Dev/i18n/pt/React/commands/check-architecture.md +369 -34
  49. package/Dev/i18n/pt/React/commands/check-code-quality.md +440 -34
  50. package/Dev/i18n/pt/React/commands/check-compliance.md +232 -62
  51. package/Dev/i18n/pt/React/commands/check-security.md +370 -31
  52. package/Dev/i18n/pt/React/commands/check-testing.md +473 -43
  53. package/Dev/i18n/pt/React/commands/generate-component.md +454 -19
  54. package/Dev/i18n/pt/React/commands/generate-hook.md +425 -24
  55. package/Dev/i18n/pt/React/commands/storybook-story.md +520 -35
  56. package/Dev/i18n/pt/ReactNative/commands/app-size.md +358 -387
  57. package/Dev/i18n/pt/ReactNative/commands/check-code-quality.md +246 -75
  58. package/Dev/i18n/pt/ReactNative/commands/check-compliance.md +191 -85
  59. package/Dev/i18n/pt/ReactNative/commands/check-security.md +363 -115
  60. package/Dev/i18n/pt/ReactNative/commands/check-testing.md +269 -79
  61. package/Dev/i18n/pt/ReactNative/commands/generate-screen.md +491 -324
  62. package/Dev/i18n/pt/ReactNative/commands/native-module.md +539 -82
  63. package/Dev/i18n/pt/ReactNative/commands/store-prepare.md +429 -185
  64. package/Dev/i18n/pt/ReactNative/rules/02-architecture.md +1084 -31
  65. package/Dev/i18n/pt/Symfony/commands/check-compliance.md +195 -123
  66. package/Dev/i18n/pt/UIUX/commands/a11y-audit.md +208 -24
  67. package/Dev/i18n/pt/UIUX/commands/a11y-component.md +281 -23
  68. package/Dev/i18n/pt/UIUX/commands/design-tokens.md +197 -33
  69. package/Dev/i18n/pt/UIUX/commands/user-flow.md +183 -20
  70. package/Dev/i18n/pt/VueJS/commands/check-compliance.md +228 -103
  71. package/Dev/i18n/pt/Workflow/commands/analyze.md +147 -146
  72. package/Dev/i18n/pt/Workflow/commands/design.md +205 -204
  73. package/Dev/i18n/pt/Workflow/commands/implement.md +184 -184
  74. package/Project/i18n/de/Sprint/commands/dev.md +339 -86
  75. package/Project/i18n/es/Sprint/commands/dev.md +342 -91
  76. package/Project/i18n/pt/Sprint/commands/dev.md +343 -92
  77. package/bundles/cursor/.cursorrules +1 -1
  78. package/bundles/windsurf/.windsurfrules +1 -1
  79. package/package.json +1 -1
@@ -1,73 +1,561 @@
1
1
  ---
2
- description: Gerar Widget Flutter
2
+ description: Geração de Widget Flutter com Testes
3
+ argument-hint: [arguments]
3
4
  ---
4
5
 
5
- # Gerar Widget Flutter
6
+ # Geração de Widget Flutter com Testes
6
7
 
7
- Gere um widget Flutter com testes e documentação.
8
+ Você é um desenvolvedor Flutter sênior. Você deve gerar um widget reutilizável com documentação, testes unitários e widget tests.
8
9
 
9
- ## Entrada
10
+ ## Argumentos
11
+ $ARGUMENTS
10
12
 
11
- - Nome do widget (ex: "CustomButton")
12
- - Tipo: [stateless, stateful, consumer]
13
- - Localização: lib/features/{feature}/presentation/widgets/
13
+ Argumentos:
14
+ - Nome do widget (ex: `CustomButton`, `UserCard`)
15
+ - (Opcional) Tipo (stateless, stateful, hook)
14
16
 
15
- ## Modo Plano
17
+ Exemplo: `/flutter:generate-widget UserCard stateless`
16
18
 
17
- > **O modo plano é obrigatório.** Antes de executar, Claude ativa o modo plano para analisar o código impactado, propor um plano de implementação e aguardar sua validação antes de realizar qualquer alteração.
19
+ ## Plan Mode
18
20
 
19
- ## Gerar
21
+ > **O modo de planejamento é obrigatório.** Antes de executar, o Claude ativa o modo de planejamento para analisar o código impactado, propor um plano de implementação e aguardar sua validação antes de realizar qualquer alteração.
20
22
 
21
- ### 1. Widget
23
+ ## MISSÃO
22
24
 
25
+ ### Etapa 1: Criar o Widget
26
+
27
+ #### StatelessWidget
23
28
  ```dart
24
- // lib/.../widgets/{widget_name}.dart
29
+ // lib/shared/widgets/{widget_name}.dart
25
30
  import 'package:flutter/material.dart';
26
31
 
27
- /// Descrição do widget
32
+ /// Um widget que exibe {description}.
33
+ ///
34
+ /// Exemplo de uso:
35
+ /// ```dart
36
+ /// {WidgetName}(
37
+ /// title: 'Meu título',
38
+ /// onTap: () => print('Tapped'),
39
+ /// )
40
+ /// ```
28
41
  class {WidgetName} extends StatelessWidget {
42
+ /// O título exibido no widget.
43
+ final String title;
44
+
45
+ /// O subtítulo opcional.
46
+ final String? subtitle;
47
+
48
+ /// O ícone exibido à esquerda.
49
+ final IconData? leadingIcon;
50
+
51
+ /// Callback chamado ao tocar.
52
+ final VoidCallback? onTap;
53
+
54
+ /// Indica se o widget está habilitado.
55
+ final bool isEnabled;
56
+
57
+ /// Cria um novo [{WidgetName}].
29
58
  const {WidgetName}({
30
59
  super.key,
31
- required this.param1,
60
+ required this.title,
61
+ this.subtitle,
62
+ this.leadingIcon,
63
+ this.onTap,
64
+ this.isEnabled = true,
32
65
  });
33
66
 
34
- final Type param1;
67
+ @override
68
+ Widget build(BuildContext context) {
69
+ final theme = Theme.of(context);
70
+
71
+ return Semantics(
72
+ button: onTap != null,
73
+ enabled: isEnabled,
74
+ child: Material(
75
+ color: Colors.transparent,
76
+ child: InkWell(
77
+ onTap: isEnabled ? onTap : null,
78
+ borderRadius: BorderRadius.circular(12),
79
+ child: Container(
80
+ padding: const EdgeInsets.all(16),
81
+ decoration: BoxDecoration(
82
+ color: theme.cardColor,
83
+ borderRadius: BorderRadius.circular(12),
84
+ boxShadow: [
85
+ BoxShadow(
86
+ color: Colors.black.withOpacity(0.05),
87
+ blurRadius: 10,
88
+ offset: const Offset(0, 2),
89
+ ),
90
+ ],
91
+ ),
92
+ child: Row(
93
+ children: [
94
+ if (leadingIcon != null) ...[
95
+ Icon(
96
+ leadingIcon,
97
+ color: isEnabled
98
+ ? theme.colorScheme.primary
99
+ : theme.disabledColor,
100
+ ),
101
+ const SizedBox(width: 12),
102
+ ],
103
+ Expanded(
104
+ child: Column(
105
+ crossAxisAlignment: CrossAxisAlignment.start,
106
+ children: [
107
+ Text(
108
+ title,
109
+ style: theme.textTheme.titleMedium?.copyWith(
110
+ color: isEnabled ? null : theme.disabledColor,
111
+ ),
112
+ ),
113
+ if (subtitle != null) ...[
114
+ const SizedBox(height: 4),
115
+ Text(
116
+ subtitle!,
117
+ style: theme.textTheme.bodySmall?.copyWith(
118
+ color: theme.textTheme.bodySmall?.color
119
+ ?.withOpacity(0.7),
120
+ ),
121
+ ),
122
+ ],
123
+ ],
124
+ ),
125
+ ),
126
+ if (onTap != null)
127
+ Icon(
128
+ Icons.chevron_right,
129
+ color: isEnabled
130
+ ? theme.colorScheme.onSurface.withOpacity(0.5)
131
+ : theme.disabledColor,
132
+ ),
133
+ ],
134
+ ),
135
+ ),
136
+ ),
137
+ ),
138
+ );
139
+ }
140
+ }
141
+ ```
142
+
143
+ #### StatefulWidget (com animação)
144
+ ```dart
145
+ // lib/shared/widgets/{widget_name}.dart
146
+ import 'package:flutter/material.dart';
147
+
148
+ class {WidgetName} extends StatefulWidget {
149
+ final String title;
150
+ final bool isExpanded;
151
+ final Widget child;
152
+ final ValueChanged<bool>? onExpansionChanged;
153
+
154
+ const {WidgetName}({
155
+ super.key,
156
+ required this.title,
157
+ this.isExpanded = false,
158
+ required this.child,
159
+ this.onExpansionChanged,
160
+ });
161
+
162
+ @override
163
+ State<{WidgetName}> createState() => _{WidgetName}State();
164
+ }
165
+
166
+ class _{WidgetName}State extends State<{WidgetName}>
167
+ with SingleTickerProviderStateMixin {
168
+ late AnimationController _controller;
169
+ late Animation<double> _heightFactor;
170
+ late Animation<double> _iconTurns;
171
+
172
+ bool _isExpanded = false;
173
+
174
+ @override
175
+ void initState() {
176
+ super.initState();
177
+ _isExpanded = widget.isExpanded;
178
+
179
+ _controller = AnimationController(
180
+ duration: const Duration(milliseconds: 200),
181
+ vsync: this,
182
+ );
183
+
184
+ _heightFactor = _controller.drive(CurveTween(curve: Curves.easeIn));
185
+ _iconTurns = _controller.drive(
186
+ Tween<double>(begin: 0.0, end: 0.5).chain(
187
+ CurveTween(curve: Curves.easeIn),
188
+ ),
189
+ );
190
+
191
+ if (_isExpanded) {
192
+ _controller.value = 1.0;
193
+ }
194
+ }
195
+
196
+ @override
197
+ void dispose() {
198
+ _controller.dispose();
199
+ super.dispose();
200
+ }
201
+
202
+ void _handleTap() {
203
+ setState(() {
204
+ _isExpanded = !_isExpanded;
205
+ if (_isExpanded) {
206
+ _controller.forward();
207
+ } else {
208
+ _controller.reverse();
209
+ }
210
+ widget.onExpansionChanged?.call(_isExpanded);
211
+ });
212
+ }
35
213
 
36
214
  @override
37
215
  Widget build(BuildContext context) {
38
- return Container();
216
+ final theme = Theme.of(context);
217
+
218
+ return AnimatedBuilder(
219
+ animation: _controller,
220
+ builder: (context, child) {
221
+ return Column(
222
+ mainAxisSize: MainAxisSize.min,
223
+ children: [
224
+ InkWell(
225
+ onTap: _handleTap,
226
+ child: Padding(
227
+ padding: const EdgeInsets.all(16),
228
+ child: Row(
229
+ children: [
230
+ Expanded(
231
+ child: Text(
232
+ widget.title,
233
+ style: theme.textTheme.titleMedium,
234
+ ),
235
+ ),
236
+ RotationTransition(
237
+ turns: _iconTurns,
238
+ child: const Icon(Icons.expand_more),
239
+ ),
240
+ ],
241
+ ),
242
+ ),
243
+ ),
244
+ ClipRect(
245
+ child: Align(
246
+ heightFactor: _heightFactor.value,
247
+ child: child,
248
+ ),
249
+ ),
250
+ ],
251
+ );
252
+ },
253
+ child: widget.child,
254
+ );
39
255
  }
40
256
  }
41
257
  ```
42
258
 
43
- ### 2. Teste de Widget
259
+ ### Etapa 2: Testes
44
260
 
261
+ #### Widget Test
45
262
  ```dart
46
- // test/.../widgets/{widget_name}_test.dart
263
+ // test/shared/widgets/{widget_name}_test.dart
47
264
  import 'package:flutter/material.dart';
48
265
  import 'package:flutter_test/flutter_test.dart';
266
+ import 'package:app/shared/widgets/{widget_name}.dart';
49
267
 
50
268
  void main() {
51
269
  group('{WidgetName}', () {
52
- testWidgets('should render correctly', (tester) async {
270
+ testWidgets('renders correctly with required props', (tester) async {
271
+ await tester.pumpWidget(
272
+ const MaterialApp(
273
+ home: Scaffold(
274
+ body: {WidgetName}(
275
+ title: 'Test Title',
276
+ ),
277
+ ),
278
+ ),
279
+ );
280
+
281
+ expect(find.text('Test Title'), findsOneWidget);
282
+ });
283
+
284
+ testWidgets('renders subtitle when provided', (tester) async {
285
+ await tester.pumpWidget(
286
+ const MaterialApp(
287
+ home: Scaffold(
288
+ body: {WidgetName}(
289
+ title: 'Test Title',
290
+ subtitle: 'Test Subtitle',
291
+ ),
292
+ ),
293
+ ),
294
+ );
295
+
296
+ expect(find.text('Test Subtitle'), findsOneWidget);
297
+ });
298
+
299
+ testWidgets('renders leading icon when provided', (tester) async {
300
+ await tester.pumpWidget(
301
+ const MaterialApp(
302
+ home: Scaffold(
303
+ body: {WidgetName}(
304
+ title: 'Test Title',
305
+ leadingIcon: Icons.person,
306
+ ),
307
+ ),
308
+ ),
309
+ );
310
+
311
+ expect(find.byIcon(Icons.person), findsOneWidget);
312
+ });
313
+
314
+ testWidgets('calls onTap when tapped', (tester) async {
315
+ var tapped = false;
316
+
53
317
  await tester.pumpWidget(
54
318
  MaterialApp(
55
319
  home: Scaffold(
56
- body: {WidgetName}(param1: testValue),
320
+ body: {WidgetName}(
321
+ title: 'Test Title',
322
+ onTap: () => tapped = true,
323
+ ),
57
324
  ),
58
325
  ),
59
326
  );
60
327
 
61
- expect(find.byType({WidgetName}), findsOneWidget);
328
+ await tester.tap(find.byType({WidgetName}));
329
+ await tester.pump();
330
+
331
+ expect(tapped, isTrue);
332
+ });
333
+
334
+ testWidgets('does not call onTap when disabled', (tester) async {
335
+ var tapped = false;
336
+
337
+ await tester.pumpWidget(
338
+ MaterialApp(
339
+ home: Scaffold(
340
+ body: {WidgetName}(
341
+ title: 'Test Title',
342
+ onTap: () => tapped = true,
343
+ isEnabled: false,
344
+ ),
345
+ ),
346
+ ),
347
+ );
348
+
349
+ await tester.tap(find.byType({WidgetName}));
350
+ await tester.pump();
351
+
352
+ expect(tapped, isFalse);
353
+ });
354
+
355
+ testWidgets('has correct semantics', (tester) async {
356
+ await tester.pumpWidget(
357
+ MaterialApp(
358
+ home: Scaffold(
359
+ body: {WidgetName}(
360
+ title: 'Test Title',
361
+ onTap: () {},
362
+ ),
363
+ ),
364
+ ),
365
+ );
366
+
367
+ final semantics = tester.getSemantics(find.byType({WidgetName}));
368
+ expect(semantics.hasFlag(SemanticsFlag.isButton), isTrue);
369
+ expect(semantics.hasFlag(SemanticsFlag.isEnabled), isTrue);
370
+ });
371
+
372
+ testWidgets('applies theme correctly', (tester) async {
373
+ await tester.pumpWidget(
374
+ MaterialApp(
375
+ theme: ThemeData.light(),
376
+ home: const Scaffold(
377
+ body: {WidgetName}(
378
+ title: 'Test Title',
379
+ ),
380
+ ),
381
+ ),
382
+ );
383
+
384
+ // Verificar que o widget utiliza as cores do tema
385
+ final container = tester.widget<Container>(
386
+ find.descendant(
387
+ of: find.byType({WidgetName}),
388
+ matching: find.byType(Container),
389
+ ).first,
390
+ );
391
+
392
+ expect(container.decoration, isNotNull);
393
+ });
394
+ });
395
+
396
+ group('{WidgetName} Golden Tests', () {
397
+ testWidgets('matches golden - light theme', (tester) async {
398
+ await tester.pumpWidget(
399
+ MaterialApp(
400
+ theme: ThemeData.light(),
401
+ home: const Scaffold(
402
+ body: Center(
403
+ child: SizedBox(
404
+ width: 300,
405
+ child: {WidgetName}(
406
+ title: 'Test Title',
407
+ subtitle: 'Test Subtitle',
408
+ leadingIcon: Icons.person,
409
+ ),
410
+ ),
411
+ ),
412
+ ),
413
+ ),
414
+ );
415
+
416
+ await expectLater(
417
+ find.byType({WidgetName}),
418
+ matchesGoldenFile('goldens/{widget_name}_light.png'),
419
+ );
420
+ });
421
+
422
+ testWidgets('matches golden - dark theme', (tester) async {
423
+ await tester.pumpWidget(
424
+ MaterialApp(
425
+ theme: ThemeData.dark(),
426
+ home: const Scaffold(
427
+ body: Center(
428
+ child: SizedBox(
429
+ width: 300,
430
+ child: {WidgetName}(
431
+ title: 'Test Title',
432
+ subtitle: 'Test Subtitle',
433
+ leadingIcon: Icons.person,
434
+ ),
435
+ ),
436
+ ),
437
+ ),
438
+ ),
439
+ );
440
+
441
+ await expectLater(
442
+ find.byType({WidgetName}),
443
+ matchesGoldenFile('goldens/{widget_name}_dark.png'),
444
+ );
62
445
  });
63
446
  });
64
447
  }
65
448
  ```
66
449
 
67
- ## Verificar
450
+ ### Etapa 3: Exportação
451
+
452
+ ```dart
453
+ // lib/shared/widgets/widgets.dart
454
+ export '{widget_name}.dart';
455
+ // Adicionar os outros widgets...
456
+ ```
457
+
458
+ ### Etapa 4: Documentação Storybook (opcional)
459
+
460
+ ```dart
461
+ // lib/shared/widgets/{widget_name}_stories.dart
462
+ import 'package:flutter/material.dart';
463
+ import '{widget_name}.dart';
464
+
465
+ class {WidgetName}Stories extends StatelessWidget {
466
+ const {WidgetName}Stories({super.key});
467
+
468
+ @override
469
+ Widget build(BuildContext context) {
470
+ return Scaffold(
471
+ appBar: AppBar(title: const Text('{WidgetName} Stories')),
472
+ body: ListView(
473
+ padding: const EdgeInsets.all(16),
474
+ children: [
475
+ _buildStory(
476
+ 'Default',
477
+ const {WidgetName}(title: 'Default Title'),
478
+ ),
479
+ _buildStory(
480
+ 'With Subtitle',
481
+ const {WidgetName}(
482
+ title: 'With Subtitle',
483
+ subtitle: 'This is a subtitle',
484
+ ),
485
+ ),
486
+ _buildStory(
487
+ 'With Icon',
488
+ const {WidgetName}(
489
+ title: 'With Icon',
490
+ leadingIcon: Icons.star,
491
+ ),
492
+ ),
493
+ _buildStory(
494
+ 'Disabled',
495
+ const {WidgetName}(
496
+ title: 'Disabled',
497
+ isEnabled: false,
498
+ ),
499
+ ),
500
+ _buildStory(
501
+ 'Full Example',
502
+ {WidgetName}(
503
+ title: 'Full Example',
504
+ subtitle: 'All props enabled',
505
+ leadingIcon: Icons.person,
506
+ onTap: () {},
507
+ ),
508
+ ),
509
+ ],
510
+ ),
511
+ );
512
+ }
513
+
514
+ Widget _buildStory(String name, Widget widget) {
515
+ return Column(
516
+ crossAxisAlignment: CrossAxisAlignment.start,
517
+ children: [
518
+ Text(
519
+ name,
520
+ style: const TextStyle(
521
+ fontSize: 12,
522
+ fontWeight: FontWeight.bold,
523
+ color: Colors.grey,
524
+ ),
525
+ ),
526
+ const SizedBox(height: 8),
527
+ widget,
528
+ const SizedBox(height: 24),
529
+ ],
530
+ );
531
+ }
532
+ }
533
+ ```
534
+
535
+ ### Resumo
536
+
537
+ ```
538
+ ══════════════════════════════════════════════════════════════
539
+ ✅ WIDGET GERADO - {WidgetName}
540
+ ══════════════════════════════════════════════════════════════
68
541
 
69
- - [ ] Widget criado
70
- - [ ] Teste criado
71
- - [ ] Documentação presente
72
- - [ ] Const constructor se stateless
73
- - [ ] Teste passa
542
+ 📁 Arquivos criados:
543
+ - lib/shared/widgets/{widget_name}.dart
544
+ - test/shared/widgets/{widget_name}_test.dart
545
+ - test/shared/widgets/goldens/{widget_name}_light.png (a gerar)
546
+ - test/shared/widgets/goldens/{widget_name}_dark.png (a gerar)
547
+
548
+ 🔧 Comandos úteis:
549
+ # Executar os testes
550
+ flutter test test/shared/widgets/{widget_name}_test.dart
551
+
552
+ # Atualizar os golden tests
553
+ flutter test --update-goldens
554
+
555
+ 📖 Props disponíveis:
556
+ - title (String, required)
557
+ - subtitle (String?)
558
+ - leadingIcon (IconData?)
559
+ - onTap (VoidCallback?)
560
+ - isEnabled (bool, default: true)
561
+ ```