kaizen-lib 0.2.1 → 0.2.2
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 +23 -1
- package/package.json +1 -1
- package/src/ui/LangSelector.tsx +71 -0
- package/src/ui/index.ts +2 -0
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ styled-components con `moduleResolution: "bundler"`, así que lo transpilan ello
|
|
|
12
12
|
|---|---|---|
|
|
13
13
|
| `kaizen-lib/tokens` | Referencias `var(--kz-*)` tipadas | listo |
|
|
14
14
|
| `kaizen-lib/tokens.css` | Valores por defecto, tema oscuro y claro | listo |
|
|
15
|
-
| `kaizen-lib/ui` | Componentes (`IconButton`, `ReactionButton`, `Medidor`, `Relieve`) | en curso |
|
|
15
|
+
| `kaizen-lib/ui` | Componentes (`IconButton`, `ReactionButton`, `Medidor`, `Relieve`, `LangSelector`) | en curso |
|
|
16
16
|
|
|
17
17
|
## Instalación
|
|
18
18
|
|
|
@@ -171,6 +171,28 @@ intercepta el `as` de cualquier componente que envuelve, así que envolverlo as
|
|
|
171
171
|
saltear toda su lógica. El relieve es neutro por defecto (negro/blanco) — un producto con
|
|
172
172
|
marca lo tiñe redefiniendo esos tres tokens, igual que con cualquier otro.
|
|
173
173
|
|
|
174
|
+
```tsx
|
|
175
|
+
import { LangSelector } from 'kaizen-lib/ui';
|
|
176
|
+
|
|
177
|
+
<LangSelector
|
|
178
|
+
actual={i18n.language}
|
|
179
|
+
onChange={(codigo) => i18n.changeLanguage(codigo)}
|
|
180
|
+
opciones={[
|
|
181
|
+
{ codigo: 'es', nombre: 'Español', icono: <ReactCountryFlag countryCode="AR" /> },
|
|
182
|
+
{ codigo: 'en', nombre: 'English', icono: <ReactCountryFlag countryCode="US" /> },
|
|
183
|
+
]}
|
|
184
|
+
/>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**`LangSelector`** es el botón de idioma de una topbar: cicla a la siguiente opción en
|
|
188
|
+
cada tap y muestra el ícono del idioma actual, con el relieve de `Relieve` ya incluido
|
|
189
|
+
(a diferencia de `IconButton`, acá no hace falta envolverlo aparte — todo consumidor lo
|
|
190
|
+
quería). No trae banderas — mismo criterio que `IconButton` no trae íconos —, así que
|
|
191
|
+
`icono` es cosa del producto; `react-country-flag` (ya usado en tuxon-front) es una
|
|
192
|
+
opción probada. `onChange` recibe el código de la opción siguiente; qué hacer con eso
|
|
193
|
+
(`i18n.changeLanguage`, `next-intl`, lo que sea) es del producto — la librería no sabe
|
|
194
|
+
qué mecanismo de traducción hay atrás.
|
|
195
|
+
|
|
174
196
|
## Desarrollo
|
|
175
197
|
|
|
176
198
|
```bash
|
package/package.json
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
import { IconButton } from './IconButton';
|
|
5
|
+
import { Relieve } from './Relieve';
|
|
6
|
+
import type { IconButtonSize } from './shell';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Una opción del selector: el código de idioma, su nombre (para el nombre
|
|
10
|
+
* accesible) y el ícono que lo representa. La librería no trae banderas —
|
|
11
|
+
* mismo criterio que `IconButton` no trae íconos — porque una bandera bien
|
|
12
|
+
* hecha es un SVG por país, no algo que valga la pena embeber en un paquete
|
|
13
|
+
* sin build. `react-country-flag` (ya usado en tuxon-front) es una opción
|
|
14
|
+
* probada; cualquier ícono sirve.
|
|
15
|
+
*/
|
|
16
|
+
export type OpcionDeIdioma<T extends string> = {
|
|
17
|
+
codigo: T;
|
|
18
|
+
/** Nombre del idioma, en ese idioma ("English", no "Inglés"). */
|
|
19
|
+
nombre: string;
|
|
20
|
+
icono: ReactNode;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type Props<T extends string> = {
|
|
24
|
+
opciones: OpcionDeIdioma<T>[];
|
|
25
|
+
actual: T;
|
|
26
|
+
onChange: (codigo: T) => void;
|
|
27
|
+
size?: IconButtonSize;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* El botón de idioma de una topbar: cicla a la siguiente opción en cada tap
|
|
32
|
+
* y muestra el ícono del idioma actual. No es un `<select>` ni un menú — es
|
|
33
|
+
* el mismo patrón que ya tenían, cada uno por su cuenta, mixbol-front,
|
|
34
|
+
* nsandev-front, tutipoker-school-front y valle-verde antes de esto.
|
|
35
|
+
*
|
|
36
|
+
* Trae el relieve neumórfico (`Relieve`) incluido: a diferencia de
|
|
37
|
+
* `IconButton`, acá no hace falta envolverlo aparte, porque el 100% de los
|
|
38
|
+
* consumidores lo quería.
|
|
39
|
+
*
|
|
40
|
+
* `onChange` recibe el CÓDIGO de la opción siguiente — qué hacer con eso
|
|
41
|
+
* (`i18n.changeLanguage`, guardarlo en `localStorage`, lo que sea) es del
|
|
42
|
+
* producto. La librería no sabe qué mecanismo de traducción hay atrás.
|
|
43
|
+
*
|
|
44
|
+
* ```tsx
|
|
45
|
+
* <LangSelector
|
|
46
|
+
* actual={idiomaActual}
|
|
47
|
+
* onChange={(codigo) => i18n.changeLanguage(codigo)}
|
|
48
|
+
* opciones={[
|
|
49
|
+
* { codigo: 'es', nombre: 'Español', icono: <ReactCountryFlag countryCode="AR" /> },
|
|
50
|
+
* { codigo: 'en', nombre: 'English', icono: <ReactCountryFlag countryCode="US" /> },
|
|
51
|
+
* ]}
|
|
52
|
+
* />
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export function LangSelector<T extends string>({ opciones, actual, onChange, size = 'lg' }: Props<T>) {
|
|
56
|
+
// Sin opciones no hay nada que ciclar. Defensivo: un selector de idioma
|
|
57
|
+
// vacío es un error de uso, no algo que la librería deba explicar.
|
|
58
|
+
if (opciones.length === 0) return null;
|
|
59
|
+
|
|
60
|
+
const indiceActual = opciones.findIndex((opcion) => opcion.codigo === actual);
|
|
61
|
+
const opcionActual = opciones[indiceActual < 0 ? 0 : indiceActual] as OpcionDeIdioma<T>;
|
|
62
|
+
const siguiente = opciones[(indiceActual + 1 + opciones.length) % opciones.length] as OpcionDeIdioma<T>;
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<Relieve>
|
|
66
|
+
<IconButton size={size} label={`Cambiar idioma a ${siguiente.nombre}`} onClick={() => onChange(siguiente.codigo)}>
|
|
67
|
+
{opcionActual.icono}
|
|
68
|
+
</IconButton>
|
|
69
|
+
</Relieve>
|
|
70
|
+
);
|
|
71
|
+
}
|
package/src/ui/index.ts
CHANGED
|
@@ -5,3 +5,5 @@ export type { MedidorSentido } from './Medidor';
|
|
|
5
5
|
export { Relieve } from './Relieve';
|
|
6
6
|
export { ReactionButton } from './ReactionButton';
|
|
7
7
|
export type { ReactionTone } from './ReactionButton';
|
|
8
|
+
export { LangSelector } from './LangSelector';
|
|
9
|
+
export type { OpcionDeIdioma } from './LangSelector';
|