@studiolxd/brand 42.0.0 → 44.0.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/CHANGELOG.md +113 -0
- package/dist/_shared/datepicker.js +75 -78
- package/dist/_shared/imagecropdialog.js +124 -123
- package/dist/_shared/validate.js +31 -5
- package/dist/_types/atoms/FileUpload/FileUpload.d.ts +79 -11
- package/dist/_types/atoms/FileUpload/validate.d.ts +36 -3
- package/dist/_types/atoms/TimeSelect/TimeSelect.d.ts +34 -6
- package/dist/_types/messages/BrandMessages.d.ts +13 -1
- package/dist/_types/messages/index.d.ts +1 -1
- package/dist/_types/molecules/AvatarUpload/AvatarUpload.d.ts +123 -25
- package/dist/_types/molecules/Calendar/Calendar.d.ts +44 -13
- package/dist/_types/molecules/CalendarPlanner/CalendarPlanner.d.ts +5 -4
- package/dist/_types/molecules/CalendarRoster/CalendarRoster.d.ts +5 -4
- package/dist/_types/molecules/DatePicker/DatePicker.d.ts +56 -26
- package/dist/_types/molecules/DatePicker/dateMask.d.ts +9 -2
- package/dist/_types/molecules/DateTimeField/DateTimeField.d.ts +12 -12
- package/dist/_types/molecules/ImageCropDialog/ImageCropDialog.d.ts +28 -4
- package/dist/_types/molecules/TimeField/TimeField.d.ts +9 -2
- package/dist/_types/molecules/_shared/calendarGrid.d.ts +6 -2
- package/dist/avatar-upload.js +98 -95
- package/dist/calendar-planner.js +47 -46
- package/dist/calendar-roster.js +62 -61
- package/dist/calendar.js +87 -86
- package/dist/file-upload.js +120 -117
- package/dist/time-select.js +57 -56
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,119 @@ El paquete sigue [semver](https://semver.org/lang/es/): **patch** para bug fixes
|
|
|
7
7
|
regeneración de `dist`, **minor** para componentes/props/variantes/tokens nuevos, **major**
|
|
8
8
|
para breaking changes.
|
|
9
9
|
|
|
10
|
+
## [44.0.0] — 2026-09-15
|
|
11
|
+
|
|
12
|
+
> **Major.** Quinta familia al proveedor de textos: las subidas. `FileUpload`,
|
|
13
|
+
> `AvatarUpload` e `ImageCropDialog` dejan de traer castellano puesto, el peso de un
|
|
14
|
+
> archivo lo escribe el `locale`, y una lista de formatos lleva la conjunción de su idioma.
|
|
15
|
+
|
|
16
|
+
### Las subidas leen del proveedor
|
|
17
|
+
|
|
18
|
+
Tres espacios nuevos en `BrandMessages`: **`fileUpload`**, **`imageCropDialog`** y
|
|
19
|
+
**`avatarUpload`**, veintidós claves. `CalendarPlanner` y `CalendarRoster` no estrenan
|
|
20
|
+
espacio: sus dos flechas leen `calendar.previousMonth` y `calendar.nextMonth`, que es
|
|
21
|
+
literalmente el mismo texto que el del `Calendar`. Mismo orden —**prop → proveedor →
|
|
22
|
+
error**— y misma naturaleza: incompatible **en tiempo de compilación**.
|
|
23
|
+
|
|
24
|
+
Un cambio incompatible más, de props: `AvatarUpload.cropTitle` pasa a **obligatorio**. El
|
|
25
|
+
diálogo no sabe qué se recorta —«Recorta tu foto», «Recorta tu logo»—, y eso es contenido de
|
|
26
|
+
la pantalla, no del sistema.
|
|
27
|
+
|
|
28
|
+
### «2,5 MB» tiene dos mitades
|
|
29
|
+
|
|
30
|
+
`formatBytes` hacía `toFixed(1) + ' KB'`: punto decimal inglés cableado, en todos los
|
|
31
|
+
idiomas. Ahora el peso lo escribe `Intl.NumberFormat` con `style: 'unit'` en el `locale`
|
|
32
|
+
del componente, y al catálogo va solo la plantilla que lo envuelve («máx. {size}»). Con el
|
|
33
|
+
mismo catálogo inglés, `es-ES` escribe «max. 2,5 MB» y `en-US` «max. 2.5 MB». Es la regla
|
|
34
|
+
de la v43 aplicada a otra cosa: *si cambia al cambiar de idioma es cromo; si cambia al
|
|
35
|
+
cambiar de país es formato.*
|
|
36
|
+
|
|
37
|
+
Efecto de asumir CLDR: las unidades son las suyas —«kB» y no «KB»— y por debajo de un
|
|
38
|
+
kilobyte un `en-US` escribe «500 byte». La alternativa era volver a decidir a mano la
|
|
39
|
+
colocación del sufijo, que es justo lo que la regla prohíbe.
|
|
40
|
+
|
|
41
|
+
### Dos textos que no se pueden traducir por separado
|
|
42
|
+
|
|
43
|
+
`AvatarUpload` tiene un botón con texto visible («Subir») y un nombre accesible («Subir el
|
|
44
|
+
logo»), y WCAG 2.5.3 exige que el segundo **contenga** al primero. Traducirlos en dos
|
|
45
|
+
sitios distintos es dejar que una traducción los despareje sin que falle nada; concatenarlos
|
|
46
|
+
en el componente es castellano disfrazado, porque el orden es del idioma —«Subir el logo»
|
|
47
|
+
lleva el verbo delante, «das Logo hochladen» lo lleva detrás—. Así que van los dos al
|
|
48
|
+
catálogo, `avatarUpload.button` y `avatarUpload.buttonFor(subject)`, con la regla escrita
|
|
49
|
+
al lado; la pantalla solo aporta el sujeto. El aviso de consola en desarrollo sigue
|
|
50
|
+
vigilando la contención.
|
|
51
|
+
|
|
52
|
+
### Una lista lleva la conjunción de su idioma
|
|
53
|
+
|
|
54
|
+
Los formatos admitidos se unían con `join(', ')` y no ponían conjunción en ningún idioma:
|
|
55
|
+
«JPEG, PNG, WEBP». Ahora es `Intl.ListFormat` con `type: 'disjunction'`: «JPEG, PNG o
|
|
56
|
+
WEBP», «JPEG, PNG, or WEBP», «JPEG, PNG oder WEBP».
|
|
57
|
+
|
|
58
|
+
### Lo que se queda como prop
|
|
59
|
+
|
|
60
|
+
`ImageCropDialog.title`, `cancelLabel` y `confirmLabel` eran ya obligatorias y sin default,
|
|
61
|
+
y son el modelo de toda la ola: el diálogo no sabe qué se recorta ni qué pasa al confirmar.
|
|
62
|
+
En `AvatarUpload`, en cambio, `cropCancel` y `cropConfirm` sí salen del catálogo, y no es
|
|
63
|
+
incoherencia: esa subida sí sabe lo que confirma —se guarda un recorte—, y vale igual en
|
|
64
|
+
todas las pantallas.
|
|
65
|
+
|
|
66
|
+
Quedan dos reenvíos puros a una pieza sin migrar: `ImageCropDialog.closeLabel` y
|
|
67
|
+
`AvatarUpload.cropCloseLabel` van al `Modal`, que aún trae su «Cerrar». Es la deuda que
|
|
68
|
+
esta ola deja apuntada, y es por donde sigue la siguiente.
|
|
69
|
+
|
|
70
|
+
## [43.0.0] — 2026-09-15
|
|
71
|
+
|
|
72
|
+
> **Major.** Cuarta familia al proveedor de textos: fecha y hora. `Calendar`, `DatePicker`
|
|
73
|
+
> y `TimeSelect` dejan de traer castellano puesto, y con ellos se cierran los reenvíos que
|
|
74
|
+
> las olas anteriores dejaron inventariados.
|
|
75
|
+
|
|
76
|
+
### Fecha y hora leen del proveedor
|
|
77
|
+
|
|
78
|
+
Tres espacios nuevos en `BrandMessages`: **`calendar`** (previousMonth, nextMonth,
|
|
79
|
+
previousYears, nextYears, yearGrid), **`datePicker`** (openCalendar, invalid, calendar y
|
|
80
|
+
las letras de la máscara) y **`timeSelect`** (hours, minutes y sus máscaras). Los campos
|
|
81
|
+
que los envuelven —`DatePickerField`, `DateTimeField`, `TimeField`— no pierden props: sus
|
|
82
|
+
reenvíos quedan como anulación puntual, pero ya no hay que enhebrar nada para traducir,
|
|
83
|
+
porque el proveedor llega por contexto a la pieza que pinta el texto. Se ha retirado
|
|
84
|
+
`SPANISH_MASK_LETTERS`, el último juego de letras castellanas vivo en el código.
|
|
85
|
+
|
|
86
|
+
Mismo orden que en las tres olas anteriores —**prop → proveedor → error**— y misma
|
|
87
|
+
naturaleza: incompatible **en tiempo de compilación**. El texto que no se pinta no se
|
|
88
|
+
exige: un `Calendar` sin navegación no pide las flechas, un `DatePicker` con fecha válida no
|
|
89
|
+
pide el aviso, un `TimeSelect` con hora no pide las máscaras.
|
|
90
|
+
|
|
91
|
+
### Una máscara tiene dos mitades
|
|
92
|
+
|
|
93
|
+
`dd/mm/aaaa` no es una cosa, son dos decididas en sitios distintos. **El orden y el
|
|
94
|
+
separador son formato**: salen del `locale` vía `Intl.DateTimeFormat`, y una aplicación en
|
|
95
|
+
inglés que enseñe fechas españolas las quiere en orden español. **Las letras son idioma**:
|
|
96
|
+
`aaaa` es «año», `yyyy` es *year*, `jjjj` es *Jahr* — la abreviatura de una palabra, y se
|
|
97
|
+
traduce. Por eso el catálogo guarda las tres letras sueltas y nunca la máscara montada: la
|
|
98
|
+
arma el componente poniendo las letras en el orden del `locale`.
|
|
99
|
+
|
|
100
|
+
Lo mismo con `HH/MM`: parecen notación técnica, pero son la inicial de una palabra, y en
|
|
101
|
+
alemán son `SS/MM`. Lo que no se traduce es el dibujo —dos cifras, la hora antes que el
|
|
102
|
+
minuto, dos puntos en medio—.
|
|
103
|
+
|
|
104
|
+
La regla, en una frase, escrita en `Foundations › Internacionalización`: **si cambia al
|
|
105
|
+
cambiar de idioma es cromo; si cambia al cambiar de país es formato.**
|
|
106
|
+
|
|
107
|
+
### Lo que se queda como prop
|
|
108
|
+
|
|
109
|
+
`label`, `helperText` y `errorMessage` de los tres campos; `gridLabel` del `Calendar`, que
|
|
110
|
+
nombra a ESE calendario («Fecha de alta») y sin el cual la rejilla toma el título del mes,
|
|
111
|
+
que ya viene del `locale`; `calendarLabel` cuando lo pone un campo, porque es su etiqueta;
|
|
112
|
+
y el `placeholder` del `DatePicker` cuando dice algo del campo («Desde»), que sustituye a la
|
|
113
|
+
máscara entera.
|
|
114
|
+
|
|
115
|
+
### Pendiente, anotado
|
|
116
|
+
|
|
117
|
+
`CalendarPlanner` y `CalendarRoster` siguen con «Mes anterior» y «Mes siguiente» cableados:
|
|
118
|
+
es el mismo texto que `Calendar` y pueden leer de `calendar.*` tal cual. Y `TimeSelect` es
|
|
119
|
+
de 24 horas por construcción; el reloj de 12 con AM/PM es cosa del `locale`, no del idioma,
|
|
120
|
+
y hoy una aplicación en inglés americano ve las horas en formato militar. No es un texto,
|
|
121
|
+
y queda por decidir.
|
|
122
|
+
|
|
10
123
|
## [42.0.0] — 2026-09-15
|
|
11
124
|
|
|
12
125
|
> **Major.** Tercera familia al proveedor de textos: los átomos y moléculas de formulario
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import '../datepicker.css';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { n as e } from "./brandmessagescontext.js";
|
|
3
|
+
import { Icon as t } from "../icon.js";
|
|
4
|
+
import { Input as n } from "../input.js";
|
|
5
|
+
import { Popover as r } from "../popover.js";
|
|
6
|
+
import { Calendar as i } from "../calendar.js";
|
|
7
|
+
import { forwardRef as a, useCallback as o, useId as s, useMemo as c, useRef as l, useState as u } from "react";
|
|
8
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
8
9
|
//#region src/stories/molecules/DatePicker/dateMask.ts
|
|
9
|
-
var
|
|
10
|
-
day: "dd",
|
|
11
|
-
month: "mm",
|
|
12
|
-
year: "aaaa"
|
|
13
|
-
}, p = /[]/g, m = new Date(2026, 8, 25);
|
|
10
|
+
var p = /[]/g, m = new Date(2026, 8, 25);
|
|
14
11
|
function h(e, t) {
|
|
15
12
|
return String(e).padStart(t, "0");
|
|
16
13
|
}
|
|
@@ -60,110 +57,110 @@ function g(e) {
|
|
|
60
57
|
function _(e) {
|
|
61
58
|
return `${String(e.getFullYear()).padStart(4, "0")}-${String(e.getMonth() + 1).padStart(2, "0")}-${String(e.getDate()).padStart(2, "0")}`;
|
|
62
59
|
}
|
|
63
|
-
var v =
|
|
64
|
-
let [
|
|
65
|
-
|
|
66
|
-
let
|
|
67
|
-
|
|
68
|
-
}, [
|
|
69
|
-
(
|
|
70
|
-
}, [
|
|
60
|
+
var v = a(function({ value: a, onChange: p, placeholder: m, maskLetters: h, invalidMessage: v, openCalendarLabel: y, minDate: b, maxDate: x, disabledDates: S, size: C = "md", disabled: w, readOnly: T, error: E = !1, locale: D = "es-ES", id: O, name: k, describedBy: ee, "aria-describedby": te, "aria-label": ne, calendarLabel: re, previousMonthLabel: ie, nextMonthLabel: ae, previousYearsLabel: A, nextYearsLabel: j, yearGridLabel: M, gridLabel: N, onBlur: P, className: F }, I) {
|
|
61
|
+
let L = e("datePicker"), [R, z] = u(!1), B = c(() => g(D), [D]), V = a instanceof Date ? B.format(a) : "", [H, U] = u(V), [W, G] = u(V);
|
|
62
|
+
V !== W && (G(V), U(V));
|
|
63
|
+
let K = l(null), q = o((e) => {
|
|
64
|
+
K.current = e, typeof I == "function" ? I(e) : I && (I.current = e);
|
|
65
|
+
}, [I]), J = H.trim(), Y = J ? B.parse(H) : null, X = J !== "" && !Y, oe = E || X, Z = `${s()}-date-picker-invalid`, se = [ee ?? te, X ? Z : void 0].filter(Boolean).join(" ") || void 0, ce = o((e) => {
|
|
66
|
+
(T || w) && e || z(e);
|
|
67
|
+
}, [w, T]), le = o((e) => {
|
|
71
68
|
let t = e.target.value;
|
|
72
|
-
if (
|
|
69
|
+
if (U(t), t.trim() === "") {
|
|
73
70
|
p?.(null);
|
|
74
71
|
return;
|
|
75
72
|
}
|
|
76
|
-
let n =
|
|
73
|
+
let n = B.parse(t);
|
|
77
74
|
n && p?.(n);
|
|
78
|
-
}, [
|
|
79
|
-
if (e.key === "ArrowDown" && !
|
|
80
|
-
e.preventDefault(),
|
|
75
|
+
}, [B, p]), ue = o((e) => {
|
|
76
|
+
if (e.key === "ArrowDown" && !T && !w) {
|
|
77
|
+
e.preventDefault(), z(!0);
|
|
81
78
|
return;
|
|
82
79
|
}
|
|
83
|
-
e.key === "Escape" &&
|
|
80
|
+
e.key === "Escape" && R && (e.preventDefault(), z(!1));
|
|
84
81
|
}, [
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
]),
|
|
89
|
-
|
|
90
|
-
}, [
|
|
82
|
+
w,
|
|
83
|
+
R,
|
|
84
|
+
T
|
|
85
|
+
]), Q = o((e) => {
|
|
86
|
+
U(B.format(e)), p?.(e), z(!1), requestAnimationFrame(() => K.current?.focus());
|
|
87
|
+
}, [B, p]), de = /* @__PURE__ */ d("button", {
|
|
91
88
|
type: "button",
|
|
92
89
|
className: "date-picker__button",
|
|
93
|
-
"aria-label": y,
|
|
90
|
+
"aria-label": L("openCalendar", y),
|
|
94
91
|
"aria-haspopup": "dialog",
|
|
95
|
-
"aria-expanded":
|
|
96
|
-
disabled:
|
|
97
|
-
tabIndex:
|
|
98
|
-
children: /* @__PURE__ */
|
|
92
|
+
"aria-expanded": R,
|
|
93
|
+
disabled: w,
|
|
94
|
+
tabIndex: T ? -1 : void 0,
|
|
95
|
+
children: /* @__PURE__ */ d(t, {
|
|
99
96
|
name: "calendar",
|
|
100
97
|
size: "sm",
|
|
101
98
|
className: "date-picker__glyph"
|
|
102
99
|
})
|
|
103
|
-
});
|
|
104
|
-
return /* @__PURE__ */
|
|
100
|
+
}), $ = L("calendar", re);
|
|
101
|
+
return /* @__PURE__ */ f("div", {
|
|
105
102
|
className: [
|
|
106
103
|
"date-picker",
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
C === "md" ? "" : `date-picker--${C}`,
|
|
105
|
+
F ?? ""
|
|
109
106
|
].filter(Boolean).join(" "),
|
|
110
107
|
children: [
|
|
111
|
-
|
|
108
|
+
k && /* @__PURE__ */ d("input", {
|
|
112
109
|
type: "hidden",
|
|
113
|
-
name:
|
|
114
|
-
value:
|
|
110
|
+
name: k,
|
|
111
|
+
value: a instanceof Date ? _(a) : ""
|
|
115
112
|
}),
|
|
116
|
-
/* @__PURE__ */
|
|
113
|
+
/* @__PURE__ */ f("div", {
|
|
117
114
|
className: "date-picker__control",
|
|
118
|
-
children: [/* @__PURE__ */
|
|
119
|
-
ref:
|
|
120
|
-
id:
|
|
115
|
+
children: [/* @__PURE__ */ d(n, {
|
|
116
|
+
ref: q,
|
|
117
|
+
id: O,
|
|
121
118
|
className: "date-picker__input",
|
|
122
119
|
type: "text",
|
|
123
120
|
inputMode: "numeric",
|
|
124
121
|
autoComplete: "off",
|
|
125
|
-
size:
|
|
126
|
-
error:
|
|
127
|
-
value:
|
|
128
|
-
placeholder: m ??
|
|
129
|
-
disabled:
|
|
130
|
-
readOnly:
|
|
122
|
+
size: C,
|
|
123
|
+
error: oe,
|
|
124
|
+
value: H,
|
|
125
|
+
placeholder: m ?? B.mask(L("maskLetters", h)),
|
|
126
|
+
disabled: w,
|
|
127
|
+
readOnly: T,
|
|
131
128
|
"aria-label": ne,
|
|
132
|
-
"aria-describedby":
|
|
133
|
-
onChange:
|
|
134
|
-
onKeyDown:
|
|
135
|
-
onBlur:
|
|
136
|
-
}), /* @__PURE__ */
|
|
137
|
-
trigger:
|
|
138
|
-
label:
|
|
139
|
-
open:
|
|
140
|
-
onOpenChange:
|
|
129
|
+
"aria-describedby": se,
|
|
130
|
+
onChange: le,
|
|
131
|
+
onKeyDown: ue,
|
|
132
|
+
onBlur: P
|
|
133
|
+
}), /* @__PURE__ */ d(r, {
|
|
134
|
+
trigger: de,
|
|
135
|
+
label: $,
|
|
136
|
+
open: R,
|
|
137
|
+
onOpenChange: ce,
|
|
141
138
|
side: "bottom",
|
|
142
139
|
align: "end",
|
|
143
140
|
sideOffset: -1,
|
|
144
141
|
className: "date-picker__popover",
|
|
145
|
-
children: /* @__PURE__ */
|
|
146
|
-
value:
|
|
147
|
-
onChange:
|
|
148
|
-
gridLabel:
|
|
149
|
-
previousMonthLabel:
|
|
150
|
-
nextMonthLabel:
|
|
151
|
-
previousYearsLabel:
|
|
152
|
-
nextYearsLabel:
|
|
153
|
-
yearGridLabel:
|
|
142
|
+
children: /* @__PURE__ */ d(i, {
|
|
143
|
+
value: Y ?? a ?? null,
|
|
144
|
+
onChange: Q,
|
|
145
|
+
gridLabel: N ?? $,
|
|
146
|
+
previousMonthLabel: ie,
|
|
147
|
+
nextMonthLabel: ae,
|
|
148
|
+
previousYearsLabel: A,
|
|
149
|
+
nextYearsLabel: j,
|
|
150
|
+
yearGridLabel: M,
|
|
154
151
|
minDate: b,
|
|
155
|
-
maxDate:
|
|
156
|
-
disabledDates:
|
|
157
|
-
locale:
|
|
158
|
-
size:
|
|
152
|
+
maxDate: x,
|
|
153
|
+
disabledDates: S,
|
|
154
|
+
locale: D,
|
|
155
|
+
size: C
|
|
159
156
|
})
|
|
160
157
|
})]
|
|
161
158
|
}),
|
|
162
|
-
|
|
163
|
-
id:
|
|
159
|
+
X && /* @__PURE__ */ d("span", {
|
|
160
|
+
id: Z,
|
|
164
161
|
className: "date-picker__message",
|
|
165
162
|
role: "alert",
|
|
166
|
-
children: v
|
|
163
|
+
children: L("invalid", v)
|
|
167
164
|
})
|
|
168
165
|
]
|
|
169
166
|
});
|