@acvl/mobile-components 0.0.0-stage → 0.0.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.
Files changed (297) hide show
  1. package/README.md +146 -2
  2. package/assets/fonts/Inter_400Regular.ttf +0 -0
  3. package/assets/fonts/Inter_500Medium.ttf +0 -0
  4. package/assets/fonts/Inter_600SemiBold.ttf +0 -0
  5. package/assets/fonts/Inter_700Bold.ttf +0 -0
  6. package/assets/fonts/Inter_800ExtraBold.ttf +0 -0
  7. package/assets/fonts/Inter_900Black.ttf +0 -0
  8. package/assets/fonts/OFL.txt +93 -0
  9. package/lib/module/componentes/AccionesDelEncabezado.js +212 -0
  10. package/lib/module/componentes/AccionesDelEncabezado.js.map +1 -0
  11. package/lib/module/componentes/BotonDeAvatar.js +55 -0
  12. package/lib/module/componentes/BotonDeAvatar.js.map +1 -0
  13. package/lib/module/componentes/BotonGrande.js +105 -0
  14. package/lib/module/componentes/BotonGrande.js.map +1 -0
  15. package/lib/module/componentes/CabeceraEmpujada.js +101 -0
  16. package/lib/module/componentes/CabeceraEmpujada.js.map +1 -0
  17. package/lib/module/componentes/Chip.js +77 -0
  18. package/lib/module/componentes/Chip.js.map +1 -0
  19. package/lib/module/componentes/ContenidoDePantalla.js +56 -0
  20. package/lib/module/componentes/ContenidoDePantalla.js.map +1 -0
  21. package/lib/module/componentes/EstadoVacio.js +65 -0
  22. package/lib/module/componentes/EstadoVacio.js.map +1 -0
  23. package/lib/module/componentes/Foto.js +106 -0
  24. package/lib/module/componentes/Foto.js.map +1 -0
  25. package/lib/module/componentes/IconoDeRenglon.js +44 -0
  26. package/lib/module/componentes/IconoDeRenglon.js.map +1 -0
  27. package/lib/module/componentes/Logo.js +44 -0
  28. package/lib/module/componentes/Logo.js.map +1 -0
  29. package/lib/module/componentes/Nota.js +51 -0
  30. package/lib/module/componentes/Nota.js.map +1 -0
  31. package/lib/module/componentes/OpcionesExcluyentes.js +69 -0
  32. package/lib/module/componentes/OpcionesExcluyentes.js.map +1 -0
  33. package/lib/module/componentes/PantallaDeError.js +84 -0
  34. package/lib/module/componentes/PantallaDeError.js.map +1 -0
  35. package/lib/module/componentes/Pestanas.js +87 -0
  36. package/lib/module/componentes/Pestanas.js.map +1 -0
  37. package/lib/module/componentes/Rotulo.js +28 -0
  38. package/lib/module/componentes/Rotulo.js.map +1 -0
  39. package/lib/module/componentes/RotuloDeSeccion.js +87 -0
  40. package/lib/module/componentes/RotuloDeSeccion.js.map +1 -0
  41. package/lib/module/componentes/Tarjeta.js +47 -0
  42. package/lib/module/componentes/Tarjeta.js.map +1 -0
  43. package/lib/module/componentes/TarjetaDeDatos.js +79 -0
  44. package/lib/module/componentes/TarjetaDeDatos.js.map +1 -0
  45. package/lib/module/componentes/TiraDeFotos.js +184 -0
  46. package/lib/module/componentes/TiraDeFotos.js.map +1 -0
  47. package/lib/module/componentes/VisorDeFoto.js +171 -0
  48. package/lib/module/componentes/VisorDeFoto.js.map +1 -0
  49. package/lib/module/componentes/logos/bola-blanca.png +0 -0
  50. package/lib/module/componentes/logos/bola.png +0 -0
  51. package/lib/module/componentes/logos/logo-blanco.png +0 -0
  52. package/lib/module/componentes/logos/logo.png +0 -0
  53. package/lib/module/dialogos/HostDeDialogos.js +170 -0
  54. package/lib/module/dialogos/HostDeDialogos.js.map +1 -0
  55. package/lib/module/dialogos/dialogos.js +112 -0
  56. package/lib/module/dialogos/dialogos.js.map +1 -0
  57. package/lib/module/formularios/CampoDeSeleccion.js +47 -0
  58. package/lib/module/formularios/CampoDeSeleccion.js.map +1 -0
  59. package/lib/module/formularios/SelectorDeOpcion.js +406 -0
  60. package/lib/module/formularios/SelectorDeOpcion.js.map +1 -0
  61. package/lib/module/formularios/TextoDeAccesoControlado.js +73 -0
  62. package/lib/module/formularios/TextoDeAccesoControlado.js.map +1 -0
  63. package/lib/module/formularios/campos.js +493 -0
  64. package/lib/module/formularios/campos.js.map +1 -0
  65. package/lib/module/formularios/controlados.js +197 -0
  66. package/lib/module/formularios/controlados.js.map +1 -0
  67. package/lib/module/formularios/errores.js +91 -0
  68. package/lib/module/formularios/errores.js.map +1 -0
  69. package/lib/module/formularios/guardado.js +78 -0
  70. package/lib/module/formularios/guardado.js.map +1 -0
  71. package/lib/module/formularios/useBusqueda.js +22 -0
  72. package/lib/module/formularios/useBusqueda.js.map +1 -0
  73. package/lib/module/fotos/elegir.js +178 -0
  74. package/lib/module/fotos/elegir.js.map +1 -0
  75. package/lib/module/fotos/index.js +8 -0
  76. package/lib/module/fotos/index.js.map +1 -0
  77. package/lib/module/fotos/reducir.js +93 -0
  78. package/lib/module/fotos/reducir.js.map +1 -0
  79. package/lib/module/hoja/HojaInferior.js +108 -0
  80. package/lib/module/hoja/HojaInferior.js.map +1 -0
  81. package/lib/module/hoja/index.js +7 -0
  82. package/lib/module/hoja/index.js.map +1 -0
  83. package/lib/module/hoja/useMasDeLaFicha.js +48 -0
  84. package/lib/module/hoja/useMasDeLaFicha.js.map +1 -0
  85. package/lib/module/index.js +66 -0
  86. package/lib/module/index.js.map +1 -0
  87. package/lib/module/listas/HojaDeFiltros.js +260 -0
  88. package/lib/module/listas/HojaDeFiltros.js.map +1 -0
  89. package/lib/module/listas/ListaPaginada.js +103 -0
  90. package/lib/module/listas/ListaPaginada.js.map +1 -0
  91. package/lib/module/listas/TarjetaDeslizable.js +118 -0
  92. package/lib/module/listas/TarjetaDeslizable.js.map +1 -0
  93. package/lib/module/listas/paginado.js +11 -0
  94. package/lib/module/listas/paginado.js.map +1 -0
  95. package/lib/module/listas/piezas.js +603 -0
  96. package/lib/module/listas/piezas.js.map +1 -0
  97. package/lib/module/navegacion/BarraDePestanas.js +162 -0
  98. package/lib/module/navegacion/BarraDePestanas.js.map +1 -0
  99. package/lib/module/navegacion/BotonDeBarra.js +58 -0
  100. package/lib/module/navegacion/BotonDeBarra.js.map +1 -0
  101. package/lib/module/navegacion/encabezado.js +103 -0
  102. package/lib/module/navegacion/encabezado.js.map +1 -0
  103. package/lib/module/pantallas/PantallaDeAcceso.js +195 -0
  104. package/lib/module/pantallas/PantallaDeAcceso.js.map +1 -0
  105. package/lib/module/pantallas/PantallaDeEdicion.js +121 -0
  106. package/lib/module/pantallas/PantallaDeEdicion.js.map +1 -0
  107. package/lib/module/pantallas/PantallaDeFicha.js +94 -0
  108. package/lib/module/pantallas/PantallaDeFicha.js.map +1 -0
  109. package/lib/module/pantallas/PantallaDePerfil.js +137 -0
  110. package/lib/module/pantallas/PantallaDePerfil.js.map +1 -0
  111. package/lib/module/tema/ProveedorDeTema.js +122 -0
  112. package/lib/module/tema/ProveedorDeTema.js.map +1 -0
  113. package/lib/module/tema/estilos.js +54 -0
  114. package/lib/module/tema/estilos.js.map +1 -0
  115. package/lib/module/tema/fuentes.js +28 -0
  116. package/lib/module/tema/fuentes.js.map +1 -0
  117. package/lib/module/tema/index.js +8 -0
  118. package/lib/module/tema/index.js.map +1 -0
  119. package/lib/module/tema/paleta.js +107 -0
  120. package/lib/module/tema/paleta.js.map +1 -0
  121. package/lib/module/tema/tipografia.js +32 -0
  122. package/lib/module/tema/tipografia.js.map +1 -0
  123. package/lib/module/texto.js +48 -0
  124. package/lib/module/texto.js.map +1 -0
  125. package/lib/typescript/src/componentes/AccionesDelEncabezado.d.ts +34 -0
  126. package/lib/typescript/src/componentes/AccionesDelEncabezado.d.ts.map +1 -0
  127. package/lib/typescript/src/componentes/BotonDeAvatar.d.ts +17 -0
  128. package/lib/typescript/src/componentes/BotonDeAvatar.d.ts.map +1 -0
  129. package/lib/typescript/src/componentes/BotonGrande.d.ts +26 -0
  130. package/lib/typescript/src/componentes/BotonGrande.d.ts.map +1 -0
  131. package/lib/typescript/src/componentes/CabeceraEmpujada.d.ts +18 -0
  132. package/lib/typescript/src/componentes/CabeceraEmpujada.d.ts.map +1 -0
  133. package/lib/typescript/src/componentes/Chip.d.ts +14 -0
  134. package/lib/typescript/src/componentes/Chip.d.ts.map +1 -0
  135. package/lib/typescript/src/componentes/ContenidoDePantalla.d.ts +17 -0
  136. package/lib/typescript/src/componentes/ContenidoDePantalla.d.ts.map +1 -0
  137. package/lib/typescript/src/componentes/EstadoVacio.d.ts +17 -0
  138. package/lib/typescript/src/componentes/EstadoVacio.d.ts.map +1 -0
  139. package/lib/typescript/src/componentes/Foto.d.ts +41 -0
  140. package/lib/typescript/src/componentes/Foto.d.ts.map +1 -0
  141. package/lib/typescript/src/componentes/IconoDeRenglon.d.ts +25 -0
  142. package/lib/typescript/src/componentes/IconoDeRenglon.d.ts.map +1 -0
  143. package/lib/typescript/src/componentes/Logo.d.ts +13 -0
  144. package/lib/typescript/src/componentes/Logo.d.ts.map +1 -0
  145. package/lib/typescript/src/componentes/Nota.d.ts +7 -0
  146. package/lib/typescript/src/componentes/Nota.d.ts.map +1 -0
  147. package/lib/typescript/src/componentes/OpcionesExcluyentes.d.ts +14 -0
  148. package/lib/typescript/src/componentes/OpcionesExcluyentes.d.ts.map +1 -0
  149. package/lib/typescript/src/componentes/PantallaDeError.d.ts +23 -0
  150. package/lib/typescript/src/componentes/PantallaDeError.d.ts.map +1 -0
  151. package/lib/typescript/src/componentes/Pestanas.d.ts +28 -0
  152. package/lib/typescript/src/componentes/Pestanas.d.ts.map +1 -0
  153. package/lib/typescript/src/componentes/Rotulo.d.ts +6 -0
  154. package/lib/typescript/src/componentes/Rotulo.d.ts.map +1 -0
  155. package/lib/typescript/src/componentes/RotuloDeSeccion.d.ts +20 -0
  156. package/lib/typescript/src/componentes/RotuloDeSeccion.d.ts.map +1 -0
  157. package/lib/typescript/src/componentes/Tarjeta.d.ts +15 -0
  158. package/lib/typescript/src/componentes/Tarjeta.d.ts.map +1 -0
  159. package/lib/typescript/src/componentes/TarjetaDeDatos.d.ts +13 -0
  160. package/lib/typescript/src/componentes/TarjetaDeDatos.d.ts.map +1 -0
  161. package/lib/typescript/src/componentes/TiraDeFotos.d.ts +36 -0
  162. package/lib/typescript/src/componentes/TiraDeFotos.d.ts.map +1 -0
  163. package/lib/typescript/src/componentes/VisorDeFoto.d.ts +23 -0
  164. package/lib/typescript/src/componentes/VisorDeFoto.d.ts.map +1 -0
  165. package/lib/typescript/src/dialogos/HostDeDialogos.d.ts +14 -0
  166. package/lib/typescript/src/dialogos/HostDeDialogos.d.ts.map +1 -0
  167. package/lib/typescript/src/dialogos/dialogos.d.ts +65 -0
  168. package/lib/typescript/src/dialogos/dialogos.d.ts.map +1 -0
  169. package/lib/typescript/src/formularios/CampoDeSeleccion.d.ts +22 -0
  170. package/lib/typescript/src/formularios/CampoDeSeleccion.d.ts.map +1 -0
  171. package/lib/typescript/src/formularios/SelectorDeOpcion.d.ts +59 -0
  172. package/lib/typescript/src/formularios/SelectorDeOpcion.d.ts.map +1 -0
  173. package/lib/typescript/src/formularios/TextoDeAccesoControlado.d.ts +18 -0
  174. package/lib/typescript/src/formularios/TextoDeAccesoControlado.d.ts.map +1 -0
  175. package/lib/typescript/src/formularios/campos.d.ts +107 -0
  176. package/lib/typescript/src/formularios/campos.d.ts.map +1 -0
  177. package/lib/typescript/src/formularios/controlados.d.ts +29 -0
  178. package/lib/typescript/src/formularios/controlados.d.ts.map +1 -0
  179. package/lib/typescript/src/formularios/errores.d.ts +36 -0
  180. package/lib/typescript/src/formularios/errores.d.ts.map +1 -0
  181. package/lib/typescript/src/formularios/guardado.d.ts +36 -0
  182. package/lib/typescript/src/formularios/guardado.d.ts.map +1 -0
  183. package/lib/typescript/src/formularios/useBusqueda.d.ts +7 -0
  184. package/lib/typescript/src/formularios/useBusqueda.d.ts.map +1 -0
  185. package/lib/typescript/src/fotos/elegir.d.ts +58 -0
  186. package/lib/typescript/src/fotos/elegir.d.ts.map +1 -0
  187. package/lib/typescript/src/fotos/index.d.ts +3 -0
  188. package/lib/typescript/src/fotos/index.d.ts.map +1 -0
  189. package/lib/typescript/src/fotos/reducir.d.ts +32 -0
  190. package/lib/typescript/src/fotos/reducir.d.ts.map +1 -0
  191. package/lib/typescript/src/hoja/HojaInferior.d.ts +21 -0
  192. package/lib/typescript/src/hoja/HojaInferior.d.ts.map +1 -0
  193. package/lib/typescript/src/hoja/index.d.ts +3 -0
  194. package/lib/typescript/src/hoja/index.d.ts.map +1 -0
  195. package/lib/typescript/src/hoja/useMasDeLaFicha.d.ts +27 -0
  196. package/lib/typescript/src/hoja/useMasDeLaFicha.d.ts.map +1 -0
  197. package/lib/typescript/src/index.d.ts +45 -0
  198. package/lib/typescript/src/index.d.ts.map +1 -0
  199. package/lib/typescript/src/listas/HojaDeFiltros.d.ts +60 -0
  200. package/lib/typescript/src/listas/HojaDeFiltros.d.ts.map +1 -0
  201. package/lib/typescript/src/listas/ListaPaginada.d.ts +39 -0
  202. package/lib/typescript/src/listas/ListaPaginada.d.ts.map +1 -0
  203. package/lib/typescript/src/listas/TarjetaDeslizable.d.ts +33 -0
  204. package/lib/typescript/src/listas/TarjetaDeslizable.d.ts.map +1 -0
  205. package/lib/typescript/src/listas/paginado.d.ts +16 -0
  206. package/lib/typescript/src/listas/paginado.d.ts.map +1 -0
  207. package/lib/typescript/src/listas/piezas.d.ts +135 -0
  208. package/lib/typescript/src/listas/piezas.d.ts.map +1 -0
  209. package/lib/typescript/src/navegacion/BarraDePestanas.d.ts +57 -0
  210. package/lib/typescript/src/navegacion/BarraDePestanas.d.ts.map +1 -0
  211. package/lib/typescript/src/navegacion/BotonDeBarra.d.ts +15 -0
  212. package/lib/typescript/src/navegacion/BotonDeBarra.d.ts.map +1 -0
  213. package/lib/typescript/src/navegacion/encabezado.d.ts +44 -0
  214. package/lib/typescript/src/navegacion/encabezado.d.ts.map +1 -0
  215. package/lib/typescript/src/pantallas/PantallaDeAcceso.d.ts +32 -0
  216. package/lib/typescript/src/pantallas/PantallaDeAcceso.d.ts.map +1 -0
  217. package/lib/typescript/src/pantallas/PantallaDeEdicion.d.ts +38 -0
  218. package/lib/typescript/src/pantallas/PantallaDeEdicion.d.ts.map +1 -0
  219. package/lib/typescript/src/pantallas/PantallaDeFicha.d.ts +35 -0
  220. package/lib/typescript/src/pantallas/PantallaDeFicha.d.ts.map +1 -0
  221. package/lib/typescript/src/pantallas/PantallaDePerfil.d.ts +19 -0
  222. package/lib/typescript/src/pantallas/PantallaDePerfil.d.ts.map +1 -0
  223. package/lib/typescript/src/tema/ProveedorDeTema.d.ts +32 -0
  224. package/lib/typescript/src/tema/ProveedorDeTema.d.ts.map +1 -0
  225. package/lib/typescript/src/tema/estilos.d.ts +31 -0
  226. package/lib/typescript/src/tema/estilos.d.ts.map +1 -0
  227. package/lib/typescript/src/tema/fuentes.d.ts +20 -0
  228. package/lib/typescript/src/tema/fuentes.d.ts.map +1 -0
  229. package/lib/typescript/src/tema/index.d.ts +6 -0
  230. package/lib/typescript/src/tema/index.d.ts.map +1 -0
  231. package/lib/typescript/src/tema/paleta.d.ts +86 -0
  232. package/lib/typescript/src/tema/paleta.d.ts.map +1 -0
  233. package/lib/typescript/src/tema/tipografia.d.ts +29 -0
  234. package/lib/typescript/src/tema/tipografia.d.ts.map +1 -0
  235. package/lib/typescript/src/texto.d.ts +16 -0
  236. package/lib/typescript/src/texto.d.ts.map +1 -0
  237. package/package.json +135 -5
  238. package/src/componentes/AccionesDelEncabezado.tsx +247 -0
  239. package/src/componentes/BotonDeAvatar.tsx +59 -0
  240. package/src/componentes/BotonGrande.tsx +100 -0
  241. package/src/componentes/CabeceraEmpujada.tsx +69 -0
  242. package/src/componentes/Chip.tsx +60 -0
  243. package/src/componentes/ContenidoDePantalla.tsx +53 -0
  244. package/src/componentes/EstadoVacio.tsx +45 -0
  245. package/src/componentes/Foto.tsx +92 -0
  246. package/src/componentes/IconoDeRenglon.tsx +42 -0
  247. package/src/componentes/Logo.tsx +34 -0
  248. package/src/componentes/Nota.tsx +37 -0
  249. package/src/componentes/OpcionesExcluyentes.tsx +62 -0
  250. package/src/componentes/PantallaDeError.tsx +76 -0
  251. package/src/componentes/Pestanas.tsx +86 -0
  252. package/src/componentes/Rotulo.tsx +21 -0
  253. package/src/componentes/RotuloDeSeccion.tsx +71 -0
  254. package/src/componentes/Tarjeta.tsx +44 -0
  255. package/src/componentes/TarjetaDeDatos.tsx +62 -0
  256. package/src/componentes/TiraDeFotos.tsx +189 -0
  257. package/src/componentes/VisorDeFoto.tsx +181 -0
  258. package/src/componentes/logos/bola-blanca.png +0 -0
  259. package/src/componentes/logos/bola.png +0 -0
  260. package/src/componentes/logos/logo-blanco.png +0 -0
  261. package/src/componentes/logos/logo.png +0 -0
  262. package/src/dialogos/HostDeDialogos.tsx +172 -0
  263. package/src/dialogos/dialogos.ts +148 -0
  264. package/src/formularios/CampoDeSeleccion.tsx +46 -0
  265. package/src/formularios/SelectorDeOpcion.tsx +407 -0
  266. package/src/formularios/TextoDeAccesoControlado.tsx +72 -0
  267. package/src/formularios/campos.tsx +483 -0
  268. package/src/formularios/controlados.tsx +198 -0
  269. package/src/formularios/errores.ts +105 -0
  270. package/src/formularios/guardado.ts +76 -0
  271. package/src/formularios/useBusqueda.ts +19 -0
  272. package/src/fotos/elegir.ts +194 -0
  273. package/src/fotos/index.ts +15 -0
  274. package/src/fotos/reducir.ts +87 -0
  275. package/src/hoja/HojaInferior.tsx +102 -0
  276. package/src/hoja/index.ts +4 -0
  277. package/src/hoja/useMasDeLaFicha.tsx +63 -0
  278. package/src/index.ts +143 -0
  279. package/src/listas/HojaDeFiltros.tsx +261 -0
  280. package/src/listas/ListaPaginada.tsx +117 -0
  281. package/src/listas/TarjetaDeslizable.tsx +126 -0
  282. package/src/listas/paginado.ts +15 -0
  283. package/src/listas/piezas.tsx +594 -0
  284. package/src/navegacion/BarraDePestanas.tsx +198 -0
  285. package/src/navegacion/BotonDeBarra.tsx +61 -0
  286. package/src/navegacion/encabezado.tsx +88 -0
  287. package/src/pantallas/PantallaDeAcceso.tsx +184 -0
  288. package/src/pantallas/PantallaDeEdicion.tsx +116 -0
  289. package/src/pantallas/PantallaDeFicha.tsx +115 -0
  290. package/src/pantallas/PantallaDePerfil.tsx +126 -0
  291. package/src/tema/ProveedorDeTema.tsx +150 -0
  292. package/src/tema/estilos.ts +51 -0
  293. package/src/tema/fuentes.ts +20 -0
  294. package/src/tema/index.ts +10 -0
  295. package/src/tema/paleta.ts +147 -0
  296. package/src/tema/tipografia.ts +29 -0
  297. package/src/texto.tsx +44 -0
@@ -0,0 +1,594 @@
1
+ import Chip from "../componentes/Chip";
2
+ import IconoDeRenglon from "../componentes/IconoDeRenglon";
3
+ import Pestanas from "../componentes/Pestanas";
4
+ import Tarjeta from "../componentes/Tarjeta";
5
+ import { crearEstilos, renglon, tipografia, usePaleta } from "../tema";
6
+ import { type Pestana } from "../componentes/Pestanas";
7
+ import { Text, TextInput } from "../texto";
8
+ import { type TonoDeChip } from "../componentes/Chip";
9
+ import MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons";
10
+ import type { Href } from "expo-router";
11
+ import { router } from "expo-router";
12
+ import React from "react";
13
+ import {
14
+ ActivityIndicator,
15
+ Linking,
16
+ Pressable,
17
+ View,
18
+ type StyleProp,
19
+ type ViewStyle,
20
+ } from "react-native";
21
+
22
+ /**
23
+ * Las piezas de las listas y las fichas: la cabecera de una lista (buscador y pestañas), la
24
+ * tarjeta de un renglón y, en las fichas, las secciones, las ligas a otra ficha y los contactos.
25
+ * Todo es de lectura.
26
+ */
27
+
28
+ /**
29
+ * El buscador de una lista y del mapa. Lo escrito se le pasa a la consulta con pausa
30
+ * (`useBusqueda`): no una petición por letra.
31
+ *
32
+ * **El texto de sugerencia va en un renglón, con «…» si no cabe.** Es un `Text` encima del campo y
33
+ * no el `placeholder` del `TextInput`: el de Android parte en dos renglones lo que no cabe, y el
34
+ * segundo queda cortado a la mitad.
35
+ */
36
+ export function Buscador({
37
+ texto,
38
+ onCambiar,
39
+ placeholder,
40
+ autoFocus,
41
+ onBlur,
42
+ style,
43
+ }: {
44
+ texto: string;
45
+ onCambiar: (texto: string) => void;
46
+ placeholder: string;
47
+ autoFocus?: boolean;
48
+ onBlur?: () => void;
49
+ style?: StyleProp<ViewStyle>;
50
+ }) {
51
+ const c = usePaleta();
52
+ const styles = useStyles();
53
+ return (
54
+ <View style={[styles.buscador, style]}>
55
+ <MaterialCommunityIcons name="magnify" size={24} color={c.secondary} />
56
+ <View style={styles.campo}>
57
+ {!texto ? (
58
+ <Text
59
+ style={styles.sugerencia}
60
+ numberOfLines={1}
61
+ ellipsizeMode="tail"
62
+ pointerEvents="none"
63
+ >
64
+ {placeholder}
65
+ </Text>
66
+ ) : null}
67
+ <TextInput
68
+ value={texto}
69
+ onChangeText={onCambiar}
70
+ accessibilityLabel={placeholder}
71
+ autoCorrect={false}
72
+ autoFocus={autoFocus}
73
+ onBlur={onBlur}
74
+ returnKeyType="search"
75
+ style={styles.entrada}
76
+ />
77
+ </View>
78
+ {texto ? (
79
+ <Pressable
80
+ onPress={() => onCambiar("")}
81
+ hitSlop={8}
82
+ accessibilityLabel="Borrar búsqueda"
83
+ >
84
+ <MaterialCommunityIcons name="close-circle" size={22} color={c.secondary} />
85
+ </Pressable>
86
+ ) : null}
87
+ </View>
88
+ );
89
+ }
90
+
91
+ /** Lo que dice el botón de los filtros de una lista y qué abre. */
92
+ export interface FiltrosDeCabecera {
93
+ /** Cuántos filtros hay puestos: el globito. */
94
+ cuenta: number;
95
+ /** Si sólo cambió el orden: un punto. */
96
+ punto: boolean;
97
+ onPress: () => void;
98
+ }
99
+
100
+ /**
101
+ * El botón de los filtros, junto al buscador: dice cuántos hay puestos, como el del mapa, y lleva un
102
+ * punto si sólo cambió el orden.
103
+ */
104
+ function BotonDeFiltros({ cuenta, punto, onPress }: FiltrosDeCabecera) {
105
+ const c = usePaleta();
106
+ const styles = useStyles();
107
+ const activo = Boolean(cuenta) || punto;
108
+ return (
109
+ <Pressable
110
+ onPress={onPress}
111
+ accessibilityRole="button"
112
+ accessibilityLabel={cuenta ? `Filtros, ${cuenta} puestos` : "Filtros y orden"}
113
+ hitSlop={4}
114
+ style={({ pressed }) => [
115
+ styles.botonDeFiltros,
116
+ activo && styles.botonDeFiltrosActivo,
117
+ pressed && styles.presionada,
118
+ ]}
119
+ >
120
+ <MaterialCommunityIcons
121
+ name="filter-variant"
122
+ size={26}
123
+ color={activo ? c.primary : c.secondaryDark}
124
+ />
125
+ {cuenta ? (
126
+ <View style={styles.globito}>
127
+ <Text style={styles.globitoTexto} maxFontSizeMultiplier={1.2}>
128
+ {cuenta}
129
+ </Text>
130
+ </View>
131
+ ) : punto ? (
132
+ <View style={styles.punto} />
133
+ ) : null}
134
+ </Pressable>
135
+ );
136
+ }
137
+
138
+ /**
139
+ * Lo de arriba de una lista: el buscador, con el botón de sus filtros a la derecha si los tiene, y
140
+ * las pestañas que la cortan («En curso», «Por iniciar»). Con una sola pestaña no se pintan.
141
+ */
142
+ export function CabeceraDeLista<K extends string>({
143
+ texto,
144
+ onBuscar,
145
+ placeholder,
146
+ pestanas,
147
+ activa,
148
+ onPestana,
149
+ filtros,
150
+ }: {
151
+ texto: string;
152
+ onBuscar: (texto: string) => void;
153
+ placeholder: string;
154
+ pestanas?: readonly Pestana<K>[];
155
+ activa?: K;
156
+ onPestana?: (key: K) => void;
157
+ filtros?: FiltrosDeCabecera;
158
+ }) {
159
+ const styles = useStyles();
160
+ return (
161
+ <View style={styles.cabecera}>
162
+ {filtros ? (
163
+ <View style={styles.filaDeBusqueda}>
164
+ <Buscador
165
+ texto={texto}
166
+ onCambiar={onBuscar}
167
+ placeholder={placeholder}
168
+ style={styles.flex}
169
+ />
170
+ <BotonDeFiltros {...filtros} />
171
+ </View>
172
+ ) : (
173
+ <Buscador texto={texto} onCambiar={onBuscar} placeholder={placeholder} />
174
+ )}
175
+ {pestanas && pestanas.length > 1 && activa && onPestana ? (
176
+ <Pestanas pestanas={pestanas} activa={activa} onSelect={onPestana} />
177
+ ) : null}
178
+ </View>
179
+ );
180
+ }
181
+
182
+ /**
183
+ * Un renglón de una lista como tarjeta: el título y, a su derecha, su estado (un `Chip`); debajo,
184
+ * lo que acompaña, un renglón por dato. Nada se recorta: con la letra al 180% parte en los
185
+ * renglones que haga falta.
186
+ */
187
+ export function TarjetaDeLista({
188
+ titulo,
189
+ estado,
190
+ lineas,
191
+ children,
192
+ onPress,
193
+ }: {
194
+ titulo: string;
195
+ estado?: React.ReactNode;
196
+ /** Los renglones de abajo; los vacíos no se pintan. */
197
+ lineas?: (string | null | undefined | false)[];
198
+ children?: React.ReactNode;
199
+ onPress?: () => void;
200
+ }) {
201
+ const styles = useStyles();
202
+ return (
203
+ <Tarjeta onPress={onPress}>
204
+ <View style={styles.tarjetaCabecera}>
205
+ <Text style={styles.tarjetaTitulo}>{titulo}</Text>
206
+ {estado}
207
+ </View>
208
+ {lineas
209
+ ?.filter((l): l is string => Boolean(l))
210
+ .map((l, i) => (
211
+ <Text key={i} style={styles.linea}>
212
+ {l}
213
+ </Text>
214
+ ))}
215
+ {children}
216
+ </Tarjeta>
217
+ );
218
+ }
219
+
220
+ /** Una sección de una ficha: su rótulo y lo suyo debajo. */
221
+ export function SeccionDeFicha({
222
+ titulo,
223
+ children,
224
+ }: {
225
+ titulo: string;
226
+ children: React.ReactNode;
227
+ }) {
228
+ const styles = useStyles();
229
+ return (
230
+ <View style={styles.seccion}>
231
+ <Text style={styles.rotulo}>{titulo}</Text>
232
+ {children}
233
+ </View>
234
+ );
235
+ }
236
+
237
+ /**
238
+ * Un renglón que abre otra ficha: «Operador · Juan Pérez ›». Sin `href` (no hay a dónde, o no se
239
+ * tiene el permiso) se pinta igual pero sin la flecha y sin abrir nada.
240
+ */
241
+ export function RenglonDeLiga({
242
+ etiqueta,
243
+ valor,
244
+ href,
245
+ detalle,
246
+ }: {
247
+ etiqueta: string;
248
+ valor: string;
249
+ href?: Href | null;
250
+ detalle?: string | null;
251
+ }) {
252
+ const c = usePaleta();
253
+ const styles = useStyles();
254
+ return (
255
+ <Pressable
256
+ onPress={href ? () => router.push(href) : undefined}
257
+ disabled={!href}
258
+ accessibilityRole={href ? "link" : undefined}
259
+ style={({ pressed }) => [styles.renglon, pressed && styles.presionada]}
260
+ >
261
+ <View style={styles.renglonTexto}>
262
+ <Text style={styles.etiqueta}>{etiqueta}</Text>
263
+ {/* En el color primario cuando abre otra ficha: así se distingue de un dato. */}
264
+ <Text style={[styles.valor, href ? styles.liga : null]}>{valor}</Text>
265
+ {detalle ? <Text style={styles.linea}>{detalle}</Text> : null}
266
+ </View>
267
+ {href ? (
268
+ <IconoDeRenglon
269
+ name="chevron-right"
270
+ fontSize={tipografia.subtitulo}
271
+ color={c.secondaryLight}
272
+ />
273
+ ) : null}
274
+ </Pressable>
275
+ );
276
+ }
277
+
278
+ /**
279
+ * Un renglón que dice cuántos hay de algo y lo abre: «Excepciones 3 ›». Como los contenidos de una
280
+ * transferencia en la app de acv-wms. Lo que abre es de quien lo usa (una `HojaInferior`).
281
+ */
282
+ export function FilaConContador({
283
+ icono,
284
+ etiqueta,
285
+ cuantos,
286
+ detalle,
287
+ onPress,
288
+ }: {
289
+ icono: React.ComponentProps<typeof MaterialCommunityIcons>["name"];
290
+ etiqueta: string;
291
+ /** `null` mientras se cuenta. */
292
+ cuantos: number | null;
293
+ /** Lo que acompaña: «2 pendientes». */
294
+ detalle?: string | null;
295
+ onPress: () => void;
296
+ }) {
297
+ const c = usePaleta();
298
+ const styles = useStyles();
299
+ return (
300
+ <Pressable
301
+ onPress={onPress}
302
+ accessibilityRole="button"
303
+ style={({ pressed }) => [styles.renglon, pressed && styles.presionada]}
304
+ >
305
+ <View style={styles.iconoDeContador}>
306
+ <MaterialCommunityIcons name={icono} size={20} color={c.primary} />
307
+ </View>
308
+ <View style={styles.renglonTexto}>
309
+ <Text style={styles.valor}>{etiqueta}</Text>
310
+ {detalle ? <Text style={styles.linea}>{detalle}</Text> : null}
311
+ </View>
312
+ <Text style={styles.cuantos}>{cuantos ?? "…"}</Text>
313
+ <IconoDeRenglon
314
+ name="chevron-right"
315
+ fontSize={tipografia.subtitulo}
316
+ color={c.secondaryLight}
317
+ />
318
+ </Pressable>
319
+ );
320
+ }
321
+
322
+ /** Los dígitos de un teléfono, para WhatsApp: `+52 664 123 4567` → `526641234567`. */
323
+ const digitos = (telefono: string) => telefono.replace(/\D/g, "");
324
+
325
+ /**
326
+ * Una persona con su teléfono y su correo, **para llamarle o escribirle desde ahí**: cada uno es un
327
+ * botón. Sin teléfono ni correo, sólo su nombre.
328
+ */
329
+ export function RenglonDeContacto({
330
+ nombre,
331
+ detalle,
332
+ telefono,
333
+ correo,
334
+ enHoja,
335
+ }: {
336
+ nombre: string;
337
+ /** El puesto, el parentesco, el tipo de contacto. */
338
+ detalle?: string | null;
339
+ telefono?: string | null;
340
+ correo?: string | null;
341
+ /** En una hoja (`HojaInferior`), del color del fondo, como `RenglonDeHoja`: si no, no se distingue. */
342
+ enHoja?: boolean;
343
+ }) {
344
+ const c = usePaleta();
345
+ const styles = useStyles();
346
+ const boton = (
347
+ icono: React.ComponentProps<typeof MaterialCommunityIcons>["name"],
348
+ etiqueta: string,
349
+ url: string,
350
+ ) => (
351
+ <Pressable
352
+ key={etiqueta}
353
+ onPress={() => Linking.openURL(url).catch(() => {})}
354
+ accessibilityRole="button"
355
+ accessibilityLabel={etiqueta}
356
+ hitSlop={6}
357
+ style={({ pressed }) => [styles.accion, pressed && styles.presionada]}
358
+ >
359
+ <MaterialCommunityIcons name={icono} size={24} color={c.primary} />
360
+ </Pressable>
361
+ );
362
+ return (
363
+ <View style={[styles.renglon, enHoja && styles.renglonEnHoja]}>
364
+ <View style={styles.renglonTexto}>
365
+ <Text style={styles.valor}>{nombre}</Text>
366
+ {detalle ? <Text style={styles.linea}>{detalle}</Text> : null}
367
+ {telefono ? <Text style={styles.linea}>{telefono}</Text> : null}
368
+ {correo ? <Text style={styles.linea}>{correo}</Text> : null}
369
+ </View>
370
+ <View style={styles.acciones}>
371
+ {telefono ? boton("phone", `Llamar a ${nombre}`, `tel:${telefono}`) : null}
372
+ {telefono
373
+ ? boton(
374
+ "whatsapp",
375
+ `WhatsApp a ${nombre}`,
376
+ `https://wa.me/${digitos(telefono)}`,
377
+ )
378
+ : null}
379
+ {correo ? boton("email-outline", `Correo a ${nombre}`, `mailto:${correo}`) : null}
380
+ </View>
381
+ </View>
382
+ );
383
+ }
384
+
385
+ /**
386
+ * Un renglón de una hoja (`HojaInferior`): el título con su chip y lo que acompaña. **No es
387
+ * `TarjetaDeLista`**: ésa es del color de la hoja y adentro de ella no se distinguía un renglón del
388
+ * siguiente. Con `onPress` se toca (abre un archivo, una ficha) y lleva una flecha.
389
+ */
390
+ export function RenglonDeHoja({
391
+ titulo,
392
+ estado,
393
+ lineas,
394
+ atenuado,
395
+ onPress,
396
+ children,
397
+ }: {
398
+ titulo: string;
399
+ estado?: { texto: string; tono: TonoDeChip } | null;
400
+ lineas: (string | null | undefined | false)[];
401
+ /** Lo que ya no cuenta (una excepción revocada, una vigencia reemplazada). */
402
+ atenuado?: boolean;
403
+ onPress?: () => void;
404
+ /** Lo que va debajo: el botón de una administrativa. */
405
+ children?: React.ReactNode;
406
+ }) {
407
+ const c = usePaleta();
408
+ const styles = useStyles();
409
+ return (
410
+ <Pressable
411
+ onPress={onPress}
412
+ disabled={!onPress}
413
+ accessibilityRole={onPress ? "button" : undefined}
414
+ style={({ pressed }) => [
415
+ styles.renglonDeHoja,
416
+ atenuado && styles.atenuado,
417
+ pressed && styles.presionada,
418
+ ]}
419
+ >
420
+ {estado || !onPress ? (
421
+ <View style={styles.tarjetaCabecera}>
422
+ <Text style={styles.tarjetaTitulo}>{titulo}</Text>
423
+ {estado ? <Chip texto={estado.texto} tono={estado.tono} /> : null}
424
+ </View>
425
+ ) : (
426
+ // Con la flecha, sin partir: el título toma lo que queda y la flecha se queda en el
427
+ // primer renglón aunque el título ocupe varios.
428
+ <View style={styles.cabeceraConFlecha}>
429
+ <Text style={[styles.tarjetaTitulo, styles.flex]}>{titulo}</Text>
430
+ <MaterialCommunityIcons name="chevron-right" size={24} color={c.secondary} />
431
+ </View>
432
+ )}
433
+ {lineas
434
+ .filter((l): l is string => Boolean(l))
435
+ .map((l, i) => (
436
+ <Text key={i} style={styles.linea}>
437
+ {l}
438
+ </Text>
439
+ ))}
440
+ {children}
441
+ </Pressable>
442
+ );
443
+ }
444
+
445
+ /**
446
+ * Lo que se dice al pie de una hoja que no trae todos (las hojas piden los primeros 100): «Hay 140;
447
+ * aquí van los 100 más recientes.» Si están todos, nada.
448
+ */
449
+ export function AvisoDeRecortados({ cuantos, traidos }: { cuantos: number; traidos: number }) {
450
+ const styles = useStyles();
451
+ if (cuantos <= traidos) return null;
452
+ return (
453
+ <Text style={styles.linea}>
454
+ Hay {cuantos}; aquí van los {traidos} más recientes.
455
+ </Text>
456
+ );
457
+ }
458
+
459
+ /** Lo que dice una hoja mientras carga, si falló o si no hay nada. */
460
+ export function EstadoDeHoja({
461
+ cargando,
462
+ fallo,
463
+ vacio,
464
+ }: {
465
+ cargando: boolean;
466
+ fallo: boolean;
467
+ vacio: string | null;
468
+ }) {
469
+ const c = usePaleta();
470
+ const styles = useStyles();
471
+ if (cargando) return <ActivityIndicator color={c.primary} />;
472
+ if (fallo)
473
+ return <Text style={styles.linea}>No se pudo cargar. Jala la ficha para releer.</Text>;
474
+ return vacio ? <Text style={styles.linea}>{vacio}</Text> : null;
475
+ }
476
+
477
+ const useStyles = crearEstilos((c) => ({
478
+ cabecera: { gap: 10, paddingTop: 12, paddingBottom: 4 },
479
+ filaDeBusqueda: { flexDirection: "row", alignItems: "center", gap: 10 },
480
+ flex: { flex: 1 },
481
+ // Del alto del buscador y con su borde, para que se lean como una sola barra.
482
+ botonDeFiltros: {
483
+ width: 52,
484
+ height: 52,
485
+ borderRadius: 14,
486
+ borderWidth: 1.5,
487
+ borderColor: c.secondaryLighter,
488
+ backgroundColor: c.superficie,
489
+ alignItems: "center",
490
+ justifyContent: "center",
491
+ },
492
+ botonDeFiltrosActivo: { borderColor: c.primary },
493
+ globito: {
494
+ position: "absolute",
495
+ top: 4,
496
+ right: 4,
497
+ minWidth: 18,
498
+ height: 18,
499
+ borderRadius: 9,
500
+ paddingHorizontal: 4,
501
+ backgroundColor: c.primary,
502
+ alignItems: "center",
503
+ justifyContent: "center",
504
+ },
505
+ globitoTexto: { color: c.sobrePrimario, fontSize: 12, fontWeight: "800" },
506
+ punto: {
507
+ position: "absolute",
508
+ top: 8,
509
+ right: 8,
510
+ width: 10,
511
+ height: 10,
512
+ borderRadius: 5,
513
+ backgroundColor: c.primary,
514
+ },
515
+ buscador: {
516
+ flexDirection: "row",
517
+ alignItems: "center",
518
+ gap: 6,
519
+ backgroundColor: c.superficie,
520
+ borderRadius: 14,
521
+ borderWidth: 1.5,
522
+ borderColor: c.secondaryLighter,
523
+ paddingHorizontal: 12,
524
+ minHeight: 52,
525
+ },
526
+ campo: { flex: 1, justifyContent: "center" },
527
+ entrada: { fontSize: tipografia.cuerpo, paddingVertical: 10, paddingHorizontal: 0 },
528
+ // Encima del campo, donde iría el `placeholder`: mismo tamaño, sin partirse.
529
+ sugerencia: {
530
+ position: "absolute",
531
+ left: 0,
532
+ right: 0,
533
+ fontSize: tipografia.cuerpo,
534
+ color: c.secondaryLight,
535
+ },
536
+ presionada: { opacity: 0.7 },
537
+ renglonDeHoja: { backgroundColor: c.fondo, borderRadius: 14, padding: 14, gap: 4 },
538
+ cabeceraConFlecha: { flexDirection: "row", alignItems: "flex-start", gap: 8 },
539
+ atenuado: { opacity: 0.55 },
540
+ tarjetaCabecera: {
541
+ flexDirection: "row",
542
+ alignItems: "flex-start",
543
+ justifyContent: "space-between",
544
+ flexWrap: "wrap",
545
+ gap: 8,
546
+ },
547
+ tarjetaTitulo: { flexShrink: 1, ...renglon(tipografia.subtitulo), fontWeight: "800" },
548
+ linea: { ...renglon(tipografia.secundario), color: c.secondary },
549
+ seccion: { gap: 8 },
550
+ rotulo: {
551
+ ...renglon(tipografia.etiqueta),
552
+ fontWeight: "800",
553
+ color: c.secondary,
554
+ textTransform: "uppercase",
555
+ letterSpacing: 0.8,
556
+ },
557
+ renglon: {
558
+ flexDirection: "row",
559
+ alignItems: "center",
560
+ gap: 10,
561
+ backgroundColor: c.superficie,
562
+ borderRadius: 14,
563
+ padding: 14,
564
+ },
565
+ renglonTexto: { flex: 1, gap: 2 },
566
+ renglonEnHoja: { backgroundColor: c.fondo },
567
+ etiqueta: {
568
+ ...renglon(tipografia.etiqueta),
569
+ fontWeight: "800",
570
+ color: c.secondary,
571
+ textTransform: "uppercase",
572
+ letterSpacing: 0.8,
573
+ },
574
+ valor: { ...renglon(tipografia.subtitulo), fontWeight: "800" },
575
+ liga: { color: c.primary },
576
+ iconoDeContador: {
577
+ width: 36,
578
+ height: 36,
579
+ borderRadius: 18,
580
+ alignItems: "center",
581
+ justifyContent: "center",
582
+ backgroundColor: c.primaryWash,
583
+ },
584
+ cuantos: { ...renglon(tipografia.subtitulo), fontWeight: "800", color: c.secondary },
585
+ acciones: { flexDirection: "row", gap: 6 },
586
+ accion: {
587
+ width: 44,
588
+ height: 44,
589
+ borderRadius: 22,
590
+ alignItems: "center",
591
+ justifyContent: "center",
592
+ backgroundColor: c.primaryWash,
593
+ },
594
+ }));