kasy-cli 1.38.0 → 1.39.0

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 (102) hide show
  1. package/lib/scaffold/CHANGELOG.json +14 -0
  2. package/lib/scaffold/backends/api/patch/README.md +15 -0
  3. package/lib/scaffold/backends/api/patch/lib/features/notifications/api/device_api.dart +11 -6
  4. package/lib/scaffold/backends/api/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +9 -1
  5. package/lib/scaffold/backends/api/pubspec.yaml.tpl +1 -0
  6. package/lib/scaffold/backends/patch-base-hashes.json +6 -6
  7. package/lib/scaffold/backends/supabase/edge-functions/admin-list-users/index.ts +3 -1
  8. package/lib/scaffold/backends/supabase/edge-functions/send-push-notification/index.ts +3 -0
  9. package/lib/scaffold/backends/supabase/migrations/20240101000012_welcome_decouple_from_push.sql +62 -0
  10. package/lib/scaffold/backends/supabase/patch/lib/features/notifications/api/device_api.dart +11 -6
  11. package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +7 -0
  12. package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +1 -0
  13. package/lib/scaffold/shared/generator-utils.js +12 -6
  14. package/package.json +1 -1
  15. package/templates/firebase/.firebase/hosting.YnVpbGQvd2Vi.cache +23 -23
  16. package/templates/firebase/DESIGN_SYSTEM.md +22 -8
  17. package/templates/firebase/assets/icons/apple_black.svg +3 -0
  18. package/templates/firebase/assets/icons/apple_white.svg +4 -0
  19. package/templates/firebase/assets/icons/facebook.svg +49 -0
  20. package/templates/firebase/assets/icons/google.svg +1 -0
  21. package/templates/firebase/functions/src/admin/functions.ts +2 -0
  22. package/templates/firebase/functions/src/authentication/functions.ts +13 -7
  23. package/templates/firebase/functions/src/notifications/triggers.ts +6 -2
  24. package/templates/firebase/lib/components/components.dart +1 -1
  25. package/templates/firebase/lib/components/kasy_app_bar.dart +314 -14
  26. package/templates/firebase/lib/components/kasy_card.dart +4 -0
  27. package/templates/firebase/lib/components/kasy_drop_down.dart +584 -0
  28. package/templates/firebase/lib/components/kasy_sidebar.dart +18 -6
  29. package/templates/firebase/lib/components/kasy_tabs.dart +31 -10
  30. package/templates/firebase/lib/components/kasy_text_field.dart +29 -7
  31. package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +27 -18
  32. package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +12 -10
  33. package/templates/firebase/lib/core/chrome/app_bar_config.dart +214 -0
  34. package/templates/firebase/lib/core/chrome/app_bar_scope.dart +102 -0
  35. package/templates/firebase/lib/core/data/api/user_api.dart +11 -0
  36. package/templates/firebase/lib/core/dev_inspector/dev_inspector_service.dart +55 -15
  37. package/templates/firebase/lib/core/rating/widgets/review_popup.dart +18 -35
  38. package/templates/firebase/lib/core/shared_preferences/shared_preferences.dart +11 -0
  39. package/templates/firebase/lib/core/states/logout_action.dart +11 -1
  40. package/templates/firebase/lib/core/states/user_state_notifier.dart +28 -1
  41. package/templates/firebase/lib/core/theme/texts.dart +21 -6
  42. package/templates/firebase/lib/core/theme/type_scale.dart +34 -15
  43. package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +51 -19
  44. package/templates/firebase/lib/core/web_viewport_scale.dart +64 -35
  45. package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +14 -3
  46. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_chat_composer.dart +1 -1
  47. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_chat_conversation_view.dart +52 -35
  48. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +1 -1
  49. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +18 -8
  50. package/templates/firebase/lib/features/authentication/ui/signin_page.dart +11 -61
  51. package/templates/firebase/lib/features/authentication/ui/signup_page.dart +11 -61
  52. package/templates/firebase/lib/features/authentication/ui/widgets/auth_card_scaffold.dart +7 -5
  53. package/templates/firebase/lib/features/authentication/ui/widgets/social_auth_tile.dart +83 -0
  54. package/templates/firebase/lib/features/feedbacks/ui/widgets/feature_card.dart +4 -4
  55. package/templates/firebase/lib/features/home/home_components_page.dart +253 -125
  56. package/templates/firebase/lib/features/home/home_components_preview_registry.dart +231 -57
  57. package/templates/firebase/lib/features/home/home_feed.dart +2 -2
  58. package/templates/firebase/lib/features/home/home_image_grid.dart +3 -3
  59. package/templates/firebase/lib/features/local_reminders/providers/reminder_notifier.dart +8 -1
  60. package/templates/firebase/lib/features/local_reminders/ui/reminder_page.dart +111 -57
  61. package/templates/firebase/lib/features/notifications/api/device_api.dart +11 -3
  62. package/templates/firebase/lib/features/notifications/ui/notifications_page.dart +16 -4
  63. package/templates/firebase/lib/features/notifications/ui/widgets/empty_notifications.dart +7 -56
  64. package/templates/firebase/lib/features/notifications/ui/widgets/notification_tile.dart +5 -5
  65. package/templates/firebase/lib/features/notifications/ui/widgets/push_permission_banner.dart +163 -0
  66. package/templates/firebase/lib/features/notifications/ui/widgets/web_notifications_bell.dart +2 -2
  67. package/templates/firebase/lib/features/onboarding/providers/onboarding_model.dart +9 -0
  68. package/templates/firebase/lib/features/onboarding/providers/onboarding_provider.dart +28 -0
  69. package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +51 -12
  70. package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +90 -32
  71. package/templates/firebase/lib/features/settings/settings_page.dart +53 -32
  72. package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +895 -111
  73. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_api.dart +7 -0
  74. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_tab.dart +445 -233
  75. package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +171 -41
  76. package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +1 -1
  77. package/templates/firebase/lib/features/settings/ui/components/delete_user_component.dart +9 -1
  78. package/templates/firebase/lib/features/settings/ui/components/language_switcher.dart +48 -47
  79. package/templates/firebase/lib/features/settings/ui/widgets/settings_bottom_sheet_option_tile.dart +21 -18
  80. package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +25 -10
  81. package/templates/firebase/lib/i18n/en.i18n.json +749 -712
  82. package/templates/firebase/lib/i18n/es.i18n.json +749 -712
  83. package/templates/firebase/lib/i18n/pt.i18n.json +749 -712
  84. package/templates/firebase/lib/main.dart +20 -7
  85. package/templates/firebase/lib/router.dart +32 -26
  86. package/templates/firebase/pubspec.yaml +2 -1
  87. package/templates/firebase/test/admin_shell_chrome_test.dart +11 -5
  88. package/templates/firebase/test/components/kasy_text_field_height_test.dart +77 -0
  89. package/templates/firebase/test/core/web_viewport_scale_test.dart +23 -16
  90. package/templates/firebase/tool/design_check.dart +9 -0
  91. package/templates/firebase/assets/icons/apple.png +0 -0
  92. package/templates/firebase/assets/icons/facebook.png +0 -0
  93. package/templates/firebase/assets/icons/google.png +0 -0
  94. package/templates/firebase/assets/icons/google_play_games.png +0 -0
  95. package/templates/firebase/lib/components/kasy_web_header.dart +0 -218
  96. package/templates/firebase/lib/core/chrome/web_header_scope.dart +0 -20
  97. package/templates/firebase/lib/features/authentication/ui/components/apple_signin.dart +0 -19
  98. package/templates/firebase/lib/features/authentication/ui/components/google_signin.dart +0 -32
  99. package/templates/firebase/lib/features/authentication/ui/widgets/round_signin.dart +0 -73
  100. package/templates/firebase/lib/features/feedbacks/ui/widgets/add_feature_button.dart +0 -66
  101. package/templates/firebase/lib/features/notifications/ui/components/notification_settings_sheet.dart +0 -179
  102. package/templates/firebase/lib/features/notifications/ui/components/push_notification_switcher.dart +0 -106
@@ -6,6 +6,7 @@ import 'package:kasy_kit/core/theme/theme.dart';
6
6
  import 'package:kasy_kit/core/widgets/kasy_hover.dart';
7
7
  import 'package:kasy_kit/core/widgets/kasy_scroll_behavior.dart';
8
8
  import 'package:kasy_kit/features/home/home_components_preview_registry.dart';
9
+ import 'package:kasy_kit/i18n/translations.g.dart';
9
10
 
10
11
  /// UI-kit catalog, reachable from the home dashboard.
11
12
  ///
@@ -38,140 +39,267 @@ class HomeComponentsPage extends StatelessWidget {
38
39
  /// The UI-kit catalog list on its own (no app bar / scaffold), so it can be the
39
40
  /// body of [HomeComponentsPage] AND a section inside the admin console (which
40
41
  /// supplies its own chrome). Fills the space it is given.
41
- class HomeComponentsCatalog extends StatelessWidget {
42
+ class HomeComponentsCatalog extends StatefulWidget {
42
43
  const HomeComponentsCatalog({super.key});
43
44
 
45
+ @override
46
+ State<HomeComponentsCatalog> createState() => _HomeComponentsCatalogState();
47
+ }
48
+
49
+ class _HomeComponentsCatalogState extends State<HomeComponentsCatalog> {
50
+ final TextEditingController _searchCtrl = TextEditingController();
51
+ String _query = '';
52
+
53
+ @override
54
+ void dispose() {
55
+ _searchCtrl.dispose();
56
+ super.dispose();
57
+ }
58
+
59
+ /// Reset the filter when leaving for a component, so coming back shows the
60
+ /// full catalog instead of the stale search term.
61
+ void _clearSearch() {
62
+ if (!mounted) return;
63
+ if (_query.isEmpty && _searchCtrl.text.isEmpty) return;
64
+ _searchCtrl.clear();
65
+ setState(() => _query = '');
66
+ }
67
+
44
68
  @override
45
69
  Widget build(BuildContext context) {
70
+ final String q = _query.trim().toLowerCase();
71
+ final List<_CatalogRow> rows = q.isEmpty
72
+ ? _kCatalog
73
+ : _kCatalog
74
+ .where((r) => r.name.toLowerCase().contains(q))
75
+ .toList(growable: false);
76
+
46
77
  return Padding(
47
- padding: EdgeInsets.fromLTRB(
48
- KasySpacing.pageHorizontalGutter,
49
- KasySpacing.belowChromeContentGap,
50
- KasySpacing.pageHorizontalGutter,
51
- MediaQuery.paddingOf(context).bottom +
52
- KasySpacing.belowChromeContentGap,
53
- ),
54
- child: _componentsCatalogInset(
55
- context,
56
- child: Padding(
57
- padding: const EdgeInsets.symmetric(
58
- horizontal: KasySpacing.xs,
59
- ),
60
- child: ScrollConfiguration(
61
- behavior: const KasyKitScrollBehavior(),
62
- child: ListView.separated(
63
- padding: EdgeInsets.zero,
64
- itemCount: _kCatalog.length + 1,
65
- separatorBuilder: (context, index) => Divider(
66
- height: 1,
67
- thickness: 1,
68
- indent: KasySpacing.md,
69
- endIndent: KasySpacing.md,
70
- color: context.colors.outline.withValues(alpha: 0.33),
78
+ padding: EdgeInsets.fromLTRB(
79
+ KasySpacing.pageHorizontalGutter,
80
+ KasySpacing.belowChromeContentGap,
81
+ KasySpacing.pageHorizontalGutter,
82
+ MediaQuery.paddingOf(context).bottom + KasySpacing.belowChromeContentGap,
83
+ ),
84
+ child: Column(
85
+ crossAxisAlignment: CrossAxisAlignment.stretch,
86
+ children: [
87
+ _ComponentsSearchField(
88
+ controller: _searchCtrl,
89
+ onChanged: (v) => setState(() => _query = v),
90
+ ),
91
+ const SizedBox(height: KasySpacing.smd),
92
+ Expanded(
93
+ child: _componentsCatalogInset(
94
+ context,
95
+ child: rows.isEmpty
96
+ ? const _ComponentsEmptyResults()
97
+ : Padding(
98
+ padding: const EdgeInsets.symmetric(
99
+ horizontal: KasySpacing.xs,
71
100
  ),
72
- itemBuilder: (context, index) {
73
- if (index >= _kCatalog.length) {
74
- return const SizedBox(height: KasySpacing.sm);
75
- }
76
- final _CatalogRow row = _kCatalog[index];
77
- return KasyHover(
78
- hapticEnabled: false,
79
- onTap: () {
80
- KasyHaptics.selection(context);
81
- if (row.name == 'Design System') {
82
- context.push('/design-system');
83
- return;
84
- }
85
- // Skip rows without a preview yet (registry returns
86
- // null); otherwise open /components/:name, which the
87
- // router resolves back to this component's preview.
88
- if (getComponentPreviewDefinition(row.name) == null) {
89
- return;
90
- }
91
- context.push(
92
- '/components/${Uri.encodeComponent(row.name)}',
93
- );
94
- },
95
- child: Padding(
96
- padding: const EdgeInsets.symmetric(
97
- horizontal: KasySpacing.smd,
98
- vertical: 16,
99
- ),
100
- child: Row(
101
- children: [
102
- Expanded(
103
- child: Row(
104
- children: [
105
- Flexible(
106
- child: Text(
107
- row.name,
108
- // Lighter weight (w500) to match the
109
- // app's row/list scale instead of the
110
- // heavier heading weight.
111
- style: context.kasyTextTheme.rowTitle
112
- .copyWith(
113
- color:
114
- context.colors.onSurface,
115
- ),
116
- ),
117
- ),
118
- if (_kReadyComponents.contains(
119
- row.name,
120
- )) ...[
121
- const SizedBox(width: KasySpacing.sm),
122
- Text(
123
- 'Pronto',
124
- style: context.textTheme.bodySmall
125
- ?.copyWith(
126
- color: context.colors.success,
127
- fontWeight: FontWeight.w600,
128
- ),
129
- ),
130
- ],
131
- if (_kWebReadyComponents.contains(
132
- row.name,
133
- )) ...[
134
- const SizedBox(width: KasySpacing.xs),
135
- Text(
136
- 'Web',
137
- style: context.textTheme.bodySmall
138
- ?.copyWith(
139
- color: context.colors.primary,
140
- fontWeight: FontWeight.w600,
141
- ),
142
- ),
143
- ],
144
- if (_kUrgentComponents.contains(
145
- row.name,
146
- )) ...[
147
- const SizedBox(width: KasySpacing.sm),
148
- Text(
149
- 'Prioridade: Urgente',
150
- style: context.textTheme.bodySmall
151
- ?.copyWith(
152
- color: context.colors.warning,
153
- fontWeight: FontWeight.w700,
154
- ),
155
- ),
156
- ],
157
- ],
158
- ),
159
- ),
160
- Icon(
161
- KasyIcons.chevronRight,
162
- color: context.colors.muted,
163
- size: 22,
164
- ),
165
- ],
101
+ child: ScrollConfiguration(
102
+ behavior: const KasyKitScrollBehavior(),
103
+ child: ListView.separated(
104
+ padding: EdgeInsets.zero,
105
+ itemCount: rows.length + 1,
106
+ separatorBuilder: (context, index) => Divider(
107
+ height: 1,
108
+ thickness: 1,
109
+ indent: KasySpacing.md,
110
+ endIndent: KasySpacing.md,
111
+ color: context.colors.outline.withValues(
112
+ alpha: 0.33,
166
113
  ),
167
114
  ),
168
- );
115
+ itemBuilder: (context, index) {
116
+ if (index >= rows.length) {
117
+ return const SizedBox(height: KasySpacing.sm);
118
+ }
119
+ return _catalogRow(context, rows[index]);
120
+ },
121
+ ),
122
+ ),
123
+ ),
124
+ ),
125
+ ),
126
+ ],
127
+ ),
128
+ );
129
+ }
169
130
 
170
- },
131
+ Widget _catalogRow(BuildContext context, _CatalogRow row) {
132
+ return KasyHover(
133
+ hapticEnabled: false,
134
+ onTap: () {
135
+ KasyHaptics.selection(context);
136
+ if (row.name == 'Design System') {
137
+ context.push('/design-system').whenComplete(_clearSearch);
138
+ return;
139
+ }
140
+ // Skip rows without a preview yet (registry returns null); otherwise
141
+ // open /components/:name, which the router resolves back to this
142
+ // component's preview.
143
+ if (getComponentPreviewDefinition(row.name) == null) {
144
+ return;
145
+ }
146
+ context
147
+ .push('/components/${Uri.encodeComponent(row.name)}')
148
+ .whenComplete(_clearSearch);
149
+ },
150
+ child: Padding(
151
+ padding: const EdgeInsets.symmetric(
152
+ horizontal: KasySpacing.smd,
153
+ vertical: 16,
154
+ ),
155
+ child: Row(
156
+ children: [
157
+ Expanded(
158
+ child: Row(
159
+ children: [
160
+ Flexible(
161
+ child: Text(
162
+ row.name,
163
+ // Lighter weight (w500) to match the app's row/list scale
164
+ // instead of the heavier heading weight.
165
+ style: context.kasyTextTheme.rowTitle.copyWith(
166
+ color: context.colors.onSurface,
167
+ ),
171
168
  ),
172
169
  ),
173
- ),
170
+ if (_kReadyComponents.contains(row.name)) ...[
171
+ const SizedBox(width: KasySpacing.sm),
172
+ Text(
173
+ 'Pronto',
174
+ style: context.textTheme.bodySmall?.copyWith(
175
+ color: context.colors.success,
176
+ fontWeight: FontWeight.w600,
177
+ ),
178
+ ),
179
+ ],
180
+ if (_kWebReadyComponents.contains(row.name)) ...[
181
+ const SizedBox(width: KasySpacing.xs),
182
+ Text(
183
+ 'Web',
184
+ style: context.textTheme.bodySmall?.copyWith(
185
+ color: context.colors.primary,
186
+ fontWeight: FontWeight.w600,
187
+ ),
188
+ ),
189
+ ],
190
+ if (_kUrgentComponents.contains(row.name)) ...[
191
+ const SizedBox(width: KasySpacing.sm),
192
+ Text(
193
+ 'Prioridade: Urgente',
194
+ style: context.textTheme.bodySmall?.copyWith(
195
+ color: context.colors.warning,
196
+ fontWeight: FontWeight.w700,
197
+ ),
198
+ ),
199
+ ],
200
+ ],
201
+ ),
202
+ ),
203
+ Icon(
204
+ KasyIcons.chevronRight,
205
+ color: context.colors.muted,
206
+ size: 22,
207
+ ),
208
+ ],
209
+ ),
210
+ ),
211
+ );
212
+ }
213
+ }
214
+
215
+ /// Compact search field above the catalog — filters the list by component name.
216
+ class _ComponentsSearchField extends StatelessWidget {
217
+ final TextEditingController controller;
218
+ final ValueChanged<String> onChanged;
219
+ const _ComponentsSearchField({
220
+ required this.controller,
221
+ required this.onChanged,
222
+ });
223
+
224
+ @override
225
+ Widget build(BuildContext context) {
226
+ return SizedBox(
227
+ height: 40,
228
+ child: TextField(
229
+ controller: controller,
230
+ onChanged: onChanged,
231
+ style: context.textTheme.bodyMedium,
232
+ decoration: InputDecoration(
233
+ hintText: t.home.dashboard.search_hint,
234
+ hintStyle: context.textTheme.bodyMedium?.copyWith(
235
+ color: context.colors.muted,
236
+ ),
237
+ prefixIcon: Icon(
238
+ Icons.search_rounded,
239
+ size: 18,
240
+ color: context.colors.muted,
241
+ ),
242
+ prefixIconConstraints: const BoxConstraints(
243
+ minWidth: 40,
244
+ minHeight: 40,
245
+ ),
246
+ isDense: true,
247
+ contentPadding: const EdgeInsets.symmetric(
248
+ horizontal: 12,
249
+ vertical: 10,
250
+ ),
251
+ filled: true,
252
+ fillColor: context.colors.surface,
253
+ enabledBorder: OutlineInputBorder(
254
+ borderRadius: BorderRadius.circular(KasyRadius.sm),
255
+ borderSide: BorderSide(
256
+ color: context.colors.outline.withValues(alpha: 0.5),
257
+ ),
258
+ ),
259
+ focusedBorder: OutlineInputBorder(
260
+ borderRadius: BorderRadius.circular(KasyRadius.sm),
261
+ borderSide: BorderSide(color: context.colors.primary, width: 1.4),
262
+ ),
263
+ border: OutlineInputBorder(
264
+ borderRadius: BorderRadius.circular(KasyRadius.sm),
265
+ borderSide: BorderSide(
266
+ color: context.colors.outline.withValues(alpha: 0.5),
267
+ ),
268
+ ),
269
+ ),
270
+ ),
271
+ );
272
+ }
273
+ }
274
+
275
+ /// Shown inside the catalog surface when a search matches nothing.
276
+ class _ComponentsEmptyResults extends StatelessWidget {
277
+ const _ComponentsEmptyResults();
278
+
279
+ @override
280
+ Widget build(BuildContext context) {
281
+ return Center(
282
+ child: Padding(
283
+ padding: const EdgeInsets.all(KasySpacing.lg),
284
+ child: Column(
285
+ mainAxisSize: MainAxisSize.min,
286
+ children: [
287
+ Icon(
288
+ Icons.search_off_rounded,
289
+ size: 30,
290
+ color: context.colors.muted,
291
+ ),
292
+ const SizedBox(height: KasySpacing.sm),
293
+ Text(
294
+ t.home.dashboard.search_empty,
295
+ textAlign: TextAlign.center,
296
+ style: context.textTheme.bodySmall?.copyWith(
297
+ color: context.colors.muted,
174
298
  ),
299
+ ),
300
+ ],
301
+ ),
302
+ ),
175
303
  );
176
304
  }
177
305
  }
@@ -195,6 +323,7 @@ const Set<String> _kReadyComponents = <String>{
195
323
  'DatePicker',
196
324
  'Design System',
197
325
  'Dialog',
326
+ 'DropDown',
198
327
  'Hover',
199
328
  'Tabs',
200
329
  'TextArea',
@@ -205,7 +334,6 @@ const Set<String> _kReadyComponents = <String>{
205
334
  'SwipeAction',
206
335
  'TextFieldOTP',
207
336
  'Toast',
208
- 'Web Header',
209
337
  };
210
338
 
211
339
  /// Components that have been adapted for web (cursor, hover, shadow, border).
@@ -222,6 +350,7 @@ const Set<String> _kWebReadyComponents = <String>{
222
350
  'DatePicker',
223
351
  'Design System',
224
352
  'Dialog',
353
+ 'DropDown',
225
354
  'Hover',
226
355
  'Sidebar',
227
356
  'Skeleton',
@@ -231,7 +360,6 @@ const Set<String> _kWebReadyComponents = <String>{
231
360
  'TextField',
232
361
  'TextFieldOTP',
233
362
  'Toast',
234
- 'Web Header',
235
363
  };
236
364
 
237
365
  const Set<String> _kUrgentComponents = <String>{
@@ -254,6 +382,7 @@ const List<_CatalogRow> _kCatalog = [
254
382
  _CatalogRow('Checkbox'),
255
383
  _CatalogRow('DatePicker'),
256
384
  _CatalogRow('Dialog'),
385
+ _CatalogRow('DropDown'),
257
386
  _CatalogRow('Hover'),
258
387
  _CatalogRow('Sidebar'),
259
388
  _CatalogRow('Skeleton'),
@@ -263,7 +392,6 @@ const List<_CatalogRow> _kCatalog = [
263
392
  _CatalogRow('TextField'),
264
393
  _CatalogRow('TextFieldOTP'),
265
394
  _CatalogRow('Toast'),
266
- _CatalogRow('Web Header'),
267
395
  // Prioridade: Urgente (_kUrgentComponents), A–Z
268
396
  _CatalogRow('Radio Group'),
269
397
  _CatalogRow('Switch'),