@satellatickets/core 0.0.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/index.d.ts +675 -30
- package/dist/index.js +331 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -19,12 +19,12 @@ theme.color.action.primary;
|
|
|
19
19
|
|
|
20
20
|
## Qué contiene
|
|
21
21
|
|
|
22
|
-
| Qué | Ejemplos
|
|
23
|
-
| ----------------------- |
|
|
24
|
-
| Contratos de props | `ButtonProps`, `BadgeProps`, `BoxProps`, `StackProps`, `TextProps`, `IconProps`
|
|
25
|
-
| Constantes de variantes | `buttonVariants`, `badgeVariants`, `textVariants`, `iconSizes`
|
|
26
|
-
| Tema | `UIContext`, `useTheme`, `useColorScheme`, `useBrand`, `resolveTheme`
|
|
27
|
-
| Hooks headless | `useButton`
|
|
22
|
+
| Qué | Ejemplos |
|
|
23
|
+
| ----------------------- | --------------------------------------------------------------------------------- |
|
|
24
|
+
| Contratos de props | `ButtonProps`, `BadgeProps`, `BoxProps`, `StackProps`, `TextProps`, `IconProps` |
|
|
25
|
+
| Constantes de variantes | `buttonVariants`, `badgeVariants`, `textVariants`, `iconSizes` |
|
|
26
|
+
| Tema | `UIContext`, `useTheme`, `useColorScheme`, `useBrand`, `resolveTheme` |
|
|
27
|
+
| Hooks headless | `useButton`, `useLink`, `useControllableState`, `useFormFieldControl`, `useToast` |
|
|
28
28
|
|
|
29
29
|
Las variantes se exportan como arrays `as const`, además de como tipos, para poder recorrerlas: en historias, en selectores o en tests.
|
|
30
30
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { BrandName, Theme, ThemeName, ThemeOverrides } from "@satellatickets/tokens";
|
|
3
|
+
//#region src/form-field/context.d.ts
|
|
4
|
+
/** Lo que `FormField` publica para el control que envuelve (ADR-037). */
|
|
5
|
+
export interface FormFieldValue {
|
|
6
|
+
/** `id` del control. `FormField` lo usa en el `htmlFor` de su etiqueta (web). */
|
|
7
|
+
controlId: string;
|
|
8
|
+
/** `id` del texto de ayuda, si lo hay (web). */
|
|
9
|
+
helpId: string | undefined;
|
|
10
|
+
/** `id` del mensaje de error, si lo hay (web). */
|
|
11
|
+
errorId: string | undefined;
|
|
12
|
+
label: string;
|
|
13
|
+
help: string | undefined;
|
|
14
|
+
error: string | undefined;
|
|
15
|
+
disabled: boolean;
|
|
16
|
+
required: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface FormFieldValueOptions {
|
|
19
|
+
label: string;
|
|
20
|
+
help?: string | undefined;
|
|
21
|
+
error?: string | undefined;
|
|
22
|
+
disabled?: boolean | undefined;
|
|
23
|
+
required?: boolean | undefined;
|
|
24
|
+
}
|
|
25
|
+
/** Construye el valor del contexto a partir de un id base (el de `useId()`). */
|
|
26
|
+
export declare function createFormFieldValue(baseId: string, { label, help, error, disabled, required }: FormFieldValueOptions): FormFieldValue;
|
|
27
|
+
/** `null` fuera de un `FormField`. */
|
|
28
|
+
export declare const FormFieldContext: import("react").Context<FormFieldValue | null>;
|
|
29
|
+
/** Las props propias de un control que se combinan con las de su `FormField`. */
|
|
30
|
+
export interface FormFieldControlOptions {
|
|
31
|
+
id?: string | undefined;
|
|
32
|
+
invalid?: boolean | undefined;
|
|
33
|
+
disabled?: boolean | undefined;
|
|
34
|
+
required?: boolean | undefined;
|
|
35
|
+
accessibilityLabel?: string | undefined;
|
|
36
|
+
}
|
|
37
|
+
/** Lo que un control necesita para enlazarse con su `FormField`, en web y en nativo. */
|
|
38
|
+
export interface FormFieldControl {
|
|
39
|
+
/** `id` del control (web): el propio o el que espera la etiqueta del campo. */
|
|
40
|
+
id: string | undefined;
|
|
41
|
+
/** Ids de la ayuda y el error para `aria-describedby` (web). */
|
|
42
|
+
describedBy: string | undefined;
|
|
43
|
+
/** Nombre accesible (nativo): el propio o la etiqueta del campo. */
|
|
44
|
+
accessibilityLabel: string | undefined;
|
|
45
|
+
/** El error y la ayuda, uno tras otro, para `accessibilityHint` (nativo). */
|
|
46
|
+
accessibilityHint: string | undefined;
|
|
47
|
+
invalid: boolean;
|
|
48
|
+
disabled: boolean;
|
|
49
|
+
required: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Combina las props de un control con las de su `FormField`. Las del control
|
|
53
|
+
* mandan en `id` y nombre accesible; `invalid`, `disabled` y `required` se suman:
|
|
54
|
+
* basta con que lo diga uno de los dos.
|
|
55
|
+
*/
|
|
56
|
+
export declare function resolveFormFieldControl(field: FormFieldValue | null, { id, invalid, disabled, required, accessibilityLabel }?: FormFieldControlOptions): FormFieldControl;
|
|
57
|
+
/** Enlaza un control con el `FormField` que lo contiene, si lo hay. */
|
|
58
|
+
export declare function useFormFieldControl(options?: FormFieldControlOptions): FormFieldControl;
|
|
59
|
+
//#endregion
|
|
3
60
|
//#region src/hooks/use-button.d.ts
|
|
4
61
|
export interface UseButtonOptions {
|
|
5
62
|
disabled?: boolean | undefined;
|
|
@@ -21,6 +78,127 @@ export interface UseButtonResult {
|
|
|
21
78
|
*/
|
|
22
79
|
export declare function useButton({ disabled, loading, onPress }: UseButtonOptions): UseButtonResult;
|
|
23
80
|
//#endregion
|
|
81
|
+
//#region src/hooks/use-controllable-state.d.ts
|
|
82
|
+
export interface UseControllableStateOptions<T> {
|
|
83
|
+
/** Valor controlado por la app. Si existe, manda sobre el estado interno. */
|
|
84
|
+
value?: T | undefined;
|
|
85
|
+
/** Valor inicial cuando el componente guarda su propio estado. */
|
|
86
|
+
defaultValue: T;
|
|
87
|
+
/** Se llama con el valor nuevo cuando cambia, en los dos modos. */
|
|
88
|
+
onChange?: ((value: T) => void) | undefined;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Estado controlado o no, a elección de la app (ADR-037). Con `value`, el componente
|
|
92
|
+
* solo avisa del cambio y espera a que la app le pase el valor nuevo; sin él, guarda
|
|
93
|
+
* el estado a partir de `defaultValue`. No avisa si el valor no cambia.
|
|
94
|
+
*/
|
|
95
|
+
export declare function useControllableState<T>({ value, defaultValue, onChange }: UseControllableStateOptions<T>): [T, (next: T) => void];
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/types/text.d.ts
|
|
98
|
+
export declare const textVariants: readonly ["hero", "display", "title", "heading", "subheading", "body", "bodySmall", "label", "caption", "code"];
|
|
99
|
+
export type TextVariant = (typeof textVariants)[number];
|
|
100
|
+
export type TextColorToken = keyof Theme['color']['text'];
|
|
101
|
+
export declare const textColors: TextColorToken[];
|
|
102
|
+
export declare const textAligns: readonly ["left", "center", "right"];
|
|
103
|
+
export type TextAlign = (typeof textAligns)[number];
|
|
104
|
+
/** Tokens que componen una variante tipográfica; ambas vistas los leen del tema. */
|
|
105
|
+
export interface TextVariantStyle {
|
|
106
|
+
family: keyof Theme['font']['family'];
|
|
107
|
+
/** Tamaño; `font.lineHeight` comparte las mismas claves (lo comprueba el typecheck de las vistas). */
|
|
108
|
+
size: keyof Theme['font']['size'];
|
|
109
|
+
weight: keyof Theme['font']['weight'];
|
|
110
|
+
uppercase?: boolean;
|
|
111
|
+
/** Espaciado entre letras en px. */
|
|
112
|
+
letterSpacing?: number;
|
|
113
|
+
/** Nivel de encabezado semántico (h1–h4) si la variante es un título. */
|
|
114
|
+
headingLevel?: 1 | 2 | 3 | 4;
|
|
115
|
+
}
|
|
116
|
+
/** Escala tipográfica de Satella: Unbounded para titulares, Hanken Grotesk para texto, IBM Plex Mono para etiquetas. */
|
|
117
|
+
export declare const textVariantStyles: Readonly<Record<TextVariant, TextVariantStyle>>;
|
|
118
|
+
export interface TextProps {
|
|
119
|
+
variant?: TextVariant | undefined;
|
|
120
|
+
color?: TextColorToken | undefined;
|
|
121
|
+
align?: TextAlign | undefined;
|
|
122
|
+
/** Una sola línea con puntos suspensivos. */
|
|
123
|
+
truncate?: boolean | undefined;
|
|
124
|
+
testID?: string | undefined;
|
|
125
|
+
children?: ReactNode;
|
|
126
|
+
}
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/types/link.d.ts
|
|
129
|
+
/**
|
|
130
|
+
* Cuándo se subraya un `Link` (ADR-009). `always` es lo correcto dentro de un párrafo:
|
|
131
|
+
* el color solo no basta para distinguir un enlace. `hover` lo subraya al pasar el
|
|
132
|
+
* puntero o enfocarlo en web, y mientras se pulsa en nativo.
|
|
133
|
+
*/
|
|
134
|
+
export declare const linkUnderlines: readonly ["always", "hover"];
|
|
135
|
+
export type LinkUnderline = (typeof linkUnderlines)[number];
|
|
136
|
+
/** Lo que recibe `onPress` de un `Link`: permite cancelar la navegación por defecto. */
|
|
137
|
+
export interface LinkPressEvent {
|
|
138
|
+
/** Cancela la navegación por defecto, por ejemplo para hacerla con el router de la app. */
|
|
139
|
+
preventDefault: () => void;
|
|
140
|
+
readonly defaultPrevented: boolean;
|
|
141
|
+
}
|
|
142
|
+
export interface LinkProps {
|
|
143
|
+
/** Destino. En web es el `href` del `<a>`; en nativo se abre con `Linking`. */
|
|
144
|
+
href: string;
|
|
145
|
+
/**
|
|
146
|
+
* Tipografía, con las mismas variantes que `Text`. Sin ella hereda la del texto
|
|
147
|
+
* que lo contiene; fuera de un `Text`, usa `body`.
|
|
148
|
+
*/
|
|
149
|
+
variant?: TextVariant | undefined;
|
|
150
|
+
/** Color del texto (por defecto `link`). */
|
|
151
|
+
color?: TextColorToken | undefined;
|
|
152
|
+
underline?: LinkUnderline | undefined;
|
|
153
|
+
/**
|
|
154
|
+
* Se llama antes de navegar. Con `event.preventDefault()` la librería no navega y
|
|
155
|
+
* la app decide qué hacer. En web no se llama si el clic lleva un modificador
|
|
156
|
+
* (Ctrl, Cmd, Mayús, Alt) o no es del botón principal: ahí manda el navegador.
|
|
157
|
+
*/
|
|
158
|
+
onPress?: ((event: LinkPressEvent) => void) | undefined;
|
|
159
|
+
/** Nombre accesible cuando el texto visible no basta para describir el destino. */
|
|
160
|
+
accessibilityLabel?: string | undefined;
|
|
161
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
162
|
+
testID?: string | undefined;
|
|
163
|
+
children: ReactNode;
|
|
164
|
+
}
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region src/hooks/use-link.d.ts
|
|
167
|
+
export interface UseLinkOptions {
|
|
168
|
+
onPress?: ((event: LinkPressEvent) => void) | undefined;
|
|
169
|
+
}
|
|
170
|
+
export interface UseLinkResult {
|
|
171
|
+
/**
|
|
172
|
+
* Llama a `onPress` y devuelve `true` si la navegación por defecto debe seguir,
|
|
173
|
+
* es decir, si nadie llamó a `preventDefault()`.
|
|
174
|
+
*/
|
|
175
|
+
press: () => boolean;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Comportamiento de `Link` común a web y nativo: `onPress` se llama antes de navegar
|
|
179
|
+
* y puede cancelar la navegación por defecto. Cada vista aporta esa navegación
|
|
180
|
+
* (el `<a>` en web, `Linking` en nativo).
|
|
181
|
+
*/
|
|
182
|
+
export declare function useLink({ onPress }: UseLinkOptions): UseLinkResult;
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/tabs/navigation.d.ts
|
|
185
|
+
/** Lo mínimo que hace falta saber de una pestaña para moverse entre ellas. */
|
|
186
|
+
export interface NavigableTab {
|
|
187
|
+
value: string;
|
|
188
|
+
disabled?: boolean | undefined;
|
|
189
|
+
}
|
|
190
|
+
/** Hacia dónde mueve el foco una tecla: flechas, Inicio y Fin. */
|
|
191
|
+
export declare const tabDirections: readonly ["next", "previous", "first", "last"];
|
|
192
|
+
export type TabDirection = (typeof tabDirections)[number];
|
|
193
|
+
/** La primera pestaña habilitada: la elegida por defecto. `undefined` si no hay ninguna. */
|
|
194
|
+
export declare function firstEnabledTab(items: readonly NavigableTab[]): string | undefined;
|
|
195
|
+
/**
|
|
196
|
+
* La pestaña a la que lleva una tecla desde la actual, saltando las deshabilitadas.
|
|
197
|
+
* `next` y `previous` dan la vuelta al llegar al final. Si no hay otra a la que ir,
|
|
198
|
+
* devuelve la actual.
|
|
199
|
+
*/
|
|
200
|
+
export declare function getTabInDirection(items: readonly NavigableTab[], current: string, direction: TabDirection): string;
|
|
201
|
+
//#endregion
|
|
24
202
|
//#region src/types/ui-provider.d.ts
|
|
25
203
|
/** Modo de tema que acepta `UIProvider` (ADR-010). */
|
|
26
204
|
export declare const themeModes: readonly ["light", "dark", "system"];
|
|
@@ -59,6 +237,121 @@ export declare function mergeTheme(base: Theme, overrides: ThemeOverrides): Them
|
|
|
59
237
|
export declare function resolveTheme(scheme: ThemeName, brand?: BrandName): Theme;
|
|
60
238
|
export declare function resolveColorScheme(mode: ThemeMode, systemScheme: ColorScheme): ColorScheme;
|
|
61
239
|
//#endregion
|
|
240
|
+
//#region src/types/feedback.d.ts
|
|
241
|
+
/**
|
|
242
|
+
* Los cuatro significados de `color.feedback` en los tokens: éxito, aviso, error e
|
|
243
|
+
* información. Los comparten los componentes que comunican un estado.
|
|
244
|
+
*/
|
|
245
|
+
export declare const feedbackTones: readonly ["success", "warning", "danger", "info"];
|
|
246
|
+
export type FeedbackTone = (typeof feedbackTones)[number];
|
|
247
|
+
export declare function isFeedbackTone(value: string): value is FeedbackTone;
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region src/types/toast.d.ts
|
|
250
|
+
/** Acción opcional de un toast, por ejemplo "Deshacer". */
|
|
251
|
+
export interface ToastAction {
|
|
252
|
+
label: string;
|
|
253
|
+
onPress: () => void;
|
|
254
|
+
}
|
|
255
|
+
/** Lo que recibe `show()` de `useToast` (ADR-039). */
|
|
256
|
+
export interface ToastOptions {
|
|
257
|
+
/** Qué comunica (por defecto `info`). Fija el icono y la urgencia con que se anuncia. */
|
|
258
|
+
tone?: FeedbackTone | undefined;
|
|
259
|
+
/** El mensaje, en una línea. */
|
|
260
|
+
title: string;
|
|
261
|
+
/** Detalle opcional. */
|
|
262
|
+
description?: string | undefined;
|
|
263
|
+
/**
|
|
264
|
+
* Milisegundos hasta que se cierra solo (por defecto 5000). Con `0` no se cierra
|
|
265
|
+
* solo: necesita `closeLabel`, una `action` o una llamada a `dismiss`.
|
|
266
|
+
*/
|
|
267
|
+
duration?: number | undefined;
|
|
268
|
+
/** Botón de acción. Al pulsarlo se llama a `onPress` y el toast se cierra. */
|
|
269
|
+
action?: ToastAction | undefined;
|
|
270
|
+
/**
|
|
271
|
+
* Si existe, el toast muestra un botón de cierre con este nombre accesible
|
|
272
|
+
* ("Cerrar aviso"). La librería no trae textos propios.
|
|
273
|
+
*/
|
|
274
|
+
closeLabel?: string | undefined;
|
|
275
|
+
}
|
|
276
|
+
/** Un toast ya en la cola: sus opciones resueltas y su identificador. */
|
|
277
|
+
export interface ToastItem {
|
|
278
|
+
id: string;
|
|
279
|
+
tone: FeedbackTone;
|
|
280
|
+
title: string;
|
|
281
|
+
description: string | undefined;
|
|
282
|
+
duration: number;
|
|
283
|
+
action: ToastAction | undefined;
|
|
284
|
+
closeLabel: string | undefined;
|
|
285
|
+
}
|
|
286
|
+
/** Lo que devuelve `useToast`. */
|
|
287
|
+
export interface ToastApi {
|
|
288
|
+
/** Muestra un toast y devuelve su `id`. */
|
|
289
|
+
show: (options: ToastOptions) => string;
|
|
290
|
+
/** Cierra el toast con ese `id`; sin `id`, los cierra todos. */
|
|
291
|
+
dismiss: (id?: string) => void;
|
|
292
|
+
}
|
|
293
|
+
//#endregion
|
|
294
|
+
//#region src/toast/store.d.ts
|
|
295
|
+
/** Milisegundos que un toast permanece visible si no se indica otra cosa. */
|
|
296
|
+
export declare const TOAST_DEFAULT_DURATION = 5000;
|
|
297
|
+
/** Toasts visibles a la vez. Al llegar uno más, se retira el más antiguo. */
|
|
298
|
+
export declare const TOAST_MAX_VISIBLE = 3;
|
|
299
|
+
interface ToastStore extends ToastApi {
|
|
300
|
+
/** Para `useSyncExternalStore`: avisa de cada cambio y devuelve cómo dejar de escuchar. */
|
|
301
|
+
subscribe: (listener: () => void) => () => void;
|
|
302
|
+
/** Los toasts visibles, del más antiguo al más reciente. Cambia de identidad con cada cambio. */
|
|
303
|
+
getSnapshot: () => readonly ToastItem[];
|
|
304
|
+
/** Detiene el cierre automático, por ejemplo mientras el puntero está sobre los toasts. */
|
|
305
|
+
pause: () => void;
|
|
306
|
+
/** Reanuda el cierre automático con el tiempo que le quedaba a cada toast. */
|
|
307
|
+
resume: () => void;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* La cola de toasts de un `UIProvider` (ADR-039): alta, baja, cierre automático, pausa
|
|
311
|
+
* y límite de visibles. No depende de React ni de la plataforma.
|
|
312
|
+
*/
|
|
313
|
+
export declare function createToastStore(): ToastStore;
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/toast/context.d.ts
|
|
316
|
+
/** La cola de toasts del `UIProvider` más cercano; `null` fuera de uno. */
|
|
317
|
+
export declare const ToastContext: import("react").Context<ToastStore | null>;
|
|
318
|
+
/**
|
|
319
|
+
* Muestra y cierra toasts (ADR-039). Necesita un `UIProvider` por encima: es él quien
|
|
320
|
+
* guarda la cola y los pinta.
|
|
321
|
+
*/
|
|
322
|
+
export declare function useToast(): ToastApi;
|
|
323
|
+
//#endregion
|
|
324
|
+
//#region src/types/alert.d.ts
|
|
325
|
+
interface AlertBaseProps {
|
|
326
|
+
/** Qué comunica (por defecto `info`). Fija el color y el icono. */
|
|
327
|
+
tone?: FeedbackTone | undefined;
|
|
328
|
+
/** Resumen en una línea. */
|
|
329
|
+
title?: string | undefined;
|
|
330
|
+
/** Explicación o siguiente paso. */
|
|
331
|
+
children?: ReactNode;
|
|
332
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
333
|
+
testID?: string | undefined;
|
|
334
|
+
}
|
|
335
|
+
interface AlertStaticProps extends AlertBaseProps {
|
|
336
|
+
onClose?: undefined;
|
|
337
|
+
closeLabel?: undefined;
|
|
338
|
+
}
|
|
339
|
+
interface AlertClosableProps extends AlertBaseProps {
|
|
340
|
+
/** Si existe, el aviso muestra un botón para cerrarlo y la llama al pulsarlo. */
|
|
341
|
+
onClose: () => void;
|
|
342
|
+
/**
|
|
343
|
+
* Nombre accesible del botón de cierre ("Cerrar aviso"). Es obligatorio con
|
|
344
|
+
* `onClose`: la librería no trae textos propios.
|
|
345
|
+
*/
|
|
346
|
+
closeLabel: string;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Contrato de `Alert`: un mensaje dentro de la página que no desaparece solo. `danger`
|
|
350
|
+
* y `warning` se anuncian de inmediato a los lectores de pantalla; `success` e `info`,
|
|
351
|
+
* cuando terminan lo que estén leyendo.
|
|
352
|
+
*/
|
|
353
|
+
export type AlertProps = AlertStaticProps | AlertClosableProps;
|
|
354
|
+
//#endregion
|
|
62
355
|
//#region src/types/badge.d.ts
|
|
63
356
|
/**
|
|
64
357
|
* Variantes de `Badge` (ADR-009): una por cada color de `color.feedback`. Las historias
|
|
@@ -146,46 +439,123 @@ export interface ButtonProps<IconName extends string = string> {
|
|
|
146
439
|
children: ReactNode;
|
|
147
440
|
}
|
|
148
441
|
//#endregion
|
|
149
|
-
//#region src/types/
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
export declare const
|
|
155
|
-
export type
|
|
156
|
-
/**
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
442
|
+
//#region src/types/card.d.ts
|
|
443
|
+
/**
|
|
444
|
+
* Variantes de `Card` (ADR-009): `outlined` se apoya en el borde; `elevated` añade
|
|
445
|
+
* sombra para separarse de lo que tiene debajo.
|
|
446
|
+
*/
|
|
447
|
+
export declare const cardVariants: readonly ["outlined", "elevated"];
|
|
448
|
+
export type CardVariant = (typeof cardVariants)[number];
|
|
449
|
+
/**
|
|
450
|
+
* Contrato de `Card`: una superficie que agrupa contenido relacionado. Con `onPress`
|
|
451
|
+
* toda la tarjeta es pulsable; en ese caso no debe contener otros controles.
|
|
452
|
+
*/
|
|
453
|
+
export interface CardProps {
|
|
454
|
+
variant?: CardVariant | undefined;
|
|
455
|
+
/** Relleno interior (por defecto 4). Con `0`, el contenido llega hasta el borde, por ejemplo una imagen. */
|
|
456
|
+
padding?: SpaceToken | undefined;
|
|
457
|
+
/** Hace pulsable toda la tarjeta, con ratón, teclado o toque. */
|
|
458
|
+
onPress?: (() => void) | undefined;
|
|
459
|
+
/**
|
|
460
|
+
* Nombre accesible de una tarjeta pulsable. Sin él, es su contenido, que suele ser lo
|
|
461
|
+
* correcto. Si se indica, tiene que incluir el texto visible: quien navega por voz
|
|
462
|
+
* dice lo que ve.
|
|
463
|
+
*/
|
|
464
|
+
accessibilityLabel?: string | undefined;
|
|
465
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
466
|
+
testID?: string | undefined;
|
|
467
|
+
children?: ReactNode;
|
|
167
468
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
|
|
469
|
+
//#endregion
|
|
470
|
+
//#region src/types/checkbox.d.ts
|
|
471
|
+
/** Contrato de `Checkbox`: una opción que se marca o no, con su etiqueta como `children`. */
|
|
472
|
+
export interface CheckboxProps {
|
|
473
|
+
/** Estado controlado por la app. Sin él, guarda su propio estado (ADR-037). */
|
|
474
|
+
checked?: boolean | undefined;
|
|
475
|
+
/** Estado inicial cuando guarda su propio estado. */
|
|
476
|
+
defaultChecked?: boolean | undefined;
|
|
477
|
+
/**
|
|
478
|
+
* Ni marcado ni sin marcar: representa a un grupo donde solo algunas opciones lo
|
|
479
|
+
* están. Es solo visual; al pulsarlo pasa a marcado o sin marcar según `checked`.
|
|
480
|
+
*/
|
|
481
|
+
indeterminate?: boolean | undefined;
|
|
482
|
+
/** Se llama con el estado nuevo al pulsarlo. */
|
|
483
|
+
onCheckedChange?: ((checked: boolean) => void) | undefined;
|
|
484
|
+
/** No se puede pulsar ni enfocar. */
|
|
485
|
+
disabled?: boolean | undefined;
|
|
486
|
+
/** El estado no es válido, por ejemplo unas condiciones sin aceptar. */
|
|
487
|
+
invalid?: boolean | undefined;
|
|
488
|
+
required?: boolean | undefined;
|
|
489
|
+
/** Nombre accesible cuando no hay etiqueta visible. */
|
|
490
|
+
accessibilityLabel?: string | undefined;
|
|
491
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
176
492
|
testID?: string | undefined;
|
|
493
|
+
/** Etiqueta. Pulsarla también marca la casilla. */
|
|
177
494
|
children?: ReactNode;
|
|
178
495
|
}
|
|
179
496
|
//#endregion
|
|
497
|
+
//#region src/types/control.d.ts
|
|
498
|
+
/**
|
|
499
|
+
* Alturas de los controles interactivos de una línea (`Input`, `Select`). Coinciden
|
|
500
|
+
* con `size.control` de los tokens y con los tamaños de `Button`, para que un campo y
|
|
501
|
+
* un botón del mismo tamaño queden alineados en una fila.
|
|
502
|
+
*/
|
|
503
|
+
export declare const controlSizes: readonly ["sm", "md", "lg"];
|
|
504
|
+
export type ControlSize = (typeof controlSizes)[number];
|
|
505
|
+
//#endregion
|
|
506
|
+
//#region src/types/divider.d.ts
|
|
507
|
+
/** Orientación de `Divider` (ADR-009). */
|
|
508
|
+
export declare const dividerOrientations: readonly ["horizontal", "vertical"];
|
|
509
|
+
export type DividerOrientation = (typeof dividerOrientations)[number];
|
|
510
|
+
/** Contrato de `Divider`: una línea fina que separa dos bloques de contenido. */
|
|
511
|
+
export interface DividerProps {
|
|
512
|
+
/**
|
|
513
|
+
* `horizontal` (por defecto) separa bloques apilados. `vertical` separa elementos de
|
|
514
|
+
* una fila y ocupa su altura.
|
|
515
|
+
*/
|
|
516
|
+
orientation?: DividerOrientation | undefined;
|
|
517
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
518
|
+
testID?: string | undefined;
|
|
519
|
+
}
|
|
520
|
+
//#endregion
|
|
521
|
+
//#region src/types/form-field.d.ts
|
|
522
|
+
/**
|
|
523
|
+
* Contrato de `FormField`: la etiqueta, la ayuda y el error de un control, enlazados
|
|
524
|
+
* con él para los lectores de pantalla (ADR-037). Envuelve un `Input`, un `TextArea`
|
|
525
|
+
* o un `Select`.
|
|
526
|
+
*/
|
|
527
|
+
export interface FormFieldProps {
|
|
528
|
+
/** Etiqueta visible. Es texto porque en nativo hace de nombre accesible del control. */
|
|
529
|
+
label: string;
|
|
530
|
+
/** Ayuda bajo el control: formato esperado, para qué se usa el dato. */
|
|
531
|
+
help?: string | undefined;
|
|
532
|
+
/** Mensaje de error. Si existe, el control se marca como inválido. */
|
|
533
|
+
error?: string | undefined;
|
|
534
|
+
/** Marca la etiqueta como obligatoria y lo comunica al control. */
|
|
535
|
+
required?: boolean | undefined;
|
|
536
|
+
/** Deshabilita el control. */
|
|
537
|
+
disabled?: boolean | undefined;
|
|
538
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
539
|
+
testID?: string | undefined;
|
|
540
|
+
/** El control. */
|
|
541
|
+
children: ReactNode;
|
|
542
|
+
}
|
|
543
|
+
//#endregion
|
|
180
544
|
//#region src/types/icon.d.ts
|
|
181
|
-
export declare const iconSizes: readonly ["sm", "md", "lg"];
|
|
545
|
+
export declare const iconSizes: readonly ["sm", "md", "lg", "xl"];
|
|
182
546
|
export type IconSize = (typeof iconSizes)[number];
|
|
183
547
|
/** Tamaño en px/puntos de cada icono. */
|
|
184
548
|
export declare const iconSizePx: {
|
|
185
549
|
sm: number;
|
|
186
550
|
md: number;
|
|
187
551
|
lg: number;
|
|
552
|
+
xl: number;
|
|
188
553
|
};
|
|
554
|
+
/**
|
|
555
|
+
* Color de un icono: un color de texto o el de un estado de feedback (`success`,
|
|
556
|
+
* `warning`, `danger`, `info`), que usa el token `color.feedback.<estado>.icon`.
|
|
557
|
+
*/
|
|
558
|
+
export type IconColor = TextColorToken | FeedbackTone;
|
|
189
559
|
/**
|
|
190
560
|
* Contrato de `Icon`. El conjunto de nombres lo aporta `@satellatickets/icons`,
|
|
191
561
|
* que está fuera de `core` (ADR-002), por eso el nombre es un parámetro de tipo.
|
|
@@ -193,24 +563,214 @@ export declare const iconSizePx: {
|
|
|
193
563
|
export interface IconProps<Name extends string = string> {
|
|
194
564
|
name: Name;
|
|
195
565
|
size?: IconSize | undefined;
|
|
196
|
-
color?:
|
|
566
|
+
color?: IconColor | undefined;
|
|
197
567
|
/** Texto alternativo. Sin él, el icono es decorativo y se oculta a los lectores de pantalla. */
|
|
198
568
|
label?: string | undefined;
|
|
199
569
|
testID?: string | undefined;
|
|
200
570
|
}
|
|
201
571
|
//#endregion
|
|
572
|
+
//#region src/types/icon-button.d.ts
|
|
573
|
+
/**
|
|
574
|
+
* Tamaño del icono para cada tamaño de `IconButton`. Es un paso mayor que en
|
|
575
|
+
* `Button`, porque aquí el icono es todo el contenido.
|
|
576
|
+
*/
|
|
577
|
+
export declare const iconButtonIconSize: {
|
|
578
|
+
readonly sm: "sm";
|
|
579
|
+
readonly md: "md";
|
|
580
|
+
readonly lg: "lg";
|
|
581
|
+
};
|
|
582
|
+
/**
|
|
583
|
+
* Contrato de `IconButton`: un `Button` cuadrado cuyo único contenido es un icono.
|
|
584
|
+
* Comparte variantes y tamaños con `Button` (`buttonVariants`). El conjunto de iconos
|
|
585
|
+
* lo aporta `@satellatickets/icons`, que está fuera de `core` (ADR-002), por eso el
|
|
586
|
+
* nombre es un parámetro de tipo.
|
|
587
|
+
*/
|
|
588
|
+
export interface IconButtonProps<IconName extends string = string> {
|
|
589
|
+
icon: IconName;
|
|
590
|
+
/**
|
|
591
|
+
* Nombre accesible. Es obligatorio porque no hay texto visible: describe la
|
|
592
|
+
* acción ("Cerrar"), no el dibujo ("Aspa").
|
|
593
|
+
*/
|
|
594
|
+
label: string;
|
|
595
|
+
/** Jerarquía visual de la acción (por defecto `ghost`). */
|
|
596
|
+
variant?: ButtonVariant | undefined;
|
|
597
|
+
size?: ButtonSize | undefined;
|
|
598
|
+
/** No se puede pulsar ni enfocar. */
|
|
599
|
+
disabled?: boolean | undefined;
|
|
600
|
+
/** Acción en curso: sustituye el icono por un spinner y no dispara `onPress`, pero conserva el foco. */
|
|
601
|
+
loading?: boolean | undefined;
|
|
602
|
+
/** Se pulsa con ratón, teclado o toque. Nombre neutral: la vista web lo mapea a `click`. */
|
|
603
|
+
onPress?: (() => void) | undefined;
|
|
604
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
605
|
+
testID?: string | undefined;
|
|
606
|
+
}
|
|
607
|
+
//#endregion
|
|
608
|
+
//#region src/types/input.d.ts
|
|
609
|
+
/**
|
|
610
|
+
* Qué se escribe en un `Input` (ADR-009). Cada vista lo traduce a su plataforma:
|
|
611
|
+
* el atributo `type` y el teclado en web, y el teclado, las mayúsculas automáticas
|
|
612
|
+
* y el autocompletado en nativo.
|
|
613
|
+
*/
|
|
614
|
+
export declare const inputTypes: readonly ["text", "email", "password", "search", "tel", "url", "number"];
|
|
615
|
+
export type InputType = (typeof inputTypes)[number];
|
|
616
|
+
/** Tamaño de los iconos de un `Input` para cada tamaño de campo. */
|
|
617
|
+
export declare const inputIconSize: {
|
|
618
|
+
readonly sm: "sm";
|
|
619
|
+
readonly md: "md";
|
|
620
|
+
readonly lg: "md";
|
|
621
|
+
};
|
|
622
|
+
/**
|
|
623
|
+
* Contrato de `Input`: un campo de texto de una línea. El conjunto de iconos lo aporta
|
|
624
|
+
* `@satellatickets/icons`, que está fuera de `core` (ADR-002), por eso el nombre es
|
|
625
|
+
* un parámetro de tipo.
|
|
626
|
+
*/
|
|
627
|
+
export interface InputProps<IconName extends string = string> {
|
|
628
|
+
/** Texto controlado por la app. Sin él, el campo guarda su propio estado (ADR-037). */
|
|
629
|
+
value?: string | undefined;
|
|
630
|
+
/** Texto inicial cuando el campo guarda su propio estado. */
|
|
631
|
+
defaultValue?: string | undefined;
|
|
632
|
+
/** Se llama con el texto nuevo en cada cambio. */
|
|
633
|
+
onChangeText?: ((text: string) => void) | undefined;
|
|
634
|
+
placeholder?: string | undefined;
|
|
635
|
+
/** Qué se escribe (por defecto `text`). */
|
|
636
|
+
type?: InputType | undefined;
|
|
637
|
+
size?: ControlSize | undefined;
|
|
638
|
+
/** No se puede editar ni enfocar. */
|
|
639
|
+
disabled?: boolean | undefined;
|
|
640
|
+
/** Se puede enfocar y copiar, pero no editar. */
|
|
641
|
+
readOnly?: boolean | undefined;
|
|
642
|
+
/** El valor no es válido. Dentro de un `FormField` con `error` se activa solo. */
|
|
643
|
+
invalid?: boolean | undefined;
|
|
644
|
+
required?: boolean | undefined;
|
|
645
|
+
/** Icono decorativo delante del texto. */
|
|
646
|
+
iconStart?: IconName | undefined;
|
|
647
|
+
/** Icono decorativo detrás del texto. */
|
|
648
|
+
iconEnd?: IconName | undefined;
|
|
649
|
+
maxLength?: number | undefined;
|
|
650
|
+
onFocus?: (() => void) | undefined;
|
|
651
|
+
onBlur?: (() => void) | undefined;
|
|
652
|
+
/** Se pulsa Intro, o la tecla de envío del teclado en pantalla. */
|
|
653
|
+
onSubmit?: (() => void) | undefined;
|
|
654
|
+
/** Nombre accesible cuando no hay un `FormField` que lo etiquete. */
|
|
655
|
+
accessibilityLabel?: string | undefined;
|
|
656
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
657
|
+
testID?: string | undefined;
|
|
658
|
+
}
|
|
659
|
+
//#endregion
|
|
660
|
+
//#region src/types/modal.d.ts
|
|
661
|
+
/**
|
|
662
|
+
* Contrato de `Modal` y de `Sheet` (ADR-040): un diálogo que interrumpe lo que hay
|
|
663
|
+
* debajo. `Modal` se centra; `Sheet` se ancla al borde inferior.
|
|
664
|
+
*/
|
|
665
|
+
export interface ModalProps {
|
|
666
|
+
/** Si está abierto. Lo decide la app. */
|
|
667
|
+
open: boolean;
|
|
668
|
+
/**
|
|
669
|
+
* El diálogo pide cerrarse: Escape, pulsar fuera, el botón atrás de Android o su
|
|
670
|
+
* botón de cierre. La app responde poniendo `open` a `false`.
|
|
671
|
+
*/
|
|
672
|
+
onClose: () => void;
|
|
673
|
+
/** Título visible. Es también su nombre accesible. */
|
|
674
|
+
title: string;
|
|
675
|
+
/** Texto bajo el título. Los lectores de pantalla lo leen al abrirse. */
|
|
676
|
+
description?: string | undefined;
|
|
677
|
+
/**
|
|
678
|
+
* Si existe, muestra un botón de cierre con este nombre accesible ("Cerrar"). La
|
|
679
|
+
* librería no trae textos propios.
|
|
680
|
+
*/
|
|
681
|
+
closeLabel?: string | undefined;
|
|
682
|
+
/**
|
|
683
|
+
* Con `false`, ni Escape, ni pulsar fuera, ni el botón atrás lo cierran: es para una
|
|
684
|
+
* pregunta que exige respuesta. Por defecto `true`.
|
|
685
|
+
*/
|
|
686
|
+
dismissible?: boolean | undefined;
|
|
687
|
+
/** Acciones al pie, normalmente botones. */
|
|
688
|
+
footer?: ReactNode;
|
|
689
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
690
|
+
testID?: string | undefined;
|
|
691
|
+
children?: ReactNode;
|
|
692
|
+
}
|
|
693
|
+
/** `Sheet` tiene el mismo contrato que `Modal`: solo cambia dónde se coloca. */
|
|
694
|
+
export type SheetProps = ModalProps;
|
|
695
|
+
/** Las dos presentaciones de un diálogo. */
|
|
696
|
+
export declare const modalPresentations: readonly ["dialog", "sheet"];
|
|
697
|
+
export type ModalPresentation = (typeof modalPresentations)[number];
|
|
698
|
+
//#endregion
|
|
699
|
+
//#region src/types/select.d.ts
|
|
700
|
+
/** Una opción de `Select`. */
|
|
701
|
+
export interface SelectOption {
|
|
702
|
+
/** Lo que recibe `onValueChange`. No puede ser una cadena vacía: eso es "sin elegir". */
|
|
703
|
+
value: string;
|
|
704
|
+
/** Lo que se muestra. */
|
|
705
|
+
label: string;
|
|
706
|
+
disabled?: boolean | undefined;
|
|
707
|
+
}
|
|
708
|
+
/** Contrato de `Select`: elegir una opción de una lista (ADR-038). */
|
|
709
|
+
export interface SelectProps {
|
|
710
|
+
options: readonly SelectOption[];
|
|
711
|
+
/** Opción elegida, controlada por la app. Sin ella, guarda su propio estado (ADR-037). */
|
|
712
|
+
value?: string | undefined;
|
|
713
|
+
/** Opción inicial cuando guarda su propio estado. */
|
|
714
|
+
defaultValue?: string | undefined;
|
|
715
|
+
/** Se llama con el `value` de la opción elegida. */
|
|
716
|
+
onValueChange?: ((value: string) => void) | undefined;
|
|
717
|
+
/** Texto que se muestra mientras no hay ninguna opción elegida. */
|
|
718
|
+
placeholder?: string | undefined;
|
|
719
|
+
size?: ControlSize | undefined;
|
|
720
|
+
/** No se puede abrir ni enfocar. */
|
|
721
|
+
disabled?: boolean | undefined;
|
|
722
|
+
/** El valor no es válido. Dentro de un `FormField` con `error` se activa solo. */
|
|
723
|
+
invalid?: boolean | undefined;
|
|
724
|
+
required?: boolean | undefined;
|
|
725
|
+
/** Nombre accesible cuando no hay un `FormField` que lo etiquete. */
|
|
726
|
+
accessibilityLabel?: string | undefined;
|
|
727
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
728
|
+
testID?: string | undefined;
|
|
729
|
+
}
|
|
730
|
+
//#endregion
|
|
731
|
+
//#region src/types/skeleton.d.ts
|
|
732
|
+
/**
|
|
733
|
+
* Formas de `Skeleton` (ADR-009): `text` ocupa el hueco de una línea de `Text`,
|
|
734
|
+
* `rectangle` el de una imagen o un control, y `circle` el de un avatar.
|
|
735
|
+
*/
|
|
736
|
+
export declare const skeletonShapes: readonly ["text", "rectangle", "circle"];
|
|
737
|
+
export type SkeletonShape = (typeof skeletonShapes)[number];
|
|
738
|
+
/**
|
|
739
|
+
* Contrato de `Skeleton`: el hueco de un contenido que todavía se está cargando. Es
|
|
740
|
+
* decorativo; que la zona está cargando lo comunica quien lo contiene.
|
|
741
|
+
*/
|
|
742
|
+
export interface SkeletonProps {
|
|
743
|
+
/** Forma (por defecto `text`). */
|
|
744
|
+
shape?: SkeletonShape | undefined;
|
|
745
|
+
/**
|
|
746
|
+
* Ancho, en puntos o como porcentaje del contenedor (`'60%'`). Por defecto ocupa
|
|
747
|
+
* todo el ancho; en `circle`, mide lo mismo que de alto.
|
|
748
|
+
*/
|
|
749
|
+
width?: number | `${number}%` | undefined;
|
|
750
|
+
/** Alto en puntos. En `text` no se usa: lo fija `variant`. */
|
|
751
|
+
height?: number | undefined;
|
|
752
|
+
/** Con `text`: la variante de `Text` cuyo hueco ocupa (por defecto `body`). */
|
|
753
|
+
variant?: TextVariant | undefined;
|
|
754
|
+
/** Con `text`: número de líneas (por defecto 1). Si hay varias, la última es más corta. */
|
|
755
|
+
lines?: number | undefined;
|
|
756
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
757
|
+
testID?: string | undefined;
|
|
758
|
+
}
|
|
759
|
+
//#endregion
|
|
202
760
|
//#region src/types/spinner.d.ts
|
|
203
761
|
/**
|
|
204
762
|
* `Spinner` comparte la escala de `Icon`: así puede ocupar el sitio de un icono
|
|
205
763
|
* (por ejemplo, dentro de un botón que carga) sin mover el resto del contenido.
|
|
764
|
+
* `xl` es para la carga de una página o de una sección entera.
|
|
206
765
|
*/
|
|
207
|
-
export declare const spinnerSizes: readonly ["sm", "md", "lg"];
|
|
766
|
+
export declare const spinnerSizes: readonly ["sm", "md", "lg", "xl"];
|
|
208
767
|
export type SpinnerSize = IconSize;
|
|
209
768
|
/** Tamaño en px/puntos de cada spinner. */
|
|
210
769
|
export declare const spinnerSizePx: {
|
|
211
770
|
sm: number;
|
|
212
771
|
md: number;
|
|
213
772
|
lg: number;
|
|
773
|
+
xl: number;
|
|
214
774
|
};
|
|
215
775
|
export interface SpinnerProps {
|
|
216
776
|
size?: SpinnerSize | undefined;
|
|
@@ -239,4 +799,89 @@ export interface StackProps extends BoxProps {
|
|
|
239
799
|
wrap?: boolean | undefined;
|
|
240
800
|
}
|
|
241
801
|
//#endregion
|
|
242
|
-
|
|
802
|
+
//#region src/types/switch.d.ts
|
|
803
|
+
/**
|
|
804
|
+
* Contrato de `Switch`: un ajuste que se activa o desactiva con efecto inmediato.
|
|
805
|
+
* Para una opción que se confirma al enviar un formulario, usa `Checkbox`.
|
|
806
|
+
*/
|
|
807
|
+
export interface SwitchProps {
|
|
808
|
+
/** Estado controlado por la app. Sin él, guarda su propio estado (ADR-037). */
|
|
809
|
+
checked?: boolean | undefined;
|
|
810
|
+
/** Estado inicial cuando guarda su propio estado. */
|
|
811
|
+
defaultChecked?: boolean | undefined;
|
|
812
|
+
/** Se llama con el estado nuevo al pulsarlo. */
|
|
813
|
+
onCheckedChange?: ((checked: boolean) => void) | undefined;
|
|
814
|
+
/** No se puede pulsar ni enfocar. */
|
|
815
|
+
disabled?: boolean | undefined;
|
|
816
|
+
/** Nombre accesible cuando no hay etiqueta visible. */
|
|
817
|
+
accessibilityLabel?: string | undefined;
|
|
818
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
819
|
+
testID?: string | undefined;
|
|
820
|
+
/** Etiqueta. Pulsarla también cambia el interruptor. */
|
|
821
|
+
children?: ReactNode;
|
|
822
|
+
}
|
|
823
|
+
//#endregion
|
|
824
|
+
//#region src/types/tabs.d.ts
|
|
825
|
+
/** Una pestaña de `Tabs`. */
|
|
826
|
+
export interface TabItem<IconName extends string = string> {
|
|
827
|
+
/** Lo que recibe `onValueChange`. */
|
|
828
|
+
value: string;
|
|
829
|
+
/** Texto de la pestaña. */
|
|
830
|
+
label: string;
|
|
831
|
+
/** Icono decorativo delante del texto. */
|
|
832
|
+
icon?: IconName | undefined;
|
|
833
|
+
disabled?: boolean | undefined;
|
|
834
|
+
/**
|
|
835
|
+
* Contenido de su panel. Sin él, `Tabs` solo pinta las pestañas y la app decide qué
|
|
836
|
+
* mostrar con `value`, por ejemplo para filtrar una lista.
|
|
837
|
+
*/
|
|
838
|
+
content?: ReactNode;
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Contrato de `Tabs`: varias vistas del mismo nivel entre las que se cambia sin salir de
|
|
842
|
+
* la página. El conjunto de iconos lo aporta `@satellatickets/icons`, que está fuera de
|
|
843
|
+
* `core` (ADR-002), por eso el nombre es un parámetro de tipo.
|
|
844
|
+
*/
|
|
845
|
+
export interface TabsProps<IconName extends string = string> {
|
|
846
|
+
items: readonly TabItem<IconName>[];
|
|
847
|
+
/** Pestaña elegida, controlada por la app. Sin ella, guarda su propio estado (ADR-037). */
|
|
848
|
+
value?: string | undefined;
|
|
849
|
+
/** Pestaña inicial cuando guarda su propio estado. Por defecto, la primera habilitada. */
|
|
850
|
+
defaultValue?: string | undefined;
|
|
851
|
+
/** Se llama con el `value` de la pestaña elegida. */
|
|
852
|
+
onValueChange?: ((value: string) => void) | undefined;
|
|
853
|
+
/** Nombre accesible del grupo de pestañas ("Mis entradas"). */
|
|
854
|
+
accessibilityLabel?: string | undefined;
|
|
855
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
856
|
+
testID?: string | undefined;
|
|
857
|
+
}
|
|
858
|
+
//#endregion
|
|
859
|
+
//#region src/types/text-area.d.ts
|
|
860
|
+
/** Contrato de `TextArea`: un campo de texto de varias líneas. */
|
|
861
|
+
export interface TextAreaProps {
|
|
862
|
+
/** Texto controlado por la app. Sin él, el campo guarda su propio estado (ADR-037). */
|
|
863
|
+
value?: string | undefined;
|
|
864
|
+
/** Texto inicial cuando el campo guarda su propio estado. */
|
|
865
|
+
defaultValue?: string | undefined;
|
|
866
|
+
/** Se llama con el texto nuevo en cada cambio. */
|
|
867
|
+
onChangeText?: ((text: string) => void) | undefined;
|
|
868
|
+
placeholder?: string | undefined;
|
|
869
|
+
/** Líneas visibles sin desplazarse (por defecto 3). Fija la altura mínima. */
|
|
870
|
+
rows?: number | undefined;
|
|
871
|
+
/** No se puede editar ni enfocar. */
|
|
872
|
+
disabled?: boolean | undefined;
|
|
873
|
+
/** Se puede enfocar y copiar, pero no editar. */
|
|
874
|
+
readOnly?: boolean | undefined;
|
|
875
|
+
/** El valor no es válido. Dentro de un `FormField` con `error` se activa solo. */
|
|
876
|
+
invalid?: boolean | undefined;
|
|
877
|
+
required?: boolean | undefined;
|
|
878
|
+
maxLength?: number | undefined;
|
|
879
|
+
onFocus?: (() => void) | undefined;
|
|
880
|
+
onBlur?: (() => void) | undefined;
|
|
881
|
+
/** Nombre accesible cuando no hay un `FormField` que lo etiquete. */
|
|
882
|
+
accessibilityLabel?: string | undefined;
|
|
883
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
884
|
+
testID?: string | undefined;
|
|
885
|
+
}
|
|
886
|
+
//#endregion
|
|
887
|
+
export type { ToastStore, UIContextValue };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
|
-
import { createContext, useCallback, useContext } from "react";
|
|
1
|
+
import { createContext, useCallback, useContext, useState } from "react";
|
|
2
2
|
import { brands, themes } from "@satellatickets/tokens";
|
|
3
|
+
//#region src/form-field/context.ts
|
|
4
|
+
/** Un texto vacío cuenta como ausente: `error={errores.email}` suele llegar así. */
|
|
5
|
+
function present(text) {
|
|
6
|
+
return text === void 0 || text === "" ? void 0 : text;
|
|
7
|
+
}
|
|
8
|
+
/** Construye el valor del contexto a partir de un id base (el de `useId()`). */
|
|
9
|
+
function createFormFieldValue(baseId, { label, help, error, disabled = false, required = false }) {
|
|
10
|
+
const helpText = present(help);
|
|
11
|
+
const errorText = present(error);
|
|
12
|
+
return {
|
|
13
|
+
controlId: `${baseId}-control`,
|
|
14
|
+
helpId: helpText === void 0 ? void 0 : `${baseId}-help`,
|
|
15
|
+
errorId: errorText === void 0 ? void 0 : `${baseId}-error`,
|
|
16
|
+
label,
|
|
17
|
+
help: helpText,
|
|
18
|
+
error: errorText,
|
|
19
|
+
disabled,
|
|
20
|
+
required
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** `null` fuera de un `FormField`. */
|
|
24
|
+
const FormFieldContext = createContext(null);
|
|
25
|
+
/**
|
|
26
|
+
* Combina las props de un control con las de su `FormField`. Las del control
|
|
27
|
+
* mandan en `id` y nombre accesible; `invalid`, `disabled` y `required` se suman:
|
|
28
|
+
* basta con que lo diga uno de los dos.
|
|
29
|
+
*/
|
|
30
|
+
function resolveFormFieldControl(field, { id, invalid = false, disabled = false, required = false, accessibilityLabel } = {}) {
|
|
31
|
+
if (field === null) return {
|
|
32
|
+
id,
|
|
33
|
+
describedBy: void 0,
|
|
34
|
+
accessibilityLabel,
|
|
35
|
+
accessibilityHint: void 0,
|
|
36
|
+
invalid,
|
|
37
|
+
disabled,
|
|
38
|
+
required
|
|
39
|
+
};
|
|
40
|
+
const describedBy = [field.helpId, field.errorId].filter((part) => part !== void 0).join(" ");
|
|
41
|
+
const hint = [field.error, field.help].filter((part) => part !== void 0).join(" ");
|
|
42
|
+
return {
|
|
43
|
+
id: id ?? field.controlId,
|
|
44
|
+
describedBy: describedBy === "" ? void 0 : describedBy,
|
|
45
|
+
accessibilityLabel: accessibilityLabel ?? field.label,
|
|
46
|
+
accessibilityHint: hint === "" ? void 0 : hint,
|
|
47
|
+
invalid: invalid || field.error !== void 0,
|
|
48
|
+
disabled: disabled || field.disabled,
|
|
49
|
+
required: required || field.required
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** Enlaza un control con el `FormField` que lo contiene, si lo hay. */
|
|
53
|
+
function useFormFieldControl(options) {
|
|
54
|
+
return resolveFormFieldControl(useContext(FormFieldContext), options);
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
3
57
|
//#region src/hooks/use-button.ts
|
|
4
58
|
/**
|
|
5
59
|
* Comportamiento de `Button` común a web y nativo: un botón deshabilitado o que
|
|
@@ -18,6 +72,78 @@ function useButton({ disabled = false, loading = false, onPress }) {
|
|
|
18
72
|
};
|
|
19
73
|
}
|
|
20
74
|
//#endregion
|
|
75
|
+
//#region src/hooks/use-controllable-state.ts
|
|
76
|
+
/**
|
|
77
|
+
* Estado controlado o no, a elección de la app (ADR-037). Con `value`, el componente
|
|
78
|
+
* solo avisa del cambio y espera a que la app le pase el valor nuevo; sin él, guarda
|
|
79
|
+
* el estado a partir de `defaultValue`. No avisa si el valor no cambia.
|
|
80
|
+
*/
|
|
81
|
+
function useControllableState({ value, defaultValue, onChange }) {
|
|
82
|
+
const [internal, setInternal] = useState(defaultValue);
|
|
83
|
+
const controlled = value !== void 0;
|
|
84
|
+
const current = controlled ? value : internal;
|
|
85
|
+
return [current, useCallback((next) => {
|
|
86
|
+
if (Object.is(next, current)) return;
|
|
87
|
+
if (!controlled) setInternal(next);
|
|
88
|
+
onChange?.(next);
|
|
89
|
+
}, [
|
|
90
|
+
controlled,
|
|
91
|
+
current,
|
|
92
|
+
onChange
|
|
93
|
+
])];
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/hooks/use-link.ts
|
|
97
|
+
/**
|
|
98
|
+
* Comportamiento de `Link` común a web y nativo: `onPress` se llama antes de navegar
|
|
99
|
+
* y puede cancelar la navegación por defecto. Cada vista aporta esa navegación
|
|
100
|
+
* (el `<a>` en web, `Linking` en nativo).
|
|
101
|
+
*/
|
|
102
|
+
function useLink({ onPress }) {
|
|
103
|
+
return { press: useCallback(() => {
|
|
104
|
+
let prevented = false;
|
|
105
|
+
onPress?.({
|
|
106
|
+
preventDefault: () => {
|
|
107
|
+
prevented = true;
|
|
108
|
+
},
|
|
109
|
+
get defaultPrevented() {
|
|
110
|
+
return prevented;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
return !prevented;
|
|
114
|
+
}, [onPress]) };
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/tabs/navigation.ts
|
|
118
|
+
/** Hacia dónde mueve el foco una tecla: flechas, Inicio y Fin. */
|
|
119
|
+
const tabDirections = [
|
|
120
|
+
"next",
|
|
121
|
+
"previous",
|
|
122
|
+
"first",
|
|
123
|
+
"last"
|
|
124
|
+
];
|
|
125
|
+
/** La primera pestaña habilitada: la elegida por defecto. `undefined` si no hay ninguna. */
|
|
126
|
+
function firstEnabledTab(items) {
|
|
127
|
+
return items.find((item) => item.disabled !== true)?.value;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* La pestaña a la que lleva una tecla desde la actual, saltando las deshabilitadas.
|
|
131
|
+
* `next` y `previous` dan la vuelta al llegar al final. Si no hay otra a la que ir,
|
|
132
|
+
* devuelve la actual.
|
|
133
|
+
*/
|
|
134
|
+
function getTabInDirection(items, current, direction) {
|
|
135
|
+
const enabled = items.filter((item) => item.disabled !== true).map((item) => item.value);
|
|
136
|
+
if (enabled.length === 0) return current;
|
|
137
|
+
const [first] = enabled;
|
|
138
|
+
const last = enabled[enabled.length - 1];
|
|
139
|
+
if (first === void 0 || last === void 0) return current;
|
|
140
|
+
if (direction === "first") return first;
|
|
141
|
+
if (direction === "last") return last;
|
|
142
|
+
const index = enabled.indexOf(current);
|
|
143
|
+
if (index === -1) return direction === "next" ? first : last;
|
|
144
|
+
return enabled[(index + (direction === "next" ? 1 : -1) + enabled.length) % enabled.length] ?? current;
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
21
147
|
//#region src/theme/resolve-theme.ts
|
|
22
148
|
function isPlainObject(value) {
|
|
23
149
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -78,6 +204,110 @@ function useBrand() {
|
|
|
78
204
|
return useContext(UIContext).brand;
|
|
79
205
|
}
|
|
80
206
|
//#endregion
|
|
207
|
+
//#region src/toast/context.ts
|
|
208
|
+
/** La cola de toasts del `UIProvider` más cercano; `null` fuera de uno. */
|
|
209
|
+
const ToastContext = createContext(null);
|
|
210
|
+
/**
|
|
211
|
+
* Muestra y cierra toasts (ADR-039). Necesita un `UIProvider` por encima: es él quien
|
|
212
|
+
* guarda la cola y los pinta.
|
|
213
|
+
*/
|
|
214
|
+
function useToast() {
|
|
215
|
+
const store = useContext(ToastContext);
|
|
216
|
+
if (store === null) throw new Error("useToast necesita un <UIProvider> por encima: es él quien pinta los toasts.");
|
|
217
|
+
return store;
|
|
218
|
+
}
|
|
219
|
+
//#endregion
|
|
220
|
+
//#region src/toast/store.ts
|
|
221
|
+
/** Milisegundos que un toast permanece visible si no se indica otra cosa. */
|
|
222
|
+
const TOAST_DEFAULT_DURATION = 5e3;
|
|
223
|
+
/** Toasts visibles a la vez. Al llegar uno más, se retira el más antiguo. */
|
|
224
|
+
const TOAST_MAX_VISIBLE = 3;
|
|
225
|
+
/**
|
|
226
|
+
* La cola de toasts de un `UIProvider` (ADR-039): alta, baja, cierre automático, pausa
|
|
227
|
+
* y límite de visibles. No depende de React ni de la plataforma.
|
|
228
|
+
*/
|
|
229
|
+
function createToastStore() {
|
|
230
|
+
let items = [];
|
|
231
|
+
let paused = false;
|
|
232
|
+
let nextId = 0;
|
|
233
|
+
const timers = /* @__PURE__ */ new Map();
|
|
234
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
235
|
+
function emit(next) {
|
|
236
|
+
items = next;
|
|
237
|
+
for (const listener of listeners) listener();
|
|
238
|
+
}
|
|
239
|
+
function stop(id) {
|
|
240
|
+
const timer = timers.get(id);
|
|
241
|
+
if (timer?.handle !== void 0) clearTimeout(timer.handle);
|
|
242
|
+
timers.delete(id);
|
|
243
|
+
}
|
|
244
|
+
function start(id, remaining) {
|
|
245
|
+
const timer = {
|
|
246
|
+
handle: void 0,
|
|
247
|
+
startedAt: Date.now(),
|
|
248
|
+
remaining
|
|
249
|
+
};
|
|
250
|
+
if (!paused) timer.handle = setTimeout(() => dismiss(id), remaining);
|
|
251
|
+
timers.set(id, timer);
|
|
252
|
+
}
|
|
253
|
+
function dismiss(id) {
|
|
254
|
+
if (id === void 0) {
|
|
255
|
+
if (items.length === 0) return;
|
|
256
|
+
for (const item of items) stop(item.id);
|
|
257
|
+
emit([]);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (!items.some((item) => item.id === id)) return;
|
|
261
|
+
stop(id);
|
|
262
|
+
emit(items.filter((item) => item.id !== id));
|
|
263
|
+
}
|
|
264
|
+
function show(options) {
|
|
265
|
+
nextId += 1;
|
|
266
|
+
const item = {
|
|
267
|
+
id: `toast-${nextId}`,
|
|
268
|
+
tone: options.tone ?? "info",
|
|
269
|
+
title: options.title,
|
|
270
|
+
description: options.description,
|
|
271
|
+
duration: options.duration ?? 5e3,
|
|
272
|
+
action: options.action,
|
|
273
|
+
closeLabel: options.closeLabel
|
|
274
|
+
};
|
|
275
|
+
const next = [...items, item];
|
|
276
|
+
for (const old of next.splice(0, Math.max(0, next.length - 3))) stop(old.id);
|
|
277
|
+
if (item.duration > 0) start(item.id, item.duration);
|
|
278
|
+
emit(next);
|
|
279
|
+
return item.id;
|
|
280
|
+
}
|
|
281
|
+
function pause() {
|
|
282
|
+
if (paused) return;
|
|
283
|
+
paused = true;
|
|
284
|
+
const now = Date.now();
|
|
285
|
+
for (const timer of timers.values()) {
|
|
286
|
+
if (timer.handle !== void 0) clearTimeout(timer.handle);
|
|
287
|
+
timer.handle = void 0;
|
|
288
|
+
timer.remaining = Math.max(0, timer.remaining - (now - timer.startedAt));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function resume() {
|
|
292
|
+
if (!paused) return;
|
|
293
|
+
paused = false;
|
|
294
|
+
for (const [id, timer] of timers) start(id, timer.remaining);
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
subscribe(listener) {
|
|
298
|
+
listeners.add(listener);
|
|
299
|
+
return () => {
|
|
300
|
+
listeners.delete(listener);
|
|
301
|
+
};
|
|
302
|
+
},
|
|
303
|
+
getSnapshot: () => items,
|
|
304
|
+
show,
|
|
305
|
+
dismiss,
|
|
306
|
+
pause,
|
|
307
|
+
resume
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
//#endregion
|
|
81
311
|
//#region src/types/badge.ts
|
|
82
312
|
/**
|
|
83
313
|
* Variantes de `Badge` (ADR-009): una por cada color de `color.feedback`. Las historias
|
|
@@ -120,23 +350,120 @@ const buttonIconSize = {
|
|
|
120
350
|
lg: "md"
|
|
121
351
|
};
|
|
122
352
|
//#endregion
|
|
353
|
+
//#region src/types/card.ts
|
|
354
|
+
/**
|
|
355
|
+
* Variantes de `Card` (ADR-009): `outlined` se apoya en el borde; `elevated` añade
|
|
356
|
+
* sombra para separarse de lo que tiene debajo.
|
|
357
|
+
*/
|
|
358
|
+
const cardVariants = ["outlined", "elevated"];
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region src/types/control.ts
|
|
361
|
+
/**
|
|
362
|
+
* Alturas de los controles interactivos de una línea (`Input`, `Select`). Coinciden
|
|
363
|
+
* con `size.control` de los tokens y con los tamaños de `Button`, para que un campo y
|
|
364
|
+
* un botón del mismo tamaño queden alineados en una fila.
|
|
365
|
+
*/
|
|
366
|
+
const controlSizes = [
|
|
367
|
+
"sm",
|
|
368
|
+
"md",
|
|
369
|
+
"lg"
|
|
370
|
+
];
|
|
371
|
+
//#endregion
|
|
372
|
+
//#region src/types/divider.ts
|
|
373
|
+
/** Orientación de `Divider` (ADR-009). */
|
|
374
|
+
const dividerOrientations = ["horizontal", "vertical"];
|
|
375
|
+
//#endregion
|
|
376
|
+
//#region src/types/feedback.ts
|
|
377
|
+
/**
|
|
378
|
+
* Los cuatro significados de `color.feedback` en los tokens: éxito, aviso, error e
|
|
379
|
+
* información. Los comparten los componentes que comunican un estado.
|
|
380
|
+
*/
|
|
381
|
+
const feedbackTones = [
|
|
382
|
+
"success",
|
|
383
|
+
"warning",
|
|
384
|
+
"danger",
|
|
385
|
+
"info"
|
|
386
|
+
];
|
|
387
|
+
function isFeedbackTone(value) {
|
|
388
|
+
return feedbackTones.includes(value);
|
|
389
|
+
}
|
|
390
|
+
//#endregion
|
|
123
391
|
//#region src/types/icon.ts
|
|
124
392
|
const iconSizes = [
|
|
125
393
|
"sm",
|
|
126
394
|
"md",
|
|
127
|
-
"lg"
|
|
395
|
+
"lg",
|
|
396
|
+
"xl"
|
|
128
397
|
];
|
|
129
398
|
/** Tamaño en px/puntos de cada icono. */
|
|
130
399
|
const iconSizePx = {
|
|
131
400
|
sm: 16,
|
|
132
401
|
md: 20,
|
|
133
|
-
lg: 24
|
|
402
|
+
lg: 24,
|
|
403
|
+
xl: 32
|
|
404
|
+
};
|
|
405
|
+
//#endregion
|
|
406
|
+
//#region src/types/icon-button.ts
|
|
407
|
+
/**
|
|
408
|
+
* Tamaño del icono para cada tamaño de `IconButton`. Es un paso mayor que en
|
|
409
|
+
* `Button`, porque aquí el icono es todo el contenido.
|
|
410
|
+
*/
|
|
411
|
+
const iconButtonIconSize = {
|
|
412
|
+
sm: "sm",
|
|
413
|
+
md: "md",
|
|
414
|
+
lg: "lg"
|
|
134
415
|
};
|
|
135
416
|
//#endregion
|
|
417
|
+
//#region src/types/input.ts
|
|
418
|
+
/**
|
|
419
|
+
* Qué se escribe en un `Input` (ADR-009). Cada vista lo traduce a su plataforma:
|
|
420
|
+
* el atributo `type` y el teclado en web, y el teclado, las mayúsculas automáticas
|
|
421
|
+
* y el autocompletado en nativo.
|
|
422
|
+
*/
|
|
423
|
+
const inputTypes = [
|
|
424
|
+
"text",
|
|
425
|
+
"email",
|
|
426
|
+
"password",
|
|
427
|
+
"search",
|
|
428
|
+
"tel",
|
|
429
|
+
"url",
|
|
430
|
+
"number"
|
|
431
|
+
];
|
|
432
|
+
/** Tamaño de los iconos de un `Input` para cada tamaño de campo. */
|
|
433
|
+
const inputIconSize = {
|
|
434
|
+
sm: "sm",
|
|
435
|
+
md: "md",
|
|
436
|
+
lg: "md"
|
|
437
|
+
};
|
|
438
|
+
//#endregion
|
|
439
|
+
//#region src/types/link.ts
|
|
440
|
+
/**
|
|
441
|
+
* Cuándo se subraya un `Link` (ADR-009). `always` es lo correcto dentro de un párrafo:
|
|
442
|
+
* el color solo no basta para distinguir un enlace. `hover` lo subraya al pasar el
|
|
443
|
+
* puntero o enfocarlo en web, y mientras se pulsa en nativo.
|
|
444
|
+
*/
|
|
445
|
+
const linkUnderlines = ["always", "hover"];
|
|
446
|
+
//#endregion
|
|
447
|
+
//#region src/types/modal.ts
|
|
448
|
+
/** Las dos presentaciones de un diálogo. */
|
|
449
|
+
const modalPresentations = ["dialog", "sheet"];
|
|
450
|
+
//#endregion
|
|
451
|
+
//#region src/types/skeleton.ts
|
|
452
|
+
/**
|
|
453
|
+
* Formas de `Skeleton` (ADR-009): `text` ocupa el hueco de una línea de `Text`,
|
|
454
|
+
* `rectangle` el de una imagen o un control, y `circle` el de un avatar.
|
|
455
|
+
*/
|
|
456
|
+
const skeletonShapes = [
|
|
457
|
+
"text",
|
|
458
|
+
"rectangle",
|
|
459
|
+
"circle"
|
|
460
|
+
];
|
|
461
|
+
//#endregion
|
|
136
462
|
//#region src/types/spinner.ts
|
|
137
463
|
/**
|
|
138
464
|
* `Spinner` comparte la escala de `Icon`: así puede ocupar el sitio de un icono
|
|
139
465
|
* (por ejemplo, dentro de un botón que carga) sin mover el resto del contenido.
|
|
466
|
+
* `xl` es para la carga de una página o de una sección entera.
|
|
140
467
|
*/
|
|
141
468
|
const spinnerSizes = iconSizes;
|
|
142
469
|
/** Tamaño en px/puntos de cada spinner. */
|
|
@@ -246,4 +573,4 @@ const themeModes = [
|
|
|
246
573
|
"system"
|
|
247
574
|
];
|
|
248
575
|
//#endregion
|
|
249
|
-
export { UIContext, backgroundTokens, badgeVariants, borderColorTokens, buttonIconSize, buttonVariants, createUIContextValue, iconSizePx, iconSizes, mergeTheme, radiusTokens, resolveColorScheme, resolveTheme, shadowTokens, spaceTokens, spinnerSizePx, spinnerSizes, stackAligns, stackDirections, stackJustifies, textAligns, textColors, textVariantStyles, textVariants, themeModes, useBrand, useButton, useColorScheme, useTheme, useUIContext };
|
|
576
|
+
export { FormFieldContext, TOAST_DEFAULT_DURATION, TOAST_MAX_VISIBLE, ToastContext, UIContext, backgroundTokens, badgeVariants, borderColorTokens, buttonIconSize, buttonVariants, cardVariants, controlSizes, createFormFieldValue, createToastStore, createUIContextValue, dividerOrientations, feedbackTones, firstEnabledTab, getTabInDirection, iconButtonIconSize, iconSizePx, iconSizes, inputIconSize, inputTypes, isFeedbackTone, linkUnderlines, mergeTheme, modalPresentations, radiusTokens, resolveColorScheme, resolveFormFieldControl, resolveTheme, shadowTokens, skeletonShapes, spaceTokens, spinnerSizePx, spinnerSizes, stackAligns, stackDirections, stackJustifies, tabDirections, textAligns, textColors, textVariantStyles, textVariants, themeModes, useBrand, useButton, useColorScheme, useControllableState, useFormFieldControl, useLink, useTheme, useToast, useUIContext };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@satellatickets/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Lógica headless de satella-ui: contratos de props, constantes de variantes, contexto de tema y hooks compartidos por React y React Native",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"react": ">=19.0"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@satellatickets/tokens": "0.
|
|
29
|
+
"@satellatickets/tokens": "0.1.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@testing-library/react": "^16.3.3",
|