@amsintegra/design-system 1.1.1 → 2.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.
- package/CHANGELOG.md +83 -0
- package/README.md +68 -137
- package/dist/index.cjs +2848 -1034
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1321 -457
- package/dist/index.d.ts +1321 -457
- package/dist/index.js +2630 -631
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -0
- package/package.json +17 -27
package/dist/index.d.ts
CHANGED
|
@@ -1,528 +1,1392 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
2
|
+
import { CSSProperties, ReactNode, AnchorHTMLAttributes, ComponentType } from 'react';
|
|
3
|
+
import { LucideIcon } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Tema (paleta + marca) por omision. Basado en `web/src/lib/tema.ts` de la plataforma SIN la llamada a su backend:
|
|
7
|
+
* se conservan los NOMBRES de los tokens (`color_primario`, `badge_exito`...). Los valores por omision son la MARCA
|
|
8
|
+
* AMS (rojo), que coinciden con el `:root` de `tokens.css` (deben mantenerse sincronizados). `variablesDeTema` es la
|
|
9
|
+
* funcion de `app/layout.tsx` que inyecta la paleta como variables CSS en `<html style=...>`.
|
|
10
|
+
*
|
|
11
|
+
* Como una marca sobreescribe los tokens (3 formas, de mas a menos recomendada):
|
|
12
|
+
* 1. Runtime: construye un `Tema` propio (de tu API/config) y pasa `variablesDeTema(tema)` al `style` de `<html>`.
|
|
13
|
+
* 2. Estatica: un CSS de marca importado despues de globals.css con `:root { --tema-primario: #...; ... }`.
|
|
14
|
+
* 3. Cambiar `TEMA_DEFAULT` y `:root` de globals.css a la vez (deben coincidir).
|
|
15
|
+
* Nunca cambies colores dentro de un componente.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
type Tema = {
|
|
19
|
+
logo_url: string | null;
|
|
20
|
+
/** Icono de pestana (ruta o URL); sin valor rige el de la marca por omision. */
|
|
21
|
+
favicon_url?: string | null;
|
|
22
|
+
color_primario: string;
|
|
23
|
+
color_primario_oscuro: string;
|
|
24
|
+
/** Acento de marca (reflejo de la pantalla de acceso, spinner); sin valor rige el del tema por omision. */
|
|
25
|
+
color_acento?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Rojo de PELIGRO (acciones destructivas y texto de error). Reservado: cuando la marca es roja, el boton
|
|
28
|
+
* primario va en neutro oscuro y este rojo queda solo para destructivos/error (ver docs/criterio-color-acciones.md).
|
|
29
|
+
*/
|
|
30
|
+
color_peligro: string;
|
|
31
|
+
color_fondo: string;
|
|
32
|
+
color_texto: string;
|
|
33
|
+
color_borde: string;
|
|
34
|
+
badge_exito: string;
|
|
35
|
+
badge_advertencia: string;
|
|
36
|
+
badge_error: string;
|
|
37
|
+
badge_neutro: string;
|
|
38
|
+
};
|
|
39
|
+
declare const NOMBRE_PRODUCTO_DEFAULT = "Backoffice";
|
|
40
|
+
/**
|
|
41
|
+
* Tema por omision = marca AMS (rojo). Mismos valores que el `:root` de `tokens.css` (deben coincidir).
|
|
42
|
+
* El rojo es la identidad/acento; el boton primario va en neutro oscuro y el rojo queda reservado a peligro
|
|
43
|
+
* (ver docs/criterio-color-acciones.md). Una marca distinta sobreescribe estos tokens via `variablesDeTema`.
|
|
44
|
+
*/
|
|
45
|
+
declare const TEMA_DEFAULT: Tema;
|
|
46
|
+
/**
|
|
47
|
+
* Variables CSS del tema como `style` inline en el `<html>`. Sobreescriben los defaults de `globals.css`; con el tema por
|
|
48
|
+
* omision son un no-op visual. (Extraido de `app/layout.tsx`.)
|
|
49
|
+
*/
|
|
50
|
+
declare function variablesDeTema(tema: Tema): CSSProperties;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Framework-agnostic link.
|
|
54
|
+
*
|
|
55
|
+
* The kit used `next/link` directly, which a publishable library cannot depend on. Components now
|
|
56
|
+
* render `LinkBase`, which by default is a plain `<a href>`. A consumer that wants client-side
|
|
57
|
+
* routing (Next's <Link>, React Router's <Link>, etc.) injects their component once via
|
|
58
|
+
* `LinkComponentProvider`; everything inside then routes through it, with no component API change.
|
|
59
|
+
*/
|
|
60
|
+
type LinkBaseProps = {
|
|
61
|
+
href: string;
|
|
62
|
+
children: ReactNode;
|
|
63
|
+
} & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href">;
|
|
64
|
+
/** Shape of an injected link component: anything that accepts `href` + anchor props. */
|
|
65
|
+
type LinkComponent = ComponentType<LinkBaseProps>;
|
|
66
|
+
declare const LinkComponentProvider: react.Provider<LinkComponent | null>;
|
|
67
|
+
declare const LinkBase: react.ForwardRefExoticComponent<{
|
|
68
|
+
href: string;
|
|
69
|
+
children: ReactNode;
|
|
70
|
+
} & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href"> & react.RefAttributes<HTMLAnchorElement>>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Framework-agnostic listing navigation (option A of the migration).
|
|
74
|
+
*
|
|
75
|
+
* The kit originally read Next's router (usePathname/useRouter/useSearchParams). A publishable
|
|
76
|
+
* library cannot depend on Next, so navigation is injected via React context instead: the consumer
|
|
77
|
+
* wires `ListadoNavProvider` to whatever drives their URL/query state (Next's router, React Router,
|
|
78
|
+
* or plain component state). The listing components (BarraListado, PaginadorUrl, EncabezadoOrdenUrl)
|
|
79
|
+
* keep their public API unchanged — only the source of `ir`/`params`/`pendiente` moved to context.
|
|
80
|
+
*
|
|
81
|
+
* `cambios` semantics are preserved: apply the given key/value changes to the current query; a null
|
|
82
|
+
* or empty value clears the key; any non-page change resets to page 1 (see hrefListado in listado.ts).
|
|
83
|
+
*/
|
|
84
|
+
type CambiosListado = Record<string, string | null | undefined>;
|
|
85
|
+
type ListadoNav = {
|
|
86
|
+
/** Apply `cambios` to the current query. `scroll` hints the consumer to scroll to top (page changes). */
|
|
87
|
+
ir: (cambios: CambiosListado, opciones?: {
|
|
88
|
+
scroll?: boolean;
|
|
89
|
+
}) => void;
|
|
90
|
+
/** True while a navigation is in flight, so controls can show a pending indicator. */
|
|
91
|
+
pendiente: boolean;
|
|
92
|
+
/** The current query string params (same shape as URLSearchParams). */
|
|
93
|
+
params: URLSearchParams;
|
|
94
|
+
};
|
|
95
|
+
declare const ListadoNavProvider: react.Provider<ListadoNav | null>;
|
|
96
|
+
/**
|
|
97
|
+
* Read the listing navigation injected by the nearest `ListadoNavProvider`. Throws a clear error if
|
|
98
|
+
* used outside a provider, so misuse fails loudly instead of silently doing nothing.
|
|
99
|
+
*/
|
|
100
|
+
declare function useNavegarListado(): ListadoNav;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* MAPA SEMANTICO CENTRAL DE ICONOGRAFIA (kit-ui-plataforma).
|
|
104
|
+
*
|
|
105
|
+
* Extraido de `web/src/lib/iconos.ts` de la plataforma: las constantes genericas (ICONO_NAV_*, ICONO_ALTA, ICONO_BAJA,
|
|
106
|
+
* ICONO_FILTRO, ICONO_COLUMNAS, ICONO_ACCIONES_FILA, ICONOS_SEMAFORO...) se copiaron TAL CUAL (mismo nombre, mismo glifo de
|
|
107
|
+
* Lucide). Se quitaron las propias del dominio de la plataforma original. Las constantes ICONO_COL_*, ICONO_KPI_*,
|
|
108
|
+
* ICONO_AVISO/ERROR/OK/SEGURIDAD y ICONOS_ESTATUS son alias NEUTROS de conceptos que alli tienen nombre de dominio (mismos
|
|
109
|
+
* glifos). Al final, "EXTENSIONES DEL KIT": conceptos del Backoffice que la plataforma no tiene; solo reutilizan glifos ya
|
|
110
|
+
* importados aqui, nunca introducen una libreria nueva.
|
|
111
|
+
*
|
|
112
|
+
* REGLAS (obligatorias):
|
|
113
|
+
* - Libreria UNICA: `lucide-react` (trazo de 2 px). Ninguna otra libreria de iconos, ningun emoji, ningun SVG suelto.
|
|
114
|
+
* - Ninguna pantalla ni componente importa de `lucide-react` directamente: importa la constante `ICONO_*` de este
|
|
115
|
+
* archivo. Un concepto nuevo se agrega AQUI una sola vez (y se documenta en references/iconos.md).
|
|
116
|
+
* - Tamanos: `TAMANO_BADGE` (16) en contextos densos (insignias, tablas, titulos de tarjeta); `TAMANO_BOTON` (20) en
|
|
117
|
+
* botones, menu lateral y titulo de pagina; el icono (i) es de 14. Iconos pequenos de apoyo: 12-13.
|
|
118
|
+
* - Color: hereda `currentColor`; jamas un color fijo nuevo.
|
|
119
|
+
* - Accesibilidad: decorativo -> `aria-hidden="true"`; unico contenido de un control -> `aria-label` y `title`.
|
|
120
|
+
* - Un icono por concepto: dos conceptos distintos no comparten glifo (p. ej. Dashboard=Activity, Salud=Gauge).
|
|
121
|
+
*/
|
|
122
|
+
|
|
123
|
+
declare const TAMANO_BADGE = 16;
|
|
124
|
+
declare const TAMANO_BOTON = 20;
|
|
125
|
+
/** Icono por defecto cuando un tipo/estatus no esta en el mapa: nunca un componente roto por un valor nuevo. */
|
|
126
|
+
declare const ICONO_DEFAULT: LucideIcon;
|
|
127
|
+
/** Tipo publico del icono (alias de `LucideIcon`) para tipar props sin importar de `lucide-react`. */
|
|
128
|
+
type LucideIconType = LucideIcon;
|
|
129
|
+
declare const ICONO_NAV_DASHBOARD: LucideIcon;
|
|
130
|
+
declare const ICONO_NAV_SALUD: LucideIcon;
|
|
131
|
+
declare const ICONO_NAV_ANALITICA: LucideIcon;
|
|
132
|
+
declare const ICONO_NAV_ENTIDADES: LucideIcon;
|
|
133
|
+
declare const ICONO_NAV_INVITACIONES: LucideIcon;
|
|
134
|
+
declare const ICONO_NAV_ETIQUETAS: LucideIcon;
|
|
135
|
+
declare const ICONO_NAV_JOBS: LucideIcon;
|
|
136
|
+
declare const ICONO_NAV_TEMA: LucideIcon;
|
|
137
|
+
declare const ICONO_NAV_CONFIGURACION: LucideIcon;
|
|
138
|
+
declare const ICONO_NAV_API_KEYS: LucideIcon;
|
|
139
|
+
declare const ICONO_NAV_BITACORA: LucideIcon;
|
|
140
|
+
declare const ICONO_NAV_NOTIFICACIONES: LucideIcon;
|
|
141
|
+
declare const ICONO_NAV_MANUAL: LucideIcon;
|
|
142
|
+
declare const ICONO_NAV_CLIENTE: LucideIcon;
|
|
143
|
+
declare const ICONO_NAV_EXTRACCIONES: LucideIcon;
|
|
144
|
+
declare const ICONO_CERRAR_SESION: LucideIcon;
|
|
145
|
+
declare const ICONO_INICIAR_SESION: LucideIcon;
|
|
146
|
+
declare const ICONO_NAV_COLAPSAR: LucideIcon;
|
|
147
|
+
declare const ICONO_NAV_EXPANDIR: LucideIcon;
|
|
148
|
+
declare const ICONO_NAV_MENU_MOVIL: LucideIcon;
|
|
149
|
+
declare const ICONO_CERRAR: LucideIcon;
|
|
150
|
+
declare const ICONO_ALTA: LucideIcon;
|
|
151
|
+
declare const ICONO_GENERAR: LucideIcon;
|
|
152
|
+
declare const ICONO_GUARDAR: LucideIcon;
|
|
153
|
+
declare const ICONO_EDITAR: LucideIcon;
|
|
154
|
+
declare const ICONO_BAJA: LucideIcon;
|
|
155
|
+
declare const ICONO_DESHABILITAR: LucideIcon;
|
|
156
|
+
declare const ICONO_INACTIVAR: LucideIcon;
|
|
157
|
+
declare const ICONO_REACTIVAR_ETIQUETA: LucideIcon;
|
|
158
|
+
declare const ICONO_REACTIVAR: LucideIcon;
|
|
159
|
+
declare const ICONO_RESTABLECER: LucideIcon;
|
|
160
|
+
declare const ICONO_REINTENTAR: LucideIcon;
|
|
161
|
+
declare const ICONO_COPIAR: LucideIcon;
|
|
162
|
+
declare const ICONO_LINK: LucideIcon;
|
|
163
|
+
declare const ICONO_DESCARGAR: LucideIcon;
|
|
164
|
+
declare const ICONO_EXPORTAR: LucideIcon;
|
|
165
|
+
declare const ICONO_EXPORTAR_CSV: LucideIcon;
|
|
166
|
+
declare const ICONO_CONFIRMAR: LucideIcon;
|
|
167
|
+
declare const ICONO_VOLVER: LucideIcon;
|
|
168
|
+
declare const ICONO_VER_TODOS: LucideIcon;
|
|
169
|
+
declare const ICONO_ROTAR_KEY: LucideIcon;
|
|
170
|
+
declare const ICONO_REVOCAR_KEY: LucideIcon;
|
|
171
|
+
declare const ICONO_API_KEY: LucideIcon;
|
|
172
|
+
declare const ICONO_EMAIL: LucideIcon;
|
|
173
|
+
declare const ICONO_INVITACION_GENERICA: LucideIcon;
|
|
174
|
+
declare const ICONO_SEGURIDAD: LucideIcon;
|
|
175
|
+
declare const ICONO_CAMPANA: LucideIcon;
|
|
176
|
+
declare const ICONO_SILENCIAR: LucideIcon;
|
|
177
|
+
declare const ICONO_FILTRO: LucideIcon;
|
|
178
|
+
declare const ICONO_BUSCAR: LucideIcon;
|
|
179
|
+
declare const ICONO_LIMPIAR: LucideIcon;
|
|
180
|
+
declare const ICONO_SELECCIONADO: LucideIcon;
|
|
181
|
+
declare const ICONO_ORDENAR_ASC: LucideIcon;
|
|
182
|
+
declare const ICONO_ORDENAR_DESC: LucideIcon;
|
|
183
|
+
declare const ICONO_ORDENAR_NEUTRO: LucideIcon;
|
|
184
|
+
declare const ICONO_PAGINA_ANTERIOR: LucideIcon;
|
|
185
|
+
declare const ICONO_PAGINA_SIGUIENTE: LucideIcon;
|
|
186
|
+
declare const ICONO_VISTA_TABLA: LucideIcon;
|
|
187
|
+
declare const ICONO_VISTA_TARJETAS: LucideIcon;
|
|
188
|
+
declare const ICONO_ARRASTRAR_COLUMNA: LucideIcon;
|
|
189
|
+
declare const ICONO_COLUMNAS: LucideIcon;
|
|
190
|
+
declare const ICONO_COLUMNA_VISIBLE: LucideIcon;
|
|
191
|
+
declare const ICONO_COLUMNA_OCULTA: LucideIcon;
|
|
192
|
+
declare const ICONO_ACCIONES_FILA: LucideIcon;
|
|
193
|
+
declare const ICONO_DENSIDAD_COMPACTA: LucideIcon;
|
|
194
|
+
declare const ICONO_DENSIDAD_COMODA: LucideIcon;
|
|
195
|
+
declare const ICONO_CARGANDO: LucideIcon;
|
|
196
|
+
declare const ICONO_INFO_EXPLICACION: LucideIcon;
|
|
197
|
+
declare const ICONO_COL_CODIGO: LucideIcon;
|
|
198
|
+
declare const ICONO_COL_NOMBRE: LucideIcon;
|
|
199
|
+
declare const ICONO_COL_ESTADO: LucideIcon;
|
|
200
|
+
declare const ICONO_COL_MECANISMO: LucideIcon;
|
|
201
|
+
declare const ICONO_COL_TOTAL: LucideIcon;
|
|
202
|
+
declare const ICONO_COL_FECHA: LucideIcon;
|
|
203
|
+
declare const ICONO_COL_FECHA_HORA: LucideIcon;
|
|
204
|
+
declare const ICONO_COL_ETIQUETA: LucideIcon;
|
|
205
|
+
declare const ICONO_COL_USUARIO: LucideIcon;
|
|
206
|
+
declare const ICONO_COL_DOCUMENTO: LucideIcon;
|
|
207
|
+
declare const ICONO_PERIODO: LucideIcon;
|
|
208
|
+
declare const ICONO_VIGENCIA: LucideIcon;
|
|
209
|
+
declare const ICONO_DURACION: LucideIcon;
|
|
210
|
+
declare const ICONO_UBICACION: LucideIcon;
|
|
211
|
+
/** Estatus de proceso. Completado=CheckCircle2, en curso=Clock, pendiente=Circle, aviso=AlertTriangle, fallido=XCircle. */
|
|
212
|
+
declare const ICONOS_ESTATUS: Record<string, LucideIcon>;
|
|
213
|
+
declare function iconoDeEstatus(estado: string): LucideIcon;
|
|
214
|
+
/** Semaforo: verde=CheckCircle2, ambar=AlertTriangle, rojo=XCircle (y siempre con texto, nunca solo color). */
|
|
215
|
+
declare const ICONOS_SEMAFORO: Record<string, LucideIcon>;
|
|
216
|
+
declare const ETIQUETAS_SEMAFORO: Record<string, string>;
|
|
217
|
+
declare function iconoDeSemaforo(color: string): LucideIcon;
|
|
218
|
+
declare function etiquetaSemaforo(color: string): string;
|
|
219
|
+
declare const ICONO_AVISO: LucideIcon;
|
|
220
|
+
declare const ICONO_ERROR: LucideIcon;
|
|
221
|
+
declare const ICONO_OK: LucideIcon;
|
|
222
|
+
declare const ICONO_KPI_RITMO: LucideIcon;
|
|
223
|
+
declare const ICONO_KPI_RENDIMIENTO: LucideIcon;
|
|
224
|
+
declare const ICONO_KPI_CONTEO: LucideIcon;
|
|
225
|
+
declare const ICONO_KPI_CREDENCIALES: LucideIcon;
|
|
226
|
+
declare const ICONO_KPI_ALERTA: LucideIcon;
|
|
227
|
+
declare const ICONO_KPI_CONSUMO: LucideIcon;
|
|
228
|
+
declare const ICONO_KPI_BLOQUEO: LucideIcon;
|
|
229
|
+
declare const ICONO_NAV_PLANES: LucideIcon;
|
|
230
|
+
declare const ICONO_NAV_PAQUETES: LucideIcon;
|
|
231
|
+
declare const ICONO_NAV_ACCESOS: LucideIcon;
|
|
232
|
+
declare const ICONO_NAV_USUARIOS: LucideIcon;
|
|
233
|
+
declare const ICONO_LOGIN_MICROSOFT: LucideIcon;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Catalogo unico de explicaciones en sitio (el patron del icono (i)).
|
|
237
|
+
*
|
|
238
|
+
* LINEAMIENTO OBLIGATORIO: cada metrica, tarjeta, grafica, lista, encabezado de columna de tabla e insignia de estatus
|
|
239
|
+
* de CUALQUIER pantalla referencia un id de este catalogo (nunca texto en linea) y responde siempre las mismas 4
|
|
240
|
+
* preguntas: Que es, Como se calcula, De donde sale, Como leerlo. Cada texto se redacta leyendo el codigo que produce el
|
|
241
|
+
* valor (no adivinando).
|
|
242
|
+
*
|
|
243
|
+
* Reglas de formato (verificables con `verificarCatalogo()` abajo): id `modulo.id` en minusculas `[a-z0-9_]`; cada
|
|
244
|
+
* respuesta <= 320 caracteres; sin comillas dobles, barras invertidas ni saltos de linea; espanol neutro y profesional.
|
|
245
|
+
*
|
|
246
|
+
* Los ids `plataforma.*` los usan los componentes del kit (tabla, listado, rol): NO los borres ni los renombres.
|
|
247
|
+
* Agrega los de tu producto con su propio prefijo (`planes.*`, `accesos.*`, `inicio.*`).
|
|
248
|
+
*/
|
|
249
|
+
type Explicacion = {
|
|
250
|
+
titulo: string;
|
|
251
|
+
que_es: string;
|
|
252
|
+
como_se_calcula: string;
|
|
253
|
+
de_donde_sale: string;
|
|
254
|
+
como_leerlo: string;
|
|
255
|
+
};
|
|
256
|
+
declare const EXPLICACIONES: {
|
|
257
|
+
readonly "plataforma.rol": {
|
|
258
|
+
readonly titulo: "Rol del usuario";
|
|
259
|
+
readonly que_es: "Tu nivel de acceso en este sistema, por ejemplo administrador, operador o consulta.";
|
|
260
|
+
readonly como_se_calcula: "Se resuelve al iniciar sesión según tu asignación; no se calcula.";
|
|
261
|
+
readonly de_donde_sale: "Asignación de rol del usuario en el directorio de acceso.";
|
|
262
|
+
readonly como_leerlo: "Determina qué módulos ves y qué acciones puedes ejecutar en cada tabla.";
|
|
263
|
+
};
|
|
264
|
+
readonly "plataforma.listado_resultados": {
|
|
265
|
+
readonly titulo: "Resultados del listado";
|
|
266
|
+
readonly que_es: "Cuántas filas cumplen la búsqueda y los filtros actuales frente al total del listado.";
|
|
267
|
+
readonly como_se_calcula: "Se cuentan las filas cuyo texto contiene lo buscado, sin distinguir mayúsculas ni acentos, y que cumplen cada filtro. La tabla muestra una página de 25, 50 o 100 de ellas.";
|
|
268
|
+
readonly de_donde_sale: "Lista que ya trae la pantalla; la búsqueda, los filtros, el orden y la página viajan en la dirección (URL).";
|
|
269
|
+
readonly como_leerlo: "Si dice N en total no hay filtro activo. Copiar la dirección comparte la misma vista.";
|
|
270
|
+
};
|
|
271
|
+
readonly "plataforma.tabla_columnas": {
|
|
272
|
+
readonly titulo: "Columnas de la tabla";
|
|
273
|
+
readonly que_es: "Lista para mostrar u ocultar las columnas de esta tabla que no están fijas. Las columnas de identidad y la de acciones siempre se ven.";
|
|
274
|
+
readonly como_se_calcula: "Cada casilla desmarcada oculta esa columna en pantalla; no cambia los datos, el orden, los filtros ni lo que se exporta.";
|
|
275
|
+
readonly de_donde_sale: "Preferencia guardada en este navegador, por tabla y por usuario. Restablecer la borra y vuelve a mostrar todas las columnas con la densidad cómoda.";
|
|
276
|
+
readonly como_leerlo: "Si falta una columna que esperabas, revisa esta lista. Con el almacenamiento del navegador bloqueado (modo privado) la elección dura solo mientras la página siga abierta.";
|
|
277
|
+
};
|
|
278
|
+
readonly "plataforma.tabla_densidad": {
|
|
279
|
+
readonly titulo: "Densidad de la tabla";
|
|
280
|
+
readonly que_es: "Alto de las filas: compacta muestra más filas por pantalla; cómoda deja más aire entre ellas.";
|
|
281
|
+
readonly como_se_calcula: "Compacta reduce el relleno vertical de cada celda; no cambia el texto ni las columnas.";
|
|
282
|
+
readonly de_donde_sale: "Preferencia guardada en este navegador, por tabla y por usuario, junto con las columnas ocultas.";
|
|
283
|
+
readonly como_leerlo: "La tabla se desplaza dentro de su propio marco: la barra horizontal queda al pie de la pantalla, el encabezado arriba y las columnas de identidad y acciones fijas a los lados. Shift + rueda del ratón desplaza a lo ancho.";
|
|
284
|
+
};
|
|
285
|
+
readonly "inicio.planes_activos": {
|
|
286
|
+
readonly titulo: "Planes activos";
|
|
287
|
+
readonly que_es: "Número de planes del catálogo que hoy se pueden contratar.";
|
|
288
|
+
readonly como_se_calcula: "Conteo de planes con estado Activo; los borradores y los archivados no cuentan.";
|
|
289
|
+
readonly de_donde_sale: "Catálogo de planes del backoffice (ejemplo con datos ficticios).";
|
|
290
|
+
readonly como_leerlo: "Un plan archivado deja de contar aunque tenga clientes vigentes; esos clientes conservan su plan hasta renovar.";
|
|
291
|
+
};
|
|
292
|
+
readonly "inicio.paquetes": {
|
|
293
|
+
readonly titulo: "Paquetes";
|
|
294
|
+
readonly que_es: "Número de paquetes de consumo definidos en el catálogo.";
|
|
295
|
+
readonly como_se_calcula: "Conteo de paquetes registrados, sin importar su estado.";
|
|
296
|
+
readonly de_donde_sale: "Catálogo de paquetes del backoffice (ejemplo con datos ficticios).";
|
|
297
|
+
readonly como_leerlo: "Un paquete puede estar asociado a varios planes; aquí se cuenta una sola vez.";
|
|
298
|
+
};
|
|
299
|
+
readonly "inicio.accesos_vigentes": {
|
|
300
|
+
readonly titulo: "Accesos vigentes";
|
|
301
|
+
readonly que_es: "Usuarios con acceso al backoffice que no están suspendidos ni vencidos.";
|
|
302
|
+
readonly como_se_calcula: "Conteo de usuarios con estado Activo y fecha de vencimiento futura o sin vencimiento.";
|
|
303
|
+
readonly de_donde_sale: "Registro de accesos del backoffice (ejemplo con datos ficticios).";
|
|
304
|
+
readonly como_leerlo: "Un usuario con rol de solo consulta cuenta igual que uno administrador.";
|
|
305
|
+
};
|
|
306
|
+
readonly "inicio.cobertura": {
|
|
307
|
+
readonly titulo: "Cobertura del catálogo";
|
|
308
|
+
readonly que_es: "Porcentaje de planes que ya tienen al menos un paquete asignado.";
|
|
309
|
+
readonly como_se_calcula: "Planes con al menos un paquete entre planes activos, por 100.";
|
|
310
|
+
readonly de_donde_sale: "Relación plan-paquete del catálogo (ejemplo con datos ficticios).";
|
|
311
|
+
readonly como_leerlo: "Menos de 100 % indica planes sin paquete: no se pueden vender hasta que se les asigne uno.";
|
|
312
|
+
};
|
|
313
|
+
readonly "inicio.resumen_catalogo": {
|
|
314
|
+
readonly titulo: "Resumen del catálogo";
|
|
315
|
+
readonly que_es: "Planes agrupados por estado, con el total de paquetes que suman.";
|
|
316
|
+
readonly como_se_calcula: "Cada plan cae en un solo estado; los paquetes de una fila son la suma de los paquetes de sus planes.";
|
|
317
|
+
readonly de_donde_sale: "Catálogo de planes y paquetes del backoffice (ejemplo con datos ficticios).";
|
|
318
|
+
readonly como_leerlo: "Un paquete compartido por dos planes se cuenta una vez por cada plan.";
|
|
319
|
+
};
|
|
320
|
+
readonly "planes.col_codigo": {
|
|
321
|
+
readonly titulo: "Código";
|
|
322
|
+
readonly que_es: "Identificador corto y estable del plan.";
|
|
323
|
+
readonly como_se_calcula: "Se captura al crear el plan; no se calcula ni se puede repetir.";
|
|
324
|
+
readonly de_donde_sale: "Catálogo de planes (ejemplo con datos ficticios).";
|
|
325
|
+
readonly como_leerlo: "Se usa en integraciones y reportes; el nombre comercial puede cambiar, el código no.";
|
|
326
|
+
};
|
|
327
|
+
readonly "planes.col_nombre": {
|
|
328
|
+
readonly titulo: "Nombre";
|
|
329
|
+
readonly que_es: "Nombre comercial del plan tal como lo ve el cliente.";
|
|
330
|
+
readonly como_se_calcula: "Se captura al crear o editar el plan; no se calcula.";
|
|
331
|
+
readonly de_donde_sale: "Catálogo de planes (ejemplo con datos ficticios).";
|
|
332
|
+
readonly como_leerlo: "La búsqueda ignora mayúsculas y acentos.";
|
|
333
|
+
};
|
|
334
|
+
readonly "planes.col_precio": {
|
|
335
|
+
readonly titulo: "Precio mensual";
|
|
336
|
+
readonly que_es: "Precio de lista del plan por mes, en pesos, sin impuestos.";
|
|
337
|
+
readonly como_se_calcula: "Se captura al crear o editar el plan; no se calcula.";
|
|
338
|
+
readonly de_donde_sale: "Catálogo de planes (ejemplo con datos ficticios).";
|
|
339
|
+
readonly como_leerlo: "Es precio de lista: un contrato puede tener un descuento que no se refleja aquí.";
|
|
58
340
|
};
|
|
59
|
-
readonly
|
|
60
|
-
readonly
|
|
61
|
-
readonly
|
|
62
|
-
readonly
|
|
63
|
-
readonly
|
|
341
|
+
readonly "planes.col_estado": {
|
|
342
|
+
readonly titulo: "Estado del plan";
|
|
343
|
+
readonly que_es: "Situación del plan en el catálogo: Activo, Borrador o Archivado.";
|
|
344
|
+
readonly como_se_calcula: "Lo fija el administrador al publicar o archivar; no se calcula.";
|
|
345
|
+
readonly de_donde_sale: "Catálogo de planes (ejemplo con datos ficticios).";
|
|
346
|
+
readonly como_leerlo: "Solo los planes Activos se pueden contratar. Archivado conserva el historial pero no admite altas nuevas.";
|
|
64
347
|
};
|
|
65
|
-
readonly
|
|
66
|
-
readonly
|
|
67
|
-
readonly
|
|
68
|
-
readonly
|
|
69
|
-
readonly
|
|
70
|
-
readonly
|
|
71
|
-
readonly inputBg: "#1b1b29";
|
|
72
|
-
readonly cardBg: "#1e1e2d";
|
|
73
|
-
readonly gray: {
|
|
74
|
-
readonly 100: "#2b2b40";
|
|
75
|
-
readonly 200: "#323248";
|
|
76
|
-
readonly 300: "#3b3b64";
|
|
77
|
-
readonly 400: "#474761";
|
|
78
|
-
readonly 500: "#565674";
|
|
79
|
-
readonly 600: "#6d6d80";
|
|
80
|
-
readonly 700: "#92929f";
|
|
81
|
-
readonly 800: "#cdcdde";
|
|
82
|
-
};
|
|
348
|
+
readonly "planes.col_actualizado": {
|
|
349
|
+
readonly titulo: "Actualizado";
|
|
350
|
+
readonly que_es: "Fecha y hora de la última modificación del plan, en tu hora local.";
|
|
351
|
+
readonly como_se_calcula: "Se registra en UTC al guardar cambios y el navegador la convierte a tu zona horaria.";
|
|
352
|
+
readonly de_donde_sale: "Bitácora de cambios del catálogo (ejemplo con datos ficticios).";
|
|
353
|
+
readonly como_leerlo: "Cambiar solo el estado también actualiza esta fecha.";
|
|
83
354
|
};
|
|
355
|
+
readonly "planes.estado_activo": {
|
|
356
|
+
readonly titulo: "Activo";
|
|
357
|
+
readonly que_es: "El plan está publicado y se puede contratar.";
|
|
358
|
+
readonly como_se_calcula: "Estado asignado al publicar el plan.";
|
|
359
|
+
readonly de_donde_sale: "Catálogo de planes (ejemplo con datos ficticios).";
|
|
360
|
+
readonly como_leerlo: "Para retirarlo del catálogo, archívalo; no lo borres.";
|
|
361
|
+
};
|
|
362
|
+
readonly "planes.estado_borrador": {
|
|
363
|
+
readonly titulo: "Borrador";
|
|
364
|
+
readonly que_es: "El plan se está preparando y aún no es visible para contratar.";
|
|
365
|
+
readonly como_se_calcula: "Estado inicial de todo plan nuevo.";
|
|
366
|
+
readonly de_donde_sale: "Catálogo de planes (ejemplo con datos ficticios).";
|
|
367
|
+
readonly como_leerlo: "Publica el plan cuando tenga precio y al menos un paquete.";
|
|
368
|
+
};
|
|
369
|
+
readonly "planes.estado_archivado": {
|
|
370
|
+
readonly titulo: "Archivado";
|
|
371
|
+
readonly que_es: "El plan se retiró del catálogo; conserva su historial.";
|
|
372
|
+
readonly como_se_calcula: "Estado asignado al archivar un plan activo.";
|
|
373
|
+
readonly de_donde_sale: "Catálogo de planes (ejemplo con datos ficticios).";
|
|
374
|
+
readonly como_leerlo: "No admite altas nuevas; los clientes existentes conservan su plan hasta renovar.";
|
|
375
|
+
};
|
|
376
|
+
};
|
|
377
|
+
type ExplicacionId = keyof typeof EXPLICACIONES;
|
|
378
|
+
/** Entrada del catalogo; un id desconocido (solo posible con un cast) falla de forma visible. */
|
|
379
|
+
declare function explicacionDe(id: ExplicacionId): Explicacion;
|
|
380
|
+
/** Devuelve la lista de violaciones de formato del catalogo (vacia = correcto). Util como prueba unitaria. */
|
|
381
|
+
declare function verificarCatalogo(): string[];
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Estado de un listado (busqueda, filtros, orden, pagina y tamano) que vive en la URL (change
|
|
385
|
+
* `ux-listados-compactos`). Funciones puras: el Server Component de cada pantalla lee los `searchParams`, aplica
|
|
386
|
+
* el listado sobre la lista ya traida de la API y pinta SOLO la pagina visible; la barra (`BarraListado`), el
|
|
387
|
+
* paginador (`PaginadorUrl`) y los encabezados ordenables (`EncabezadoOrdenUrl`) solo reescriben la URL.
|
|
388
|
+
*
|
|
389
|
+
* Por que en el servidor de Next y no en el backend: cada lista esta acotada (decenas a cientos de filas) y la busqueda sin acentos obligaria a la API a un scan de todos
|
|
390
|
+
* modos. Aqui el navegador recibe una sola pagina (25/50/100 filas) y el trabajo por fila (etiquetas, enlaces) se
|
|
391
|
+
* hace solo para esa pagina.
|
|
392
|
+
*/
|
|
393
|
+
declare const TAMANOS_LISTADO: readonly [25, 50, 100];
|
|
394
|
+
declare const TAMANO_LISTADO_DEFAULT = 25;
|
|
395
|
+
type Direccion = "asc" | "desc";
|
|
396
|
+
type ParamsUrl = Record<string, string | string[] | undefined>;
|
|
397
|
+
type EstadoListado = {
|
|
398
|
+
q: string;
|
|
399
|
+
pagina: number;
|
|
400
|
+
tamano: number;
|
|
401
|
+
orden: string;
|
|
402
|
+
dir: Direccion;
|
|
403
|
+
/** Solo los filtros declarados por la pantalla y con valor. */
|
|
404
|
+
filtros: Record<string, string>;
|
|
405
|
+
};
|
|
406
|
+
type OpcionesListado = {
|
|
407
|
+
/** Claves de filtro que la pantalla entiende (p. ej. `estado`, `mecanismo`). */
|
|
408
|
+
filtros: readonly string[];
|
|
409
|
+
/** Claves de orden validas. */
|
|
410
|
+
ordenes: readonly string[];
|
|
411
|
+
ordenDefault: string;
|
|
412
|
+
dirDefault?: Direccion;
|
|
84
413
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
readonly xl: 12;
|
|
414
|
+
type DefListado<T> = {
|
|
415
|
+
/** Texto en el que busca `q` (nombre, codigo, etc.). */
|
|
416
|
+
texto: (item: T) => string;
|
|
417
|
+
filtrar?: (item: T, filtros: Record<string, string>) => boolean;
|
|
418
|
+
/** Valor por el que ordena cada clave de orden. `null`/`undefined`/`""`/`NaN` = ausente (siempre al final). */
|
|
419
|
+
valoresOrden: Record<string, (item: T) => string | number | null | undefined>;
|
|
92
420
|
};
|
|
93
|
-
/**
|
|
94
|
-
declare
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
421
|
+
/** Minusculas, sin acentos (NFD sin marcas combinantes) y espacios colapsados: " PEÑA Ávila" -> "pena avila". */
|
|
422
|
+
declare function normalizarTexto(s: string): string;
|
|
423
|
+
declare function leerListado(sp: ParamsUrl, opc: OpcionesListado): EstadoListado;
|
|
424
|
+
declare function aplicarListado<T>(items: readonly T[], estado: EstadoListado, def: DefListado<T>): {
|
|
425
|
+
itemsPagina: T[];
|
|
426
|
+
totalFiltrado: number;
|
|
427
|
+
total: number;
|
|
428
|
+
pagina: number;
|
|
429
|
+
totalPaginas: number;
|
|
430
|
+
};
|
|
431
|
+
/**
|
|
432
|
+
* URL con `cambios` aplicados sobre la query actual. Un valor vacio o `null` borra la clave. Cualquier cambio que
|
|
433
|
+
* no sea de pagina regresa a la pagina 1 (borra `pagina`); `pagina=1` tambien se omite para que la URL quede limpia.
|
|
434
|
+
*/
|
|
435
|
+
declare function hrefListado(ruta: string, actual: string | URLSearchParams, cambios: Record<string, string | null | undefined>): string;
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Unico punto por el que las cifras del snapshot llegan a pantalla (decision D10 de `reporte-riesgo-crediticio`).
|
|
439
|
+
*
|
|
440
|
+
* Reglas: las cifras son CADENAS decimales ya redondeadas por el backend; aqui solo se agrupan los miles y se acomoda el
|
|
441
|
+
* signo y el punto decimal manipulando texto, jamas con `Number`, `parseFloat` ni `toFixed` (un float distinto entre el
|
|
442
|
+
* HTML y el PDF cambiaria una cifra). Un dato ausente (`null`) se muestra como `NO_DISPONIBLE`, nunca como cero.
|
|
443
|
+
* Este modulo no importa nada de `next/*` ni hace red: lo comparten el sitio y el empaquetado del PDF.
|
|
444
|
+
*/
|
|
445
|
+
declare const NO_DISPONIBLE = "\u2014";
|
|
446
|
+
/** Dinero en pesos: `1234.50` -> `$1,234.50` (los decimales son los que trae la cadena). */
|
|
447
|
+
declare function formatoMxn(valor: string | null | undefined): string;
|
|
448
|
+
/** Decimal generico (pendientes, promedios): agrupa los miles y respeta los decimales de la cadena. */
|
|
449
|
+
declare function formatoNumero(valor: string | null | undefined): string;
|
|
450
|
+
declare function formatoEntero(valor: number | null | undefined): string;
|
|
451
|
+
/** Razon (`0.1234`) como porcentaje (`12.34 %`): se corre el punto dos lugares en el texto, sin aritmetica. */
|
|
452
|
+
declare function formatoPct(razon: string | null | undefined): string;
|
|
453
|
+
declare function formatoDias(valor: string | null | undefined): string;
|
|
454
|
+
/** `AAAA-MM-DD` -> `AAAA/MM/DD` (formato unico de fecha de la plataforma). */
|
|
455
|
+
declare function formatoFecha(iso: string | null | undefined): string;
|
|
456
|
+
declare function formatoMes(mes: string | null | undefined): string;
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Formato unico de fecha/hora para TODO el sistema (pedido explicito del usuario:
|
|
460
|
+
* "todos los periodos y fechas usemos formato yyyy/MM/dd HH:mm:ss"), SIEMPRE en hora
|
|
461
|
+
* LOCAL del navegador (pedido del usuario: "en la base guardamos UTC pero en el view
|
|
462
|
+
* debe ser hora local").
|
|
463
|
+
*
|
|
464
|
+
* La API entrega fechas en DOS familias, que se distinguen por el sufijo de zona:
|
|
465
|
+
* - CON sufijo UTC (`Z` o `+00:00`): timestamps del sistema escritos con
|
|
466
|
+
* `now_utc().isoformat()` -> `...+00:00` (creado_en, terminado_en, `ts` de bitacora,
|
|
467
|
+
* downloaded_at, etc.). Son instantes ABSOLUTOS en UTC y DEBEN convertirse a local.
|
|
468
|
+
* - SIN sufijo (naive `YYYY-MM-DDTHH:MM:SS`): fechas de negocio (documento/portal)
|
|
469
|
+
* (`fecha_emision`, `fecha_timbrado`, `start`/`end` de ventana, `date_from/to`) que
|
|
470
|
+
* ya vienen en la hora que reporto la fuente -- NO se re-convierten (no tienen un
|
|
471
|
+
* offset conocido; reinterpretarlas correria la hora sin base).
|
|
472
|
+
*
|
|
473
|
+
* En ambos casos la salida es `yyyy/MM/dd HH:mm:ss`. `date_from/to` puede venir como
|
|
474
|
+
* `YYYY-MM-DD` puro (sin hora) -> se muestra la fecha a medianoche, sin conversion.
|
|
475
|
+
*/
|
|
476
|
+
declare function formatearFechaHora(iso: string | null | undefined): string;
|
|
477
|
+
/**
|
|
478
|
+
* Como `formatearFechaHora`, pero un instante CON zona se muestra en America/Mexico_City (no en la
|
|
479
|
+
* zona del proceso). Para componentes de servidor, donde "hora local" seria la del servidor (UTC).
|
|
480
|
+
* Las fechas naive (fecha de negocio) o `YYYY-MM-DD` se muestran tal cual, igual que en la otra.
|
|
481
|
+
*/
|
|
482
|
+
declare function formatearFechaHoraCDMX(iso: string | null | undefined): string;
|
|
483
|
+
/** Formatea un rango `[desde, hasta]` con el mismo formato, unido por un guion largo. */
|
|
484
|
+
declare function formatearRangoFechaHora(desde: string | null | undefined, hasta: string | null | undefined): string;
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Tamano legible de un archivo (base 1024) para la estimacion y las partes ZIP de una
|
|
488
|
+
* extraccion. Solo formatea: nunca recalcula nada.
|
|
489
|
+
*/
|
|
490
|
+
declare function formatearBytes(n: number | null | undefined): string;
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Helper central para el lineamiento "toda accion dispara el spinner de marca"
|
|
494
|
+
* (lineamiento "toda accion dispara el spinner de marca"). Envuelve una funcion async y expone:
|
|
495
|
+
* - `ejecutando`: true mientras la accion corre (para deshabilitar el boton).
|
|
496
|
+
* - `ejecutar(fn, etiqueta?)`: corre `fn`, muestra el overlay de marca y lo cierra al
|
|
497
|
+
* terminar (aunque `fn` lance).
|
|
498
|
+
* - `Overlay`: componente listo para montar; pinta el `OverlayCargando` solo mientras
|
|
499
|
+
* `ejecutando`. Asi cualquier accion obtiene el feedback homologado con una linea.
|
|
500
|
+
*
|
|
501
|
+
* Uso:
|
|
502
|
+
* const { ejecutando, ejecutar, Overlay } = useAccionConSpinner();
|
|
503
|
+
* <button disabled={ejecutando} onClick={() => ejecutar(guardar, "Guardando...")}>Guardar</button>
|
|
504
|
+
* <Overlay />
|
|
505
|
+
*/
|
|
506
|
+
declare function useAccionConSpinner(): {
|
|
507
|
+
ejecutando: boolean;
|
|
508
|
+
ejecutar: <T>(fn: () => Promise<T>, etiquetaAccion?: string) => Promise<T | undefined>;
|
|
509
|
+
Overlay: () => react.JSX.Element;
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Hook de React sobre `preferenciasTabla`: mantiene el orden, los anchos y las columnas
|
|
514
|
+
* ocultas de UNA tabla, persistidos en localStorage bajo `clave`, y expone acciones para
|
|
515
|
+
* reordenar/redimensionar/ocultar/restablecer.
|
|
516
|
+
*
|
|
517
|
+
* `idsDefault` es el orden natural de las columnas de la tabla (por id). El hook resuelve
|
|
518
|
+
* el orden efectivo combinando lo guardado con los defaults (columnas nuevas al final,
|
|
519
|
+
* ids viejos ignorados) via `ordenarColumnas`.
|
|
520
|
+
*
|
|
521
|
+
* SSR-safe: en el primer render (servidor y cliente) usa los defaults; tras montar, lee
|
|
522
|
+
* localStorage y re-renderiza. Asi no hay desajuste de hidratacion.
|
|
523
|
+
*/
|
|
524
|
+
declare function useTablaPreferencias(clave: string, idsDefault: string[]): {
|
|
525
|
+
/** Ids en el orden efectivo, SIN las ocultas — para pintar la tabla. */
|
|
526
|
+
idsVisibles: string[];
|
|
527
|
+
/** Ids en el orden efectivo, incluyendo ocultas — para el menu de mostrar/ocultar. */
|
|
528
|
+
idsOrdenados: string[];
|
|
529
|
+
/** Set de ids ocultos. */
|
|
530
|
+
ocultas: Set<string>;
|
|
531
|
+
/** Ancho persistido de una columna, o undefined si no se ha redimensionado. */
|
|
532
|
+
anchoDe: (id: string) => number | undefined;
|
|
533
|
+
mover: (desde: number, hasta: number) => void;
|
|
534
|
+
redimensionar: (id: string, ancho: number) => void;
|
|
535
|
+
alternarVisible: (id: string) => void;
|
|
536
|
+
restablecer: () => void;
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Calculo puro de la posicion de un popover `fixed` dentro del viewport. Separado del
|
|
541
|
+
* componente para poder probarlo sin layout real (jsdom no mide).
|
|
542
|
+
*/
|
|
543
|
+
type RectLike = {
|
|
544
|
+
left: number;
|
|
545
|
+
top: number;
|
|
546
|
+
right: number;
|
|
547
|
+
bottom: number;
|
|
548
|
+
width: number;
|
|
549
|
+
height: number;
|
|
550
|
+
};
|
|
551
|
+
type EntradaPosicion = {
|
|
552
|
+
trigger: RectLike;
|
|
553
|
+
/** Tamano medido del contenido (ya acotado a `anchoMax` si aplica). */
|
|
554
|
+
contenido: {
|
|
555
|
+
ancho: number;
|
|
556
|
+
alto: number;
|
|
557
|
+
};
|
|
558
|
+
viewport: {
|
|
559
|
+
ancho: number;
|
|
560
|
+
alto: number;
|
|
103
561
|
};
|
|
562
|
+
margen?: number;
|
|
563
|
+
separacion?: number;
|
|
564
|
+
/** Ancho maximo deseado (default 360). */
|
|
565
|
+
anchoPreferido?: number;
|
|
104
566
|
};
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
567
|
+
type PosicionPopover = {
|
|
568
|
+
top: number;
|
|
569
|
+
left: number;
|
|
570
|
+
/** Alto maximo para scroll interno. */
|
|
571
|
+
maxHeight: number;
|
|
572
|
+
/** Ancho maximo: min(preferido, viewport - 2*margen). */
|
|
573
|
+
anchoMax: number;
|
|
109
574
|
};
|
|
575
|
+
declare function calcularPosicionPopover({ trigger, contenido, viewport, margen, separacion, anchoPreferido, }: EntradaPosicion): PosicionPopover;
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Clases Tailwind CANONICAS de botones, campos y avisos. La plataforma las escribe en linea en cada pantalla; aqui estan
|
|
579
|
+
* agrupadas VERBATIM (docs/sistema-diseno-ui.md 7.1, 7.2 y 7.9 del proyecto original, y las clases mas repetidas en su
|
|
580
|
+
* codigo) para que no se reinventen. Uso: `<button className={CLASE_BOTON_PRIMARIO}>`.
|
|
581
|
+
* Regla: una sola accion primaria por vista o modal. Destructivo: siempre con confirmacion previa.
|
|
582
|
+
*/
|
|
110
583
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
584
|
+
* Primario estandar (36 px de alto): accion principal de una vista o modal.
|
|
585
|
+
* Relleno NEUTRO OSCURO (var(--tema-texto)), NO el rojo de marca: el rojo queda reservado a peligro
|
|
586
|
+
* (ver docs/criterio-color-acciones.md). El rojo de marca aparece como acento (titulos, foco, seleccion).
|
|
587
|
+
*/
|
|
588
|
+
declare const CLASE_BOTON_PRIMARIO = "inline-flex items-center gap-1.5 rounded-md bg-[var(--tema-texto)] px-4 py-2 text-sm font-medium text-white transition hover:brightness-125 disabled:opacity-50";
|
|
589
|
+
/** Primario compacto (32 px): modales y barras de herramientas. Mismo criterio neutro oscuro. */
|
|
590
|
+
declare const CLASE_BOTON_PRIMARIO_COMPACTO = "inline-flex items-center gap-1.5 rounded-md bg-[var(--tema-texto)] px-3 py-1.5 text-sm font-medium text-white transition hover:brightness-125 disabled:opacity-50";
|
|
591
|
+
/** Secundario: cancelar, acciones de fila, paginador. */
|
|
592
|
+
declare const CLASE_BOTON_SECUNDARIO = "inline-flex items-center gap-1.5 rounded-md border border-[var(--tema-borde)] px-3 py-1.5 text-sm font-medium text-[#3c3c3b] transition hover:bg-[var(--tema-badge-neutro)] disabled:opacity-50";
|
|
593
|
+
/** Pequeno (28 px): barras de herramientas de tabla (mismo que el boton "Columnas"). */
|
|
594
|
+
declare const CLASE_BOTON_PEQUENO = "inline-flex items-center gap-1.5 rounded-md border border-[var(--tema-borde)] px-2.5 py-1.5 text-xs font-medium text-[#3c3c3b] transition hover:bg-[var(--tema-badge-neutro)] disabled:opacity-50";
|
|
595
|
+
/** Contorno primario: accion secundaria que debe destacar. */
|
|
596
|
+
declare const CLASE_BOTON_CONTORNO = "rounded-md border border-[var(--tema-primario)] px-3 py-1 text-xs font-medium text-[var(--tema-primario)] transition hover:bg-[#eaf2fb]";
|
|
597
|
+
/** Solo icono (cerrar, copiar, colapsar): exige `aria-label` y `title`. */
|
|
598
|
+
declare const CLASE_BOTON_ICONO = "rounded-md p-1 text-[#807f7f] transition hover:bg-[var(--tema-badge-neutro)]";
|
|
599
|
+
/** Destructivo (bajas): contorno en el rojo de peligro (tematizable); confirmar siempre antes de ejecutar. */
|
|
600
|
+
declare const CLASE_BOTON_PELIGRO = "inline-flex items-center gap-1.5 rounded-md border border-[var(--tema-peligro)] px-3 py-1.5 text-sm font-medium text-[var(--tema-peligro)] transition hover:bg-[var(--tema-badge-error)] disabled:opacity-50";
|
|
601
|
+
/** Input / select / textarea estandar. Compacto (filtros): `px-2 py-1.5`. */
|
|
602
|
+
declare const CLASE_CAMPO = "rounded-md border border-[var(--tema-borde)] bg-[var(--tema-fondo)] px-3 py-2 text-sm text-[#3c3c3b] focus:border-[var(--tema-primario)] focus:outline-none disabled:bg-[#f4f8fc] disabled:text-[#807f7f]";
|
|
603
|
+
declare const CLASE_CAMPO_COMPACTO = "rounded-md border border-[var(--tema-borde)] bg-[var(--tema-fondo)] px-2 py-1.5 text-sm text-[#3c3c3b] focus:border-[var(--tema-primario)] focus:outline-none";
|
|
604
|
+
/** Etiqueta (label) de campo: encima del campo, separada 4 px (`flex flex-col gap-1`). */
|
|
605
|
+
declare const CLASE_ETIQUETA_CAMPO = "text-sm font-medium text-[#3c3c3b]";
|
|
606
|
+
/** Texto de ayuda bajo el campo. */
|
|
607
|
+
declare const CLASE_AYUDA_CAMPO = "text-xs text-[#807f7f]";
|
|
608
|
+
/** Error de un campo o del envio (con `role="alert"`). */
|
|
609
|
+
declare const CLASE_ERROR_CAMPO = "text-sm text-[var(--tema-peligro)]";
|
|
610
|
+
/** Exito bajo el formulario (con `role="status"`). */
|
|
611
|
+
declare const CLASE_EXITO_CAMPO = "text-sm text-[#1e7a34]";
|
|
612
|
+
/** Tarjeta / seccion: borde fino, sin sombra, sin fondo. */
|
|
613
|
+
declare const CLASE_TARJETA = "rounded-lg border border-[var(--tema-borde)] p-4";
|
|
614
|
+
/** Titulos. */
|
|
615
|
+
declare const CLASE_TITULO_PAGINA = "flex items-center gap-2 text-xl font-semibold text-[var(--tema-primario-oscuro)]";
|
|
616
|
+
declare const CLASE_TITULO_SECCION = "text-sm font-semibold text-[var(--tema-primario-oscuro)]";
|
|
617
|
+
declare const CLASE_TEXTO_ATENUADO = "text-sm text-[#807f7f]";
|
|
618
|
+
|
|
619
|
+
declare const CLASES: {
|
|
620
|
+
readonly exito: "bg-[var(--tema-badge-exito)] text-[#1e6b34]";
|
|
621
|
+
readonly error: "bg-[var(--tema-badge-error)] text-[var(--tema-peligro)]";
|
|
622
|
+
readonly aviso: "bg-[var(--tema-badge-advertencia)] text-[#8a5a00]";
|
|
623
|
+
readonly neutro: "bg-[var(--tema-badge-neutro)] text-[#565656]";
|
|
130
624
|
};
|
|
131
|
-
type
|
|
625
|
+
type Tono = keyof typeof CLASES;
|
|
626
|
+
declare function Insignia({ tono, children, info, icono: Icono, }: {
|
|
627
|
+
tono: keyof typeof CLASES;
|
|
628
|
+
children: ReactNode;
|
|
629
|
+
/** Icono de 12 px antes del texto (KIT: patron de `BadgeEstado` de la plataforma; el color nunca es la unica senal). */
|
|
630
|
+
icono?: LucideIconType;
|
|
631
|
+
/** Explicacion en sitio de la insignia: el icono va justo despues del chip, nunca dentro de el. */
|
|
632
|
+
info?: ExplicacionId;
|
|
633
|
+
}): react.JSX.Element;
|
|
634
|
+
declare function Tarjeta({ titulo, children, nota, info, }: {
|
|
635
|
+
titulo: string;
|
|
636
|
+
children: ReactNode;
|
|
637
|
+
nota?: ReactNode;
|
|
638
|
+
/** Explicacion en sitio del titulo (catalogo `lib/explicaciones.ts`). */
|
|
639
|
+
info?: ExplicacionId;
|
|
640
|
+
}): react.JSX.Element;
|
|
641
|
+
declare function Metrica({ etiqueta, valor, info, }: {
|
|
642
|
+
etiqueta: string;
|
|
643
|
+
valor: ReactNode;
|
|
644
|
+
/** Explicacion en sitio de la metrica (catalogo `lib/explicaciones.ts`). */
|
|
645
|
+
info?: ExplicacionId;
|
|
646
|
+
}): react.JSX.Element;
|
|
647
|
+
/** Encabezado de columna con su explicacion en sitio (el icono va junto al texto, alineado segun la columna). */
|
|
648
|
+
declare function ThInfo({ info, children, className, derecha, scope, atributos, }: {
|
|
649
|
+
info: ExplicacionId;
|
|
650
|
+
children: ReactNode;
|
|
651
|
+
className?: string;
|
|
652
|
+
derecha?: boolean;
|
|
653
|
+
scope?: "col" | "row";
|
|
654
|
+
/** Atributos de columna del marco de tablas: `fija("izq", i)` o `col(id)` (`@/kit/tabla/celdas`). */
|
|
655
|
+
atributos?: object;
|
|
656
|
+
}): react.JSX.Element;
|
|
132
657
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
658
|
+
/**
|
|
659
|
+
* Icono de ayuda (change `explicaciones-analitica-conceptos`): al pasar el mouse o enfocar con teclado abre un
|
|
660
|
+
* popover con las 4 preguntas fijas (que es, como se calcula, de donde sale, como leerlo) del catalogo
|
|
661
|
+
* `lib/explicaciones.ts`. Reusa `PopoverHover` (focusable, `aria-describedby`, posicion `fixed`).
|
|
662
|
+
*
|
|
663
|
+
* Sin desplazamiento de layout: el disparador es un icono de tamano fijo (14px) en un `span` en linea; el
|
|
664
|
+
* contenido solo existe mientras esta abierto. Un id fuera del catalogo lanza (`explicacionDe`): preferible a
|
|
665
|
+
* dejar una metrica sin explicacion en silencio. El `data-explicacion-id` lo leen las pruebas de cobertura.
|
|
666
|
+
*/
|
|
667
|
+
declare function InfoExplicacion({ id }: {
|
|
668
|
+
id: ExplicacionId;
|
|
669
|
+
}): react.JSX.Element;
|
|
670
|
+
|
|
671
|
+
declare const TIPOS: {
|
|
672
|
+
readonly error: "rounded-md bg-[var(--tema-badge-error)] px-3 py-2 text-sm text-[var(--tema-peligro)]";
|
|
673
|
+
readonly advertencia: "rounded-md bg-[var(--tema-badge-advertencia)] px-3 py-2 text-xs text-[#8a5a00]";
|
|
674
|
+
readonly neutro: "rounded-lg bg-[var(--tema-badge-neutro)] px-3 py-2 text-sm text-[#565656]";
|
|
675
|
+
readonly exito: "rounded-md bg-[var(--tema-badge-exito)] px-3 py-2 text-sm text-[#1e7a34]";
|
|
676
|
+
};
|
|
677
|
+
/** Aviso en linea: empieza con una frase en negrita (`titulo`) y sigue el detalle. `error` -> role="alert"; el resto "status". */
|
|
678
|
+
declare function Aviso({ tipo, titulo, children, info, }: {
|
|
679
|
+
tipo: keyof typeof TIPOS;
|
|
680
|
+
titulo?: string;
|
|
155
681
|
children?: ReactNode;
|
|
156
|
-
|
|
682
|
+
info?: ExplicacionId;
|
|
683
|
+
}): react.JSX.Element;
|
|
684
|
+
/** Vacio en bloque (borde punteado). Dentro de una tabla se usa una fila `td colSpan` con `EstadoVacioFila`. */
|
|
685
|
+
declare function EstadoVacio({ children }: {
|
|
686
|
+
children: ReactNode;
|
|
687
|
+
}): react.JSX.Element;
|
|
688
|
+
/** Fila de "Sin resultados" para el `<tbody>` de una tabla. */
|
|
689
|
+
declare function EstadoVacioFila({ columnas, children }: {
|
|
690
|
+
columnas: number;
|
|
691
|
+
children?: ReactNode;
|
|
692
|
+
}): react.JSX.Element;
|
|
693
|
+
/** "No disponible": un calculo que no pudo hacerse. Dice por que; NUNCA pinta un cero. */
|
|
694
|
+
declare function NoDisponible({ motivo, info }: {
|
|
695
|
+
motivo: string;
|
|
696
|
+
info: ExplicacionId;
|
|
697
|
+
}): react.JSX.Element;
|
|
698
|
+
/** Barra de progreso (6 px de alto). */
|
|
699
|
+
declare function BarraProgreso({ porcentaje, etiqueta }: {
|
|
700
|
+
porcentaje: number;
|
|
701
|
+
etiqueta: string;
|
|
702
|
+
}): react.JSX.Element;
|
|
703
|
+
|
|
704
|
+
type AvisoAccion = {
|
|
705
|
+
tipo: "ok" | "error";
|
|
706
|
+
texto: string;
|
|
707
|
+
};
|
|
708
|
+
type IdInfo = Parameters<typeof InfoExplicacion>[0]["id"];
|
|
709
|
+
/**
|
|
710
|
+
* Estado de una accion asincrona (patron unico: "Reintentar", "Sincronizar", etc.): `correr` la
|
|
711
|
+
* ejecuta una vez, `ejecutando` deshabilita el disparador y `aviso` dice el resultado. Un error lanzado se dice con
|
|
712
|
+
* `errorGenerico`; `onHecho` solo se llama si la accion termino bien (para refrescar lo que se ve). Change
|
|
713
|
+
* separado del boton para que el disparador pueda vivir en el menu "⋯" de la fila (que
|
|
714
|
+
* se cierra al elegir) mientras el spinner y el aviso se pintan en la fila.
|
|
715
|
+
*/
|
|
716
|
+
declare function useAccionAviso({ ejecutar, errorGenerico, onHecho, }: {
|
|
717
|
+
ejecutar: () => Promise<AvisoAccion>;
|
|
718
|
+
errorGenerico: string;
|
|
719
|
+
onHecho?: () => void;
|
|
720
|
+
}): {
|
|
721
|
+
ejecutando: boolean;
|
|
722
|
+
aviso: AvisoAccion | null;
|
|
723
|
+
correr: () => Promise<void>;
|
|
724
|
+
};
|
|
725
|
+
/** Spinner mientras la accion corre y el aviso del resultado (`status` si salio bien, `alert` si fallo). */
|
|
726
|
+
declare function AvisoAccionEstado({ ejecutando, aviso, etiquetaSpinner, }: {
|
|
727
|
+
ejecutando: boolean;
|
|
728
|
+
aviso: AvisoAccion | null;
|
|
729
|
+
etiquetaSpinner: string;
|
|
730
|
+
}): react.JSX.Element;
|
|
157
731
|
/**
|
|
158
|
-
*
|
|
732
|
+
* Boton de accion con su (i), spinner y aviso del resultado. Deshabilitado mientras `ejecutar` corre.
|
|
733
|
+
* Compone `useAccionAviso` + `AvisoAccionEstado`.
|
|
734
|
+
*/
|
|
735
|
+
declare function BotonAccionAviso({ etiqueta, etiquetaEjecutando, etiquetaSpinner, ariaLabel, info, errorGenerico, ejecutar, onHecho, }: {
|
|
736
|
+
etiqueta: string;
|
|
737
|
+
etiquetaEjecutando: string;
|
|
738
|
+
etiquetaSpinner: string;
|
|
739
|
+
ariaLabel: string;
|
|
740
|
+
info: IdInfo;
|
|
741
|
+
errorGenerico: string;
|
|
742
|
+
ejecutar: () => Promise<AvisoAccion>;
|
|
743
|
+
onHecho?: () => void;
|
|
744
|
+
}): react.JSX.Element;
|
|
745
|
+
|
|
746
|
+
type GrupoNavegacion = {
|
|
747
|
+
/** Titulo overline del grupo ("Operacion", "Administracion"...). Sin titulo = grupo sin encabezado. */
|
|
748
|
+
titulo?: string;
|
|
749
|
+
enlaces: {
|
|
750
|
+
href: string;
|
|
751
|
+
etiqueta: string;
|
|
752
|
+
icono: LucideIconType;
|
|
753
|
+
}[];
|
|
754
|
+
};
|
|
755
|
+
declare function CascaronApp({ producto, hrefInicio, logo, usuario, hrefCerrarSesion, grupos, pieExtra, children, }: {
|
|
756
|
+
/** Nombre del producto (14 px, 600, color primario) bajo el logo. */
|
|
757
|
+
producto: string;
|
|
758
|
+
hrefInicio?: string;
|
|
759
|
+
/** Logo opcional (ya dimensionado). Sin logo se muestra solo el nombre. */
|
|
760
|
+
logo?: {
|
|
761
|
+
src: string;
|
|
762
|
+
alt: string;
|
|
763
|
+
ancho: number;
|
|
764
|
+
alto: number;
|
|
765
|
+
};
|
|
766
|
+
usuario: {
|
|
767
|
+
nombre: string;
|
|
768
|
+
rol?: string;
|
|
769
|
+
idEstable?: string;
|
|
770
|
+
};
|
|
771
|
+
hrefCerrarSesion?: string;
|
|
772
|
+
grupos: GrupoNavegacion[];
|
|
773
|
+
/** Controles extra del pie (p. ej. la campana de notificaciones), a la izquierda del usuario. */
|
|
774
|
+
pieExtra?: ReactNode;
|
|
775
|
+
children: ReactNode;
|
|
776
|
+
}): react.JSX.Element;
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Enlace del menu lateral. Server-compatible (sin estado): el colapso lo decide CSS via el
|
|
780
|
+
* atributo `data-colapsado` del `<aside>` (`SidebarColapsable`, grupo `side`). Con el menu
|
|
781
|
+
* colapsado (escritorio) solo se ve el icono; `aria-label` y `title` conservan el nombre
|
|
782
|
+
* accesible y el tooltip nativo.
|
|
783
|
+
*/
|
|
784
|
+
declare function EnlaceNav({ href, icono, etiqueta, }: {
|
|
785
|
+
href: string;
|
|
786
|
+
icono: ReactNode;
|
|
787
|
+
etiqueta: string;
|
|
788
|
+
}): react.JSX.Element;
|
|
789
|
+
/** Seccion del menu: el titulo se oculta (queda un separador) cuando el menu esta colapsado. */
|
|
790
|
+
declare function SeccionNav({ titulo, children }: {
|
|
791
|
+
titulo?: string;
|
|
792
|
+
children: ReactNode;
|
|
793
|
+
}): react.JSX.Element;
|
|
794
|
+
|
|
795
|
+
/** Migas: "← Volver" (enlace primario subrayado) / valor actual (mono si es un codigo). */
|
|
796
|
+
declare function Migas({ hrefVolver, etiquetaVolver, actual, actualMono, }: {
|
|
797
|
+
hrefVolver: string;
|
|
798
|
+
/** Texto del enlace, p. ej. "Planes". Se pinta como "← Planes". */
|
|
799
|
+
etiquetaVolver: string;
|
|
800
|
+
actual: string;
|
|
801
|
+
actualMono?: boolean;
|
|
802
|
+
}): react.JSX.Element;
|
|
803
|
+
/** Sub-navegacion entre vistas hermanas de una misma entidad (pildoras con borde; la activa lleva `aria-current`). */
|
|
804
|
+
declare function SubNav({ etiqueta, secciones, activa, }: {
|
|
805
|
+
etiqueta: string;
|
|
806
|
+
secciones: readonly {
|
|
807
|
+
id: string;
|
|
808
|
+
texto: string;
|
|
809
|
+
href: string;
|
|
810
|
+
}[];
|
|
811
|
+
activa: string;
|
|
812
|
+
}): react.JSX.Element;
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Cambio `web-paneles-ajustables` — menu lateral colapsable.
|
|
159
816
|
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* through the `useThemeMode` hook.
|
|
165
|
-
* - Accepts a `theme` override merged on top of the AMS theme.
|
|
817
|
+
* Escritorio (`md`+): boton para colapsar a un rail de solo iconos (w-14); la preferencia
|
|
818
|
+
* persiste en localStorage. Movil (<`md`): el menu es un cajon fuera de pantalla con boton
|
|
819
|
+
* hamburguesa, fondo que lo cierra, Escape y cierre al elegir un enlace (antes ocupaba
|
|
820
|
+
* 15rem fijos del viewport).
|
|
166
821
|
*
|
|
167
|
-
*
|
|
822
|
+
* El estado se expone como `data-colapsado` en el `<aside>` (grupo `side`): los enlaces del
|
|
823
|
+
* Server Component (`EnlaceNav`) reaccionan por CSS, sin convertirse en cliente. El render
|
|
824
|
+
* inicial es expandido (igual que el SSR) y el valor guardado se aplica tras montar.
|
|
825
|
+
* Convive con el asistente anclado: este rail solo cambia SU ancho; el area de contenido es
|
|
826
|
+
* `flex-1` y el asistente reserva su espacio aparte con `--asistente-ancho`.
|
|
168
827
|
*/
|
|
169
|
-
declare function
|
|
828
|
+
declare function SidebarColapsable({ cabecera, pie, children, }: {
|
|
829
|
+
cabecera: ReactNode;
|
|
830
|
+
pie: ReactNode;
|
|
831
|
+
children: ReactNode;
|
|
832
|
+
}): react.JSX.Element;
|
|
170
833
|
|
|
834
|
+
declare const BOTON: {
|
|
835
|
+
readonly primario: "inline-flex items-center gap-1.5 rounded-md bg-[var(--tema-texto)] px-3 py-1.5 text-sm font-medium text-white transition hover:brightness-125 disabled:opacity-50";
|
|
836
|
+
readonly secundario: "inline-flex items-center gap-1.5 rounded-md border border-[var(--tema-borde)] px-3 py-1.5 text-sm font-medium text-[#3c3c3b] transition hover:bg-[var(--tema-badge-neutro)] disabled:opacity-50";
|
|
837
|
+
};
|
|
171
838
|
/**
|
|
172
|
-
*
|
|
173
|
-
*
|
|
839
|
+
* Boton que abre un dialogo modal con un formulario (change `ux-listados-compactos`): saca de la vista los
|
|
840
|
+
* formularios de alta que ocupaban la pantalla antes del listado. Sigue el sistema de diseno 7.11: `role="dialog"`,
|
|
841
|
+
* `aria-modal`, titulo asociado, foco al primer campo al abrir, `Escape`, boton Cerrar y clic en el fondo cierran,
|
|
842
|
+
* y el foco vuelve al boton que lo abrio. El contenido (el formulario) se monta solo mientras esta abierto.
|
|
174
843
|
*/
|
|
175
|
-
declare function
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
844
|
+
declare function AccionConDialogo({ etiqueta, titulo, icono, variante, children, }: {
|
|
845
|
+
etiqueta: string;
|
|
846
|
+
titulo: string;
|
|
847
|
+
icono?: ReactNode;
|
|
848
|
+
variante?: keyof typeof BOTON;
|
|
849
|
+
children: ReactNode;
|
|
850
|
+
}): react.JSX.Element;
|
|
180
851
|
|
|
181
|
-
/** Reads the initial mode: saved preference → OS preference → light. */
|
|
182
|
-
declare function getInitialThemeMode(defaultMode?: ThemeMode): ThemeMode;
|
|
183
|
-
/** Reflects the mode on the DOM so CSS can react (mirrors mf-container). */
|
|
184
|
-
declare function applyThemeModeToDOM(mode: ThemeMode): void;
|
|
185
|
-
interface ThemeModeContextValue {
|
|
186
|
-
mode: ThemeMode;
|
|
187
|
-
setMode: (mode: ThemeMode) => void;
|
|
188
|
-
toggle: () => void;
|
|
189
|
-
isDark: boolean;
|
|
190
|
-
}
|
|
191
852
|
/**
|
|
192
|
-
*
|
|
193
|
-
* `
|
|
853
|
+
* Modal de detalle con tabla (change `listados-ajuste-viewport`, lineamiento `docs/lineamientos-ui.md` "Tablas"): el
|
|
854
|
+
* dialogo nunca crece mas alla de la ventana (`max-h-[90dvh]`, ancho `min(96vw, ...)`); la cabecera y el resumen no se
|
|
855
|
+
* encogen y la tabla (`MarcoTabla ajuste="pagina"` dentro de `children`) toma el alto restante, asi que solo ella se
|
|
856
|
+
* desplaza en ambos ejes con su encabezado y columnas fijas. Antes cada modal crecia con su tabla y se cortaba el pie y
|
|
857
|
+
* las columnas de la derecha.
|
|
194
858
|
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
859
|
+
* `role="dialog"` + `aria-modal`, titulo asociado (`tituloId`), foco al dialogo al abrir; `Escape`, el boton Cerrar y
|
|
860
|
+
* el clic en el fondo cierran.
|
|
197
861
|
*/
|
|
198
|
-
declare function
|
|
862
|
+
declare function ModalPanel({ titulo, tituloId, acciones, onCerrar, etiquetaCerrar, ancho, children, }: {
|
|
863
|
+
/** Contenido del `<h2>` (texto, codigo, explicacion en sitio). */
|
|
864
|
+
titulo: ReactNode;
|
|
865
|
+
tituloId: string;
|
|
866
|
+
/** Botones junto al de cerrar (p. ej. "Descargar CSV"). */
|
|
867
|
+
acciones?: ReactNode;
|
|
868
|
+
onCerrar: () => void;
|
|
869
|
+
etiquetaCerrar?: string;
|
|
870
|
+
/** Clase de ancho maximo (Tailwind). */
|
|
871
|
+
ancho?: string;
|
|
872
|
+
children: ReactNode;
|
|
873
|
+
}): react.JSX.Element;
|
|
874
|
+
|
|
875
|
+
declare function Pestanas({ etiqueta, pestanas, inicial, extra, }: {
|
|
876
|
+
etiqueta: string;
|
|
877
|
+
pestanas: {
|
|
878
|
+
id: string;
|
|
879
|
+
texto: string;
|
|
880
|
+
contenido: ReactNode;
|
|
881
|
+
}[];
|
|
882
|
+
inicial?: string;
|
|
883
|
+
/** Normalmente el (i) de las pestanas, alineado al centro del grupo. */
|
|
884
|
+
extra?: ReactNode;
|
|
885
|
+
}): react.JSX.Element;
|
|
199
886
|
|
|
200
|
-
interface ButtonProps extends ButtonProps$1 {
|
|
201
|
-
}
|
|
202
887
|
/**
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
888
|
+
* Popover reusable que aparece al pasar el mouse (hover) o al enfocar con teclado (focus)
|
|
889
|
+
* sobre su disparador, y se oculta al salir/desenfocar. Nace del widget del tag schedule,
|
|
890
|
+
* pero es generico: cualquier control que quiera mostrar contenido rico al hover lo usa.
|
|
891
|
+
*
|
|
892
|
+
* Por que un componente y no el `title` nativo (unico patron previo en el sistema): el
|
|
893
|
+
* `title` solo muestra texto plano de una linea, no permite contenido estructurado (tabla
|
|
894
|
+
* de ejecuciones con iconos de estatus) ni es navegable. Este es accesible: el disparador
|
|
895
|
+
* es un boton focusable, el contenido se asocia por `aria-describedby` y responde a
|
|
896
|
+
* teclado (focus/blur), no solo a mouse.
|
|
897
|
+
*
|
|
898
|
+
* POSICIONAMIENTO `fixed` (no `absolute`): el widget vive dentro de tablas cuyo contenedor
|
|
899
|
+
* tiene `overflow-hidden`/`overflow-x-auto`; un popover `absolute` quedaba RECORTADO por
|
|
900
|
+
* ese overflow y no se veia. Con `fixed` + las coordenadas del disparador
|
|
901
|
+
* (`getBoundingClientRect`) el contenido flota sobre todo, fuera del flujo recortado.
|
|
902
|
+
*
|
|
903
|
+
* VIEWPORT-AWARE: `fixed` en la esquina del disparador desbordaba el viewport cerca del
|
|
904
|
+
* borde derecho/inferior (texto cortado e ilegible). Tras abrir se MIDE el contenido y
|
|
905
|
+
* `calcularPosicionPopover` lo acota al viewport (desplaza a la izquierda, abre arriba si
|
|
906
|
+
* no cabe abajo, limita ancho/alto con scroll interno). Se recalcula con scroll/resize y
|
|
907
|
+
* Escape lo cierra.
|
|
206
908
|
*/
|
|
207
|
-
declare
|
|
909
|
+
declare function PopoverHover({ etiqueta, disparador, children, }: {
|
|
910
|
+
/** Nombre accesible del disparador (aria-label + tooltip nativo de respaldo). */
|
|
911
|
+
etiqueta: string;
|
|
912
|
+
/** Contenido visible del disparador (normalmente un icono). */
|
|
913
|
+
disparador: ReactNode;
|
|
914
|
+
/** Contenido del popover. */
|
|
915
|
+
children: ReactNode;
|
|
916
|
+
}): react.JSX.Element;
|
|
917
|
+
|
|
918
|
+
type CapacidadAcceso = {
|
|
919
|
+
icono: LucideIconType;
|
|
920
|
+
titulo: string;
|
|
921
|
+
descripcion: string;
|
|
922
|
+
};
|
|
923
|
+
declare function PantallaAcceso({ producto, titulo, descripcion, hrefLogin, etiquetaBoton, capacidades, logo, error, }: {
|
|
924
|
+
producto: string;
|
|
925
|
+
titulo: string;
|
|
926
|
+
descripcion: string;
|
|
927
|
+
hrefLogin: string;
|
|
928
|
+
etiquetaBoton?: string;
|
|
929
|
+
capacidades?: readonly CapacidadAcceso[];
|
|
930
|
+
/** Logo opcional ya renderizado (p. ej. `<Image .../>`). */
|
|
931
|
+
logo?: ReactNode;
|
|
932
|
+
/** Mensaje de error de acceso (p. ej. "Tu cuenta no tiene acceso"). Se pinta con role="alert". */
|
|
933
|
+
error?: string;
|
|
934
|
+
}): react.JSX.Element;
|
|
208
935
|
|
|
209
|
-
/** AMS semantic tag intents mapped to brand tokens. */
|
|
210
|
-
type TagIntent = 'success' | 'error' | 'warning' | 'info' | 'primary';
|
|
211
|
-
interface TagProps extends TagProps$1 {
|
|
212
|
-
/**
|
|
213
|
-
* Semantic intent that resolves to an AMS brand color. Takes precedence over
|
|
214
|
-
* antd's `color` when set. Formalizes the inline `#50cd89` / `#f1416c` colors
|
|
215
|
-
* previously hardcoded in mf-boveda's DataTable.
|
|
216
|
-
*/
|
|
217
|
-
intent?: TagIntent;
|
|
218
|
-
}
|
|
219
936
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
937
|
+
* Pantalla de carga a pagina completa (cambio `ux-spinner-marca`). Se usa como
|
|
938
|
+
* `loading.tsx` de las rutas densas: Next.js la muestra AL INSTANTE mientras el Server
|
|
939
|
+
* Component hace su fetch (SSR), en vez de dejar la pantalla congelada/en blanco -- que
|
|
940
|
+
* es lo que hacia sentir el cambio de pantalla "muy lento" (pedido del usuario). No es
|
|
941
|
+
* maquillaje: el fetch tarda lo mismo, pero el usuario ve feedback inmediato de marca en
|
|
942
|
+
* lugar de una pantalla muerta, que es la causa real de la lentitud PERCIBIDA.
|
|
222
943
|
*/
|
|
223
|
-
declare
|
|
944
|
+
declare function PantallaCargando({ etiqueta }: {
|
|
945
|
+
etiqueta?: string;
|
|
946
|
+
}): react.JSX.Element;
|
|
224
947
|
|
|
225
948
|
/**
|
|
226
|
-
*
|
|
949
|
+
* Overlay de carga para ACCIONES (cambio `ux-spinner-marca`). Pedido del usuario: en cada
|
|
950
|
+
* accion que dispara al hacer click y consume un servicio, mostrar el spinner de marca
|
|
951
|
+
* llenandose. A diferencia de `loading.tsx` (navegacion entre pantallas), este cubre las
|
|
952
|
+
* mutaciones dentro de una pantalla (crear job, reintentar, exportar...). Se monta encima
|
|
953
|
+
* del contenido con un velo semitransparente y BLOQUEA la interaccion mientras `visible`.
|
|
227
954
|
*
|
|
228
|
-
*
|
|
229
|
-
|
|
230
|
-
|
|
955
|
+
* Uso: `{enviando && <OverlayCargando etiqueta="Creando job..." />}`.
|
|
956
|
+
*/
|
|
957
|
+
declare function OverlayCargando({ etiqueta, visible, }: {
|
|
958
|
+
etiqueta?: string;
|
|
959
|
+
visible?: boolean;
|
|
960
|
+
}): react.JSX.Element | null;
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* Spinner de marca: el logo de la instalacion que se "llena" de color de abajo hacia arriba, en
|
|
964
|
+
* bucle (cambio `ux-spinner-marca`). Pedido explicito del usuario: entre
|
|
965
|
+
* cambios de pantalla y en cada accion que consume un servicio, mostrar "un spinner con el logo
|
|
966
|
+
* llenandose de manera gradual".
|
|
231
967
|
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
968
|
+
* COMO FUNCIONA (solucion de raiz, sin GIF ni libreria): se pinta la MISMA imagen del logo dos
|
|
969
|
+
* veces superpuestas:
|
|
970
|
+
* 1. una capa base tenue (el logo "vacio", en gris muy claro),
|
|
971
|
+
* 2. una capa de color de marca recortada con `mask` a la forma del logo (`mask-image` = la
|
|
972
|
+
* imagen), cuya ALTURA visible sube de 0% a 100% con una animacion CSS en bucle.
|
|
973
|
+
* Asi el color solo aparece DENTRO de la silueta del logo y da el efecto de llenado gradual.
|
|
974
|
+
* Respeta `prefers-reduced-motion` (si el usuario lo pide, no anima: muestra el logo lleno y
|
|
975
|
+
* estatico, accesible).
|
|
236
976
|
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
977
|
+
* La imagen sale de la variable CSS `--tema-logo-spinner` (la fija el layout raiz con el logo del
|
|
978
|
+
* producto o tenant); sin ella rige el icono de la marca por omision (`globals.css`). `tamano` en px (ancho);
|
|
979
|
+
* la altura se deriva del aspect ratio del logo (~120x52).
|
|
239
980
|
*/
|
|
240
|
-
|
|
241
|
-
|
|
981
|
+
declare function SpinnerMarca({ tamano, etiqueta, }: {
|
|
982
|
+
tamano?: number;
|
|
983
|
+
etiqueta?: string;
|
|
984
|
+
}): react.JSX.Element;
|
|
242
985
|
|
|
243
986
|
/**
|
|
244
|
-
*
|
|
987
|
+
* Muestra un timestamp UTC en HORA LOCAL del navegador SIN romper la hidratacion
|
|
988
|
+
* (cambio `fix-hydration-fecha`).
|
|
989
|
+
*
|
|
990
|
+
* EL PROBLEMA (React #418): `formatearFechaHora` convierte los timestamps con sufijo UTC
|
|
991
|
+
* a hora local usando `new Date().getHours()` (metodos locales de Date). En el SERVIDOR
|
|
992
|
+
* (SSR en Lambda) la hora local es UTC; en el CLIENTE es la del navegador (p.ej. CDMX,
|
|
993
|
+
* UTC-6). Para el mismo instante el texto difiere -> "text content does not match
|
|
994
|
+
* server-rendered HTML" -> React descarta el arbol hidratado y puede romper el render.
|
|
245
995
|
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
996
|
+
* LA SOLUCION DE RAIZ (sin renunciar a la hora local que pidio el usuario): en el PRIMER
|
|
997
|
+
* render (SSR + primera pintura del cliente) se muestra el MISMO texto determinista para
|
|
998
|
+
* ambos (formato ISO legible, sin conversion), y TRAS montar (`useEffect`, solo cliente)
|
|
999
|
+
* se re-renderiza ya en hora local. Asi el HTML del server y el primer render del cliente
|
|
1000
|
+
* coinciden byte a byte (no hay mismatch), y el usuario termina viendo su hora local. No
|
|
1001
|
+
* es maquillaje: es el patron correcto de Next para valores dependientes del entorno del
|
|
1002
|
+
* cliente (timezone).
|
|
1003
|
+
*/
|
|
1004
|
+
declare function FechaHoraLocal({ iso }: {
|
|
1005
|
+
iso: string | null | undefined;
|
|
1006
|
+
}): react.JSX.Element;
|
|
1007
|
+
|
|
1008
|
+
declare const ANCHOS: {
|
|
1009
|
+
readonly completo: "";
|
|
1010
|
+
readonly "2xl": "mx-auto max-w-2xl";
|
|
1011
|
+
readonly "3xl": "mx-auto max-w-3xl";
|
|
1012
|
+
readonly "4xl": "mx-auto max-w-4xl";
|
|
1013
|
+
};
|
|
1014
|
+
declare function PaginaContenido({ titulo, icono, descripcion, acciones, ancho, children, }: {
|
|
1015
|
+
titulo: ReactNode;
|
|
1016
|
+
/** Icono de 20 px (TAMANO_BOTON) antes del titulo. */
|
|
1017
|
+
icono?: ReactNode;
|
|
1018
|
+
descripcion?: ReactNode;
|
|
1019
|
+
/** Botones de la pantalla, alineados a la derecha del encabezado. */
|
|
1020
|
+
acciones?: ReactNode;
|
|
1021
|
+
ancho?: keyof typeof ANCHOS;
|
|
1022
|
+
children: ReactNode;
|
|
1023
|
+
}): react.JSX.Element;
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Pantalla de listado que cabe en la ventana (change `listados-ajuste-viewport`, lineamiento `docs/lineamientos-ui.md`
|
|
1027
|
+
* "Tablas"): la pagina NO se desplaza; solo el cuerpo de la tabla lo hace y el paginador y la barra horizontal quedan
|
|
1028
|
+
* siempre visibles al pie.
|
|
250
1029
|
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
1030
|
+
* Como funciona (layout, sin numeros magicos): la columna de contenido del layout raiz toma el alto de la ventana cuando
|
|
1031
|
+
* contiene un `[data-pagina-listado]` (`globals.css`); esta pagina es una columna flex `flex-1 min-h-0`, la cabecera y
|
|
1032
|
+
* las barras no se encogen, y la tabla (`MarcoTabla ajuste="pagina"`) toma el alto restante. Cada envoltorio entre la
|
|
1033
|
+
* pagina y el marco lleva `CLASE_REGION_LISTADO` para no romper la cadena `min-h-0`.
|
|
254
1034
|
*
|
|
255
|
-
*
|
|
1035
|
+
* Sin `"use client"`: la usan paginas Server Component.
|
|
256
1036
|
*/
|
|
257
|
-
|
|
1037
|
+
/** Clases de un envoltorio entre `PaginaListado` y `MarcoTabla ajuste="pagina"` (pasa el alto restante hacia la tabla). */
|
|
1038
|
+
declare const CLASE_REGION_LISTADO = "flex min-h-0 flex-1 flex-col";
|
|
1039
|
+
declare function PaginaListado({ titulo, icono, descripcion, acciones, className, children, }: {
|
|
1040
|
+
titulo: ReactNode;
|
|
1041
|
+
/** Icono de 20 px antes del titulo (opcional). */
|
|
1042
|
+
icono?: ReactNode;
|
|
1043
|
+
/** Una linea junto al titulo; si no cabe se recorta con elipsis y el texto completo queda en el tooltip. */
|
|
1044
|
+
descripcion?: string;
|
|
1045
|
+
/** Botones o enlaces de la pantalla (a la derecha de la cabecera). */
|
|
1046
|
+
acciones?: ReactNode;
|
|
1047
|
+
className?: string;
|
|
1048
|
+
children: ReactNode;
|
|
1049
|
+
}): react.JSX.Element;
|
|
258
1050
|
|
|
259
1051
|
/**
|
|
260
|
-
*
|
|
1052
|
+
* Paginación CLIENT-SIDE sobre una lista ya cargada. Para listas acotadas
|
|
1053
|
+
* (decenas–cientos de filas) sin cursor de servidor: paginarlas en el cliente es lo proporcional.
|
|
1054
|
+
* Mismo patrón visual que el resto de listados (Anterior/Siguiente + tamaño de página, con iconos).
|
|
261
1055
|
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
|
|
1056
|
+
* `usePaginacionLocal` corta la lista; `PaginadorLocal` son los controles. Van juntos
|
|
1057
|
+
* pero separados para poder probar el corte sin renderizar la UI.
|
|
1058
|
+
*/
|
|
1059
|
+
declare function usePaginacionLocal<T>(items: T[], tamanoInicial?: number): {
|
|
1060
|
+
itemsPagina: T[];
|
|
1061
|
+
paginaActual: number;
|
|
1062
|
+
totalPaginas: number;
|
|
1063
|
+
tamano: number;
|
|
1064
|
+
totalItems: number;
|
|
1065
|
+
siguiente: () => void;
|
|
1066
|
+
anterior: () => void;
|
|
1067
|
+
cambiarTamano: (n: number) => void;
|
|
1068
|
+
};
|
|
1069
|
+
declare function PaginadorLocal({ paginaActual, totalPaginas, totalItems, tamano, tamanos, onAnterior, onSiguiente, onCambiarTamano, }: {
|
|
1070
|
+
paginaActual: number;
|
|
1071
|
+
totalPaginas: number;
|
|
1072
|
+
totalItems: number;
|
|
1073
|
+
tamano: number;
|
|
1074
|
+
/** Tamanos ofrecidos (por omision 10/25/50/100). Los listados por URL usan 25/50/100. */
|
|
1075
|
+
tamanos?: readonly number[];
|
|
1076
|
+
onAnterior: () => void;
|
|
1077
|
+
onSiguiente: () => void;
|
|
1078
|
+
/** Sin este callback no se pinta el selector de tamano (p. ej. cuando vive en `BarraListado`). */
|
|
1079
|
+
onCambiarTamano?: (n: number) => void;
|
|
1080
|
+
}): react.JSX.Element | null;
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* Paginador de un listado cuyo estado vive en la URL (change `ux-listados-compactos`). Reusa los controles de
|
|
1084
|
+
* `PaginadorLocal` (mismo aspecto que los demas grids); solo cambia de donde sale la pagina: `?pagina=N`. El
|
|
1085
|
+
* tamano de pagina se elige en `BarraListado`, por eso aqui no se pinta su selector. Al cambiar de pagina se
|
|
1086
|
+
* regresa al inicio de la pantalla (`scroll: true`).
|
|
1087
|
+
*/
|
|
1088
|
+
declare function PaginadorUrl({ pagina, totalPaginas, totalItems, tamano, }: {
|
|
1089
|
+
pagina: number;
|
|
1090
|
+
totalPaginas: number;
|
|
1091
|
+
totalItems: number;
|
|
1092
|
+
tamano: number;
|
|
1093
|
+
}): react.JSX.Element | null;
|
|
1094
|
+
|
|
1095
|
+
type FiltroListado = {
|
|
1096
|
+
tipo?: "seleccion";
|
|
1097
|
+
clave: string;
|
|
1098
|
+
etiqueta: string;
|
|
1099
|
+
/** La primera opcion suele ser "Todos" con `valor: ""` (sin filtro). */
|
|
1100
|
+
opciones: {
|
|
1101
|
+
valor: string;
|
|
1102
|
+
etiqueta: string;
|
|
1103
|
+
}[];
|
|
1104
|
+
} | {
|
|
1105
|
+
tipo: "numero";
|
|
1106
|
+
clave: string;
|
|
1107
|
+
etiqueta: string;
|
|
1108
|
+
min?: number;
|
|
1109
|
+
max?: number;
|
|
1110
|
+
};
|
|
1111
|
+
/**
|
|
1112
|
+
* Barra de un listado (change `ux-listados-compactos`): busqueda de texto, filtros de la pantalla,
|
|
1113
|
+
* tamano de pagina y conteo. Todo vive en la URL (`useNavegarListado`), asi que un enlace copiado reproduce la
|
|
1114
|
+
* misma vista; cualquier cambio regresa a la pagina 1.
|
|
265
1115
|
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
1116
|
+
* La busqueda espera 300 ms sin teclear (o `Enter`) y navega UNA vez. Vive en su propio `<form role="search">`
|
|
1117
|
+
* con `preventDefault`: `Enter` aqui nunca envia otro formulario de la pantalla. `Escape` o el boton X limpian.
|
|
1118
|
+
* Los filtros de seleccion aplican al elegir; los numericos al salir del campo o con `Enter`.
|
|
269
1119
|
*/
|
|
270
|
-
declare function
|
|
1120
|
+
declare function BarraListado({ filtros, totalFiltrado, total, placeholder, etiquetaBusqueda, extra, }: {
|
|
1121
|
+
filtros: FiltroListado[];
|
|
1122
|
+
totalFiltrado: number;
|
|
1123
|
+
total: number;
|
|
1124
|
+
placeholder?: string;
|
|
1125
|
+
/** Rotulo (label) del campo de busqueda. */
|
|
1126
|
+
etiquetaBusqueda?: string;
|
|
1127
|
+
/** Controles adicionales a la derecha (p. ej. alternar vista tabla/tarjetas). */
|
|
1128
|
+
extra?: ReactNode;
|
|
1129
|
+
}): react.JSX.Element;
|
|
271
1130
|
|
|
272
1131
|
/**
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
1132
|
+
* Encabezado ordenable de un listado por URL (change `ux-listados-compactos`; sistema de diseno 7.3). El `th`
|
|
1133
|
+
* lleva `aria-sort`; el boton alterna asc -> desc -> orden por omision de la pantalla (borra `orden`/`dir`) y escribe `orden`/`dir` en la URL, asi
|
|
1134
|
+
* que ordena TODO el resultado filtrado (no solo la pagina visible). La explicacion (i) va fuera del boton.
|
|
276
1135
|
*/
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
* mf-boveda table builds it: `{prefix} {total} {suffix}` → "Total 250 registros".
|
|
301
|
-
* Set `showRange` to render "{prefix} {from}-{to} {suffix}" instead.
|
|
302
|
-
* Ignored when `total` (the function form) is provided.
|
|
303
|
-
*/
|
|
304
|
-
totalText?: {
|
|
305
|
-
/** Word(s) before the number, e.g. "Total". */
|
|
306
|
-
prefix?: string;
|
|
307
|
-
/** Word(s) after the number, e.g. "registros". */
|
|
308
|
-
suffix?: string;
|
|
309
|
-
/** Use the "from-to" range instead of just the total. Default false. */
|
|
310
|
-
showRange?: boolean;
|
|
311
|
-
};
|
|
312
|
-
/** Visible text for the "previous" button (overrides the arrow). */
|
|
313
|
-
previousText?: ReactNode;
|
|
314
|
-
/** Visible text for the "next" button (overrides the arrow). */
|
|
315
|
-
nextText?: ReactNode;
|
|
316
|
-
}
|
|
317
|
-
interface PaginationProps extends PaginationProps$1 {
|
|
318
|
-
/** Translatable text labels. */
|
|
319
|
-
labels?: PaginationLabels;
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* AMS Pagination — antd `Pagination` with translatable text via a single
|
|
323
|
-
* `labels` prop (page, records/total, previous/next, items-per-page, jumper).
|
|
324
|
-
* The rest of the antd Pagination API passes through. `showTotal` and
|
|
325
|
-
* `itemRender` still work if you prefer to set them directly; explicit
|
|
326
|
-
* `showTotal`/`itemRender`/`locale` props win over `labels`.
|
|
327
|
-
*/
|
|
328
|
-
declare function Pagination({ labels, showTotal, itemRender, locale, ...rest }: PaginationProps): react.JSX.Element;
|
|
329
|
-
|
|
330
|
-
type CardComponent = react.ForwardRefExoticComponent<CardProps & react.RefAttributes<HTMLDivElement>> & {
|
|
331
|
-
Grid: (typeof Card$1)['Grid'];
|
|
332
|
-
Meta: (typeof Card$1)['Meta'];
|
|
1136
|
+
declare function EncabezadoOrdenUrl({ clave, etiqueta, icono, info, ordenActual, dirActual, alineado, celda, }: {
|
|
1137
|
+
clave: string;
|
|
1138
|
+
etiqueta: string;
|
|
1139
|
+
icono?: ReactNode;
|
|
1140
|
+
info: ExplicacionId;
|
|
1141
|
+
ordenActual: string;
|
|
1142
|
+
dirActual: Direccion;
|
|
1143
|
+
alineado?: "left" | "right";
|
|
1144
|
+
/** Atributos del marco de tablas para el `th`: `{...fija("izq", 0)}` o `{...col("id")}` (change `tablas-columnas-fijas`). */
|
|
1145
|
+
celda?: Record<string, string | number | undefined>;
|
|
1146
|
+
}): react.JSX.Element;
|
|
1147
|
+
|
|
1148
|
+
/** Envuelve un arbol que se exporta (PDF/HTML): sus tablas conservan el layout original. */
|
|
1149
|
+
declare function TablaPlana({ children }: {
|
|
1150
|
+
children: ReactNode;
|
|
1151
|
+
}): react.JSX.Element;
|
|
1152
|
+
declare function UsuarioTablas({ usuario, children }: {
|
|
1153
|
+
usuario?: string | null;
|
|
1154
|
+
children: ReactNode;
|
|
1155
|
+
}): react.JSX.Element;
|
|
1156
|
+
type ColumnaOcultable = {
|
|
1157
|
+
id: string;
|
|
1158
|
+
etiqueta: string;
|
|
333
1159
|
};
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
*/
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
1160
|
+
/**
|
|
1161
|
+
* `pagina`: la tabla es el contenido principal de una pantalla de listado (`PaginaListado`) y toma el alto restante.
|
|
1162
|
+
* `acotado`: la tabla vive dentro de una pagina que se desplaza; su alto maximo se acota (`--marco-alto`, default 70dvh).
|
|
1163
|
+
*/
|
|
1164
|
+
type AjusteMarco = "pagina" | "acotado";
|
|
1165
|
+
declare function MarcoTabla({ clave, etiqueta, columnas, barra, alto, ajuste, pie, controles, className, clasePlana, children, }: {
|
|
1166
|
+
/** Id estable de la tabla (persistencia): `modulo.tabla`. */
|
|
1167
|
+
clave: string;
|
|
1168
|
+
/** Nombre accesible de la region desplazable. */
|
|
1169
|
+
etiqueta: string;
|
|
1170
|
+
/** Columnas que el usuario puede ocultar (las que llevan `col(id)`). Sin ellas no hay menu "Columnas". */
|
|
1171
|
+
columnas?: ColumnaOcultable[];
|
|
1172
|
+
/** Controles propios de la tabla que van en la misma barra (a la izquierda). */
|
|
1173
|
+
barra?: ReactNode;
|
|
1174
|
+
/** Alto maximo del marco en el ajuste `acotado` (CSS). Default `70dvh`, nunca menos de 18rem. */
|
|
1175
|
+
alto?: string;
|
|
1176
|
+
/** `pagina` en pantallas de listado (la pagina no se desplaza, solo el cuerpo); `acotado` (default) en el resto. */
|
|
1177
|
+
ajuste?: AjusteMarco;
|
|
1178
|
+
/** Pie del marco (paginador): fila `shrink-0` bajo la region desplazable, siempre visible. */
|
|
1179
|
+
pie?: ReactNode;
|
|
1180
|
+
/** `false` oculta la barra (densidad/columnas) en tablas minimas; el marco y las columnas fijas se mantienen. */
|
|
1181
|
+
controles?: boolean;
|
|
1182
|
+
className?: string;
|
|
1183
|
+
/** Clases del contenedor bajo `TablaPlana` (exportaciones): las que tenia la tabla antes del marco, para no alterar su layout. */
|
|
1184
|
+
clasePlana?: string;
|
|
1185
|
+
children: ReactNode;
|
|
1186
|
+
}): react.JSX.Element;
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* Columna de una tabla configurable. `id` es estable (se usa para persistir orden/ancho);
|
|
1190
|
+
* `encabezado` es el contenido del <th> (texto + icono); `celda` recibe la fila y devuelve
|
|
1191
|
+
* el contenido del <td>. `alineado` afecta th y td. `minAncho` en px (default 80).
|
|
1192
|
+
* `fijaAncho`: si true, la columna respeta su ancho (util para UUID que debe verse
|
|
1193
|
+
* completo); si false/omitido, crece con el contenido salvo que el usuario la redimensione.
|
|
1194
|
+
*/
|
|
1195
|
+
type ColumnaConfig<T> = {
|
|
1196
|
+
id: string;
|
|
1197
|
+
encabezado: ReactNode;
|
|
1198
|
+
/** Version del encabezado para el menu de columnas (que vive dentro de un <button>): sin controles
|
|
1199
|
+
* interactivos anidados, como el icono de explicacion en sitio. Si se omite se usa `encabezado`. */
|
|
1200
|
+
encabezadoMenu?: ReactNode;
|
|
365
1201
|
/**
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
* Merged into `pagination`; anything set directly on `pagination`
|
|
370
|
-
* (`showTotal`/`itemRender`/`locale`) wins.
|
|
1202
|
+
* Explicacion en sitio de la columna (catalogo `lib/explicaciones.ts`). Se pinta FUERA del boton de orden
|
|
1203
|
+
* (sin controles anidados) y no aparece en el menu de columnas. Obligatoria por lineamiento
|
|
1204
|
+
* (docs/lineamientos-ui.md): la compuerta `cobertura-explicaciones.test.ts` la exige.
|
|
371
1205
|
*/
|
|
372
|
-
|
|
1206
|
+
info?: ExplicacionId;
|
|
1207
|
+
celda: (fila: T) => ReactNode;
|
|
1208
|
+
alineado?: "left" | "right";
|
|
1209
|
+
/** Ancho inicial en px (antes de que el usuario redimensione). Default 160. */
|
|
1210
|
+
anchoDefault?: number;
|
|
373
1211
|
/**
|
|
374
|
-
*
|
|
375
|
-
* (
|
|
376
|
-
*
|
|
377
|
-
*
|
|
1212
|
+
* Si true, el encabezado se vuelve un boton que ordena la PAGINA VISIBLE por esta
|
|
1213
|
+
* columna (client-side, sobre las filas ya cargadas). Es un orden POR PAGINA, no
|
|
1214
|
+
* global -- la aria-label lo declara explicitamente para no confundir con el orden
|
|
1215
|
+
* global por fecha (que va por URL, filtros por URL). Requiere
|
|
1216
|
+
* `valorOrden` para saber por que valor comparar.
|
|
378
1217
|
*/
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
/** Initial open state in uncontrolled mode. */
|
|
388
|
-
defaultOpen?: boolean;
|
|
389
|
-
/** Node or render-prop that opens the modal when clicked. */
|
|
390
|
-
trigger?: ReactNode | TriggerRenderer;
|
|
391
|
-
/** Close automatically after `onOk` resolves. Default true. */
|
|
392
|
-
closeOnOk?: boolean;
|
|
393
|
-
/** Close automatically after `onCancel`. Default true. */
|
|
394
|
-
closeOnCancel?: boolean;
|
|
395
|
-
/** Notified whenever the open state changes (controlled or not). */
|
|
396
|
-
onOpenChange?: (next: boolean) => void;
|
|
397
|
-
children?: ReactNode;
|
|
398
|
-
}
|
|
1218
|
+
ordenable?: boolean;
|
|
1219
|
+
/** Valor por el que ordenar cuando `ordenable`. String -> orden alfabetico
|
|
1220
|
+
* (localeCompare); number -> orden numerico. Ausente/undefined -> al final. */
|
|
1221
|
+
valorOrden?: (fila: T) => string | number | undefined;
|
|
1222
|
+
/** Etiqueta legible para la aria-label del boton de orden (ej. "Monto"). Si se
|
|
1223
|
+
* omite y `encabezado` es un string, se usa ese; si no, "esta columna". */
|
|
1224
|
+
etiquetaOrden?: string;
|
|
1225
|
+
};
|
|
399
1226
|
/**
|
|
400
|
-
*
|
|
1227
|
+
* Tabla con columnas REORDENABLES (arrastrar el encabezado), REDIMENSIONABLES (arrastrar
|
|
1228
|
+
* el borde derecho del encabezado) y con menu de mostrar/ocultar columnas. Las
|
|
1229
|
+
* preferencias persisten en localStorage por `clavePrefs` (ver preferenciasTabla.ts).
|
|
1230
|
+
* Lineamiento del sistema: cualquier tabla puede usar este componente.
|
|
401
1231
|
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
* - `closeOnOk` / `closeOnCancel` with async `onOk` support (waits for the
|
|
406
|
-
* returned promise before closing).
|
|
1232
|
+
* Drag & drop nativo (HTML5 draggable) y resize con eventos de mouse -- sin dependencias
|
|
1233
|
+
* externas. Accesible: el asa de arrastre tiene aria-label; el menu de columnas es de
|
|
1234
|
+
* checkboxes.
|
|
407
1235
|
*
|
|
408
|
-
*
|
|
1236
|
+
* Change `tablas-columnas-fijas`: se pinta dentro de `MarcoTabla` (desplazamiento acotado, encabezado fijo, densidad).
|
|
1237
|
+
* `columnaFija` (casilla) e `idsFijos` (identidad: codigo, nombre...) quedan fijas a la izquierda y no se pueden
|
|
1238
|
+
* arrastrar ni ocultar; `columnaAcciones` queda fija a la derecha.
|
|
409
1239
|
*/
|
|
410
|
-
declare function
|
|
1240
|
+
declare function TablaConfigurable<T>({ columnas, filas, claveFila, clavePrefs, columnaFija, columnaAcciones, idsFijos, etiqueta, mensajeVacio, ajuste, pie, barraExtra, }: {
|
|
1241
|
+
columnas: ColumnaConfig<T>[];
|
|
1242
|
+
filas: T[];
|
|
1243
|
+
claveFila: (fila: T) => string;
|
|
1244
|
+
clavePrefs: string;
|
|
1245
|
+
/** Contenido opcional de una primera columna FIJA no reordenable (ej. checkbox). */
|
|
1246
|
+
columnaFija?: {
|
|
1247
|
+
encabezado?: ReactNode;
|
|
1248
|
+
celda: (fila: T) => ReactNode;
|
|
1249
|
+
};
|
|
1250
|
+
/** Contenido opcional de una ultima columna FIJA no reordenable (ej. acciones). */
|
|
1251
|
+
columnaAcciones?: {
|
|
1252
|
+
encabezado?: ReactNode;
|
|
1253
|
+
celda: (fila: T) => ReactNode;
|
|
1254
|
+
};
|
|
1255
|
+
/** Ids de columnas de identidad fijas a la izquierda (en este orden), despues de `columnaFija`. */
|
|
1256
|
+
idsFijos?: string[];
|
|
1257
|
+
/** Nombre accesible de la region desplazable. */
|
|
1258
|
+
etiqueta?: string;
|
|
1259
|
+
mensajeVacio?: ReactNode;
|
|
1260
|
+
/** Ajuste del marco: `pagina` en pantallas de listado (`PaginaListado`), `acotado` (default) en el resto. */
|
|
1261
|
+
ajuste?: AjusteMarco;
|
|
1262
|
+
/** Pie del marco (paginador), siempre visible bajo la tabla. */
|
|
1263
|
+
pie?: ReactNode;
|
|
1264
|
+
/** Controles de la pantalla que van en la misma barra de la tabla (p. ej. el indicador en vivo): ahorra una fila. */
|
|
1265
|
+
barraExtra?: ReactNode;
|
|
1266
|
+
}): react.JSX.Element;
|
|
411
1267
|
|
|
412
|
-
interface FilterOption {
|
|
413
|
-
value: string;
|
|
414
|
-
label: ReactNode;
|
|
415
|
-
disabled?: boolean;
|
|
416
|
-
}
|
|
417
|
-
interface FilterSelectProps extends Omit<SelectProps<string>, 'options' | 'filterOption'> {
|
|
418
|
-
options: FilterOption[];
|
|
419
|
-
/** Enable client-side search with accent-insensitive matching. */
|
|
420
|
-
showSearch?: boolean;
|
|
421
|
-
/** Override the default accent-insensitive filter. */
|
|
422
|
-
filterOption?: SelectProps<string>['filterOption'];
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* AMS FilterSelect — a Select preset for dashboard filters.
|
|
426
|
-
*
|
|
427
|
-
* Ports mf-boveda's FilterSelect: accent-insensitive search over both the
|
|
428
|
-
* option label and value, full-width by default. i18n is the consumer's
|
|
429
|
-
* responsibility (pass already-translated labels).
|
|
430
|
-
*/
|
|
431
|
-
declare function FilterSelect({ options, showSearch, filterOption, className, style, ...rest }: FilterSelectProps): react.JSX.Element;
|
|
432
|
-
|
|
433
|
-
type UploadMessage = string | ((fileName: string) => string);
|
|
434
|
-
type UploadChangeInfo = Parameters<NonNullable<UploadProps['onChange']>>[0];
|
|
435
|
-
interface FileUploadDraggerProps extends Omit<UploadProps, 'onChange'> {
|
|
436
|
-
/** Success toast text or a builder receiving the file name. */
|
|
437
|
-
successMessage?: UploadMessage;
|
|
438
|
-
/** Error toast text or a builder receiving the file name. */
|
|
439
|
-
errorMessage?: UploadMessage;
|
|
440
|
-
/** Show success/error toasts on upload status changes. Default true. */
|
|
441
|
-
showStatusMessages?: boolean;
|
|
442
|
-
/** Prompt text shown inside the drop area (when no children given). */
|
|
443
|
-
hintText?: ReactNode;
|
|
444
|
-
onUploadSuccess?: (info: UploadChangeInfo) => void;
|
|
445
|
-
onUploadError?: (info: UploadChangeInfo) => void;
|
|
446
|
-
onChange?: UploadProps['onChange'];
|
|
447
|
-
children?: ReactNode;
|
|
448
|
-
}
|
|
449
|
-
/**
|
|
450
|
-
* AMS FileUploadDragger — drag-and-drop uploader.
|
|
451
|
-
*
|
|
452
|
-
* Ports mf-boveda's FileUploadDragger with two DS improvements:
|
|
453
|
-
* - toasts use the context-safe `useAmsMessage()` (no antd v5 static warning),
|
|
454
|
-
* - all copy is passed via props (i18n stays in the consumer); no default
|
|
455
|
-
* upload endpoint is baked in.
|
|
456
|
-
*/
|
|
457
|
-
declare function FileUploadDragger({ successMessage, errorMessage, showStatusMessages, hintText, onUploadSuccess, onUploadError, onChange: externalOnChange, children, ...uploadProps }: FileUploadDraggerProps): react.JSX.Element;
|
|
458
|
-
|
|
459
|
-
interface BreadcrumbItem {
|
|
460
|
-
title: ReactNode;
|
|
461
|
-
href?: string;
|
|
462
|
-
}
|
|
463
|
-
interface PageHeaderProps {
|
|
464
|
-
/** Page title. Rendered as an h1. */
|
|
465
|
-
title: ReactNode;
|
|
466
|
-
/** Breadcrumb trail. When omitted, no breadcrumb is shown. */
|
|
467
|
-
breadcrumbs?: BreadcrumbItem[];
|
|
468
|
-
/** Breadcrumb separator. Defaults to ">". */
|
|
469
|
-
separator?: ReactNode;
|
|
470
|
-
/** Uppercase the title (matches the b2bmx convention). Default true. */
|
|
471
|
-
uppercaseTitle?: boolean;
|
|
472
|
-
/** Content aligned to the right of the title (actions). */
|
|
473
|
-
extra?: ReactNode;
|
|
474
|
-
className?: string;
|
|
475
|
-
}
|
|
476
1268
|
/**
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
* Consolidates mf-boveda's Header + Breadcrums. Decoupled from react-router
|
|
480
|
-
* and the boveda domain: the consumer builds the breadcrumb items (already
|
|
481
|
-
* translated) and passes them in.
|
|
1269
|
+
* Campos de filtro compartidos por todos los buscadores: mismo aspecto, mismas etiquetas con icono y `label` asociado. Son
|
|
1270
|
+
* NO controlados (`defaultValue`): el formulario lee los valores con `FormData` al enviar.
|
|
482
1271
|
*/
|
|
483
|
-
|
|
1272
|
+
/** Etiqueta de encabezado (icono + texto) para las columnas de la tabla configurable.
|
|
1273
|
+
* Ya NO envuelve un <th> (eso lo pone TablaConfigurable): es solo el contenido. */
|
|
1274
|
+
declare function EtiquetaCol({ icono: Icono, texto, info, }: {
|
|
1275
|
+
icono?: LucideIconType;
|
|
1276
|
+
texto: string;
|
|
1277
|
+
/** Explicacion en sitio del encabezado (catalogo `lib/explicaciones.ts`). */
|
|
1278
|
+
info?: ExplicacionId;
|
|
1279
|
+
}): react.JSX.Element;
|
|
1280
|
+
declare function Campo({ id, name, etiqueta, defaultValue, tipo, icono: Icono, }: {
|
|
1281
|
+
id: string;
|
|
1282
|
+
name: string;
|
|
1283
|
+
etiqueta: string;
|
|
1284
|
+
defaultValue: string;
|
|
1285
|
+
tipo?: string;
|
|
1286
|
+
icono?: LucideIconType;
|
|
1287
|
+
}): react.JSX.Element;
|
|
1288
|
+
declare function CampoSelect({ id, name, etiqueta, defaultValue, opciones, icono: Icono, }: {
|
|
1289
|
+
id: string;
|
|
1290
|
+
name: string;
|
|
1291
|
+
etiqueta: string;
|
|
1292
|
+
defaultValue: string;
|
|
1293
|
+
opciones: {
|
|
1294
|
+
valor: string;
|
|
1295
|
+
etiqueta: string;
|
|
1296
|
+
}[];
|
|
1297
|
+
icono?: LucideIconType;
|
|
1298
|
+
}): react.JSX.Element;
|
|
1299
|
+
|
|
1300
|
+
declare function IconoConEtiqueta({ Icono, texto, info }: {
|
|
1301
|
+
Icono: LucideIconType;
|
|
1302
|
+
texto: ReactNode;
|
|
1303
|
+
info?: ExplicacionId;
|
|
1304
|
+
}): react.JSX.Element;
|
|
1305
|
+
declare function MetricaKpi({ etiqueta, valor, icono: Icono, destacada, sub, progreso, info, }: {
|
|
1306
|
+
etiqueta: string;
|
|
1307
|
+
valor: string | number;
|
|
1308
|
+
icono: LucideIconType;
|
|
1309
|
+
info: ExplicacionId;
|
|
1310
|
+
destacada?: boolean;
|
|
1311
|
+
sub?: string;
|
|
1312
|
+
progreso?: {
|
|
1313
|
+
porcentaje: number;
|
|
1314
|
+
etiqueta: string;
|
|
1315
|
+
};
|
|
1316
|
+
}): react.JSX.Element;
|
|
1317
|
+
/** Subtitulo de un grupo de metricas, para que las cajitas se lean agrupadas por concepto en vez de un mar plano. */
|
|
1318
|
+
declare function GrupoMetricas({ titulo, icono: Icono, children }: {
|
|
1319
|
+
titulo: string;
|
|
1320
|
+
icono: LucideIconType;
|
|
1321
|
+
children: ReactNode;
|
|
1322
|
+
}): react.JSX.Element;
|
|
1323
|
+
/** Rejilla de KPI de la plataforma (extraida de `riesgo-credito/piezas.tsx`): 1 col movil, 2 `sm`, 4 `lg`. */
|
|
1324
|
+
declare function RejillaMetricas({ children }: {
|
|
1325
|
+
children: ReactNode;
|
|
1326
|
+
}): react.JSX.Element;
|
|
1327
|
+
/** Rotulo de un bloque o grafica con su (i) (extraido de `riesgo-credito/piezas.tsx`). */
|
|
1328
|
+
declare function Rotulo({ texto, info }: {
|
|
1329
|
+
texto: string;
|
|
1330
|
+
info: ExplicacionId;
|
|
1331
|
+
}): react.JSX.Element;
|
|
484
1332
|
|
|
485
|
-
interface DownloadButtonProps extends ButtonProps {
|
|
486
|
-
/** Button label. Defaults to "CSV". */
|
|
487
|
-
label?: React.ReactNode;
|
|
488
|
-
}
|
|
489
1333
|
/**
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
* with the full Button API available. i18n via the `label`/`children` props.
|
|
1334
|
+
* Atributos de celda del marco de tablas (change `tablas-columnas-fijas`). SIN "use client": las paginas Server
|
|
1335
|
+
* Component llaman `fija()` / `col()` y pintan `CeldaIdentidad` al armar su `<table>` (una funcion exportada desde un
|
|
1336
|
+
* modulo cliente no se puede llamar en el servidor). El comportamiento vive en `MarcoTabla.tsx` y `app/globals.css`.
|
|
494
1337
|
*/
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
/** Mark the confirm action as destructive (red primary button). */
|
|
501
|
-
danger?: boolean;
|
|
502
|
-
children?: ReactNode;
|
|
503
|
-
}
|
|
1338
|
+
type AtributosFija = {
|
|
1339
|
+
"data-fija": "izq" | "der";
|
|
1340
|
+
"data-fija-idx"?: number;
|
|
1341
|
+
"data-fija-primaria"?: "";
|
|
1342
|
+
};
|
|
504
1343
|
/**
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
* inherits controlled/uncontrolled state, trigger, and async `onOk` from
|
|
509
|
-
* ModalDialog. Set `danger` for destructive actions. Copy via props (i18n).
|
|
1344
|
+
* Marca una celda (`th` o `td`) como fija. `izq` lleva el indice de la columna fija (0, 1, 2, 3, en orden de izquierda a
|
|
1345
|
+
* derecha); la 0 es la columna primaria salvo `{ primaria: true }` en otra (p. ej. cuando la 0 es una casilla). La
|
|
1346
|
+
* primaria es la unica que sigue fija en pantallas angostas. Se aplica igual en el encabezado y en cada fila.
|
|
510
1347
|
*/
|
|
511
|
-
declare function
|
|
1348
|
+
declare function fija(lado: "izq" | "der", idx?: number, opciones?: {
|
|
1349
|
+
primaria?: boolean;
|
|
1350
|
+
}): AtributosFija;
|
|
1351
|
+
/** Marca una celda como parte de la columna ocultable `id` (el mismo id que se declara en `columnas`). */
|
|
1352
|
+
declare function col(id: string): {
|
|
1353
|
+
"data-col": string;
|
|
1354
|
+
};
|
|
1355
|
+
/** Texto de identidad largo (razon social): una linea con elipsis y el texto completo como tooltip. */
|
|
1356
|
+
declare function CeldaIdentidad({ texto, className }: {
|
|
1357
|
+
texto: string | null | undefined;
|
|
1358
|
+
className?: string;
|
|
1359
|
+
}): react.JSX.Element;
|
|
1360
|
+
/**
|
|
1361
|
+
* Estilo unico de una accion de fila con icono + texto corto (enlace o boton), en linea o dentro del menu "⋯" de
|
|
1362
|
+
* `AccionesFila` (change `avance-rfc-acciones-compactas`; antes vivia solo en Analitica).
|
|
1363
|
+
*/
|
|
1364
|
+
declare const CLASE_ACCION_FILA = "inline-flex items-center gap-1 whitespace-nowrap rounded-md border border-[var(--tema-borde)] px-2.5 py-1 text-xs hover:bg-[var(--tema-badge-neutro)] disabled:opacity-50";
|
|
512
1365
|
|
|
513
|
-
interface UseControllableStateOptions<T> {
|
|
514
|
-
/** Controlled value. When defined, the hook is in controlled mode. */
|
|
515
|
-
value?: T;
|
|
516
|
-
/** Initial value for uncontrolled mode. */
|
|
517
|
-
defaultValue: T;
|
|
518
|
-
/** Called on every change (both modes). */
|
|
519
|
-
onChange?: (next: T) => void;
|
|
520
|
-
}
|
|
521
1366
|
/**
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
*
|
|
1367
|
+
* Celda compacta de acciones por fila (change `tablas-columnas-fijas`). Hasta 2 acciones se pintan en linea (botones de
|
|
1368
|
+
* icono con `title`/`aria-label`, o enlaces cortos); con mas de 2, un solo boton "..." abre un menu. El menu es
|
|
1369
|
+
* `position: fixed` y vive en un portal en `body` (calculado del boton) para no quedar recortado por el marco desplazable ni
|
|
1370
|
+
* debajo de otras celdas fijas. Escape, clic fuera o elegir una accion lo cierran; si la accion abre un dialogo
|
|
1371
|
+
* (`aria-modal`), el menu sigue montado hasta que el dialogo se cierra (desmontarlo cerraria el dialogo). Va dentro de la
|
|
1372
|
+
* celda fija derecha (`fija("der")`).
|
|
525
1373
|
*/
|
|
526
|
-
declare function
|
|
1374
|
+
declare function AccionesFila({ etiqueta, children, }: {
|
|
1375
|
+
etiqueta?: string;
|
|
1376
|
+
children: ReactNode;
|
|
1377
|
+
}): react.JSX.Element;
|
|
1378
|
+
/**
|
|
1379
|
+
* Accion de fila con icono + texto corto y, opcional, su (i) al lado (change `avance-rfc-acciones-compactas`). Sirve en
|
|
1380
|
+
* linea y dentro del menu "⋯" de `AccionesFila` con el mismo aspecto (`CLASE_ACCION_FILA`). `disabled` mientras la
|
|
1381
|
+
* accion corre; el spinner y el resultado los pinta la fila, porque el menu se cierra al elegir.
|
|
1382
|
+
*/
|
|
1383
|
+
declare function BotonAccionFila({ icono: Icono, etiqueta, ariaLabel, onClick, disabled, info, }: {
|
|
1384
|
+
icono: LucideIconType;
|
|
1385
|
+
etiqueta: string;
|
|
1386
|
+
ariaLabel?: string;
|
|
1387
|
+
onClick: () => void;
|
|
1388
|
+
disabled?: boolean;
|
|
1389
|
+
info?: Parameters<typeof InfoExplicacion>[0]["id"];
|
|
1390
|
+
}): react.JSX.Element;
|
|
527
1391
|
|
|
528
|
-
export {
|
|
1392
|
+
export { AccionConDialogo, AccionesFila, type AjusteMarco, Aviso, type AvisoAccion, AvisoAccionEstado, BarraListado, BarraProgreso, BotonAccionAviso, BotonAccionFila, CLASE_ACCION_FILA, CLASE_AYUDA_CAMPO, CLASE_BOTON_CONTORNO, CLASE_BOTON_ICONO, CLASE_BOTON_PELIGRO, CLASE_BOTON_PEQUENO, CLASE_BOTON_PRIMARIO, CLASE_BOTON_PRIMARIO_COMPACTO, CLASE_BOTON_SECUNDARIO, CLASE_CAMPO, CLASE_CAMPO_COMPACTO, CLASE_ERROR_CAMPO, CLASE_ETIQUETA_CAMPO, CLASE_EXITO_CAMPO, CLASE_REGION_LISTADO, CLASE_TARJETA, CLASE_TEXTO_ATENUADO, CLASE_TITULO_PAGINA, CLASE_TITULO_SECCION, type CambiosListado, Campo, CampoSelect, type CapacidadAcceso, CascaronApp, CeldaIdentidad, type ColumnaConfig, type ColumnaOcultable, type DefListado, type Direccion, ETIQUETAS_SEMAFORO, EXPLICACIONES, EncabezadoOrdenUrl, EnlaceNav, type EntradaPosicion, type EstadoListado, EstadoVacio, EstadoVacioFila, EtiquetaCol, type Explicacion, type ExplicacionId, FechaHoraLocal, type FiltroListado, GrupoMetricas, type GrupoNavegacion, ICONOS_ESTATUS, ICONOS_SEMAFORO, ICONO_ACCIONES_FILA, ICONO_ALTA, ICONO_API_KEY, ICONO_ARRASTRAR_COLUMNA, ICONO_AVISO, ICONO_BAJA, ICONO_BUSCAR, ICONO_CAMPANA, ICONO_CARGANDO, ICONO_CERRAR, ICONO_CERRAR_SESION, ICONO_COLUMNAS, ICONO_COLUMNA_OCULTA, ICONO_COLUMNA_VISIBLE, ICONO_COL_CODIGO, ICONO_COL_DOCUMENTO, ICONO_COL_ESTADO, ICONO_COL_ETIQUETA, ICONO_COL_FECHA, ICONO_COL_FECHA_HORA, ICONO_COL_MECANISMO, ICONO_COL_NOMBRE, ICONO_COL_TOTAL, ICONO_COL_USUARIO, ICONO_CONFIRMAR, ICONO_COPIAR, ICONO_DEFAULT, ICONO_DENSIDAD_COMODA, ICONO_DENSIDAD_COMPACTA, ICONO_DESCARGAR, ICONO_DESHABILITAR, ICONO_DURACION, ICONO_EDITAR, ICONO_EMAIL, ICONO_ERROR, ICONO_EXPORTAR, ICONO_EXPORTAR_CSV, ICONO_FILTRO, ICONO_GENERAR, ICONO_GUARDAR, ICONO_INACTIVAR, ICONO_INFO_EXPLICACION, ICONO_INICIAR_SESION, ICONO_INVITACION_GENERICA, ICONO_KPI_ALERTA, ICONO_KPI_BLOQUEO, ICONO_KPI_CONSUMO, ICONO_KPI_CONTEO, ICONO_KPI_CREDENCIALES, ICONO_KPI_RENDIMIENTO, ICONO_KPI_RITMO, ICONO_LIMPIAR, ICONO_LINK, ICONO_LOGIN_MICROSOFT, ICONO_NAV_ACCESOS, ICONO_NAV_ANALITICA, ICONO_NAV_API_KEYS, ICONO_NAV_BITACORA, ICONO_NAV_CLIENTE, ICONO_NAV_COLAPSAR, ICONO_NAV_CONFIGURACION, ICONO_NAV_DASHBOARD, ICONO_NAV_ENTIDADES, ICONO_NAV_ETIQUETAS, ICONO_NAV_EXPANDIR, ICONO_NAV_EXTRACCIONES, ICONO_NAV_INVITACIONES, ICONO_NAV_JOBS, ICONO_NAV_MANUAL, ICONO_NAV_MENU_MOVIL, ICONO_NAV_NOTIFICACIONES, ICONO_NAV_PAQUETES, ICONO_NAV_PLANES, ICONO_NAV_SALUD, ICONO_NAV_TEMA, ICONO_NAV_USUARIOS, ICONO_OK, ICONO_ORDENAR_ASC, ICONO_ORDENAR_DESC, ICONO_ORDENAR_NEUTRO, ICONO_PAGINA_ANTERIOR, ICONO_PAGINA_SIGUIENTE, ICONO_PERIODO, ICONO_REACTIVAR, ICONO_REACTIVAR_ETIQUETA, ICONO_REINTENTAR, ICONO_RESTABLECER, ICONO_REVOCAR_KEY, ICONO_ROTAR_KEY, ICONO_SEGURIDAD, ICONO_SELECCIONADO, ICONO_SILENCIAR, ICONO_UBICACION, ICONO_VER_TODOS, ICONO_VIGENCIA, ICONO_VISTA_TABLA, ICONO_VISTA_TARJETAS, ICONO_VOLVER, IconoConEtiqueta, InfoExplicacion, Insignia, LinkBase, type LinkBaseProps, type LinkComponent, LinkComponentProvider, type ListadoNav, ListadoNavProvider, type LucideIconType, MarcoTabla, Metrica, MetricaKpi, Migas, ModalPanel, NOMBRE_PRODUCTO_DEFAULT, NO_DISPONIBLE, NoDisponible, type OpcionesListado, OverlayCargando, PaginaContenido, PaginaListado, PaginadorLocal, PaginadorUrl, PantallaAcceso, PantallaCargando, type ParamsUrl, Pestanas, PopoverHover, type PosicionPopover, type RectLike, RejillaMetricas, Rotulo, SeccionNav, SidebarColapsable, SpinnerMarca, SubNav, TAMANOS_LISTADO, TAMANO_BADGE, TAMANO_BOTON, TAMANO_LISTADO_DEFAULT, TEMA_DEFAULT, TablaConfigurable, TablaPlana, Tarjeta, type Tema, ThInfo, type Tono, UsuarioTablas, aplicarListado, calcularPosicionPopover, col, etiquetaSemaforo, explicacionDe, fija, formatearBytes, formatearFechaHora, formatearFechaHoraCDMX, formatearRangoFechaHora, formatoDias, formatoEntero, formatoFecha, formatoMes, formatoMxn, formatoNumero, formatoPct, hrefListado, iconoDeEstatus, iconoDeSemaforo, leerListado, normalizarTexto, useAccionAviso, useAccionConSpinner, useNavegarListado, usePaginacionLocal, useTablaPreferencias, variablesDeTema, verificarCatalogo };
|