@studiolxd/brand 42.0.0 → 43.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 +53 -0
- package/dist/_shared/datepicker.js +75 -78
- package/dist/_types/atoms/TimeSelect/TimeSelect.d.ts +34 -6
- package/dist/_types/messages/BrandMessages.d.ts +7 -1
- package/dist/_types/messages/index.d.ts +1 -1
- package/dist/_types/molecules/Calendar/Calendar.d.ts +44 -13
- 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/TimeField/TimeField.d.ts +9 -2
- package/dist/_types/molecules/_shared/calendarGrid.d.ts +6 -2
- package/dist/calendar.js +87 -86
- package/dist/time-select.js +57 -56
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,59 @@ 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
|
+
## [43.0.0] — 2026-09-15
|
|
11
|
+
|
|
12
|
+
> **Major.** Cuarta familia al proveedor de textos: fecha y hora. `Calendar`, `DatePicker`
|
|
13
|
+
> y `TimeSelect` dejan de traer castellano puesto, y con ellos se cierran los reenvíos que
|
|
14
|
+
> las olas anteriores dejaron inventariados.
|
|
15
|
+
|
|
16
|
+
### Fecha y hora leen del proveedor
|
|
17
|
+
|
|
18
|
+
Tres espacios nuevos en `BrandMessages`: **`calendar`** (previousMonth, nextMonth,
|
|
19
|
+
previousYears, nextYears, yearGrid), **`datePicker`** (openCalendar, invalid, calendar y
|
|
20
|
+
las letras de la máscara) y **`timeSelect`** (hours, minutes y sus máscaras). Los campos
|
|
21
|
+
que los envuelven —`DatePickerField`, `DateTimeField`, `TimeField`— no pierden props: sus
|
|
22
|
+
reenvíos quedan como anulación puntual, pero ya no hay que enhebrar nada para traducir,
|
|
23
|
+
porque el proveedor llega por contexto a la pieza que pinta el texto. Se ha retirado
|
|
24
|
+
`SPANISH_MASK_LETTERS`, el último juego de letras castellanas vivo en el código.
|
|
25
|
+
|
|
26
|
+
Mismo orden que en las tres olas anteriores —**prop → proveedor → error**— y misma
|
|
27
|
+
naturaleza: incompatible **en tiempo de compilación**. El texto que no se pinta no se
|
|
28
|
+
exige: un `Calendar` sin navegación no pide las flechas, un `DatePicker` con fecha válida no
|
|
29
|
+
pide el aviso, un `TimeSelect` con hora no pide las máscaras.
|
|
30
|
+
|
|
31
|
+
### Una máscara tiene dos mitades
|
|
32
|
+
|
|
33
|
+
`dd/mm/aaaa` no es una cosa, son dos decididas en sitios distintos. **El orden y el
|
|
34
|
+
separador son formato**: salen del `locale` vía `Intl.DateTimeFormat`, y una aplicación en
|
|
35
|
+
inglés que enseñe fechas españolas las quiere en orden español. **Las letras son idioma**:
|
|
36
|
+
`aaaa` es «año», `yyyy` es *year*, `jjjj` es *Jahr* — la abreviatura de una palabra, y se
|
|
37
|
+
traduce. Por eso el catálogo guarda las tres letras sueltas y nunca la máscara montada: la
|
|
38
|
+
arma el componente poniendo las letras en el orden del `locale`.
|
|
39
|
+
|
|
40
|
+
Lo mismo con `HH/MM`: parecen notación técnica, pero son la inicial de una palabra, y en
|
|
41
|
+
alemán son `SS/MM`. Lo que no se traduce es el dibujo —dos cifras, la hora antes que el
|
|
42
|
+
minuto, dos puntos en medio—.
|
|
43
|
+
|
|
44
|
+
La regla, en una frase, escrita en `Foundations › Internacionalización`: **si cambia al
|
|
45
|
+
cambiar de idioma es cromo; si cambia al cambiar de país es formato.**
|
|
46
|
+
|
|
47
|
+
### Lo que se queda como prop
|
|
48
|
+
|
|
49
|
+
`label`, `helperText` y `errorMessage` de los tres campos; `gridLabel` del `Calendar`, que
|
|
50
|
+
nombra a ESE calendario («Fecha de alta») y sin el cual la rejilla toma el título del mes,
|
|
51
|
+
que ya viene del `locale`; `calendarLabel` cuando lo pone un campo, porque es su etiqueta;
|
|
52
|
+
y el `placeholder` del `DatePicker` cuando dice algo del campo («Desde»), que sustituye a la
|
|
53
|
+
máscara entera.
|
|
54
|
+
|
|
55
|
+
### Pendiente, anotado
|
|
56
|
+
|
|
57
|
+
`CalendarPlanner` y `CalendarRoster` siguen con «Mes anterior» y «Mes siguiente» cableados:
|
|
58
|
+
es el mismo texto que `Calendar` y pueden leer de `calendar.*` tal cual. Y `TimeSelect` es
|
|
59
|
+
de 24 horas por construcción; el reloj de 12 con AM/PM es cosa del `locale`, no del idioma,
|
|
60
|
+
y hoy una aplicación en inglés americano ve las horas en formato militar. No es un texto,
|
|
61
|
+
y queda por decidir.
|
|
62
|
+
|
|
10
63
|
## [42.0.0] — 2026-09-15
|
|
11
64
|
|
|
12
65
|
> **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
|
});
|
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
import './TimeSelect.css';
|
|
2
|
+
/**
|
|
3
|
+
* El cromo de la hora: cómo se llaman los dos desplegables y qué pone dentro
|
|
4
|
+
* mientras no hay hora elegida.
|
|
5
|
+
*
|
|
6
|
+
* **Las dos máscaras también son idioma, no formato.** `HH` y `MM` parecen
|
|
7
|
+
* notación técnica, pero son la inicial de una palabra —hora y minuto— y
|
|
8
|
+
* cambian con ella: en alemán se escriben `SS`/`MM` (*Stunde*, *Minute*). Lo
|
|
9
|
+
* que NO se traduce es el dibujo: dos cifras, la hora antes que el minuto y
|
|
10
|
+
* los dos puntos en medio; eso no lo decide ni la prop ni el catálogo.
|
|
11
|
+
*
|
|
12
|
+
* Las **cifras de las opciones** (`00`…`23`) tampoco están aquí: son datos.
|
|
13
|
+
*/
|
|
14
|
+
export interface TimeSelectMessages {
|
|
15
|
+
/** Nombre accesible del desplegable de horas. */
|
|
16
|
+
hours: string;
|
|
17
|
+
/** Nombre accesible del desplegable de minutos. */
|
|
18
|
+
minutes: string;
|
|
19
|
+
/** Máscara del desplegable de horas sin valor: `HH`. */
|
|
20
|
+
maskHours: string;
|
|
21
|
+
/** Máscara del desplegable de minutos sin valor: `MM`. */
|
|
22
|
+
maskMinutes: string;
|
|
23
|
+
}
|
|
2
24
|
export interface TimeValue {
|
|
3
25
|
h: number;
|
|
4
26
|
m: number;
|
|
@@ -27,18 +49,24 @@ export interface TimeSelectProps {
|
|
|
27
49
|
/** Se añade DESPUÉS de las clases propias del componente. */
|
|
28
50
|
className?: string;
|
|
29
51
|
/**
|
|
30
|
-
* aria-label del selector de horas.
|
|
31
|
-
*
|
|
52
|
+
* aria-label del selector de horas. **Sin default**: sin él, el texto sale
|
|
53
|
+
* de `timeSelect.hours` del `BrandMessagesProvider`.
|
|
32
54
|
*/
|
|
33
55
|
hoursLabel?: string;
|
|
34
56
|
/**
|
|
35
|
-
* aria-label del selector de minutos.
|
|
36
|
-
*
|
|
57
|
+
* aria-label del selector de minutos. **Sin default**: sin él, sale de
|
|
58
|
+
* `timeSelect.minutes` del `BrandMessagesProvider`.
|
|
37
59
|
*/
|
|
38
60
|
minutesLabel?: string;
|
|
39
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Máscara del selector de horas. **Sin default**: sin ella, sale de
|
|
63
|
+
* `timeSelect.maskHours` del `BrandMessagesProvider`.
|
|
64
|
+
*/
|
|
40
65
|
hoursPlaceholder?: string;
|
|
41
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Máscara del selector de minutos. **Sin default**: sin ella, sale de
|
|
68
|
+
* `timeSelect.maskMinutes` del `BrandMessagesProvider`.
|
|
69
|
+
*/
|
|
42
70
|
minutesPlaceholder?: string;
|
|
43
71
|
}
|
|
44
72
|
/**
|
|
@@ -13,6 +13,9 @@ import type { AsyncMultiSelectMessages } from '../atoms/AsyncMultiSelect/AsyncMu
|
|
|
13
13
|
import type { DocsSearchMessages } from '../molecules/DocsSearch/DocsSearch';
|
|
14
14
|
import type { SearchFormMessages } from '../molecules/SearchForm/SearchForm';
|
|
15
15
|
import type { FilterBarMessages } from '../molecules/FilterBar/FilterBar';
|
|
16
|
+
import type { CalendarMessages } from '../molecules/Calendar/Calendar';
|
|
17
|
+
import type { DatePickerMessages } from '../molecules/DatePicker/DatePicker';
|
|
18
|
+
import type { TimeSelectMessages } from '../atoms/TimeSelect/TimeSelect';
|
|
16
19
|
/**
|
|
17
20
|
* El contrato de textos de la librería: un espacio por componente, y dentro
|
|
18
21
|
* de cada espacio **todas las claves obligatorias**.
|
|
@@ -50,5 +53,8 @@ export interface BrandMessages {
|
|
|
50
53
|
docsSearch: DocsSearchMessages;
|
|
51
54
|
searchForm: SearchFormMessages;
|
|
52
55
|
filterBar: FilterBarMessages;
|
|
56
|
+
calendar: CalendarMessages;
|
|
57
|
+
datePicker: DatePickerMessages;
|
|
58
|
+
timeSelect: TimeSelectMessages;
|
|
53
59
|
}
|
|
54
|
-
export type { PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, };
|
|
60
|
+
export type { PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, };
|
|
@@ -2,4 +2,4 @@ export { BrandMessagesProvider } from './BrandMessagesProvider';
|
|
|
2
2
|
export type { BrandMessagesProviderProps } from './BrandMessagesProvider';
|
|
3
3
|
export { useBrandMessages } from './BrandMessagesContext';
|
|
4
4
|
export type { BrandMessagesReader } from './BrandMessagesContext';
|
|
5
|
-
export type { BrandMessages, PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, } from './BrandMessages';
|
|
5
|
+
export type { BrandMessages, PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, } from './BrandMessages';
|
|
@@ -1,4 +1,32 @@
|
|
|
1
1
|
import './Calendar.css';
|
|
2
|
+
/**
|
|
3
|
+
* El cromo del calendario: las dos flechas —que cambian de nombre según la
|
|
4
|
+
* vista— y el rótulo de la rejilla de años. Dicen lo mismo en toda la suite,
|
|
5
|
+
* así que salen del catálogo y no de una prop por uso.
|
|
6
|
+
*
|
|
7
|
+
* **Lo que NO está aquí, y no es olvido:** los nombres de los meses, los de
|
|
8
|
+
* los días de la semana, las cifras del año y el nombre accesible de cada
|
|
9
|
+
* celda («lunes, 15 de enero de 2025»). Eso no es texto de interfaz sino
|
|
10
|
+
* **formato de fecha**: sale de `locale` con `Intl`, que además es quien sabe
|
|
11
|
+
* en qué día empieza la semana y con qué cifras se escribe el año. Traducirlo
|
|
12
|
+
* por catálogo sería reescribir a mano lo que el navegador ya trae bien.
|
|
13
|
+
*
|
|
14
|
+
* Tampoco está `gridLabel`: nombra a ESTE calendario («Fecha de alta»), que
|
|
15
|
+
* es contenido de la pantalla. Sin él la rejilla toma como nombre el título
|
|
16
|
+
* del mes visible, que ya viene del locale.
|
|
17
|
+
*/
|
|
18
|
+
export interface CalendarMessages {
|
|
19
|
+
/** Nombre accesible de la flecha de retroceso sobre la rejilla de días. */
|
|
20
|
+
previousMonth: string;
|
|
21
|
+
/** Nombre accesible de la flecha de avance sobre la rejilla de días. */
|
|
22
|
+
nextMonth: string;
|
|
23
|
+
/** Nombre accesible de la flecha de retroceso sobre la rejilla de años. */
|
|
24
|
+
previousYears: string;
|
|
25
|
+
/** Nombre accesible de la flecha de avance sobre la rejilla de años. */
|
|
26
|
+
nextYears: string;
|
|
27
|
+
/** Nombre accesible de la rejilla de años. */
|
|
28
|
+
yearGrid: string;
|
|
29
|
+
}
|
|
2
30
|
export interface CalendarProps {
|
|
3
31
|
/** Fecha seleccionada (modo controlado) */
|
|
4
32
|
value?: Date | null;
|
|
@@ -21,34 +49,37 @@ export interface CalendarProps {
|
|
|
21
49
|
/** Locale para nombres de mes y día. Default: 'es-ES' */
|
|
22
50
|
locale?: string;
|
|
23
51
|
/**
|
|
24
|
-
* aria-label del botón de mes anterior.
|
|
25
|
-
*
|
|
52
|
+
* aria-label del botón de mes anterior. **Sin default**: sin él, el texto
|
|
53
|
+
* sale de `calendar.previousMonth` del `BrandMessagesProvider`.
|
|
26
54
|
*/
|
|
27
55
|
previousMonthLabel?: string;
|
|
28
56
|
/**
|
|
29
|
-
* aria-label del botón de mes siguiente.
|
|
30
|
-
*
|
|
57
|
+
* aria-label del botón de mes siguiente. **Sin default**: sin él, el texto
|
|
58
|
+
* sale de `calendar.nextMonth` del `BrandMessagesProvider`.
|
|
31
59
|
*/
|
|
32
60
|
nextMonthLabel?: string;
|
|
33
61
|
/**
|
|
34
|
-
* aria-label del botón de retroceso **en la vista de años**.
|
|
35
|
-
*
|
|
62
|
+
* aria-label del botón de retroceso **en la vista de años**. **Sin
|
|
63
|
+
* default**: sin él, sale de `calendar.previousYears` del
|
|
64
|
+
* `BrandMessagesProvider`.
|
|
36
65
|
*/
|
|
37
66
|
previousYearsLabel?: string;
|
|
38
67
|
/**
|
|
39
|
-
* aria-label del botón de avance en la vista de años.
|
|
40
|
-
*
|
|
68
|
+
* aria-label del botón de avance en la vista de años. **Sin default**: sin
|
|
69
|
+
* él, sale de `calendar.nextYears` del `BrandMessagesProvider`.
|
|
41
70
|
*/
|
|
42
71
|
nextYearsLabel?: string;
|
|
43
72
|
/**
|
|
44
|
-
* aria-label de la rejilla de años.
|
|
73
|
+
* aria-label de la rejilla de años. **Sin default**: sin él, sale de
|
|
74
|
+
* `calendar.yearGrid` del `BrandMessagesProvider`.
|
|
45
75
|
*/
|
|
46
76
|
yearGridLabel?: string;
|
|
47
77
|
/**
|
|
48
|
-
* aria-label de la rejilla de días.
|
|
49
|
-
*
|
|
50
|
-
* nombre
|
|
51
|
-
*
|
|
78
|
+
* aria-label de la rejilla de días. **No sale del catálogo**: nombra a ESTE
|
|
79
|
+
* calendario («Fecha de alta»), que es contenido de la pantalla. Sin ella,
|
|
80
|
+
* la rejilla toma como nombre el título del mes visible. Cuando el
|
|
81
|
+
* calendario vive dentro de un panel con nombre propio (el `Popover` de
|
|
82
|
+
* `DatePicker`), conviene pasarlo aquí.
|
|
52
83
|
*/
|
|
53
84
|
gridLabel?: string;
|
|
54
85
|
/** Tamaño del componente. Default: 'md' */
|
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
import type { CalendarProps } from '../Calendar/Calendar';
|
|
2
2
|
import { type DateMaskLetters } from './dateMask';
|
|
3
3
|
import './DatePicker.css';
|
|
4
|
+
/**
|
|
5
|
+
* El cromo del selector de fecha: el botón que abre el calendario, el aviso de
|
|
6
|
+
* fecha incompleta, el nombre del panel y **las letras de la máscara**.
|
|
7
|
+
*
|
|
8
|
+
* Las letras están aquí a propósito, y son el caso interesante de esta
|
|
9
|
+
* familia. `dd/mm/aaaa` tiene dos mitades que no se deciden igual:
|
|
10
|
+
*
|
|
11
|
+
* - **El orden y el separador son formato**: que `es` escriba 25/09/2026,
|
|
12
|
+
* `en-US` 09/25/2026 y `de` 25.09.2026 sale del `locale` con `Intl`
|
|
13
|
+
* (`dateMask.ts`), no de una prop ni del catálogo. Una app en inglés
|
|
14
|
+
* mostrando fechas españolas las quiere en orden español.
|
|
15
|
+
* - **Las letras son idioma**: `aaaa` es «año», `yyyy` es *year* y `jjjj` es
|
|
16
|
+
* *Jahr*. Son la abreviatura de una palabra, así que se traducen — y por eso
|
|
17
|
+
* son cromo y salen del catálogo, como cualquier otro rótulo.
|
|
18
|
+
*
|
|
19
|
+
* Por eso el catálogo trae solo las tres letras y no la máscara montada: la
|
|
20
|
+
* máscara la arma el componente poniendo las letras en el orden del locale.
|
|
21
|
+
*/
|
|
22
|
+
export interface DatePickerMessages {
|
|
23
|
+
/** Nombre accesible del botón que abre el calendario. */
|
|
24
|
+
openCalendar: string;
|
|
25
|
+
/** Aviso de fecha incompleta o inexistente, anunciado con `role="alert"`. */
|
|
26
|
+
invalid: string;
|
|
27
|
+
/** Nombre accesible del panel del calendario (`role="dialog"`). */
|
|
28
|
+
calendar: string;
|
|
29
|
+
/**
|
|
30
|
+
* Las letras de la máscara, una por parte: `{ day: 'dd', month: 'mm',
|
|
31
|
+
* year: 'aaaa' }`. El orden y el separador NO están aquí: salen del
|
|
32
|
+
* `locale`.
|
|
33
|
+
*/
|
|
34
|
+
maskLetters: DateMaskLetters;
|
|
35
|
+
}
|
|
4
36
|
export interface DatePickerProps {
|
|
5
37
|
value?: Date | null;
|
|
6
38
|
/**
|
|
@@ -9,23 +41,28 @@ export interface DatePickerProps {
|
|
|
9
41
|
*/
|
|
10
42
|
onChange?: (date: Date | null) => void;
|
|
11
43
|
/**
|
|
12
|
-
* Pista dentro del campo.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
44
|
+
* Pista dentro del campo. Sin ella, la máscara del locale con las letras
|
|
45
|
+
* del catálogo (`dd/mm/aaaa`, `mm/dd/aaaa` en `en-US`). Es la anulación
|
|
46
|
+
* puntual: un campo que quiere decir otra cosa («Desde») la pasa.
|
|
15
47
|
*/
|
|
16
48
|
placeholder?: string;
|
|
17
49
|
/**
|
|
18
|
-
* Letras de la máscara del marcador de posición.
|
|
19
|
-
*
|
|
20
|
-
* son props: salen del `locale` con
|
|
50
|
+
* Letras de la máscara del marcador de posición. **Sin default**: sin
|
|
51
|
+
* ellas, salen de `datePicker.maskLetters` del `BrandMessagesProvider`. El
|
|
52
|
+
* orden y el separador no son props ni catálogo: salen del `locale` con
|
|
53
|
+
* `Intl`.
|
|
21
54
|
*/
|
|
22
55
|
maskLetters?: DateMaskLetters;
|
|
23
56
|
/**
|
|
24
|
-
* Mensaje cuando lo escrito no es una fecha completa y válida.
|
|
25
|
-
*
|
|
57
|
+
* Mensaje cuando lo escrito no es una fecha completa y válida. **Sin
|
|
58
|
+
* default**: sin él, sale de `datePicker.invalid` del
|
|
59
|
+
* `BrandMessagesProvider`; se anuncia con `role="alert"`.
|
|
26
60
|
*/
|
|
27
61
|
invalidMessage?: string;
|
|
28
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Nombre accesible del botón que abre el calendario. **Sin default**: sin
|
|
64
|
+
* él, sale de `datePicker.openCalendar` del `BrandMessagesProvider`.
|
|
65
|
+
*/
|
|
29
66
|
openCalendarLabel?: string;
|
|
30
67
|
minDate?: CalendarProps['minDate'];
|
|
31
68
|
maxDate?: CalendarProps['maxDate'];
|
|
@@ -43,29 +80,22 @@ export interface DatePickerProps {
|
|
|
43
80
|
'aria-describedby'?: string;
|
|
44
81
|
/** Nombre accesible cuando el control va suelto. En un campo lo nombra la etiqueta. */
|
|
45
82
|
'aria-label'?: string;
|
|
46
|
-
/** Nombre accesible del panel del calendario (`role="dialog"`). */
|
|
47
|
-
calendarLabel?: string;
|
|
48
83
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
84
|
+
* Nombre accesible del panel del calendario (`role="dialog"`). **Sin
|
|
85
|
+
* default**: sin él, sale de `datePicker.calendar` del
|
|
86
|
+
* `BrandMessagesProvider`. En un campo lo pone la etiqueta del campo, que es
|
|
87
|
+
* contenido de la pantalla y gana como cualquier prop.
|
|
51
88
|
*/
|
|
89
|
+
calendarLabel?: string;
|
|
90
|
+
/** aria-label del botón de mes anterior. Sin él, `calendar.previousMonth`. */
|
|
52
91
|
previousMonthLabel?: CalendarProps['previousMonthLabel'];
|
|
53
|
-
/**
|
|
54
|
-
* aria-label del botón de mes siguiente. Default: «Mes siguiente»
|
|
55
|
-
* (castellano).
|
|
56
|
-
*/
|
|
92
|
+
/** aria-label del botón de mes siguiente. Sin él, `calendar.nextMonth`. */
|
|
57
93
|
nextMonthLabel?: CalendarProps['nextMonthLabel'];
|
|
58
|
-
/**
|
|
59
|
-
* aria-label del botón de retroceso **en la vista de años**. Default: «Años
|
|
60
|
-
* anteriores» (castellano).
|
|
61
|
-
*/
|
|
94
|
+
/** aria-label del retroceso en la vista de años. Sin él, `calendar.previousYears`. */
|
|
62
95
|
previousYearsLabel?: CalendarProps['previousYearsLabel'];
|
|
63
|
-
/**
|
|
64
|
-
* aria-label del botón de avance en la vista de años. Default: «Años
|
|
65
|
-
* siguientes» (castellano).
|
|
66
|
-
*/
|
|
96
|
+
/** aria-label del avance en la vista de años. Sin él, `calendar.nextYears`. */
|
|
67
97
|
nextYearsLabel?: CalendarProps['nextYearsLabel'];
|
|
68
|
-
/** aria-label de la rejilla de años.
|
|
98
|
+
/** aria-label de la rejilla de años. Sin él, `calendar.yearGrid`. */
|
|
69
99
|
yearGridLabel?: CalendarProps['yearGridLabel'];
|
|
70
100
|
/**
|
|
71
101
|
* aria-label de la rejilla de días. Por defecto toma `calendarLabel`, que ya
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
export type DatePartName = 'day' | 'month' | 'year';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Letras de la máscara del marcador de posición, una por parte.
|
|
4
|
+
*
|
|
5
|
+
* **No hay juego por defecto, y es deliberado**: las letras se traducen
|
|
6
|
+
* (`aaaa` es «año», `yyyy` es *year*, `jjjj` es *Jahr*), así que salen del
|
|
7
|
+
* catálogo de la aplicación —`datePicker.maskLetters`— igual que cualquier
|
|
8
|
+
* otro rótulo. Lo que este módulo decide es el **orden** y el **separador**,
|
|
9
|
+
* que son formato y salen del `locale`.
|
|
10
|
+
*/
|
|
3
11
|
export interface DateMaskLetters {
|
|
4
12
|
day: string;
|
|
5
13
|
month: string;
|
|
6
14
|
year: string;
|
|
7
15
|
}
|
|
8
|
-
export declare const SPANISH_MASK_LETTERS: DateMaskLetters;
|
|
9
16
|
export interface DateMask {
|
|
10
17
|
/** Orden de las partes en ese locale, p. ej. `['day', 'month', 'year']`. */
|
|
11
18
|
order: DatePartName[];
|
|
@@ -33,29 +33,29 @@ export interface DateTimeFieldProps {
|
|
|
33
33
|
locale?: string;
|
|
34
34
|
/** Se añade DESPUÉS de las clases propias (el consumidor añade, no sustituye). */
|
|
35
35
|
className?: string;
|
|
36
|
-
/** Nombre accesible del panel del calendario.
|
|
36
|
+
/** Nombre accesible del panel del calendario. Sin él, la etiqueta del campo. */
|
|
37
37
|
calendarLabel?: DatePickerProps['calendarLabel'];
|
|
38
|
-
/** Nombre accesible del botón que abre el calendario.
|
|
38
|
+
/** Nombre accesible del botón que abre el calendario. Sin él, `datePicker.openCalendar`. */
|
|
39
39
|
openCalendarLabel?: DatePickerProps['openCalendarLabel'];
|
|
40
|
-
/** Mensaje de fecha incompleta del campo de texto.
|
|
40
|
+
/** Mensaje de fecha incompleta del campo de texto. Sin él, `datePicker.invalid`. */
|
|
41
41
|
invalidMessage?: DatePickerProps['invalidMessage'];
|
|
42
|
-
/** Letras de la máscara del marcador de posición.
|
|
42
|
+
/** Letras de la máscara del marcador de posición. Sin ellas, `datePicker.maskLetters`. */
|
|
43
43
|
maskLetters?: DatePickerProps['maskLetters'];
|
|
44
|
-
/** aria-label del botón de mes anterior
|
|
44
|
+
/** aria-label del botón de mes anterior. Sin él, `calendar.previousMonth`. */
|
|
45
45
|
previousMonthLabel?: DatePickerProps['previousMonthLabel'];
|
|
46
|
-
/** aria-label del botón de mes siguiente.
|
|
46
|
+
/** aria-label del botón de mes siguiente. Sin él, `calendar.nextMonth`. */
|
|
47
47
|
nextMonthLabel?: DatePickerProps['nextMonthLabel'];
|
|
48
|
-
/** aria-label del
|
|
48
|
+
/** aria-label del retroceso en la vista de años. Sin él, `calendar.previousYears`. */
|
|
49
49
|
previousYearsLabel?: DatePickerProps['previousYearsLabel'];
|
|
50
|
-
/** aria-label del
|
|
50
|
+
/** aria-label del avance en la vista de años. Sin él, `calendar.nextYears`. */
|
|
51
51
|
nextYearsLabel?: DatePickerProps['nextYearsLabel'];
|
|
52
|
-
/** aria-label de la rejilla de años.
|
|
52
|
+
/** aria-label de la rejilla de años. Sin él, `calendar.yearGrid`. */
|
|
53
53
|
yearGridLabel?: DatePickerProps['yearGridLabel'];
|
|
54
|
-
/** aria-label de la rejilla de días.
|
|
54
|
+
/** aria-label de la rejilla de días. Sin él, el nombre del panel. */
|
|
55
55
|
gridLabel?: DatePickerProps['gridLabel'];
|
|
56
|
-
/** aria-label del desplegable de horas.
|
|
56
|
+
/** aria-label del desplegable de horas. Sin él, `timeSelect.hours`. */
|
|
57
57
|
hoursLabel?: string;
|
|
58
|
-
/** aria-label del desplegable de minutos.
|
|
58
|
+
/** aria-label del desplegable de minutos. Sin él, `timeSelect.minutes`. */
|
|
59
59
|
minutesLabel?: string;
|
|
60
60
|
onChange?: (date: Date | null) => void;
|
|
61
61
|
/** Se llama al salir de cualquiera de los dos controles: el campo de fecha (un `<input>`) o los desplegables de hora (dos `<button>`). */
|
|
@@ -29,9 +29,16 @@ export interface TimeFieldProps {
|
|
|
29
29
|
helperText?: string;
|
|
30
30
|
/** Se añade DESPUÉS de las clases propias (el consumidor añade, no sustituye). */
|
|
31
31
|
className?: string;
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* aria-label del desplegable de horas. **Sin default**: sin él, el texto
|
|
34
|
+
* sale de `timeSelect.hours` del `BrandMessagesProvider`, que el
|
|
35
|
+
* `TimeSelect` de dentro lee por contexto.
|
|
36
|
+
*/
|
|
33
37
|
hoursLabel?: string;
|
|
34
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* aria-label del desplegable de minutos. **Sin default**: sin él, sale de
|
|
40
|
+
* `timeSelect.minutes` del `BrandMessagesProvider`.
|
|
41
|
+
*/
|
|
35
42
|
minutesLabel?: string;
|
|
36
43
|
onChange?: (value: TimeValue) => void;
|
|
37
44
|
onBlur?: React.FocusEventHandler<HTMLButtonElement>;
|
|
@@ -51,10 +51,14 @@ export interface CalendarMonthNavOptions {
|
|
|
51
51
|
/**
|
|
52
52
|
* Nombre accesible del botón de retroceso. Depende de la vista: «Mes
|
|
53
53
|
* anterior» sobre la rejilla de días, «Años anteriores» sobre la de años.
|
|
54
|
+
*
|
|
55
|
+
* Opcional porque sin `navigable` no se pinta ningún botón: quien la monta
|
|
56
|
+
* lee el texto de su catálogo **solo cuando hay flechas**, y un calendario
|
|
57
|
+
* estático no exige un texto que nadie va a ver.
|
|
54
58
|
*/
|
|
55
|
-
previousLabel
|
|
59
|
+
previousLabel?: string;
|
|
56
60
|
/** Nombre accesible del botón de avance, también según la vista. */
|
|
57
|
-
nextLabel
|
|
61
|
+
nextLabel?: string;
|
|
58
62
|
prevDisabled?: boolean;
|
|
59
63
|
nextDisabled?: boolean;
|
|
60
64
|
onPrev: () => void;
|
package/dist/calendar.js
CHANGED
|
@@ -1,121 +1,122 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import './calendar.css';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { n as e } from "./_shared/brandmessagescontext.js";
|
|
4
|
+
import { a as t, c as n, i as r, l as i, n as a, o, r as ee, s as te, t as ne } from "./_shared/calendargrid.js";
|
|
5
|
+
import { useCallback as s, useEffect as c, useId as l, useRef as u, useState as d } from "react";
|
|
6
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
6
7
|
//#region src/stories/molecules/Calendar/Calendar.tsx
|
|
7
|
-
var
|
|
8
|
-
function
|
|
9
|
-
return Math.floor(e /
|
|
8
|
+
var m = 12, h = 4;
|
|
9
|
+
function g(e) {
|
|
10
|
+
return Math.floor(e / m) * m;
|
|
10
11
|
}
|
|
11
|
-
function
|
|
12
|
-
let [
|
|
13
|
-
|
|
14
|
-
}, [
|
|
12
|
+
function _({ value: _, onChange: re, defaultMonth: ie, month: v, onMonthChange: y, navigable: b = !0, disabledDates: x, minDate: S, maxDate: C, locale: w = "es-ES", previousMonthLabel: ae, nextMonthLabel: oe, previousYearsLabel: T, nextYearsLabel: E, yearGridLabel: D, gridLabel: O, size: k = "md", className: A }) {
|
|
13
|
+
let j = e("calendar"), [se, ce] = d(() => v ?? ie ?? (_ instanceof Date ? _ : /* @__PURE__ */ new Date())), M = v ?? se, N = s((e) => {
|
|
14
|
+
ce(e), y?.(e);
|
|
15
|
+
}, [y]), P = /* @__PURE__ */ new Date(), le = s((e) => S && e < S || C && e > C ? !0 : Array.isArray(x) ? x.some((t) => r(t, e)) : typeof x == "function" ? x(e) : !1, [
|
|
15
16
|
x,
|
|
16
17
|
S,
|
|
17
18
|
C
|
|
18
|
-
]),
|
|
19
|
-
month:
|
|
20
|
-
onMonthChange:
|
|
21
|
-
selected:
|
|
19
|
+
]), F = i({
|
|
20
|
+
month: M,
|
|
21
|
+
onMonthChange: N,
|
|
22
|
+
selected: _ ?? null,
|
|
22
23
|
minDate: S,
|
|
23
24
|
maxDate: C
|
|
24
|
-
}), [
|
|
25
|
-
let e =
|
|
26
|
-
|
|
27
|
-
}, [
|
|
28
|
-
|
|
29
|
-
}, []),
|
|
30
|
-
|
|
25
|
+
}), [I, L] = d("days"), [R, z] = d(() => g(M.getFullYear())), [B, V] = d(() => M.getFullYear()), H = u(null), U = u(/* @__PURE__ */ new Map()), W = u(null), ue = s(() => {
|
|
26
|
+
let e = M.getFullYear();
|
|
27
|
+
z(g(e)), V(e), W.current = "year", L("years");
|
|
28
|
+
}, [M]), G = s(() => {
|
|
29
|
+
W.current = "title", L("days");
|
|
30
|
+
}, []), de = s((e) => {
|
|
31
|
+
N(new Date(e, M.getMonth(), 1)), G();
|
|
31
32
|
}, [
|
|
32
33
|
G,
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
M,
|
|
35
|
+
N
|
|
35
36
|
]);
|
|
36
37
|
c(() => {
|
|
37
|
-
if (!
|
|
38
|
-
let e =
|
|
39
|
-
|
|
40
|
-
}, [
|
|
41
|
-
let
|
|
38
|
+
if (!W.current) return;
|
|
39
|
+
let e = W.current;
|
|
40
|
+
W.current = null, e === "title" ? H.current?.focus() : U.current.get(B)?.focus();
|
|
41
|
+
}, [I, B]);
|
|
42
|
+
let fe = k === "sm" ? "xs" : k === "lg" ? "md" : "sm", pe = new Intl.DateTimeFormat(w, {
|
|
42
43
|
month: "long",
|
|
43
44
|
year: "numeric"
|
|
44
|
-
}).format(
|
|
45
|
+
}).format(M), me = new Intl.DateTimeFormat(w, { year: "numeric" }), K = (e) => me.format(new Date(e, 0, 1)), he = Array.from({ length: m }, (e, t) => R + t), ge = `${K(R)}–${K(R + m - 1)}`, _e = new Intl.DateTimeFormat(w, {
|
|
45
46
|
weekday: "long",
|
|
46
47
|
day: "numeric",
|
|
47
48
|
month: "long",
|
|
48
49
|
year: "numeric"
|
|
49
|
-
}),
|
|
50
|
-
(e <
|
|
51
|
-
},
|
|
50
|
+
}), ve = ee(w, "narrow"), ye = ne(a(M)), q = n(M, -1), J = n(M, 1), be = S ? !t(q, S) && q < S : !1, xe = C ? !t(J, C) && J > C : !1, Se = (e) => (S ? e < S.getFullYear() : !1) || (C ? e > C.getFullYear() : !1), Ce = S ? R - 1 < S.getFullYear() : !1, we = C ? R + m > C.getFullYear() : !1, Y = I === "years", X = B >= R && B <= R + m - 1 ? B : R, Te = (e) => {
|
|
51
|
+
(e < R || e > R + m - 1) && z(g(e)), W.current = "year", V(e);
|
|
52
|
+
}, Z = (e) => {
|
|
52
53
|
let t = null;
|
|
53
54
|
switch (e.key) {
|
|
54
55
|
case "ArrowLeft":
|
|
55
|
-
t =
|
|
56
|
+
t = X - 1;
|
|
56
57
|
break;
|
|
57
58
|
case "ArrowRight":
|
|
58
|
-
t =
|
|
59
|
+
t = X + 1;
|
|
59
60
|
break;
|
|
60
61
|
case "ArrowUp":
|
|
61
|
-
t =
|
|
62
|
+
t = X - h;
|
|
62
63
|
break;
|
|
63
64
|
case "ArrowDown":
|
|
64
|
-
t =
|
|
65
|
+
t = X + h;
|
|
65
66
|
break;
|
|
66
67
|
case "Home":
|
|
67
|
-
t =
|
|
68
|
+
t = R;
|
|
68
69
|
break;
|
|
69
70
|
case "End":
|
|
70
|
-
t =
|
|
71
|
+
t = R + m - 1;
|
|
71
72
|
break;
|
|
72
73
|
case "PageUp":
|
|
73
|
-
t =
|
|
74
|
+
t = X - m;
|
|
74
75
|
break;
|
|
75
76
|
case "PageDown":
|
|
76
|
-
t =
|
|
77
|
+
t = X + m;
|
|
77
78
|
break;
|
|
78
79
|
case "Escape":
|
|
79
80
|
e.preventDefault(), G();
|
|
80
81
|
return;
|
|
81
82
|
default: return;
|
|
82
83
|
}
|
|
83
|
-
e.preventDefault(),
|
|
84
|
-
}, Q =
|
|
85
|
-
return /* @__PURE__ */
|
|
84
|
+
e.preventDefault(), Te(t);
|
|
85
|
+
}, Q = l(), $ = Y ? `${Q}-calendar-title-${R}` : `${Q}-calendar-title-${M.getFullYear()}-${M.getMonth()}`;
|
|
86
|
+
return /* @__PURE__ */ p("div", {
|
|
86
87
|
className: [
|
|
87
88
|
"calendar",
|
|
88
|
-
`calendar--${
|
|
89
|
-
|
|
89
|
+
`calendar--${k}`,
|
|
90
|
+
A
|
|
90
91
|
].filter(Boolean).join(" "),
|
|
91
|
-
children: [
|
|
92
|
+
children: [o({
|
|
92
93
|
block: "calendar",
|
|
93
|
-
title:
|
|
94
|
+
title: Y ? ge : pe,
|
|
94
95
|
titleId: $,
|
|
95
|
-
navigable:
|
|
96
|
-
previousLabel:
|
|
97
|
-
nextLabel:
|
|
98
|
-
prevDisabled:
|
|
99
|
-
nextDisabled:
|
|
100
|
-
onPrev:
|
|
101
|
-
onNext:
|
|
102
|
-
chevronSize:
|
|
103
|
-
onTitleClick:
|
|
104
|
-
titleExpanded:
|
|
105
|
-
titleRef:
|
|
106
|
-
}),
|
|
96
|
+
navigable: b,
|
|
97
|
+
previousLabel: b ? Y ? j("previousYears", T) : j("previousMonth", ae) : void 0,
|
|
98
|
+
nextLabel: b ? Y ? j("nextYears", E) : j("nextMonth", oe) : void 0,
|
|
99
|
+
prevDisabled: Y ? Ce : be,
|
|
100
|
+
nextDisabled: Y ? we : xe,
|
|
101
|
+
onPrev: Y ? () => z(R - m) : () => N(q),
|
|
102
|
+
onNext: Y ? () => z(R + m) : () => N(J),
|
|
103
|
+
chevronSize: fe,
|
|
104
|
+
onTitleClick: Y ? G : ue,
|
|
105
|
+
titleExpanded: Y,
|
|
106
|
+
titleRef: H
|
|
107
|
+
}), Y ? /* @__PURE__ */ f("div", {
|
|
107
108
|
className: "calendar__years",
|
|
108
109
|
role: "grid",
|
|
109
|
-
"aria-label":
|
|
110
|
-
onKeyDown:
|
|
111
|
-
children: Array.from({ length:
|
|
110
|
+
"aria-label": j("yearGrid", D),
|
|
111
|
+
onKeyDown: Z,
|
|
112
|
+
children: Array.from({ length: m / h }, (e, t) => /* @__PURE__ */ f("div", {
|
|
112
113
|
role: "row",
|
|
113
114
|
className: "calendar__row",
|
|
114
|
-
children:
|
|
115
|
-
let t =
|
|
116
|
-
return /* @__PURE__ */
|
|
115
|
+
children: he.slice(t * h, t * h + h).map((e) => {
|
|
116
|
+
let t = Se(e), n = e === P.getFullYear(), r = _ instanceof Date ? _.getFullYear() === e : !1;
|
|
117
|
+
return /* @__PURE__ */ f("button", {
|
|
117
118
|
ref: (t) => {
|
|
118
|
-
t ?
|
|
119
|
+
t ? U.current.set(e, t) : U.current.delete(e);
|
|
119
120
|
},
|
|
120
121
|
type: "button",
|
|
121
122
|
role: "gridcell",
|
|
@@ -128,45 +129,45 @@ function g({ value: g, onChange: _, defaultMonth: v, month: y, onMonthChange: b,
|
|
|
128
129
|
"aria-selected": r,
|
|
129
130
|
"aria-disabled": t ? "true" : void 0,
|
|
130
131
|
"aria-current": n ? "date" : void 0,
|
|
131
|
-
tabIndex: e ===
|
|
132
|
-
onFocus: () =>
|
|
133
|
-
onClick: t ? void 0 : () =>
|
|
132
|
+
tabIndex: e === X ? 0 : -1,
|
|
133
|
+
onFocus: () => V(e),
|
|
134
|
+
onClick: t ? void 0 : () => de(e),
|
|
134
135
|
children: K(e)
|
|
135
136
|
}, e);
|
|
136
137
|
})
|
|
137
138
|
}, t))
|
|
138
|
-
}) : /* @__PURE__ */
|
|
139
|
+
}) : /* @__PURE__ */ p("div", {
|
|
139
140
|
className: "calendar__grid",
|
|
140
141
|
role: "grid",
|
|
141
|
-
"aria-label":
|
|
142
|
-
"aria-labelledby":
|
|
143
|
-
onKeyDown:
|
|
144
|
-
children: [
|
|
142
|
+
"aria-label": O,
|
|
143
|
+
"aria-labelledby": O ? void 0 : $,
|
|
144
|
+
onKeyDown: F.onKeyDown,
|
|
145
|
+
children: [te({
|
|
145
146
|
block: "calendar",
|
|
146
|
-
weekdays:
|
|
147
|
-
}),
|
|
147
|
+
weekdays: ve
|
|
148
|
+
}), ye.map((e, t) => /* @__PURE__ */ f("div", {
|
|
148
149
|
role: "row",
|
|
149
150
|
className: "calendar__row",
|
|
150
151
|
children: e.map(({ date: e, outside: t }) => {
|
|
151
|
-
let
|
|
152
|
+
let n = le(e), i = r(e, P), a = _ instanceof Date ? r(e, _) : !1, o = [
|
|
152
153
|
"calendar__day",
|
|
153
154
|
t && "calendar__day--outside",
|
|
154
155
|
i && "calendar__day--today",
|
|
155
156
|
a && "calendar__day--selected",
|
|
156
|
-
|
|
157
|
+
n && "calendar__day--disabled"
|
|
157
158
|
].filter(Boolean).join(" ");
|
|
158
|
-
return /* @__PURE__ */
|
|
159
|
-
ref:
|
|
159
|
+
return /* @__PURE__ */ f("button", {
|
|
160
|
+
ref: F.cellRef(e),
|
|
160
161
|
type: "button",
|
|
161
162
|
role: "gridcell",
|
|
162
163
|
className: o,
|
|
163
|
-
"aria-label":
|
|
164
|
+
"aria-label": _e.format(e),
|
|
164
165
|
"aria-selected": a,
|
|
165
|
-
"aria-disabled":
|
|
166
|
+
"aria-disabled": n ? "true" : void 0,
|
|
166
167
|
"aria-current": i ? "date" : void 0,
|
|
167
|
-
tabIndex:
|
|
168
|
-
onFocus: () =>
|
|
169
|
-
onClick:
|
|
168
|
+
tabIndex: F.isTabbable(e) ? 0 : -1,
|
|
169
|
+
onFocus: () => F.onCellFocus(e),
|
|
170
|
+
onClick: n ? void 0 : () => re?.(e),
|
|
170
171
|
children: e.getDate()
|
|
171
172
|
}, e.toISOString());
|
|
172
173
|
})
|
|
@@ -175,4 +176,4 @@ function g({ value: g, onChange: _, defaultMonth: v, month: y, onMonthChange: b,
|
|
|
175
176
|
});
|
|
176
177
|
}
|
|
177
178
|
//#endregion
|
|
178
|
-
export {
|
|
179
|
+
export { _ as Calendar };
|
package/dist/time-select.js
CHANGED
|
@@ -1,84 +1,85 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import './time-select.css';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { n as e } from "./_shared/brandmessagescontext.js";
|
|
4
|
+
import { Select as t } from "./select.js";
|
|
5
|
+
import { forwardRef as n, useMemo as r } from "react";
|
|
6
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
6
7
|
//#region src/stories/atoms/TimeSelect/TimeSelect.tsx
|
|
7
|
-
function
|
|
8
|
+
function o(e) {
|
|
8
9
|
return String(e).padStart(2, "0");
|
|
9
10
|
}
|
|
10
|
-
var
|
|
11
|
-
let
|
|
11
|
+
var s = n(function({ value: n, onChange: s, step: c = 5, size: l = "md", disabled: u, readOnly: d, error: f, id: p, name: m, required: h, "aria-labelledby": g, "aria-describedby": _, onBlur: v, className: y, hoursLabel: b, minutesLabel: x, hoursPlaceholder: S, minutesPlaceholder: C }, w) {
|
|
12
|
+
let T = e("timeSelect"), E = r(() => Array.from({ length: 24 }, (e, t) => ({
|
|
12
13
|
value: String(t),
|
|
13
|
-
label:
|
|
14
|
-
})), []),
|
|
14
|
+
label: o(t)
|
|
15
|
+
})), []), D = r(() => {
|
|
15
16
|
let e = [];
|
|
16
|
-
for (let t = 0; t < 60; t +=
|
|
17
|
+
for (let t = 0; t < 60; t += c) e.push({
|
|
17
18
|
value: String(t),
|
|
18
|
-
label:
|
|
19
|
+
label: o(t)
|
|
19
20
|
});
|
|
20
21
|
return e;
|
|
21
|
-
}, [
|
|
22
|
-
let
|
|
23
|
-
|
|
24
|
-
h:
|
|
22
|
+
}, [c]), O = (e) => {
|
|
23
|
+
let t = parseInt(e, 10), r = n?.m ?? 0;
|
|
24
|
+
s?.({
|
|
25
|
+
h: t,
|
|
25
26
|
m: r
|
|
26
27
|
});
|
|
27
|
-
},
|
|
28
|
-
let
|
|
29
|
-
|
|
30
|
-
h:
|
|
28
|
+
}, k = (e) => {
|
|
29
|
+
let t = n?.h ?? 0;
|
|
30
|
+
s?.({
|
|
31
|
+
h: t,
|
|
31
32
|
m: parseInt(e, 10)
|
|
32
33
|
});
|
|
33
|
-
},
|
|
34
|
-
return /* @__PURE__ */
|
|
35
|
-
className:
|
|
34
|
+
}, A = ["time-select", y ?? ""].filter(Boolean).join(" "), j = n == null ? "" : String(n.h), M = n == null ? "" : String(n.m);
|
|
35
|
+
return /* @__PURE__ */ a("div", {
|
|
36
|
+
className: A,
|
|
36
37
|
role: "group",
|
|
37
|
-
"aria-labelledby":
|
|
38
|
-
"aria-describedby":
|
|
39
|
-
"aria-invalid":
|
|
40
|
-
"aria-required":
|
|
38
|
+
"aria-labelledby": g,
|
|
39
|
+
"aria-describedby": _,
|
|
40
|
+
"aria-invalid": f || void 0,
|
|
41
|
+
"aria-required": h || void 0,
|
|
41
42
|
children: [
|
|
42
|
-
/* @__PURE__ */
|
|
43
|
-
ref:
|
|
44
|
-
id:
|
|
45
|
-
options:
|
|
46
|
-
value:
|
|
47
|
-
placeholder:
|
|
48
|
-
size:
|
|
49
|
-
disabled:
|
|
50
|
-
readOnly:
|
|
51
|
-
required:
|
|
52
|
-
"aria-label":
|
|
53
|
-
"aria-invalid":
|
|
54
|
-
onValueChange:
|
|
55
|
-
onBlur:
|
|
43
|
+
/* @__PURE__ */ i(t, {
|
|
44
|
+
ref: w,
|
|
45
|
+
id: p,
|
|
46
|
+
options: E,
|
|
47
|
+
value: j,
|
|
48
|
+
placeholder: j === "" ? T("maskHours", S) : void 0,
|
|
49
|
+
size: l,
|
|
50
|
+
disabled: u,
|
|
51
|
+
readOnly: d,
|
|
52
|
+
required: h,
|
|
53
|
+
"aria-label": T("hours", b),
|
|
54
|
+
"aria-invalid": f,
|
|
55
|
+
onValueChange: O,
|
|
56
|
+
onBlur: v
|
|
56
57
|
}),
|
|
57
|
-
/* @__PURE__ */
|
|
58
|
+
/* @__PURE__ */ i("span", {
|
|
58
59
|
className: "time-select__sep",
|
|
59
60
|
"aria-hidden": "true",
|
|
60
61
|
children: ":"
|
|
61
62
|
}),
|
|
62
|
-
/* @__PURE__ */
|
|
63
|
-
options:
|
|
64
|
-
value:
|
|
65
|
-
placeholder:
|
|
66
|
-
size:
|
|
67
|
-
disabled:
|
|
68
|
-
readOnly:
|
|
69
|
-
required:
|
|
70
|
-
"aria-label":
|
|
71
|
-
"aria-invalid":
|
|
72
|
-
onValueChange:
|
|
73
|
-
onBlur:
|
|
63
|
+
/* @__PURE__ */ i(t, {
|
|
64
|
+
options: D,
|
|
65
|
+
value: M,
|
|
66
|
+
placeholder: M === "" ? T("maskMinutes", C) : void 0,
|
|
67
|
+
size: l,
|
|
68
|
+
disabled: u,
|
|
69
|
+
readOnly: d,
|
|
70
|
+
required: h,
|
|
71
|
+
"aria-label": T("minutes", x),
|
|
72
|
+
"aria-invalid": f,
|
|
73
|
+
onValueChange: k,
|
|
74
|
+
onBlur: v
|
|
74
75
|
}),
|
|
75
|
-
|
|
76
|
+
m && /* @__PURE__ */ i("input", {
|
|
76
77
|
type: "hidden",
|
|
77
|
-
name:
|
|
78
|
-
value:
|
|
78
|
+
name: m,
|
|
79
|
+
value: n == null ? "" : `${o(n.h)}:${o(n.m)}`
|
|
79
80
|
})
|
|
80
81
|
]
|
|
81
82
|
});
|
|
82
83
|
});
|
|
83
84
|
//#endregion
|
|
84
|
-
export {
|
|
85
|
+
export { s as TimeSelect };
|