mobile-design 0.0.0-stage → 0.1.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 (121) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSE-Apache-2.0.txt +55 -0
  3. package/NOTICE +11 -0
  4. package/README.md +96 -2
  5. package/assets/fonts/MaterialSymbolsRounded.ttf +0 -0
  6. package/assets/fonts/MaterialSymbolsRounded.woff2 +0 -0
  7. package/assets/fonts/roboto/OFL.txt +93 -0
  8. package/assets/fonts/roboto/Roboto_400Regular.ttf +0 -0
  9. package/assets/fonts/roboto/Roboto_400Regular.woff2 +0 -0
  10. package/assets/fonts/roboto/Roboto_400Regular_Italic.ttf +0 -0
  11. package/assets/fonts/roboto/Roboto_400Regular_Italic.woff2 +0 -0
  12. package/assets/fonts/roboto/Roboto_500Medium.ttf +0 -0
  13. package/assets/fonts/roboto/Roboto_500Medium.woff2 +0 -0
  14. package/assets/fonts/roboto/Roboto_500Medium_Italic.ttf +0 -0
  15. package/assets/fonts/roboto/Roboto_500Medium_Italic.woff2 +0 -0
  16. package/assets/fonts/roboto/Roboto_600SemiBold.ttf +0 -0
  17. package/assets/fonts/roboto/Roboto_600SemiBold.woff2 +0 -0
  18. package/assets/fonts/roboto/Roboto_600SemiBold_Italic.ttf +0 -0
  19. package/assets/fonts/roboto/Roboto_600SemiBold_Italic.woff2 +0 -0
  20. package/assets/fonts/roboto/Roboto_700Bold.ttf +0 -0
  21. package/assets/fonts/roboto/Roboto_700Bold.woff2 +0 -0
  22. package/assets/fonts/roboto/Roboto_700Bold_Italic.ttf +0 -0
  23. package/assets/fonts/roboto/Roboto_700Bold_Italic.woff2 +0 -0
  24. package/assets/fonts/roboto/Roboto_800ExtraBold.ttf +0 -0
  25. package/assets/fonts/roboto/Roboto_800ExtraBold.woff2 +0 -0
  26. package/assets/fonts/roboto/Roboto_800ExtraBold_Italic.ttf +0 -0
  27. package/assets/fonts/roboto/Roboto_800ExtraBold_Italic.woff2 +0 -0
  28. package/assets/logo.svg +13 -0
  29. package/package.json +62 -3
  30. package/src/catalog.ts +683 -0
  31. package/src/color-scheme.ts +68 -0
  32. package/src/color.ts +35 -0
  33. package/src/components/action-surface.tsx +83 -0
  34. package/src/components/appbar-layout.ts +85 -0
  35. package/src/components/appbar-scroll-behavior.tsx +386 -0
  36. package/src/components/appbar.tsx +474 -0
  37. package/src/components/avatar.tsx +135 -0
  38. package/src/components/bottom-sheet-text-field.tsx +13 -0
  39. package/src/components/bottom-sheet-text-input.tsx +2 -0
  40. package/src/components/bottom-sheet-text-input.web.tsx +2 -0
  41. package/src/components/button-group.tsx +996 -0
  42. package/src/components/button.tsx +504 -0
  43. package/src/components/card.tsx +284 -0
  44. package/src/components/carousel-full-screen.tsx +374 -0
  45. package/src/components/carousel-layout.ts +418 -0
  46. package/src/components/carousel-scroll-controller.tsx +303 -0
  47. package/src/components/carousel-vertical-layout.ts +92 -0
  48. package/src/components/carousel-vertical.tsx +505 -0
  49. package/src/components/carousel.tsx +678 -0
  50. package/src/components/choice-motion.tsx +108 -0
  51. package/src/components/choice-types.ts +52 -0
  52. package/src/components/choice.tsx +400 -0
  53. package/src/components/choice.web.ts +1 -0
  54. package/src/components/circular-progress-status.tsx +218 -0
  55. package/src/components/container-transform.tsx +304 -0
  56. package/src/components/content.tsx +1450 -0
  57. package/src/components/date-picker-calendar.tsx +933 -0
  58. package/src/components/date-picker-months.tsx +102 -0
  59. package/src/components/date-picker-utils.ts +96 -0
  60. package/src/components/date-picker.tsx +641 -0
  61. package/src/components/dialog.tsx +340 -0
  62. package/src/components/docked-date-picker.tsx +525 -0
  63. package/src/components/drawer.tsx +248 -0
  64. package/src/components/fab.tsx +1221 -0
  65. package/src/components/focus-order.ts +40 -0
  66. package/src/components/full-screen-dialog.tsx +234 -0
  67. package/src/components/icon-button.tsx +72 -0
  68. package/src/components/list-focus.tsx +182 -0
  69. package/src/components/list-reorder.tsx +349 -0
  70. package/src/components/loading-indicator.tsx +378 -0
  71. package/src/components/menu.tsx +1091 -0
  72. package/src/components/navigation-bar.tsx +390 -0
  73. package/src/components/navigation-focus.ts +45 -0
  74. package/src/components/navigation-rail-layout.ts +53 -0
  75. package/src/components/navigation.tsx +682 -0
  76. package/src/components/popup.tsx +624 -0
  77. package/src/components/press-scope.ts +17 -0
  78. package/src/components/progress-indicator-paths.ts +254 -0
  79. package/src/components/progress-indicator.tsx +570 -0
  80. package/src/components/progress.tsx +39 -0
  81. package/src/components/pull-to-refresh.tsx +379 -0
  82. package/src/components/rich-tooltip.tsx +183 -0
  83. package/src/components/search-icon-button.tsx +8 -0
  84. package/src/components/search-trigger.tsx +28 -0
  85. package/src/components/search-view.tsx +790 -0
  86. package/src/components/searchbar.tsx +190 -0
  87. package/src/components/segmented-buttons.tsx +456 -0
  88. package/src/components/selection-controls.tsx +760 -0
  89. package/src/components/sheets.tsx +1027 -0
  90. package/src/components/slider.tsx +1290 -0
  91. package/src/components/snackbar.tsx +430 -0
  92. package/src/components/split-button.tsx +525 -0
  93. package/src/components/swipe-list-item.tsx +793 -0
  94. package/src/components/switch.tsx +319 -0
  95. package/src/components/tabs-pager.tsx +241 -0
  96. package/src/components/tabs-pager.web.tsx +110 -0
  97. package/src/components/tabs.tsx +759 -0
  98. package/src/components/text-field.tsx +673 -0
  99. package/src/components/time-picker.tsx +1248 -0
  100. package/src/components/toolbar.tsx +590 -0
  101. package/src/components/tooltip.tsx +273 -0
  102. package/src/components/web-choice.tsx +572 -0
  103. package/src/core.tsx +169 -0
  104. package/src/font-assets.ts +28 -0
  105. package/src/font-assets.web.ts +25 -0
  106. package/src/index.ts +139 -0
  107. package/src/material-symbol-codepoints.ts +67 -0
  108. package/src/material-symbol-paths.ts +340 -0
  109. package/src/material-symbols.tsx +155 -0
  110. package/src/native-modal.tsx +50 -0
  111. package/src/outside-interaction.tsx +39 -0
  112. package/src/paper-icon-aliases.ts +147 -0
  113. package/src/paper-internals.d.ts +15 -0
  114. package/src/paper-motion-bridge.tsx +11 -0
  115. package/src/paper-motion.tsx +24 -0
  116. package/src/primitives.tsx +13 -0
  117. package/src/ripple.tsx +7 -0
  118. package/src/ripple.web.tsx +108 -0
  119. package/src/scroll-indicators.ts +12 -0
  120. package/src/typography.ts +9 -0
  121. package/src/web-accessibility.ts +19 -0
package/src/catalog.ts ADDED
@@ -0,0 +1,683 @@
1
+ export type MobileDesignCategory = 'actions' | 'communication' | 'containment' | 'navigation' | 'selection' | 'input';
2
+ export type MobileDesignImplementation = 'paper' | 'paper-composition' | 'mobile-design';
3
+ /** Groups in the Components navigation drawer on m3.material.io. */
4
+ export const mobileDesignCatalogGroups = [
5
+ { id: 'buttons', title: 'Buttons' },
6
+ { id: 'date-time-pickers', title: 'Date & time pickers' },
7
+ { id: 'loading-progress', title: 'Loading & progress' },
8
+ { id: 'navigation', title: 'Navigation' },
9
+ { id: 'sheets', title: 'Sheets' },
10
+ { id: 'extensions', title: 'Extensiones de Mobile Design' },
11
+ ] as const;
12
+ export type MobileDesignCatalogGroupId = (typeof mobileDesignCatalogGroups)[number]['id'];
13
+ export type MobileDesignCatalogEntry = {
14
+ id: string;
15
+ title: string;
16
+ searchAliases: readonly string[];
17
+ group: MobileDesignCatalogGroupId | null;
18
+ category: MobileDesignCategory;
19
+ /** Implemented variants, rather than a promise of device-verified visual equivalence. */
20
+ variants: readonly string[];
21
+ /** Options, states and compositions are separate from the documented variants. */
22
+ configurations?: readonly string[];
23
+ implementation: MobileDesignImplementation;
24
+ exports: readonly string[];
25
+ reference?: string;
26
+ notes: readonly string[];
27
+ };
28
+
29
+ /** Material 3 families in navigation order, followed by Mobile Design extensions. */
30
+ export const mobileDesignCatalog = [
31
+ {
32
+ id: 'app-bars',
33
+ title: 'App bars',
34
+ searchAliases: ['Barras de aplicación'],
35
+ group: null,
36
+ category: 'navigation',
37
+ variants: ['Search app bar', 'Small', 'Medium flexible', 'Large flexible'],
38
+ configurations: ['centered text', 'subtitle', 'image', 'filled action', 'scroll behavior'],
39
+ implementation: 'mobile-design',
40
+ exports: ['TopAppBar', 'useAppBarScrollBehavior'],
41
+ reference: 'https://m3.material.io/components/app-bars/overview',
42
+ notes: [
43
+ 'Cuatro variantes actuales; texto centrado, subtítulos, imágenes y acciones son configuraciones. TopAppBar mide su contenido y comparte el controlador de scroll con la pantalla.',
44
+ ],
45
+ },
46
+ {
47
+ id: 'badges',
48
+ title: 'Badges',
49
+ searchAliases: ['Insignias'],
50
+ group: null,
51
+ category: 'communication',
52
+ variants: ['Small', 'Large'],
53
+ implementation: 'mobile-design',
54
+ exports: ['Badge', 'BadgedBox'],
55
+ reference: 'https://m3.material.io/components/badges/overview',
56
+ notes: [
57
+ 'Small6dp sin texto; Large mínimo16dp con LabelSmall y hasta4 caracteres. BadgedBox conserva el ancla superior al extremo lógico del icono; el destino anuncia su significado.',
58
+ ],
59
+ },
60
+ {
61
+ id: 'button-groups',
62
+ title: 'Button groups',
63
+ searchAliases: ['Grupos de botones'],
64
+ group: 'buttons',
65
+ category: 'actions',
66
+ variants: ['standard', 'connected'],
67
+ configurations: ['5 sizes', 'round', 'square', 'icons', 'labels', 'single selection', 'multiple selection'],
68
+ implementation: 'mobile-design',
69
+ exports: ['ButtonGroup'],
70
+ reference: 'https://m3.material.io/components/button-groups/overview',
71
+ notes: [
72
+ 'Dos variantes; cinco tamaños y formas round/square son configuraciones. Standard amplía el botón pulsado y comprime sólo los vecinos inmediatos dentro de su padding disponible.',
73
+ 'Connected cambia la forma de cada botón sin desplazar a sus vecinos. Permite acciones o selección única/múltiple; las etiquetas se miden antes de resolver overflow.',
74
+ ],
75
+ },
76
+ {
77
+ id: 'buttons',
78
+ title: 'Buttons',
79
+ searchAliases: ['Botones', 'filled', 'tonal', 'elevated', 'outlined', 'text', 'round', 'square', '5 sizes'],
80
+ group: 'buttons',
81
+ category: 'actions',
82
+ variants: ['Default', 'Toggle'],
83
+ configurations: ['filled', 'tonal', 'elevated', 'outlined', 'text', '5 sizes', 'round', 'square'],
84
+ implementation: 'mobile-design',
85
+ exports: ['Button'],
86
+ reference: 'https://m3.material.io/components/buttons/overview',
87
+ notes: [
88
+ 'Dos variantes: Default y Toggle. Elevated, Filled, Tonal, Outlined y Text son configuraciones; Text no admite Toggle.',
89
+ 'El Button de Paper instalado conserva medidas de la generación anterior; el paquete exporta su extensión.',
90
+ ],
91
+ },
92
+ {
93
+ id: 'extended-fab',
94
+ title: 'Extended FABs',
95
+ searchAliases: ['FAB extendido'],
96
+ group: 'buttons',
97
+ category: 'actions',
98
+ variants: ['small', 'medium', 'large'],
99
+ configurations: ['6 color roles', 'expanded', 'collapsed'],
100
+ implementation: 'mobile-design',
101
+ exports: ['FAB.Extended'],
102
+ reference: 'https://m3.material.io/components/extended-fab/overview',
103
+ notes: [
104
+ 'Tres tamaños y seis pares semánticos. Colapso por anchura y opacidad sin escalar glifos; movimiento FastSpatial/FastEffects y preferencia de movimiento compartida.',
105
+ ],
106
+ },
107
+ {
108
+ id: 'fab-menu',
109
+ title: 'FAB menu',
110
+ searchAliases: ['Menú FAB'],
111
+ group: 'buttons',
112
+ category: 'actions',
113
+ variants: ['FAB menu'],
114
+ configurations: [
115
+ 'trailing',
116
+ '2–6 actions',
117
+ '3 trigger sizes',
118
+ '3 menu color roles',
119
+ 'expanded',
120
+ 'collapsed',
121
+ 'scrollable extension',
122
+ ],
123
+ implementation: 'mobile-design',
124
+ exports: ['FAB.Menu'],
125
+ reference: 'https://m3.material.io/components/fab-menu/overview',
126
+ notes: [
127
+ 'Apilado local, anclaje al borde superior trailing, cierre accesible, scroll acotado y rama web baseline.',
128
+ 'Alineación trailing lógica en LTR/RTL, conforme a Guidelines; sin posiciones alternativas heredadas.',
129
+ ],
130
+ },
131
+ {
132
+ id: 'floating-action-button',
133
+ title: 'FABs',
134
+ searchAliases: ['Botón de acción flotante'],
135
+ group: 'buttons',
136
+ category: 'actions',
137
+ variants: ['FAB', 'medium FAB', 'large FAB'],
138
+ configurations: ['primary', 'secondary', 'tertiary', 'tonalPrimary', 'tonalSecondary', 'tonalTertiary', 'show/hide'],
139
+ implementation: 'mobile-design',
140
+ exports: ['FAB'],
141
+ reference: 'https://m3.material.io/components/floating-action-button/overview',
142
+ notes: ['56/80/96dp y radios16/20/28dp; presencia desde escala0.2 y colores semánticos actuales.'],
143
+ },
144
+ {
145
+ id: 'icon-buttons',
146
+ title: 'Icon buttons',
147
+ searchAliases: ['Botones de icono'],
148
+ group: 'buttons',
149
+ category: 'actions',
150
+ variants: ['default', 'toggle'],
151
+ configurations: ['standard', 'filled', 'tonal', 'outlined', '5 sizes', '3 widths', 'round', 'square'],
152
+ implementation: 'mobile-design',
153
+ exports: ['IconButton'],
154
+ reference: 'https://m3.material.io/components/icon-buttons/overview',
155
+ notes: ['Escala expresiva separada de size numérico del glifo; exige accessibilityLabel para acciones sin texto.'],
156
+ },
157
+ {
158
+ id: 'segmented-buttons',
159
+ title: 'Segmented buttons',
160
+ searchAliases: ['Botones segmentados'],
161
+ group: 'buttons',
162
+ category: 'selection',
163
+ variants: ['single-select', 'multi-select'],
164
+ configurations: ['icons', 'labels', 'selected check', 'density', 'disabled'],
165
+ implementation: 'mobile-design',
166
+ exports: ['SegmentedButtons'],
167
+ reference: 'https://m3.material.io/components/segmented-buttons/overview',
168
+ notes: [
169
+ 'La documentación mantiene esta familia, pero M3 Expressive recomienda Button groups connected. Motor local actualizado, selección única/múltiple y target48dp.',
170
+ ],
171
+ },
172
+ {
173
+ id: 'split-button',
174
+ title: 'Split button',
175
+ searchAliases: ['Botón dividido'],
176
+ group: 'buttons',
177
+ category: 'actions',
178
+ variants: ['split button'],
179
+ configurations: ['filled', 'tonal', 'outlined', 'elevated', '5 sizes', 'expanded'],
180
+ implementation: 'mobile-design',
181
+ exports: ['SplitButton'],
182
+ reference: 'https://m3.material.io/components/split-button/overview',
183
+ notes: ['Acción primaria independiente y menú local acotado; las esquinas internas y el chevrón responden a presión/expansión.'],
184
+ },
185
+ {
186
+ id: 'cards',
187
+ title: 'Cards',
188
+ searchAliases: ['Tarjetas'],
189
+ group: null,
190
+ category: 'containment',
191
+ variants: ['elevated', 'filled', 'outlined'],
192
+ configurations: ['cover', 'content', 'actions', 'selection', 'media', 'collections', 'swipe', 'reorder'],
193
+ implementation: 'paper-composition',
194
+ exports: ['Card'],
195
+ reference: 'https://m3.material.io/components/cards/overview',
196
+ notes: [
197
+ 'Tres variantes de contenedor local con colores, bordes y elevaciones de estado actuales; conserva Title/Content/Cover/Actions de Paper.',
198
+ 'Selección, media, colecciones y gestos son composiciones de ejemplos. El viewport de gestos posee su FlatList y no añade controles de laboratorio a la tarjeta.',
199
+ ],
200
+ },
201
+ {
202
+ id: 'carousel',
203
+ title: 'Carousel',
204
+ searchAliases: ['Carrusel'],
205
+ group: null,
206
+ category: 'containment',
207
+ variants: ['multi-browse', 'hero', 'center-aligned-hero', 'uncontained', 'uncontained-multi-aspect', 'full-screen', 'vertical'],
208
+ configurations: [
209
+ 'uncontained multi-aspect ratio',
210
+ 'centered',
211
+ 'center-aligned hero',
212
+ 'text placement',
213
+ 'snap scrolling',
214
+ 'default scrolling',
215
+ 'vertical gallery',
216
+ 'variable item aspect ratio',
217
+ ],
218
+ implementation: 'mobile-design',
219
+ exports: ['Carousel'],
220
+ reference: 'https://m3.material.io/components/carousel/overview',
221
+ notes: [
222
+ 'Keylines y máscaras adaptados de MDC Android; indíces y navegación interrumpible en UI thread.',
223
+ 'Full-screen requiere portrait compacto/medio; gesto/snap y FPS requieren revisión nativa.',
224
+ 'Vertical es una extensión propia de Mobile Design: galería con varias fotos, proporciones individuales y scroll libre; no es una variante oficial de MD3 ni el feed Full-screen.',
225
+ ],
226
+ },
227
+ {
228
+ id: 'checkbox',
229
+ title: 'Checkbox',
230
+ searchAliases: ['Casillas'],
231
+ group: null,
232
+ category: 'selection',
233
+ variants: [],
234
+ configurations: ['unchecked', 'checked', 'indeterminate', 'disabled', 'error', 'label'],
235
+ implementation: 'mobile-design',
236
+ exports: ['Checkbox'],
237
+ reference: 'https://m3.material.io/components/checkbox/overview',
238
+ notes: ['Animación SVG, checked/indeterminate/error y foco propios con objetivo48dp. Forma MD3 consistente en ambas plataformas.'],
239
+ },
240
+ {
241
+ id: 'chips',
242
+ title: 'Chips',
243
+ searchAliases: ['Chips'],
244
+ group: null,
245
+ category: 'selection',
246
+ variants: ['assist', 'filter', 'input', 'suggestion'],
247
+ configurations: ['elevated', 'outlined', 'selected', 'disabled', 'avatar', 'remove action'],
248
+ implementation: 'mobile-design',
249
+ exports: ['Chip'],
250
+ reference: 'https://m3.material.io/components/chips/overview',
251
+ notes: [
252
+ 'Assist/filter/input/suggestion con roles distintos, selección, iconos/avatar y cierre independiente; visual32dp y targets48dp.',
253
+ ],
254
+ },
255
+ {
256
+ id: 'date-pickers',
257
+ title: 'Date pickers',
258
+ searchAliases: ['Selectores de fecha'],
259
+ group: 'date-time-pickers',
260
+ category: 'input',
261
+ variants: ['docked', 'modal date picker', 'modal date input'],
262
+ configurations: ['single date', 'date range', 'month selection', 'year selection', 'full-screen', 'locale', 'limits'],
263
+ implementation: 'mobile-design',
264
+ exports: ['DatePicker', 'DockedDatePicker'],
265
+ reference: 'https://m3.material.io/components/date-pickers/overview',
266
+ notes: [
267
+ 'DatePicker maneja selección simple o rango; validación, límites, localización y teclado están en la API.',
268
+ 'La fidelidad de animación y gestos nativos se documenta por separado de la cobertura.',
269
+ ],
270
+ },
271
+ {
272
+ id: 'time-pickers',
273
+ title: 'Time pickers',
274
+ searchAliases: ['Selectores de hora'],
275
+ group: 'date-time-pickers',
276
+ category: 'input',
277
+ variants: ['dial', 'input'],
278
+ configurations: ['12-hour', '24-hour', 'hour/minute selection', 'period selection', 'landscape'],
279
+ implementation: 'mobile-design',
280
+ exports: ['TimePicker'],
281
+ reference: 'https://m3.material.io/components/time-pickers/overview',
282
+ notes: ['Reloj/entrada controlados en modal; el paquete no instala un picker del sistema distinto de MD3.'],
283
+ },
284
+ {
285
+ id: 'dialogs',
286
+ title: 'Dialogs',
287
+ searchAliases: ['Diálogos'],
288
+ group: null,
289
+ category: 'containment',
290
+ variants: ['basic', 'full-screen'],
291
+ configurations: ['icon', 'title', 'supporting text', 'scrollable', 'actions', 'adaptive layout'],
292
+ implementation: 'paper-composition',
293
+ exports: ['Dialog', 'FullScreenDialog', 'Portal'],
294
+ reference: 'https://m3.material.io/components/dialogs/overview',
295
+ notes: [
296
+ 'Contenedor NativeModal y piezas propias con inset24, acciones adaptativas/RTL y alternativa full-screen que adapta a modal560dp.',
297
+ 'El Modal genérico de Paper sigue disponible como primitiva y no es accesible por defecto.',
298
+ ],
299
+ },
300
+ {
301
+ id: 'divider',
302
+ title: 'Divider',
303
+ searchAliases: ['Separadores'],
304
+ group: null,
305
+ category: 'containment',
306
+ variants: [],
307
+ configurations: ['full width', 'start inset', 'middle inset', 'vertical', '1dp'],
308
+ implementation: 'mobile-design',
309
+ exports: ['Divider'],
310
+ reference: 'https://m3.material.io/components/divider/overview',
311
+ notes: ['Separador OutlineVariant de1dp por defecto; horizontal/vertical y full/insets16dp.'],
312
+ },
313
+ {
314
+ id: 'lists',
315
+ title: 'Lists',
316
+ searchAliases: ['Listas'],
317
+ group: null,
318
+ category: 'containment',
319
+ variants: ['standard', 'segmented'],
320
+ configurations: [
321
+ 'single selection',
322
+ 'multi selection',
323
+ 'multi-action',
324
+ 'single-action',
325
+ 'non-interactive',
326
+ 'one line',
327
+ 'two line',
328
+ 'three line',
329
+ 'expand',
330
+ 'reorder',
331
+ 'swipe direct',
332
+ 'swipe indirect',
333
+ ],
334
+ implementation: 'mobile-design',
335
+ exports: ['List', 'ListReorderGroup', 'SwipeListItem', 'SwipeListGroup'],
336
+ reference: 'https://m3.material.io/components/lists/overview',
337
+ notes: [
338
+ 'Listas expresivas estándar/segmentadas, selección única/múltiple y acciones independientes; baseline explícito56/72/88dp. No virtualiza: combinar con FlatList.',
339
+ ],
340
+ },
341
+ {
342
+ id: 'loading-indicator',
343
+ title: 'Loading indicator',
344
+ searchAliases: ['Indicador de carga'],
345
+ group: 'loading-progress',
346
+ category: 'communication',
347
+ variants: ['loading indicator'],
348
+ configurations: [
349
+ 'default',
350
+ 'contained',
351
+ 'scaled',
352
+ 'gesture progress',
353
+ 'paused',
354
+ 'button',
355
+ 'tab icon',
356
+ 'append',
357
+ 'pull-to-refresh overlay',
358
+ 'pull-to-refresh adjacent',
359
+ 'separate success/error composition',
360
+ ],
361
+ implementation: 'mobile-design',
362
+ exports: ['LoadingIndicator', 'PullToRefresh'],
363
+ reference: 'https://m3.material.io/components/loading-indicator/overview',
364
+ notes: [
365
+ 'Morph real de siete contornos SVG MaterialShapes, intervalo650ms y giro4666ms.',
366
+ 'La correspondencia de puntos SVG adapta AndroidX Morph; no implica equivalencia píxel a píxel con su motor de polígonos.',
367
+ ],
368
+ },
369
+ {
370
+ id: 'progress-indicators',
371
+ title: 'Progress indicators',
372
+ searchAliases: ['Indicadores de progreso'],
373
+ group: 'loading-progress',
374
+ category: 'communication',
375
+ variants: ['linear', 'circular'],
376
+ configurations: ['flat', 'wavy', 'determinate', 'indeterminate', 'variable thickness', 'success composition', 'paused'],
377
+ implementation: 'mobile-design',
378
+ exports: ['ProgressIndicator', 'CircularProgressStatus'],
379
+ reference: 'https://m3.material.io/components/progress-indicators/overview',
380
+ notes: [
381
+ 'Geometría y fases expresivas independientes del ActivityIndicator/ProgressBar básico de Paper.',
382
+ 'CircularProgressStatus reproduce la composición progreso→anillo→check del vídeo Overview. El check mantiene posición/color; sus tiempos observados no son tokens normativos.',
383
+ ],
384
+ },
385
+ {
386
+ id: 'menus',
387
+ title: 'Menus',
388
+ searchAliases: ['Menús'],
389
+ group: null,
390
+ category: 'containment',
391
+ variants: ['vertical menu'],
392
+ configurations: [
393
+ 'standard',
394
+ 'vibrant',
395
+ 'grouped',
396
+ 'single selection',
397
+ 'multi selection',
398
+ 'anchored',
399
+ 'context',
400
+ 'scrollable',
401
+ 'submenus',
402
+ 'filtering',
403
+ 'slots',
404
+ ],
405
+ implementation: 'mobile-design',
406
+ exports: ['Menu'],
407
+ reference: 'https://m3.material.io/components/menus/overview',
408
+ notes: [
409
+ 'Estándar/vibrante/baseline, grupos, selección y popup local FastSpatial/FastEffects con límites de ventana/teclado. La auditoría distingue soporte nativo y web.',
410
+ ],
411
+ },
412
+ {
413
+ id: 'navigation-bar',
414
+ title: 'Navigation bar',
415
+ searchAliases: ['Barra de navegación'],
416
+ group: 'navigation',
417
+ category: 'navigation',
418
+ variants: ['flexible navigation bar'],
419
+ configurations: ['64dp', 'top icons', 'start icons', 'equal', 'centered', 'labels', 'badges'],
420
+ implementation: 'mobile-design',
421
+ exports: ['NavigationBar'],
422
+ reference: 'https://m3.material.io/components/navigation-bar/overview',
423
+ notes: [
424
+ 'Flexible64dp, iconos arriba/al inicio y distribución igual/centrada. La altura80dp sigue como referencia anterior en Specs, no como recomendación actual. El host aplica rutas y selección.',
425
+ ],
426
+ },
427
+ {
428
+ id: 'navigation-drawer',
429
+ title: 'Navigation drawer',
430
+ searchAliases: ['Cajón de navegación'],
431
+ group: 'navigation',
432
+ category: 'navigation',
433
+ variants: ['standard', 'modal'],
434
+ configurations: ['sections', 'selected destination', 'header', 'footer'],
435
+ implementation: 'mobile-design',
436
+ exports: ['NavigationDrawer', 'NavigationDrawerModal'],
437
+ reference: 'https://m3.material.io/components/navigation-drawer/overview',
438
+ notes: ['Drawer estándar y modal con selección, header/footer y estado controlado. Conserva Drawer de Paper como API adicional.'],
439
+ },
440
+ {
441
+ id: 'navigation-rail',
442
+ title: 'Navigation rail',
443
+ searchAliases: ['Rail de navegación'],
444
+ group: 'navigation',
445
+ category: 'navigation',
446
+ variants: ['collapsed', 'expanded'],
447
+ configurations: ['modal', 'non-modal', 'header', 'FAB', 'badges', 'adaptive layout'],
448
+ implementation: 'mobile-design',
449
+ exports: ['NavigationRail', 'NavigationRailModal'],
450
+ reference: 'https://m3.material.io/components/navigation-rail/overview',
451
+ notes: ['Colapsada, expandida y modal; colores, intervalos y destinos actuales. El host decide breakpoint y ruta.'],
452
+ },
453
+ {
454
+ id: 'radio-button',
455
+ title: 'Radio button',
456
+ searchAliases: ['Botones de opción'],
457
+ group: null,
458
+ category: 'selection',
459
+ variants: [],
460
+ configurations: ['selected', 'unselected', 'disabled', 'group', 'label'],
461
+ implementation: 'mobile-design',
462
+ exports: ['RadioButton'],
463
+ reference: 'https://m3.material.io/components/radio-button/overview',
464
+ notes: ['Círculo y animación MD3 locales, Group/Item, foco y objetivo48dp en iOS y Android.'],
465
+ },
466
+ {
467
+ id: 'search',
468
+ title: 'Search',
469
+ searchAliases: ['Búsqueda'],
470
+ group: null,
471
+ category: 'navigation',
472
+ variants: ['Search'],
473
+ configurations: ['contained', 'divided', 'docked', 'full-screen', 'results', 'empty', 'loading', 'keyboard'],
474
+ implementation: 'mobile-design',
475
+ exports: ['Searchbar', 'SearchView', 'SearchTrigger', 'SearchIconButton'],
476
+ reference: 'https://m3.material.io/components/search/overview',
477
+ notes: [
478
+ 'Barra MD3 con controles compartidos, estilo contained o divided y adaptación docked/full-screen. El consumidor obtiene los datos.',
479
+ ],
480
+ },
481
+ {
482
+ id: 'bottom-sheets',
483
+ title: 'Bottom sheets',
484
+ searchAliases: ['Hojas inferiores'],
485
+ group: 'sheets',
486
+ category: 'containment',
487
+ variants: ['standard', 'modal'],
488
+ configurations: ['snap points', 'content sizing', 'minimized standard', 'full-height', 'drag handle', 'scrollable', 'keyboard'],
489
+ implementation: 'mobile-design',
490
+ exports: [
491
+ 'BottomSheet',
492
+ 'BottomSheetScrollView',
493
+ 'BottomSheetFlatList',
494
+ 'BottomSheetSectionList',
495
+ 'BottomSheetTextInput',
496
+ 'BottomSheetTextField',
497
+ ],
498
+ reference: 'https://m3.material.io/components/bottom-sheets/overview',
499
+ notes: ['Usa el motor de gestos instalado de Gorhom con superficies y contexto Paper; necesita GestureHandlerRootView.'],
500
+ },
501
+ {
502
+ id: 'side-sheets',
503
+ title: 'Side sheets',
504
+ searchAliases: ['Hojas laterales'],
505
+ group: 'sheets',
506
+ category: 'containment',
507
+ variants: ['standard', 'modal'],
508
+ configurations: ['start', 'end', 'attached', 'detached', 'draggable', 'header', 'footer', 'independent scroll', 'adaptive layout'],
509
+ implementation: 'mobile-design',
510
+ exports: ['SideSheet'],
511
+ reference: 'https://m3.material.io/components/side-sheets/overview',
512
+ notes: ['La hoja estándar participa en el layout; modal gestiona scrim, cierre y accesibilidad en NativeModal.'],
513
+ },
514
+ {
515
+ id: 'sliders',
516
+ title: 'Sliders',
517
+ searchAliases: ['Deslizadores'],
518
+ group: null,
519
+ category: 'selection',
520
+ variants: ['standard', 'centered', 'range'],
521
+ configurations: ['vertical', 'horizontal', '5 sizes', 'inset icons', 'stops', 'value labels', 'reversed', 'disabled'],
522
+ implementation: 'mobile-design',
523
+ exports: ['Slider', 'RangeSlider'],
524
+ reference: 'https://m3.material.io/components/sliders/overview',
525
+ notes: [
526
+ 'Gestos/UI thread, límites y acciones de incremento/decremento accesibles; la precisión del gesto necesita prueba nativa.',
527
+ 'Continuous/discrete describen la configuración de step y stops del API, no nuevas familias de slider.',
528
+ ],
529
+ },
530
+ {
531
+ id: 'snackbar',
532
+ title: 'Snackbar',
533
+ searchAliases: ['Snackbar'],
534
+ group: null,
535
+ category: 'communication',
536
+ variants: [],
537
+ configurations: [
538
+ 'single line',
539
+ 'single line with action',
540
+ 'two lines',
541
+ 'two lines with action',
542
+ 'action on new line',
543
+ 'optional dismiss',
544
+ 'accessible duration',
545
+ 'placement',
546
+ 'consecutive messages',
547
+ ],
548
+ implementation: 'mobile-design',
549
+ exports: ['Snackbar'],
550
+ reference: 'https://m3.material.io/components/snackbar/overview',
551
+ notes: [
552
+ 'Contenedor y ciclo de vida propios, FastSpatial/FastEffects, anuncios corteses, acciones persistentes y plazo accesible; bottomOffset evita solapamiento con navegación/FAB.',
553
+ ],
554
+ },
555
+ {
556
+ id: 'switch',
557
+ title: 'Switch',
558
+ searchAliases: ['Interruptores'],
559
+ group: null,
560
+ category: 'selection',
561
+ variants: [],
562
+ configurations: [
563
+ 'without icons',
564
+ 'selected icon',
565
+ 'both icons',
566
+ 'on / off',
567
+ 'hover / focus / press',
568
+ 'disabled',
569
+ 'drag',
570
+ 'immediate settings',
571
+ ],
572
+ implementation: 'mobile-design',
573
+ exports: ['Switch'],
574
+ reference: 'https://m3.material.io/components/switch/overview',
575
+ notes: [
576
+ 'Track 52×32 dp, handle 16/24/28 dp, tinta de 40 dp y objetivo de 52×48 dp. Gesto horizontal, colores FastEffects, posición FastSpatial y foco de teclado; los ajustes se aplican inmediatamente.',
577
+ ],
578
+ },
579
+ {
580
+ id: 'tabs',
581
+ title: 'Tabs',
582
+ searchAliases: ['Pestañas'],
583
+ group: null,
584
+ category: 'navigation',
585
+ variants: ['primary', 'secondary'],
586
+ configurations: ['fixed', 'scrollable', 'labels', 'icons', 'icons and labels', 'badges', 'swipe pager'],
587
+ implementation: 'mobile-design',
588
+ exports: ['Tabs', 'TabsPager'],
589
+ reference: 'https://m3.material.io/components/tabs/overview',
590
+ notes: [
591
+ 'Primary y secondary compartidos; selección controlada, indicador medido y posición fraccional opcional enlazada al pager en el hilo UI.',
592
+ 'Configuraciones fixed/scrollable, etiquetas, iconos, icono + etiqueta y badges; no son variantes adicionales.',
593
+ ],
594
+ },
595
+ {
596
+ id: 'text-fields',
597
+ title: 'Text fields',
598
+ searchAliases: ['Campos de texto'],
599
+ group: null,
600
+ category: 'input',
601
+ variants: ['filled', 'outlined'],
602
+ configurations: ['leading', 'trailing', 'supporting text', 'error', 'counter', 'read-only', 'multiline', 'bottom sheet input'],
603
+ implementation: 'mobile-design',
604
+ exports: ['TextField', 'BottomSheetTextField'],
605
+ reference: 'https://m3.material.io/components/text-fields/overview',
606
+ notes: [
607
+ 'TextField propio con entrada nativa, tipografía/iconos/tema Paper y etiqueta flotante16→12sp; expone handle de foco y adaptador BottomSheetTextField.',
608
+ ],
609
+ },
610
+ {
611
+ id: 'toolbars',
612
+ title: 'Toolbars',
613
+ searchAliases: ['Barras de herramientas'],
614
+ group: null,
615
+ category: 'navigation',
616
+ variants: ['docked', 'floating'],
617
+ configurations: ['horizontal', 'vertical', 'standard', 'vibrant', 'overflow', 'expand/collapse'],
618
+ implementation: 'mobile-design',
619
+ exports: ['Toolbar'],
620
+ reference: 'https://m3.material.io/components/toolbars/overview',
621
+ notes: ['Acciones con objetivos48dp y superficies Paper; posición de la barra flotante se controla desde el host.'],
622
+ },
623
+ {
624
+ id: 'tooltips',
625
+ title: 'Tooltips',
626
+ searchAliases: ['Ayudas contextuales'],
627
+ group: null,
628
+ category: 'communication',
629
+ variants: ['plain', 'rich'],
630
+ configurations: ['title', 'body', 'actions', 'controlled visibility', 'hover', 'long press', 'focus'],
631
+ implementation: 'mobile-design',
632
+ exports: ['Tooltip', 'RichTooltip'],
633
+ reference: 'https://m3.material.io/components/tooltips/overview',
634
+ notes: [
635
+ 'Plain24×40dp mínimo e inverso; rich320dp y roles SurfaceContainer/OnSurfaceVariant. Temporizadores, long press/hover, exclusión mutua y popup adaptativo propios.',
636
+ ],
637
+ },
638
+ {
639
+ id: 'select',
640
+ title: 'Select',
641
+ searchAliases: ['Selector', 'Lista desplegable'],
642
+ group: 'extensions',
643
+ category: 'input',
644
+ variants: ['outlined', 'filled'],
645
+ configurations: [
646
+ 'Selección única',
647
+ 'Opción deshabilitada',
648
+ 'Campo deshabilitado',
649
+ 'Lista desplazable',
650
+ 'Sin opciones',
651
+ 'Configuración de reproducción',
652
+ ],
653
+ implementation: 'mobile-design',
654
+ exports: ['Select'],
655
+ notes: ['Extensión basada en TextField y una lista de opciones anclada. El consumidor controla el valor seleccionado.'],
656
+ },
657
+ {
658
+ id: 'autocomplete',
659
+ title: 'Autocomplete',
660
+ searchAliases: ['Autocompletar', 'Sugerencias'],
661
+ group: 'extensions',
662
+ category: 'input',
663
+ variants: ['outlined', 'filled'],
664
+ configurations: [
665
+ 'Sugerencias ancladas',
666
+ 'Sugerencias en línea',
667
+ 'Filtro local',
668
+ 'Resultados del consumidor',
669
+ 'Apertura al escribir',
670
+ 'Campo deshabilitado',
671
+ 'Sin resultados',
672
+ 'Ciudad del evento',
673
+ ],
674
+ implementation: 'mobile-design',
675
+ exports: ['Autocomplete'],
676
+ notes: ['Extensión basada en TextField. Permite escribir y elegir sugerencias con iconos y descripciones.'],
677
+ },
678
+ ] as const satisfies readonly MobileDesignCatalogEntry[];
679
+
680
+ export type MobileDesignComponentId = (typeof mobileDesignCatalog)[number]['id'];
681
+ export function getMobileDesignComponent(id: string): (typeof mobileDesignCatalog)[number] | undefined {
682
+ return mobileDesignCatalog.find((entry) => entry.id === id);
683
+ }