@satellatickets/core 0.2.0 → 0.3.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/dist/client-DpHlKasm.d.ts +300 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.js +158 -0
- package/dist/index.d.ts +27 -291
- package/dist/index.js +59 -182
- package/dist/resolve-theme-DbIlzBBD.js +36 -0
- package/package.json +1 -1
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
|
|
2
|
+
import { BrandName, Theme, ThemeName } from "@satellatickets/tokens";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
//#region src/form-field/context.d.ts
|
|
5
|
+
/** Lo que `FormField` publica para el control que envuelve (ADR-037). */
|
|
6
|
+
interface FormFieldValue {
|
|
7
|
+
/** `id` del control. `FormField` lo usa en el `htmlFor` de su etiqueta (web). */
|
|
8
|
+
controlId: string;
|
|
9
|
+
/** `id` del texto de ayuda, si lo hay (web). */
|
|
10
|
+
helpId: string | undefined;
|
|
11
|
+
/** `id` del mensaje de error, si lo hay (web). */
|
|
12
|
+
errorId: string | undefined;
|
|
13
|
+
label: string;
|
|
14
|
+
help: string | undefined;
|
|
15
|
+
error: string | undefined;
|
|
16
|
+
disabled: boolean;
|
|
17
|
+
required: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface FormFieldValueOptions {
|
|
20
|
+
label: string;
|
|
21
|
+
help?: string | undefined;
|
|
22
|
+
error?: string | undefined;
|
|
23
|
+
disabled?: boolean | undefined;
|
|
24
|
+
required?: boolean | undefined;
|
|
25
|
+
}
|
|
26
|
+
/** Construye el valor del contexto a partir de un id base (el de `useId()`). */
|
|
27
|
+
declare function createFormFieldValue(baseId: string, { label, help, error, disabled, required }: FormFieldValueOptions): FormFieldValue;
|
|
28
|
+
/** `null` fuera de un `FormField`. */
|
|
29
|
+
declare const FormFieldContext: import("react").Context<FormFieldValue | null>;
|
|
30
|
+
/** Las props propias de un control que se combinan con las de su `FormField`. */
|
|
31
|
+
interface FormFieldControlOptions {
|
|
32
|
+
id?: string | undefined;
|
|
33
|
+
invalid?: boolean | undefined;
|
|
34
|
+
disabled?: boolean | undefined;
|
|
35
|
+
required?: boolean | undefined;
|
|
36
|
+
accessibilityLabel?: string | undefined;
|
|
37
|
+
}
|
|
38
|
+
/** Lo que un control necesita para enlazarse con su `FormField`, en web y en nativo. */
|
|
39
|
+
interface FormFieldControl {
|
|
40
|
+
/** `id` del control (web): el propio o el que espera la etiqueta del campo. */
|
|
41
|
+
id: string | undefined;
|
|
42
|
+
/** Ids de la ayuda y el error para `aria-describedby` (web). */
|
|
43
|
+
describedBy: string | undefined;
|
|
44
|
+
/** Nombre accesible (nativo): el propio o la etiqueta del campo. */
|
|
45
|
+
accessibilityLabel: string | undefined;
|
|
46
|
+
/** El error y la ayuda, uno tras otro, para `accessibilityHint` (nativo). */
|
|
47
|
+
accessibilityHint: string | undefined;
|
|
48
|
+
invalid: boolean;
|
|
49
|
+
disabled: boolean;
|
|
50
|
+
required: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Combina las props de un control con las de su `FormField`. Las del control
|
|
54
|
+
* mandan en `id` y nombre accesible; `invalid`, `disabled` y `required` se suman:
|
|
55
|
+
* basta con que lo diga uno de los dos.
|
|
56
|
+
*/
|
|
57
|
+
declare function resolveFormFieldControl(field: FormFieldValue | null, { id, invalid, disabled, required, accessibilityLabel }?: FormFieldControlOptions): FormFieldControl;
|
|
58
|
+
/** Enlaza un control con el `FormField` que lo contiene, si lo hay. */
|
|
59
|
+
declare function useFormFieldControl(options?: FormFieldControlOptions): FormFieldControl;
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/hooks/use-button.d.ts
|
|
62
|
+
interface UseButtonOptions {
|
|
63
|
+
disabled?: boolean | undefined;
|
|
64
|
+
loading?: boolean | undefined;
|
|
65
|
+
onPress?: (() => void) | undefined;
|
|
66
|
+
}
|
|
67
|
+
interface UseButtonResult {
|
|
68
|
+
disabled: boolean;
|
|
69
|
+
loading: boolean;
|
|
70
|
+
/** `false` si está deshabilitado o cargando: el botón no responde a la pulsación. */
|
|
71
|
+
interactive: boolean;
|
|
72
|
+
/** Llama a `onPress` solo si el botón es interactivo. */
|
|
73
|
+
press: () => void;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Comportamiento de `Button` común a web y nativo: un botón deshabilitado o que
|
|
77
|
+
* está cargando no dispara `onPress`. Cada vista añade su accesibilidad
|
|
78
|
+
* (`disabled`/`aria-busy` en web, `accessibilityState` en nativo).
|
|
79
|
+
*/
|
|
80
|
+
declare function useButton({ disabled, loading, onPress }: UseButtonOptions): UseButtonResult;
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/hooks/use-controllable-state.d.ts
|
|
83
|
+
interface UseControllableStateOptions<T> {
|
|
84
|
+
/** Valor controlado por la app. Si existe, manda sobre el estado interno. */
|
|
85
|
+
value?: T | undefined;
|
|
86
|
+
/** Valor inicial cuando el componente guarda su propio estado. */
|
|
87
|
+
defaultValue: T;
|
|
88
|
+
/** Se llama con el valor nuevo cuando cambia, en los dos modos. */
|
|
89
|
+
onChange?: ((value: T) => void) | undefined;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Estado controlado o no, a elección de la app (ADR-037). Con `value`, el componente
|
|
93
|
+
* solo avisa del cambio y espera a que la app le pase el valor nuevo; sin él, guarda
|
|
94
|
+
* el estado a partir de `defaultValue`. No avisa si el valor no cambia.
|
|
95
|
+
*/
|
|
96
|
+
declare function useControllableState<T>({ value, defaultValue, onChange }: UseControllableStateOptions<T>): [T, (next: T) => void];
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/types/text.d.ts
|
|
99
|
+
declare const textVariants: readonly ["hero", "display", "title", "heading", "subheading", "body", "bodySmall", "label", "caption", "code"];
|
|
100
|
+
type TextVariant = (typeof textVariants)[number];
|
|
101
|
+
type TextColorToken = keyof Theme['color']['text'];
|
|
102
|
+
declare const textColors: TextColorToken[];
|
|
103
|
+
declare const textAligns: readonly ["left", "center", "right"];
|
|
104
|
+
type TextAlign = (typeof textAligns)[number];
|
|
105
|
+
/** Tokens que componen una variante tipográfica; ambas vistas los leen del tema. */
|
|
106
|
+
interface TextVariantStyle {
|
|
107
|
+
family: keyof Theme['font']['family'];
|
|
108
|
+
/** Tamaño; `font.lineHeight` comparte las mismas claves (lo comprueba el typecheck de las vistas). */
|
|
109
|
+
size: keyof Theme['font']['size'];
|
|
110
|
+
weight: keyof Theme['font']['weight'];
|
|
111
|
+
uppercase?: boolean;
|
|
112
|
+
/** Espaciado entre letras en px. */
|
|
113
|
+
letterSpacing?: number;
|
|
114
|
+
/** Nivel de encabezado semántico (h1–h4) si la variante es un título. */
|
|
115
|
+
headingLevel?: 1 | 2 | 3 | 4;
|
|
116
|
+
}
|
|
117
|
+
/** Escala tipográfica de Satella: Unbounded para titulares, Hanken Grotesk para texto, IBM Plex Mono para etiquetas. */
|
|
118
|
+
declare const textVariantStyles: Readonly<Record<TextVariant, TextVariantStyle>>;
|
|
119
|
+
interface TextProps {
|
|
120
|
+
variant?: TextVariant | undefined;
|
|
121
|
+
color?: TextColorToken | undefined;
|
|
122
|
+
align?: TextAlign | undefined;
|
|
123
|
+
/** Una sola línea con puntos suspensivos. */
|
|
124
|
+
truncate?: boolean | undefined;
|
|
125
|
+
testID?: string | undefined;
|
|
126
|
+
children?: ReactNode;
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/types/link.d.ts
|
|
130
|
+
/**
|
|
131
|
+
* Cuándo se subraya un `Link` (ADR-009). `always` es lo correcto dentro de un párrafo:
|
|
132
|
+
* el color solo no basta para distinguir un enlace. `hover` lo subraya al pasar el
|
|
133
|
+
* puntero o enfocarlo en web, y mientras se pulsa en nativo.
|
|
134
|
+
*/
|
|
135
|
+
declare const linkUnderlines: readonly ["always", "hover"];
|
|
136
|
+
type LinkUnderline = (typeof linkUnderlines)[number];
|
|
137
|
+
/** Lo que recibe `onPress` de un `Link`: permite cancelar la navegación por defecto. */
|
|
138
|
+
interface LinkPressEvent {
|
|
139
|
+
/** Cancela la navegación por defecto, por ejemplo para hacerla con el router de la app. */
|
|
140
|
+
preventDefault: () => void;
|
|
141
|
+
readonly defaultPrevented: boolean;
|
|
142
|
+
}
|
|
143
|
+
interface LinkProps {
|
|
144
|
+
/** Destino. En web es el `href` del `<a>`; en nativo se abre con `Linking`. */
|
|
145
|
+
href: string;
|
|
146
|
+
/**
|
|
147
|
+
* Tipografía, con las mismas variantes que `Text`. Sin ella hereda la del texto
|
|
148
|
+
* que lo contiene; fuera de un `Text`, usa `body`.
|
|
149
|
+
*/
|
|
150
|
+
variant?: TextVariant | undefined;
|
|
151
|
+
/** Color del texto (por defecto `link`). */
|
|
152
|
+
color?: TextColorToken | undefined;
|
|
153
|
+
underline?: LinkUnderline | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Se llama antes de navegar. Con `event.preventDefault()` la librería no navega y
|
|
156
|
+
* la app decide qué hacer. En web no se llama si el clic lleva un modificador
|
|
157
|
+
* (Ctrl, Cmd, Mayús, Alt) o no es del botón principal: ahí manda el navegador.
|
|
158
|
+
*/
|
|
159
|
+
onPress?: ((event: LinkPressEvent) => void) | undefined;
|
|
160
|
+
/** Nombre accesible cuando el texto visible no basta para describir el destino. */
|
|
161
|
+
accessibilityLabel?: string | undefined;
|
|
162
|
+
/** `data-testid` en web, `testID` en nativo. */
|
|
163
|
+
testID?: string | undefined;
|
|
164
|
+
children: ReactNode;
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/hooks/use-link.d.ts
|
|
168
|
+
interface UseLinkOptions {
|
|
169
|
+
onPress?: ((event: LinkPressEvent) => void) | undefined;
|
|
170
|
+
}
|
|
171
|
+
interface UseLinkResult {
|
|
172
|
+
/**
|
|
173
|
+
* Llama a `onPress` y devuelve `true` si la navegación por defecto debe seguir,
|
|
174
|
+
* es decir, si nadie llamó a `preventDefault()`.
|
|
175
|
+
*/
|
|
176
|
+
press: () => boolean;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Comportamiento de `Link` común a web y nativo: `onPress` se llama antes de navegar
|
|
180
|
+
* y puede cancelar la navegación por defecto. Cada vista aporta esa navegación
|
|
181
|
+
* (el `<a>` en web, `Linking` en nativo).
|
|
182
|
+
*/
|
|
183
|
+
declare function useLink({ onPress }: UseLinkOptions): UseLinkResult;
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/types/ui-provider.d.ts
|
|
186
|
+
/** Modo de tema que acepta `UIProvider` (ADR-010). */
|
|
187
|
+
declare const themeModes: readonly ["light", "dark", "system"];
|
|
188
|
+
type ThemeMode = (typeof themeModes)[number];
|
|
189
|
+
/** Esquema resuelto: siempre uno de los temas definidos en tokens. */
|
|
190
|
+
type ColorScheme = ThemeName;
|
|
191
|
+
interface UIProviderProps {
|
|
192
|
+
/** Tema claro, oscuro o el del sistema (por defecto `system`). */
|
|
193
|
+
theme?: ThemeMode | undefined;
|
|
194
|
+
/** Marca registrada en tokens. Sin marca se usa la identidad por defecto. */
|
|
195
|
+
brand?: BrandName | undefined;
|
|
196
|
+
children: ReactNode;
|
|
197
|
+
}
|
|
198
|
+
//#endregion
|
|
199
|
+
//#region src/theme/context.d.ts
|
|
200
|
+
interface UIContextValue {
|
|
201
|
+
theme: Theme;
|
|
202
|
+
colorScheme: ColorScheme;
|
|
203
|
+
mode: ThemeMode;
|
|
204
|
+
brand: BrandName | undefined;
|
|
205
|
+
}
|
|
206
|
+
declare function createUIContextValue(mode: ThemeMode, systemScheme: ColorScheme, brand?: BrandName): UIContextValue;
|
|
207
|
+
/** Sin `UIProvider` se usa el tema claro por defecto, para que los componentes funcionen aislados. */
|
|
208
|
+
declare const UIContext: import("react").Context<UIContextValue>;
|
|
209
|
+
declare function useUIContext(): UIContextValue;
|
|
210
|
+
/** Tema resuelto (tokens con la marca aplicada). Imprescindible en las vistas nativas (ADR-008). */
|
|
211
|
+
declare function useTheme(): Theme;
|
|
212
|
+
/** `'light' | 'dark'` ya resuelto, también con `theme="system"`. */
|
|
213
|
+
declare function useColorScheme(): ColorScheme;
|
|
214
|
+
declare function useBrand(): BrandName | undefined;
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/types/feedback.d.ts
|
|
217
|
+
/**
|
|
218
|
+
* Los cuatro significados de `color.feedback` en los tokens: éxito, aviso, error e
|
|
219
|
+
* información. Los comparten los componentes que comunican un estado.
|
|
220
|
+
*/
|
|
221
|
+
declare const feedbackTones: readonly ["success", "warning", "danger", "info"];
|
|
222
|
+
type FeedbackTone = (typeof feedbackTones)[number];
|
|
223
|
+
declare function isFeedbackTone(value: string): value is FeedbackTone;
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region src/types/toast.d.ts
|
|
226
|
+
/** Acción opcional de un toast, por ejemplo "Deshacer". */
|
|
227
|
+
interface ToastAction {
|
|
228
|
+
label: string;
|
|
229
|
+
onPress: () => void;
|
|
230
|
+
}
|
|
231
|
+
/** Lo que recibe `show()` de `useToast` (ADR-039). */
|
|
232
|
+
interface ToastOptions {
|
|
233
|
+
/** Qué comunica (por defecto `info`). Fija el icono y la urgencia con que se anuncia. */
|
|
234
|
+
tone?: FeedbackTone | undefined;
|
|
235
|
+
/** El mensaje, en una línea. */
|
|
236
|
+
title: string;
|
|
237
|
+
/** Detalle opcional. */
|
|
238
|
+
description?: string | undefined;
|
|
239
|
+
/**
|
|
240
|
+
* Milisegundos hasta que se cierra solo (por defecto 5000). Con `0` no se cierra
|
|
241
|
+
* solo: necesita `closeLabel`, una `action` o una llamada a `dismiss`.
|
|
242
|
+
*/
|
|
243
|
+
duration?: number | undefined;
|
|
244
|
+
/** Botón de acción. Al pulsarlo se llama a `onPress` y el toast se cierra. */
|
|
245
|
+
action?: ToastAction | undefined;
|
|
246
|
+
/**
|
|
247
|
+
* Si existe, el toast muestra un botón de cierre con este nombre accesible
|
|
248
|
+
* ("Cerrar aviso"). La librería no trae textos propios.
|
|
249
|
+
*/
|
|
250
|
+
closeLabel?: string | undefined;
|
|
251
|
+
}
|
|
252
|
+
/** Un toast ya en la cola: sus opciones resueltas y su identificador. */
|
|
253
|
+
interface ToastItem {
|
|
254
|
+
id: string;
|
|
255
|
+
tone: FeedbackTone;
|
|
256
|
+
title: string;
|
|
257
|
+
description: string | undefined;
|
|
258
|
+
duration: number;
|
|
259
|
+
action: ToastAction | undefined;
|
|
260
|
+
closeLabel: string | undefined;
|
|
261
|
+
}
|
|
262
|
+
/** Lo que devuelve `useToast`. */
|
|
263
|
+
interface ToastApi {
|
|
264
|
+
/** Muestra un toast y devuelve su `id`. */
|
|
265
|
+
show: (options: ToastOptions) => string;
|
|
266
|
+
/** Cierra el toast con ese `id`; sin `id`, los cierra todos. */
|
|
267
|
+
dismiss: (id?: string) => void;
|
|
268
|
+
}
|
|
269
|
+
//#endregion
|
|
270
|
+
//#region src/toast/store.d.ts
|
|
271
|
+
/** Milisegundos que un toast permanece visible si no se indica otra cosa. */
|
|
272
|
+
declare const TOAST_DEFAULT_DURATION = 5000;
|
|
273
|
+
/** Toasts visibles a la vez. Al llegar uno más, se retira el más antiguo. */
|
|
274
|
+
declare const TOAST_MAX_VISIBLE = 3;
|
|
275
|
+
interface ToastStore extends ToastApi {
|
|
276
|
+
/** Para `useSyncExternalStore`: avisa de cada cambio y devuelve cómo dejar de escuchar. */
|
|
277
|
+
subscribe: (listener: () => void) => () => void;
|
|
278
|
+
/** Los toasts visibles, del más antiguo al más reciente. Cambia de identidad con cada cambio. */
|
|
279
|
+
getSnapshot: () => readonly ToastItem[];
|
|
280
|
+
/** Detiene el cierre automático, por ejemplo mientras el puntero está sobre los toasts. */
|
|
281
|
+
pause: () => void;
|
|
282
|
+
/** Reanuda el cierre automático con el tiempo que le quedaba a cada toast. */
|
|
283
|
+
resume: () => void;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* La cola de toasts de un `UIProvider` (ADR-039): alta, baja, cierre automático, pausa
|
|
287
|
+
* y límite de visibles. No depende de React ni de la plataforma.
|
|
288
|
+
*/
|
|
289
|
+
declare function createToastStore(): ToastStore;
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region src/toast/context.d.ts
|
|
292
|
+
/** La cola de toasts del `UIProvider` más cercano; `null` fuera de uno. */
|
|
293
|
+
declare const ToastContext: import("react").Context<ToastStore | null>;
|
|
294
|
+
/**
|
|
295
|
+
* Muestra y cierra toasts (ADR-039). Necesita un `UIProvider` por encima: es él quien
|
|
296
|
+
* guarda la cola y los pinta.
|
|
297
|
+
*/
|
|
298
|
+
declare function useToast(): ToastApi;
|
|
299
|
+
//#endregion
|
|
300
|
+
export { useFormFieldControl as $, LinkUnderline as A, textVariants as B, UIProviderProps as C, useLink as D, UseLinkResult as E, TextVariant as F, useButton as G, useControllableState as H, TextVariantStyle as I, FormFieldControlOptions as J, FormFieldContext as K, textAligns as L, TextAlign as M, TextColorToken as N, LinkPressEvent as O, TextProps as P, resolveFormFieldControl as Q, textColors as R, ThemeMode as S, UseLinkOptions as T, UseButtonOptions as U, UseControllableStateOptions as V, UseButtonResult as W, FormFieldValueOptions as X, FormFieldValue as Y, createFormFieldValue as Z, useBrand as _, ToastStore as a, useUIContext as b, ToastApi as c, FeedbackTone as d, feedbackTones as f, createUIContextValue as g, UIContextValue as h, TOAST_MAX_VISIBLE as i, linkUnderlines as j, LinkProps as k, ToastItem as l, UIContext as m, useToast as n, createToastStore as o, isFeedbackTone as p, FormFieldControl as q, TOAST_DEFAULT_DURATION as r, ToastAction as s, ToastContext as t, ToastOptions as u, useColorScheme as v, themeModes as w, ColorScheme as x, useTheme as y, textVariantStyles as z };
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
|
|
2
|
+
import { $ as useFormFieldControl, D as useLink, E as UseLinkResult, G as useButton, H as useControllableState, J as FormFieldControlOptions, K as FormFieldContext, Q as resolveFormFieldControl, T as UseLinkOptions, U as UseButtonOptions, V as UseControllableStateOptions, W as UseButtonResult, X as FormFieldValueOptions, Y as FormFieldValue, Z as createFormFieldValue, _ as useBrand, b as useUIContext, g as createUIContextValue, h as UIContextValue, m as UIContext, n as useToast, q as FormFieldControl, t as ToastContext, v as useColorScheme, y as useTheme } from "./client-DpHlKasm.js";
|
|
3
|
+
export { FormFieldContext, FormFieldControl, FormFieldControlOptions, FormFieldValue, FormFieldValueOptions, ToastContext, UIContext, type UIContextValue, UseButtonOptions, UseButtonResult, UseControllableStateOptions, UseLinkOptions, UseLinkResult, createFormFieldValue, createUIContextValue, resolveFormFieldControl, useBrand, useButton, useColorScheme, useControllableState, useFormFieldControl, useLink, useTheme, useToast, useUIContext };
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { n as resolveColorScheme, r as resolveTheme } from "./resolve-theme-DbIlzBBD.js";
|
|
3
|
+
import { createContext, useCallback, useContext, useState } from "react";
|
|
4
|
+
//#region src/form-field/context.ts
|
|
5
|
+
/** Un texto vacío cuenta como ausente: `error={errores.email}` suele llegar así. */
|
|
6
|
+
function present(text) {
|
|
7
|
+
return text === void 0 || text === "" ? void 0 : text;
|
|
8
|
+
}
|
|
9
|
+
/** Construye el valor del contexto a partir de un id base (el de `useId()`). */
|
|
10
|
+
function createFormFieldValue(baseId, { label, help, error, disabled = false, required = false }) {
|
|
11
|
+
const helpText = present(help);
|
|
12
|
+
const errorText = present(error);
|
|
13
|
+
return {
|
|
14
|
+
controlId: `${baseId}-control`,
|
|
15
|
+
helpId: helpText === void 0 ? void 0 : `${baseId}-help`,
|
|
16
|
+
errorId: errorText === void 0 ? void 0 : `${baseId}-error`,
|
|
17
|
+
label,
|
|
18
|
+
help: helpText,
|
|
19
|
+
error: errorText,
|
|
20
|
+
disabled,
|
|
21
|
+
required
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** `null` fuera de un `FormField`. */
|
|
25
|
+
const FormFieldContext = createContext(null);
|
|
26
|
+
/**
|
|
27
|
+
* Combina las props de un control con las de su `FormField`. Las del control
|
|
28
|
+
* mandan en `id` y nombre accesible; `invalid`, `disabled` y `required` se suman:
|
|
29
|
+
* basta con que lo diga uno de los dos.
|
|
30
|
+
*/
|
|
31
|
+
function resolveFormFieldControl(field, { id, invalid = false, disabled = false, required = false, accessibilityLabel } = {}) {
|
|
32
|
+
if (field === null) return {
|
|
33
|
+
id,
|
|
34
|
+
describedBy: void 0,
|
|
35
|
+
accessibilityLabel,
|
|
36
|
+
accessibilityHint: void 0,
|
|
37
|
+
invalid,
|
|
38
|
+
disabled,
|
|
39
|
+
required
|
|
40
|
+
};
|
|
41
|
+
const describedBy = [field.helpId, field.errorId].filter((part) => part !== void 0).join(" ");
|
|
42
|
+
const hint = [field.error, field.help].filter((part) => part !== void 0).join(" ");
|
|
43
|
+
return {
|
|
44
|
+
id: id ?? field.controlId,
|
|
45
|
+
describedBy: describedBy === "" ? void 0 : describedBy,
|
|
46
|
+
accessibilityLabel: accessibilityLabel ?? field.label,
|
|
47
|
+
accessibilityHint: hint === "" ? void 0 : hint,
|
|
48
|
+
invalid: invalid || field.error !== void 0,
|
|
49
|
+
disabled: disabled || field.disabled,
|
|
50
|
+
required: required || field.required
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** Enlaza un control con el `FormField` que lo contiene, si lo hay. */
|
|
54
|
+
function useFormFieldControl(options) {
|
|
55
|
+
return resolveFormFieldControl(useContext(FormFieldContext), options);
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/hooks/use-button.ts
|
|
59
|
+
/**
|
|
60
|
+
* Comportamiento de `Button` común a web y nativo: un botón deshabilitado o que
|
|
61
|
+
* está cargando no dispara `onPress`. Cada vista añade su accesibilidad
|
|
62
|
+
* (`disabled`/`aria-busy` en web, `accessibilityState` en nativo).
|
|
63
|
+
*/
|
|
64
|
+
function useButton({ disabled = false, loading = false, onPress }) {
|
|
65
|
+
const interactive = !disabled && !loading;
|
|
66
|
+
return {
|
|
67
|
+
disabled,
|
|
68
|
+
loading,
|
|
69
|
+
interactive,
|
|
70
|
+
press: useCallback(() => {
|
|
71
|
+
if (interactive) onPress?.();
|
|
72
|
+
}, [interactive, onPress])
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/hooks/use-controllable-state.ts
|
|
77
|
+
/**
|
|
78
|
+
* Estado controlado o no, a elección de la app (ADR-037). Con `value`, el componente
|
|
79
|
+
* solo avisa del cambio y espera a que la app le pase el valor nuevo; sin él, guarda
|
|
80
|
+
* el estado a partir de `defaultValue`. No avisa si el valor no cambia.
|
|
81
|
+
*/
|
|
82
|
+
function useControllableState({ value, defaultValue, onChange }) {
|
|
83
|
+
const [internal, setInternal] = useState(defaultValue);
|
|
84
|
+
const controlled = value !== void 0;
|
|
85
|
+
const current = controlled ? value : internal;
|
|
86
|
+
return [current, useCallback((next) => {
|
|
87
|
+
if (Object.is(next, current)) return;
|
|
88
|
+
if (!controlled) setInternal(next);
|
|
89
|
+
onChange?.(next);
|
|
90
|
+
}, [
|
|
91
|
+
controlled,
|
|
92
|
+
current,
|
|
93
|
+
onChange
|
|
94
|
+
])];
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/hooks/use-link.ts
|
|
98
|
+
/**
|
|
99
|
+
* Comportamiento de `Link` común a web y nativo: `onPress` se llama antes de navegar
|
|
100
|
+
* y puede cancelar la navegación por defecto. Cada vista aporta esa navegación
|
|
101
|
+
* (el `<a>` en web, `Linking` en nativo).
|
|
102
|
+
*/
|
|
103
|
+
function useLink({ onPress }) {
|
|
104
|
+
return { press: useCallback(() => {
|
|
105
|
+
let prevented = false;
|
|
106
|
+
onPress?.({
|
|
107
|
+
preventDefault: () => {
|
|
108
|
+
prevented = true;
|
|
109
|
+
},
|
|
110
|
+
get defaultPrevented() {
|
|
111
|
+
return prevented;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
return !prevented;
|
|
115
|
+
}, [onPress]) };
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/theme/context.ts
|
|
119
|
+
function createUIContextValue(mode, systemScheme, brand) {
|
|
120
|
+
const colorScheme = resolveColorScheme(mode, systemScheme);
|
|
121
|
+
return {
|
|
122
|
+
theme: resolveTheme(colorScheme, brand),
|
|
123
|
+
colorScheme,
|
|
124
|
+
mode,
|
|
125
|
+
brand
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/** Sin `UIProvider` se usa el tema claro por defecto, para que los componentes funcionen aislados. */
|
|
129
|
+
const UIContext = createContext(createUIContextValue("light", "light"));
|
|
130
|
+
function useUIContext() {
|
|
131
|
+
return useContext(UIContext);
|
|
132
|
+
}
|
|
133
|
+
/** Tema resuelto (tokens con la marca aplicada). Imprescindible en las vistas nativas (ADR-008). */
|
|
134
|
+
function useTheme() {
|
|
135
|
+
return useContext(UIContext).theme;
|
|
136
|
+
}
|
|
137
|
+
/** `'light' | 'dark'` ya resuelto, también con `theme="system"`. */
|
|
138
|
+
function useColorScheme() {
|
|
139
|
+
return useContext(UIContext).colorScheme;
|
|
140
|
+
}
|
|
141
|
+
function useBrand() {
|
|
142
|
+
return useContext(UIContext).brand;
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
//#region src/toast/context.ts
|
|
146
|
+
/** La cola de toasts del `UIProvider` más cercano; `null` fuera de uno. */
|
|
147
|
+
const ToastContext = createContext(null);
|
|
148
|
+
/**
|
|
149
|
+
* Muestra y cierra toasts (ADR-039). Necesita un `UIProvider` por encima: es él quien
|
|
150
|
+
* guarda la cola y los pinta.
|
|
151
|
+
*/
|
|
152
|
+
function useToast() {
|
|
153
|
+
const store = useContext(ToastContext);
|
|
154
|
+
if (store === null) throw new Error("useToast necesita un <UIProvider> por encima: es él quien pinta los toasts.");
|
|
155
|
+
return store;
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
export { FormFieldContext, ToastContext, UIContext, createFormFieldValue, createUIContextValue, resolveFormFieldControl, useBrand, useButton, useColorScheme, useControllableState, useFormFieldControl, useLink, useTheme, useToast, useUIContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,185 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import { $ as useFormFieldControl, A as LinkUnderline, B as textVariants, C as UIProviderProps, D as useLink, E as UseLinkResult, F as TextVariant, G as useButton, H as useControllableState, I as TextVariantStyle, J as FormFieldControlOptions, K as FormFieldContext, L as textAligns, M as TextAlign, N as TextColorToken, O as LinkPressEvent, P as TextProps, Q as resolveFormFieldControl, R as textColors, S as ThemeMode, T as UseLinkOptions, U as UseButtonOptions, V as UseControllableStateOptions, W as UseButtonResult, X as FormFieldValueOptions, Y as FormFieldValue, Z as createFormFieldValue, _ as useBrand, a as ToastStore, b as useUIContext, c as ToastApi, d as FeedbackTone, f as feedbackTones, g as createUIContextValue, h as UIContextValue, i as TOAST_MAX_VISIBLE, j as linkUnderlines, k as LinkProps, l as ToastItem, m as UIContext, n as useToast, o as createToastStore, p as isFeedbackTone, q as FormFieldControl, r as TOAST_DEFAULT_DURATION, s as ToastAction, t as ToastContext, u as ToastOptions, v as useColorScheme, w as themeModes, x as ColorScheme, y as useTheme, z as textVariantStyles } from "./client-DpHlKasm.js";
|
|
2
3
|
import { BrandName, Theme, ThemeName, ThemeOverrides } from "@satellatickets/tokens";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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 {
|
|
4
|
+
import { ReactNode } from "react";
|
|
5
|
+
//#region src/select/navigation.d.ts
|
|
6
|
+
/** Lo mínimo que hace falta saber de una opción para moverse entre ellas y buscarla. */
|
|
7
|
+
export interface NavigableOption {
|
|
8
|
+
value: string;
|
|
19
9
|
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
10
|
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
|
|
60
|
-
//#region src/hooks/use-button.d.ts
|
|
61
|
-
export interface UseButtonOptions {
|
|
62
|
-
disabled?: boolean | undefined;
|
|
63
|
-
loading?: boolean | undefined;
|
|
64
|
-
onPress?: (() => void) | undefined;
|
|
65
|
-
}
|
|
66
|
-
export interface UseButtonResult {
|
|
67
|
-
disabled: boolean;
|
|
68
|
-
loading: boolean;
|
|
69
|
-
/** `false` si está deshabilitado o cargando: el botón no responde a la pulsación. */
|
|
70
|
-
interactive: boolean;
|
|
71
|
-
/** Llama a `onPress` solo si el botón es interactivo. */
|
|
72
|
-
press: () => void;
|
|
73
11
|
}
|
|
12
|
+
/** Hacia dónde mueve el resaltado una tecla: flechas, Inicio, Fin, AvPág y RePág. */
|
|
13
|
+
export declare const optionDirections: readonly ["next", "previous", "first", "last", "nextPage", "previousPage"];
|
|
14
|
+
export type OptionDirection = (typeof optionDirections)[number];
|
|
15
|
+
/** Cuántas opciones salta AvPág o RePág. */
|
|
16
|
+
export declare const OPTION_PAGE_SIZE = 10;
|
|
74
17
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
18
|
+
* La opción a la que lleva una tecla desde la actual, saltando las deshabilitadas. No da
|
|
19
|
+
* la vuelta: al llegar a un extremo se queda en él (ADR-042). Si no hay ninguna a la
|
|
20
|
+
* que ir, devuelve la actual.
|
|
78
21
|
*/
|
|
79
|
-
export declare function
|
|
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
|
-
}
|
|
22
|
+
export declare function getOptionInDirection(options: readonly NavigableOption[], current: string | undefined, direction: OptionDirection): string | undefined;
|
|
90
23
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
24
|
+
* La opción habilitada cuyo texto empieza por lo que el usuario ha escrito, o `undefined`
|
|
25
|
+
* si no hay ninguna.
|
|
26
|
+
*
|
|
27
|
+
* - Una sola letra busca a partir de la siguiente a la actual, así que pulsarla varias
|
|
28
|
+
* veces recorre las que empiezan por ella.
|
|
29
|
+
* - Un texto más largo se queda en la actual mientras siga coincidiendo.
|
|
30
|
+
* - La misma letra repetida ("bb") que no es el principio de ninguna opción vale como
|
|
31
|
+
* pulsarla otra vez.
|
|
94
32
|
*/
|
|
95
|
-
export declare function
|
|
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;
|
|
33
|
+
export declare function findOptionByText(options: readonly NavigableOption[], text: string, current?: string): string | undefined;
|
|
183
34
|
//#endregion
|
|
184
35
|
//#region src/tabs/navigation.d.ts
|
|
185
36
|
/** Lo mínimo que hace falta saber de una pestaña para moverse entre ellas. */
|
|
@@ -199,37 +50,6 @@ export declare function firstEnabledTab(items: readonly NavigableTab[]): string
|
|
|
199
50
|
*/
|
|
200
51
|
export declare function getTabInDirection(items: readonly NavigableTab[], current: string, direction: TabDirection): string;
|
|
201
52
|
//#endregion
|
|
202
|
-
//#region src/types/ui-provider.d.ts
|
|
203
|
-
/** Modo de tema que acepta `UIProvider` (ADR-010). */
|
|
204
|
-
export declare const themeModes: readonly ["light", "dark", "system"];
|
|
205
|
-
export type ThemeMode = (typeof themeModes)[number];
|
|
206
|
-
/** Esquema resuelto: siempre uno de los temas definidos en tokens. */
|
|
207
|
-
export type ColorScheme = ThemeName;
|
|
208
|
-
export interface UIProviderProps {
|
|
209
|
-
/** Tema claro, oscuro o el del sistema (por defecto `system`). */
|
|
210
|
-
theme?: ThemeMode | undefined;
|
|
211
|
-
/** Marca registrada en tokens. Sin marca se usa la identidad por defecto. */
|
|
212
|
-
brand?: BrandName | undefined;
|
|
213
|
-
children: ReactNode;
|
|
214
|
-
}
|
|
215
|
-
//#endregion
|
|
216
|
-
//#region src/theme/context.d.ts
|
|
217
|
-
interface UIContextValue {
|
|
218
|
-
theme: Theme;
|
|
219
|
-
colorScheme: ColorScheme;
|
|
220
|
-
mode: ThemeMode;
|
|
221
|
-
brand: BrandName | undefined;
|
|
222
|
-
}
|
|
223
|
-
export declare function createUIContextValue(mode: ThemeMode, systemScheme: ColorScheme, brand?: BrandName): UIContextValue;
|
|
224
|
-
/** Sin `UIProvider` se usa el tema claro por defecto, para que los componentes funcionen aislados. */
|
|
225
|
-
export declare const UIContext: import("react").Context<UIContextValue>;
|
|
226
|
-
export declare function useUIContext(): UIContextValue;
|
|
227
|
-
/** Tema resuelto (tokens con la marca aplicada). Imprescindible en las vistas nativas (ADR-008). */
|
|
228
|
-
export declare function useTheme(): Theme;
|
|
229
|
-
/** `'light' | 'dark'` ya resuelto, también con `theme="system"`. */
|
|
230
|
-
export declare function useColorScheme(): ColorScheme;
|
|
231
|
-
export declare function useBrand(): BrandName | undefined;
|
|
232
|
-
//#endregion
|
|
233
53
|
//#region src/theme/resolve-theme.d.ts
|
|
234
54
|
/** Combina los overrides de una marca sobre un tema (ADR-010). Los arrays (sombras) se sustituyen enteros. */
|
|
235
55
|
export declare function mergeTheme(base: Theme, overrides: ThemeOverrides): Theme;
|
|
@@ -237,90 +57,6 @@ export declare function mergeTheme(base: Theme, overrides: ThemeOverrides): Them
|
|
|
237
57
|
export declare function resolveTheme(scheme: ThemeName, brand?: BrandName): Theme;
|
|
238
58
|
export declare function resolveColorScheme(mode: ThemeMode, systemScheme: ColorScheme): ColorScheme;
|
|
239
59
|
//#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
60
|
//#region src/types/alert.d.ts
|
|
325
61
|
interface AlertBaseProps {
|
|
326
62
|
/** Qué comunica (por defecto `info`). Fija el color y el icono. */
|
|
@@ -705,7 +441,7 @@ export interface SelectOption {
|
|
|
705
441
|
label: string;
|
|
706
442
|
disabled?: boolean | undefined;
|
|
707
443
|
}
|
|
708
|
-
/** Contrato de `Select`: elegir una opción de una lista (ADR-
|
|
444
|
+
/** Contrato de `Select`: elegir una opción de una lista (ADR-042). */
|
|
709
445
|
export interface SelectProps {
|
|
710
446
|
options: readonly SelectOption[];
|
|
711
447
|
/** Opción elegida, controlada por la app. Sin ella, guarda su propio estado (ADR-037). */
|
|
@@ -884,4 +620,4 @@ export interface TextAreaProps {
|
|
|
884
620
|
testID?: string | undefined;
|
|
885
621
|
}
|
|
886
622
|
//#endregion
|
|
887
|
-
export type
|
|
623
|
+
export { ColorScheme, FeedbackTone, FormFieldContext, FormFieldControl, FormFieldControlOptions, FormFieldValue, FormFieldValueOptions, LinkPressEvent, LinkProps, LinkUnderline, TOAST_DEFAULT_DURATION, TOAST_MAX_VISIBLE, TextAlign, TextColorToken, TextProps, TextVariant, TextVariantStyle, ThemeMode, ToastAction, ToastApi, ToastContext, ToastItem, ToastOptions, type ToastStore, UIContext, type UIContextValue, UIProviderProps, UseButtonOptions, UseButtonResult, UseControllableStateOptions, UseLinkOptions, UseLinkResult, createFormFieldValue, createToastStore, createUIContextValue, feedbackTones, isFeedbackTone, linkUnderlines, resolveFormFieldControl, textAligns, textColors, textVariantStyles, textVariants, themeModes, useBrand, useButton, useColorScheme, useControllableState, useFormFieldControl, useLink, useTheme, useToast, useUIContext };
|
package/dist/index.js
CHANGED
|
@@ -1,117 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
/** `null` fuera de un `FormField`. */
|
|
24
|
-
const FormFieldContext = createContext(null);
|
|
1
|
+
|
|
2
|
+
import { n as resolveColorScheme, r as resolveTheme, t as mergeTheme } from "./resolve-theme-DbIlzBBD.js";
|
|
3
|
+
import { themes } from "@satellatickets/tokens";
|
|
4
|
+
export * from "./client.js";
|
|
5
|
+
//#region src/select/navigation.ts
|
|
6
|
+
/** Hacia dónde mueve el resaltado una tecla: flechas, Inicio, Fin, AvPág y RePág. */
|
|
7
|
+
const optionDirections = [
|
|
8
|
+
"next",
|
|
9
|
+
"previous",
|
|
10
|
+
"first",
|
|
11
|
+
"last",
|
|
12
|
+
"nextPage",
|
|
13
|
+
"previousPage"
|
|
14
|
+
];
|
|
15
|
+
/** Cuántas opciones salta AvPág o RePág. */
|
|
16
|
+
const OPTION_PAGE_SIZE = 10;
|
|
17
|
+
const steps = {
|
|
18
|
+
next: 1,
|
|
19
|
+
previous: -1,
|
|
20
|
+
nextPage: 10,
|
|
21
|
+
previousPage: -10
|
|
22
|
+
};
|
|
25
23
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* La opción a la que lleva una tecla desde la actual, saltando las deshabilitadas. No da
|
|
25
|
+
* la vuelta: al llegar a un extremo se queda en él (ADR-042). Si no hay ninguna a la
|
|
26
|
+
* que ir, devuelve la actual.
|
|
29
27
|
*/
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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);
|
|
28
|
+
function getOptionInDirection(options, current, direction) {
|
|
29
|
+
const enabled = options.filter((option) => option.disabled !== true).map(({ value }) => value);
|
|
30
|
+
const [first] = enabled;
|
|
31
|
+
const last = enabled[enabled.length - 1];
|
|
32
|
+
if (first === void 0 || last === void 0) return current;
|
|
33
|
+
if (direction === "first") return first;
|
|
34
|
+
if (direction === "last") return last;
|
|
35
|
+
const step = steps[direction];
|
|
36
|
+
const index = current === void 0 ? -1 : enabled.indexOf(current);
|
|
37
|
+
if (index === -1) return step > 0 ? first : last;
|
|
38
|
+
return enabled[Math.min(Math.max(index + step, 0), enabled.length - 1)] ?? current;
|
|
55
39
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
* Comportamiento de `Button` común a web y nativo: un botón deshabilitado o que
|
|
60
|
-
* está cargando no dispara `onPress`. Cada vista añade su accesibilidad
|
|
61
|
-
* (`disabled`/`aria-busy` en web, `accessibilityState` en nativo).
|
|
62
|
-
*/
|
|
63
|
-
function useButton({ disabled = false, loading = false, onPress }) {
|
|
64
|
-
const interactive = !disabled && !loading;
|
|
65
|
-
return {
|
|
66
|
-
disabled,
|
|
67
|
-
loading,
|
|
68
|
-
interactive,
|
|
69
|
-
press: useCallback(() => {
|
|
70
|
-
if (interactive) onPress?.();
|
|
71
|
-
}, [interactive, onPress])
|
|
72
|
-
};
|
|
40
|
+
/** Sin mayúsculas ni acentos: al escribir "avila" se encuentra "Ávila". */
|
|
41
|
+
function normalize(text) {
|
|
42
|
+
return text.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLocaleLowerCase();
|
|
73
43
|
}
|
|
74
|
-
//#endregion
|
|
75
|
-
//#region src/hooks/use-controllable-state.ts
|
|
76
44
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
45
|
+
* La opción habilitada cuyo texto empieza por lo que el usuario ha escrito, o `undefined`
|
|
46
|
+
* si no hay ninguna.
|
|
47
|
+
*
|
|
48
|
+
* - Una sola letra busca a partir de la siguiente a la actual, así que pulsarla varias
|
|
49
|
+
* veces recorre las que empiezan por ella.
|
|
50
|
+
* - Un texto más largo se queda en la actual mientras siga coincidiendo.
|
|
51
|
+
* - La misma letra repetida ("bb") que no es el principio de ninguna opción vale como
|
|
52
|
+
* pulsarla otra vez.
|
|
80
53
|
*/
|
|
81
|
-
function
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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]) };
|
|
54
|
+
function findOptionByText(options, text, current) {
|
|
55
|
+
const query = normalize(text);
|
|
56
|
+
const [letter] = query;
|
|
57
|
+
if (letter === void 0) return void 0;
|
|
58
|
+
const enabled = options.filter((option) => option.disabled !== true);
|
|
59
|
+
const index = enabled.findIndex((option) => option.value === current);
|
|
60
|
+
const startingWith = (prefix, from) => [...enabled.slice(from), ...enabled.slice(0, from)].find((option) => normalize(option.label).startsWith(prefix))?.value;
|
|
61
|
+
if (query.length === 1) return startingWith(letter, index + 1);
|
|
62
|
+
const match = startingWith(query, Math.max(index, 0));
|
|
63
|
+
if (match !== void 0) return match;
|
|
64
|
+
return [...query].every((char) => char === letter) ? startingWith(letter, index + 1) : void 0;
|
|
115
65
|
}
|
|
116
66
|
//#endregion
|
|
117
67
|
//#region src/tabs/navigation.ts
|
|
@@ -144,79 +94,6 @@ function getTabInDirection(items, current, direction) {
|
|
|
144
94
|
return enabled[(index + (direction === "next" ? 1 : -1) + enabled.length) % enabled.length] ?? current;
|
|
145
95
|
}
|
|
146
96
|
//#endregion
|
|
147
|
-
//#region src/theme/resolve-theme.ts
|
|
148
|
-
function isPlainObject(value) {
|
|
149
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
150
|
-
}
|
|
151
|
-
function merge(base, overrides) {
|
|
152
|
-
const result = { ...base };
|
|
153
|
-
for (const [key, value] of Object.entries(overrides)) {
|
|
154
|
-
if (value === void 0) continue;
|
|
155
|
-
const current = base[key];
|
|
156
|
-
result[key] = isPlainObject(current) && isPlainObject(value) ? merge(current, value) : value;
|
|
157
|
-
}
|
|
158
|
-
return result;
|
|
159
|
-
}
|
|
160
|
-
/** Combina los overrides de una marca sobre un tema (ADR-010). Los arrays (sombras) se sustituyen enteros. */
|
|
161
|
-
function mergeTheme(base, overrides) {
|
|
162
|
-
return merge(base, overrides);
|
|
163
|
-
}
|
|
164
|
-
const cache = /* @__PURE__ */ new Map();
|
|
165
|
-
/** Tema resuelto para un esquema y una marca; memoizado para que la identidad sea estable. */
|
|
166
|
-
function resolveTheme(scheme, brand) {
|
|
167
|
-
const key = `${scheme}/${brand ?? ""}`;
|
|
168
|
-
const cached = cache.get(key);
|
|
169
|
-
if (cached) return cached;
|
|
170
|
-
const base = themes[scheme];
|
|
171
|
-
const overrides = brand === void 0 ? void 0 : brands[brand]?.[scheme];
|
|
172
|
-
const resolved = overrides === void 0 ? base : mergeTheme(base, overrides);
|
|
173
|
-
cache.set(key, resolved);
|
|
174
|
-
return resolved;
|
|
175
|
-
}
|
|
176
|
-
function resolveColorScheme(mode, systemScheme) {
|
|
177
|
-
return mode === "system" ? systemScheme : mode;
|
|
178
|
-
}
|
|
179
|
-
//#endregion
|
|
180
|
-
//#region src/theme/context.ts
|
|
181
|
-
function createUIContextValue(mode, systemScheme, brand) {
|
|
182
|
-
const colorScheme = resolveColorScheme(mode, systemScheme);
|
|
183
|
-
return {
|
|
184
|
-
theme: resolveTheme(colorScheme, brand),
|
|
185
|
-
colorScheme,
|
|
186
|
-
mode,
|
|
187
|
-
brand
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
/** Sin `UIProvider` se usa el tema claro por defecto, para que los componentes funcionen aislados. */
|
|
191
|
-
const UIContext = createContext(createUIContextValue("light", "light"));
|
|
192
|
-
function useUIContext() {
|
|
193
|
-
return useContext(UIContext);
|
|
194
|
-
}
|
|
195
|
-
/** Tema resuelto (tokens con la marca aplicada). Imprescindible en las vistas nativas (ADR-008). */
|
|
196
|
-
function useTheme() {
|
|
197
|
-
return useContext(UIContext).theme;
|
|
198
|
-
}
|
|
199
|
-
/** `'light' | 'dark'` ya resuelto, también con `theme="system"`. */
|
|
200
|
-
function useColorScheme() {
|
|
201
|
-
return useContext(UIContext).colorScheme;
|
|
202
|
-
}
|
|
203
|
-
function useBrand() {
|
|
204
|
-
return useContext(UIContext).brand;
|
|
205
|
-
}
|
|
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
97
|
//#region src/toast/store.ts
|
|
221
98
|
/** Milisegundos que un toast permanece visible si no se indica otra cosa. */
|
|
222
99
|
const TOAST_DEFAULT_DURATION = 5e3;
|
|
@@ -573,4 +450,4 @@ const themeModes = [
|
|
|
573
450
|
"system"
|
|
574
451
|
];
|
|
575
452
|
//#endregion
|
|
576
|
-
export {
|
|
453
|
+
export { OPTION_PAGE_SIZE, TOAST_DEFAULT_DURATION, TOAST_MAX_VISIBLE, backgroundTokens, badgeVariants, borderColorTokens, buttonIconSize, buttonVariants, cardVariants, controlSizes, createToastStore, dividerOrientations, feedbackTones, findOptionByText, firstEnabledTab, getOptionInDirection, getTabInDirection, iconButtonIconSize, iconSizePx, iconSizes, inputIconSize, inputTypes, isFeedbackTone, linkUnderlines, mergeTheme, modalPresentations, optionDirections, radiusTokens, resolveColorScheme, resolveTheme, shadowTokens, skeletonShapes, spaceTokens, spinnerSizePx, spinnerSizes, stackAligns, stackDirections, stackJustifies, tabDirections, textAligns, textColors, textVariantStyles, textVariants, themeModes };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
import { brands, themes } from "@satellatickets/tokens";
|
|
3
|
+
//#region src/theme/resolve-theme.ts
|
|
4
|
+
function isPlainObject(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function merge(base, overrides) {
|
|
8
|
+
const result = { ...base };
|
|
9
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
10
|
+
if (value === void 0) continue;
|
|
11
|
+
const current = base[key];
|
|
12
|
+
result[key] = isPlainObject(current) && isPlainObject(value) ? merge(current, value) : value;
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
/** Combina los overrides de una marca sobre un tema (ADR-010). Los arrays (sombras) se sustituyen enteros. */
|
|
17
|
+
function mergeTheme(base, overrides) {
|
|
18
|
+
return merge(base, overrides);
|
|
19
|
+
}
|
|
20
|
+
const cache = /* @__PURE__ */ new Map();
|
|
21
|
+
/** Tema resuelto para un esquema y una marca; memoizado para que la identidad sea estable. */
|
|
22
|
+
function resolveTheme(scheme, brand) {
|
|
23
|
+
const key = `${scheme}/${brand ?? ""}`;
|
|
24
|
+
const cached = cache.get(key);
|
|
25
|
+
if (cached) return cached;
|
|
26
|
+
const base = themes[scheme];
|
|
27
|
+
const overrides = brand === void 0 ? void 0 : brands[brand]?.[scheme];
|
|
28
|
+
const resolved = overrides === void 0 ? base : mergeTheme(base, overrides);
|
|
29
|
+
cache.set(key, resolved);
|
|
30
|
+
return resolved;
|
|
31
|
+
}
|
|
32
|
+
function resolveColorScheme(mode, systemScheme) {
|
|
33
|
+
return mode === "system" ? systemScheme : mode;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { resolveColorScheme as n, resolveTheme as r, mergeTheme as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@satellatickets/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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": {
|