@studiolxd/brand 43.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.
@@ -1,5 +1,40 @@
1
1
  import { type FormSize } from '../../constants/form-size';
2
2
  import './FileUpload.css';
3
+ /**
4
+ * El cromo de la zona de subida: lo que dice la zona, lo que dice de los
5
+ * límites y lo que dice cuando un archivo no vale.
6
+ *
7
+ * Las dos pistas de límite son **plantillas y no frases hechas**, y ahí está
8
+ * la parte interesante. «Máximo 2,5 MB» tiene dos mitades que se deciden en
9
+ * sitios distintos, igual que `dd/mm/aaaa`: la frase es idioma y sale de aquí;
10
+ * la cifra —la coma o el punto decimal, el espacio antes de `MB`— es formato y
11
+ * la escribe `Intl.NumberFormat` con el `locale` del componente. Por eso el
12
+ * catálogo recibe el peso **ya formateado** y solo lo envuelve: una traducción
13
+ * que escribiera «max. 2.5 MB» a mano metería el punto inglés en una interfaz
14
+ * española.
15
+ */
16
+ export interface FileUploadMessages {
17
+ /** Texto visible de la zona de arrastre en reposo. */
18
+ dropzone: string;
19
+ /** Texto visible mientras se arrastra un archivo por encima. */
20
+ dropzoneActive: string;
21
+ /** Texto visible secundario: que además se puede hacer clic. */
22
+ dropzoneHint: string;
23
+ /** Pista de peso máximo. Recibe el peso **ya escrito en el locale** («2,5 MB»). */
24
+ maxSize: (maxSize: string) => string;
25
+ /** Pista de número máximo de archivos. */
26
+ maxFiles: (maxFiles: number) => string;
27
+ /** aria-label de la lista de archivos elegidos. */
28
+ files: string;
29
+ /** aria-label de la barra de progreso. */
30
+ progress: string;
31
+ /** aria-label del botón de quitar un archivo de la lista. */
32
+ removeFile: (fileName: string) => string;
33
+ /** Error de archivo demasiado pesado. Recibe el peso ya escrito en el locale. */
34
+ tooLarge: (maxSize: string) => string;
35
+ /** Error de tipo de archivo no admitido. */
36
+ invalidType: string;
37
+ }
3
38
  export interface FileUploadProps {
4
39
  multiple?: boolean;
5
40
  accept?: string;
@@ -35,27 +70,60 @@ export interface FileUploadProps {
35
70
  /** Se añade DESPUÉS de las clases propias del componente. */
36
71
  className?: string;
37
72
  /**
38
- * Texto visible de la zona de arrastre. Default: "Arrastra archivos aquí" (castellano).
39
- * Una app multiidioma debe pasarlo traducido — igual que el resto de props de texto.
73
+ * Locale con el que se escriben **los pesos** («2,5 MB» / «2.5 MB»). No
74
+ * decide el idioma de los textos —eso es el catálogo— sino el formato de la
75
+ * cifra. Default `'es-ES'`.
76
+ */
77
+ locale?: string;
78
+ /**
79
+ * Texto visible de la zona de arrastre. **Sin default**: sin él, sale de
80
+ * `fileUpload.dropzone` del `BrandMessagesProvider`.
40
81
  */
41
82
  dropzoneLabel?: string;
42
- /** Texto visible mientras se arrastra encima. Default: "Suelta los archivos aquí" */
83
+ /**
84
+ * Texto visible mientras se arrastra encima. **Sin default**: sin él, sale
85
+ * de `fileUpload.dropzoneActive`.
86
+ */
43
87
  dropzoneActiveLabel?: string;
44
- /** Texto visible secundario de la zona. Default: "o haz clic para seleccionar" */
88
+ /**
89
+ * Texto visible secundario de la zona. **Sin default**: sin él, sale de
90
+ * `fileUpload.dropzoneHint`.
91
+ */
45
92
  dropzoneHintLabel?: string;
46
- /** Pista de tamaño máximo. Default: `máx. ${size}` (el tamaño ya viene formateado) */
93
+ /**
94
+ * Pista de peso máximo. Recibe el peso **ya escrito en el locale**.
95
+ * **Sin default**: sin ella, sale de `fileUpload.maxSize`.
96
+ */
47
97
  maxSizeHint?: (maxSize: string) => string;
48
- /** Pista de número máximo de archivos. Default: `hasta ${n} archivos` */
98
+ /**
99
+ * Pista de número máximo de archivos. **Sin default**: sin ella, sale de
100
+ * `fileUpload.maxFiles`.
101
+ */
49
102
  maxFilesHint?: (maxFiles: number) => string;
50
- /** aria-label de la lista de archivos. Default: "Archivos seleccionados" */
103
+ /**
104
+ * aria-label de la lista de archivos. **Sin default**: sin él, sale de
105
+ * `fileUpload.files`.
106
+ */
51
107
  filesLabel?: string;
52
- /** aria-label de la barra de progreso. Default: "Progreso de subida" */
108
+ /**
109
+ * aria-label de la barra de progreso. **Sin default**: sin él, sale de
110
+ * `fileUpload.progress`.
111
+ */
53
112
  progressLabel?: string;
54
- /** aria-label del botón de eliminar archivo. Default: `Eliminar ${nombre}` */
113
+ /**
114
+ * aria-label del botón de quitar un archivo. **Sin default**: sin él, sale
115
+ * de `fileUpload.removeFile`.
116
+ */
55
117
  removeFileLabel?: (fileName: string) => string;
56
- /** Error de archivo demasiado grande. Default: `Archivo demasiado grande (máx. ${size})` */
118
+ /**
119
+ * Error de archivo demasiado pesado. **Sin default**: sin él, sale de
120
+ * `fileUpload.tooLarge`.
121
+ */
57
122
  tooLargeError?: (maxSize: string) => string;
58
- /** Error de tipo no admitido. Default: "Tipo de archivo no permitido" */
123
+ /**
124
+ * Error de tipo no admitido. **Sin default**: sin él, sale de
125
+ * `fileUpload.invalidType`.
126
+ */
59
127
  invalidTypeError?: string;
60
128
  }
61
129
  /**
@@ -4,11 +4,44 @@
4
4
  * otra cosa (la diana es el avatar, no una zona de arrastre), pero acepta y
5
5
  * rechaza exactamente por la misma regla, y una segunda copia de esta función
6
6
  * sería una segunda definición de qué archivo vale.
7
+ *
8
+ * Aquí vive además la mitad **de formato** de esta familia: el peso escrito y
9
+ * la lista de formatos. La regla de la campaña del proveedor es la misma que
10
+ * en la máscara de fecha: *si cambia al cambiar de idioma es cromo y va al
11
+ * catálogo; si cambia al cambiar de país es formato y sale del `locale`*.
7
12
  */
8
- /** El peso de un archivo, en la unidad que toque. */
9
- export declare function formatBytes(bytes: number): string;
13
+ /** El locale que se usa cuando el componente no recibe ninguno. */
14
+ export declare const DEFAULT_LOCALE = "es-ES";
15
+ /**
16
+ * El peso de un archivo, escrito **en el locale**: `2,5 MB` en `es-ES` y
17
+ * `2.5 MB` en `en-US`.
18
+ *
19
+ * «2,5 MB» tiene dos mitades, igual que `dd/mm/aaaa`:
20
+ *
21
+ * - **El símbolo no se traduce.** `MB` es `MB` en las seis lenguas de la
22
+ * suite; no es una palabra, es una unidad del SI.
23
+ * - **El separador decimal y la colocación del sufijo son formato.** La coma
24
+ * o el punto, el espacio antes de la unidad y hasta si va delante o detrás
25
+ * los decide el `locale`, no el idioma de la interfaz.
26
+ *
27
+ * Por eso esto no es una plantilla del catálogo sino `Intl.NumberFormat` con
28
+ * `style: 'unit'`: la cifra la escribe el navegador. Al catálogo va solo la
29
+ * frase que la envuelve («Máximo {size}»), que sí es cromo.
30
+ */
31
+ export declare function formatFileSize(bytes: number, locale?: string): string;
32
+ /**
33
+ * Una lista de cosas escrita con la conjunción del idioma: `JPEG, PNG o WEBP`
34
+ * en castellano, `JPEG, PNG, or WEBP` en inglés, `JPEG, PNG oder WEBP` en
35
+ * alemán.
36
+ *
37
+ * Es `Intl.ListFormat` y no un `join(', ')` con una «o» pegada: la conjunción,
38
+ * la coma de Oxford y el espaciado cambian de una lengua a otra, y pegarlos a
39
+ * mano deja el texto en castellano dentro de una frase traducida. `disjunction`
40
+ * porque se acepta **uno** de los formatos, no todos.
41
+ */
42
+ export declare function formatList(items: string[], locale?: string): string;
10
43
  /**
11
44
  * `null` si el archivo pasa; si no, el mensaje que lo explica. Los mensajes
12
45
  * los pone quien llama: son texto de producto, no de esta función.
13
46
  */
14
- export declare function validateFile(file: File, accept: string | undefined, maxSize: number | undefined, tooLargeError: (maxSize: string) => string, invalidTypeError: string): string | null;
47
+ export declare function validateFile(file: File, accept: string | undefined, maxSize: number | undefined, tooLargeError: (maxSize: string) => string, invalidTypeError: string, locale?: string): string | null;
@@ -16,6 +16,9 @@ import type { FilterBarMessages } from '../molecules/FilterBar/FilterBar';
16
16
  import type { CalendarMessages } from '../molecules/Calendar/Calendar';
17
17
  import type { DatePickerMessages } from '../molecules/DatePicker/DatePicker';
18
18
  import type { TimeSelectMessages } from '../atoms/TimeSelect/TimeSelect';
19
+ import type { FileUploadMessages } from '../atoms/FileUpload/FileUpload';
20
+ import type { ImageCropDialogMessages } from '../molecules/ImageCropDialog/ImageCropDialog';
21
+ import type { AvatarUploadMessages } from '../molecules/AvatarUpload/AvatarUpload';
19
22
  /**
20
23
  * El contrato de textos de la librería: un espacio por componente, y dentro
21
24
  * de cada espacio **todas las claves obligatorias**.
@@ -56,5 +59,8 @@ export interface BrandMessages {
56
59
  calendar: CalendarMessages;
57
60
  datePicker: DatePickerMessages;
58
61
  timeSelect: TimeSelectMessages;
62
+ fileUpload: FileUploadMessages;
63
+ imageCropDialog: ImageCropDialogMessages;
64
+ avatarUpload: AvatarUploadMessages;
59
65
  }
60
- export type { PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, };
66
+ export type { PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, FileUploadMessages, ImageCropDialogMessages, AvatarUploadMessages, };
@@ -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, CalendarMessages, DatePickerMessages, TimeSelectMessages, } from './BrandMessages';
5
+ export type { BrandMessages, PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, FileUploadMessages, ImageCropDialogMessages, AvatarUploadMessages, } from './BrandMessages';
@@ -1,6 +1,53 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import { type FormSize } from '../../constants/form-size';
3
3
  import './AvatarUpload.css';
4
+ /**
5
+ * El cromo de la subida de avatar. Todo lo de aquí vale igual en la pantalla
6
+ * de la cuenta y en la de la organización; lo que cambia entre las dos —qué se
7
+ * sube— entra por `subject`, que es contenido y sigue siendo prop.
8
+ *
9
+ * **El par visible/accesible del botón está aquí entero, y a propósito.**
10
+ * WCAG 2.5.3 (Label in Name) exige que el nombre accesible **contenga** el
11
+ * texto visible: quien navega por voz dice lo que ve. Si el visible saliera
12
+ * del catálogo común («Subir») y el accesible de la pantalla («Subir logo»),
13
+ * los dos lados del contrato vivirían en ficheros distintos y una traducción
14
+ * podría romperlo sin que nada fallara — el botón quedaría inalcanzable por
15
+ * voz. Por eso el catálogo trae los dos: `button`, el verbo suelto, y
16
+ * `buttonFor`, la **plantilla** que lo envuelve con el sujeto.
17
+ *
18
+ * La plantilla, y no una concatenación en el componente, porque el orden es
19
+ * del idioma: «Subir el logo» y *«Upload the logo»* ponen el verbo delante,
20
+ * pero el alemán lo pone al final («das Logo hochladen»). Un `${verbo}
21
+ * ${sujeto}` cableado aquí sería castellano disfrazado.
22
+ *
23
+ * **La regla del catálogo, en una línea: `buttonFor(x)` tiene que contener
24
+ * `button`.** En desarrollo se avisa por consola si no lo cumple.
25
+ */
26
+ export interface AvatarUploadMessages {
27
+ /** Texto **visible** del botón: el verbo suelto («Subir»). */
28
+ button: string;
29
+ /**
30
+ * Nombre **accesible** del botón, con el sujeto dentro («Subir el logo»).
31
+ * Tiene que contener `button`, o WCAG 2.5.3 se rompe.
32
+ */
33
+ buttonFor: (subject: string) => string;
34
+ /** Qué se sube cuando la pantalla no lo dice: el sujeto genérico («el avatar»). */
35
+ subject: string;
36
+ /** Pista **visible** de que además se puede arrastrar. */
37
+ dropHint: (subject: string) => string;
38
+ /** Lo que se anuncia cuando empieza un arrastre sobre la ventana. */
39
+ dropActive: (subject: string) => string;
40
+ /** Pista de peso máximo. Recibe el peso **ya escrito en el locale** («2,5 MB»). */
41
+ maxSize: (maxSize: string) => string;
42
+ /** Error de formato. Recibe los formatos **ya unidos con la conjunción del idioma**. */
43
+ invalidType: (formats: string) => string;
44
+ /** Error de peso. Recibe el peso ya escrito en el locale. */
45
+ tooLarge: (maxSize: string) => string;
46
+ /** Texto del botón que descarta el recorte. */
47
+ cropCancel: string;
48
+ /** Texto del botón que confirma el recorte. */
49
+ cropConfirm: string;
50
+ }
4
51
  export interface AvatarUploadProps {
5
52
  /** URL de la imagen actual. Sin ella, el avatar enseña las iniciales de `name`. */
6
53
  src?: string | null;
@@ -36,16 +83,31 @@ export interface AvatarUploadProps {
36
83
  /** Un archivo rechazado por la validación de cliente, con el mensaje que se enseña. */
37
84
  onError?: (message: string) => void;
38
85
  /**
39
- * Texto **visible** del botón. Default: "Subir" (castellano).
40
- * Corto a propósito: el nombre completo va en `buttonAccessibleLabel`.
86
+ * **Qué** se sube, como sintagma con artículo: `"el logo"`, `"la foto de
87
+ * perfil"`. Es lo único de esta pieza que cambia de una pantalla a otra, así
88
+ * que es contenido y entra por aquí, del catálogo de la aplicación.
89
+ *
90
+ * Con él se arman el nombre accesible del botón, la pista de arrastre y el
91
+ * aviso de soltar, cada uno con su plantilla del catálogo. Sin él, el sujeto
92
+ * genérico de `avatarUpload.subject` («el avatar»).
93
+ */
94
+ subject?: string;
95
+ /**
96
+ * Texto **visible** del botón. **Sin default**: sin él, sale de
97
+ * `avatarUpload.button` del `BrandMessagesProvider`.
98
+ *
99
+ * Corto a propósito: el sujeto va en el nombre accesible, que se arma con
100
+ * `subject`.
41
101
  */
42
102
  buttonLabel?: string;
43
103
  /**
44
- * Nombre **accesible** del botón, para decir de qué es la subida ("Subir
45
- * logo", "Subir avatar"). Por defecto, `buttonLabel`.
104
+ * Nombre **accesible** del botón, entero. Es la salida de emergencia: lo
105
+ * normal es pasar `subject` y dejar que el catálogo lo arme, porque así el
106
+ * verbo visible y el accesible salen del mismo sitio y no se pueden
107
+ * desparejar al traducir.
46
108
  *
47
109
  * WCAG 2.5.3 (Label in Name) exige que **contenga** el texto visible: quien
48
- * navega por voz dice lo que ve. "Subir" dentro de "Subir logo" cumple;
110
+ * navega por voz dice lo que ve. "Subir" dentro de "Subir el logo" cumple;
49
111
  * "Cargar imagen de la organización" no, y deja el control inalcanzable.
50
112
  * En desarrollo se avisa por consola si no lo contiene.
51
113
  */
@@ -58,51 +120,87 @@ export interface AvatarUploadProps {
58
120
  hintLabel?: string;
59
121
  /**
60
122
  * Los formatos, escritos para leer. Default: los subtipos de `accept` en
61
- * mayúsculas. Con comodines (`image/*`) pásalo escrito.
123
+ * mayúsculas, unidos con la conjunción del `locale` (`JPEG, PNG o WEBP`).
124
+ * Con comodines (`image/*`) pásalo escrito.
62
125
  */
63
126
  formatsLabel?: string;
64
- /** Pista de peso máximo. Default: `máx. ${size}` (el peso ya viene formateado). */
127
+ /**
128
+ * Locale con el que se escriben **el peso** («2,5 MB» / «2.5 MB») y **la
129
+ * conjunción de la lista de formatos** («o» / «or» / «oder»). No decide el
130
+ * idioma de los textos —eso es el catálogo— sino el formato. Default
131
+ * `'es-ES'`.
132
+ */
133
+ locale?: string;
134
+ /**
135
+ * Pista de peso máximo. Recibe el peso **ya escrito en el locale**.
136
+ * **Sin default**: sin ella, sale de `avatarUpload.maxSize`.
137
+ */
65
138
  maxSizeHint?: (maxSize: string) => string;
66
139
  /**
67
- * Error de formato. Default: `Formato no admitido. Se aceptan ${formatos}.`
68
- * Dice lo que SÍ se acepta: por el botón el error es imposible (lo filtra el
69
- * diálogo del sistema), pero soltando un archivo no hay filtro que valga.
140
+ * Error de formato. **Sin default**: sin él, sale de
141
+ * `avatarUpload.invalidType`. Dice lo que SÍ se acepta: por el botón el
142
+ * error es imposible (lo filtra el diálogo del sistema), pero soltando un
143
+ * archivo no hay filtro que valga.
70
144
  */
71
145
  invalidTypeError?: (formats: string) => string;
72
- /** Error de peso. Default: `El archivo pesa demasiado. El máximo es ${max}.` */
146
+ /**
147
+ * Error de peso. **Sin default**: sin él, sale de `avatarUpload.tooLarge`.
148
+ */
73
149
  tooLargeError?: (maxSize: string) => string;
74
150
  /**
75
- * Lo que se anuncia cuando empieza un arrastre sobre la ventana.
76
- * Default: "Suelta la imagen sobre el avatar para subirla".
151
+ * Lo que se anuncia cuando empieza un arrastre sobre la ventana. **Sin
152
+ * default**: sin él, `avatarUpload.dropActive` con el `subject`.
77
153
  */
78
154
  dropActiveMessage?: string;
79
155
  /**
80
156
  * Pista **visible** bajo el botón: dice que además se puede arrastrar, que
81
- * es lo único de esta pieza que no se adivina mirándola. Default castellano:
82
- * "…o arrastra la imagen hasta el avatar". Con cadena vacía no se pinta.
157
+ * es lo único de esta pieza que no se adivina mirándola. **Sin default**:
158
+ * sin ella, `avatarUpload.dropHint` con el `subject`. Con cadena vacía no se
159
+ * pinta.
83
160
  */
84
161
  dropHintLabel?: string;
85
162
  /**
86
- * Título del diálogo de recorte. Default: "Recortar imagen" (castellano).
87
- * Es una acción, no una invitación: nombra lo que va a pasar, sin segunda
88
- * persona, como el resto de títulos de diálogo del sistema.
163
+ * Título del diálogo de recorte. **Obligatorio y sin default**, como el
164
+ * `title` del propio `ImageCropDialog`: el diálogo no sabe qué se recorta
165
+ * («Recorta tu foto», «Recorta tu logo») y eso es contenido de la pantalla.
89
166
  */
90
- cropTitle?: string;
167
+ cropTitle: string;
91
168
  /**
92
169
  * Descripción del diálogo de recorte. **Sin default**: el diálogo enseña la
93
170
  * imagen y su marco de selección, que se explican solos. Pásala solo si en
94
171
  * tu caso hay algo que decir que no esté ya a la vista.
95
172
  */
96
173
  cropDescription?: ReactNode;
97
- /** Default: "Cancelar". */
174
+ /**
175
+ * Texto del botón que descarta el recorte. **Sin default**: sin él, sale de
176
+ * `avatarUpload.cropCancel`.
177
+ *
178
+ * Aquí sí sale del catálogo, al revés que en `ImageCropDialog`: el diálogo
179
+ * genérico no sabe qué confirma («Aplicar», «Usar esta imagen») y por eso lo
180
+ * exige; esta subida sí lo sabe —se descarta o se guarda un recorte— y el
181
+ * par vale igual en todas las pantallas.
182
+ */
98
183
  cropCancelLabel?: ReactNode;
99
- /** Default: "Guardar". */
184
+ /**
185
+ * Texto del botón que confirma el recorte. **Sin default**: sin él, sale de
186
+ * `avatarUpload.cropConfirm`.
187
+ */
100
188
  cropConfirmLabel?: ReactNode;
101
- /** Etiqueta del aspa de cerrar. Default: "Cerrar". */
189
+ /**
190
+ * Etiqueta del aspa de cerrar. Se reenvía **tal cual** al `ImageCropDialog`
191
+ * y de ahí al `Modal`, que todavía no lee del proveedor: mientras no se
192
+ * migre, sin esta prop el aspa dice lo que diga `Modal`.
193
+ */
102
194
  cropCloseLabel?: string;
103
- /** Lo que se dice mientras la imagen se carga en el diálogo. Default: "Cargando imagen…". */
195
+ /**
196
+ * Lo que se dice mientras la imagen se carga en el diálogo. Reenvío puro:
197
+ * sin él, el `ImageCropDialog` lo lee de `imageCropDialog.loading`.
198
+ */
104
199
  cropLoadingLabel?: string;
105
- /** Lo que se dice cuando la imagen no se puede cargar. Default: "No hemos podido cargar la imagen. Prueba con otro archivo.". */
200
+ /**
201
+ * Lo que se dice cuando la imagen no se puede cargar. Reenvío puro: sin él,
202
+ * el `ImageCropDialog` lo lee de `imageCropDialog.error`.
203
+ */
106
204
  cropErrorMessage?: string;
107
205
  /** Se añade DESPUÉS de las clases propias del componente. */
108
206
  className?: string;
@@ -122,4 +220,4 @@ export interface AvatarUploadProps {
122
220
  * arrastrar no existe para el teclado, así que es la vía principal, no un
123
221
  * respaldo.
124
222
  */
125
- export declare function AvatarUpload({ src, name, alt, shape, size: sizeProp, accept, maxSize, outputMimeType, outputSize, disabled, busy, errorMessage, onChange, onSelect, onError, buttonLabel, buttonAccessibleLabel, hintLabel, formatsLabel, maxSizeHint, invalidTypeError, tooLargeError, dropActiveMessage, dropHintLabel, cropTitle, cropDescription, cropCancelLabel, cropConfirmLabel, cropCloseLabel, cropLoadingLabel, cropErrorMessage, className, }: AvatarUploadProps): import("react/jsx-runtime").JSX.Element;
223
+ export declare function AvatarUpload({ src, name, alt, shape, size: sizeProp, accept, maxSize, outputMimeType, outputSize, disabled, busy, errorMessage, onChange, onSelect, onError, subject: subjectProp, buttonLabel, buttonAccessibleLabel, hintLabel, formatsLabel, locale, maxSizeHint, invalidTypeError, tooLargeError, dropActiveMessage, dropHintLabel, cropTitle, cropDescription, cropCancelLabel, cropConfirmLabel, cropCloseLabel, cropLoadingLabel, cropErrorMessage, className, }: AvatarUploadProps): import("react/jsx-runtime").JSX.Element;
@@ -43,13 +43,14 @@ export interface CalendarPlannerProps {
43
43
  /** Locale para nombres de mes y día. Default: 'es-ES' */
44
44
  locale?: string;
45
45
  /**
46
- * aria-label del botón de mes anterior. Default: "Mes anterior" (castellano).
47
- * Una app multiidioma debe pasarla traducida.
46
+ * aria-label del botón de mes anterior. **Sin default**: sin él, sale de
47
+ * `calendar.previousMonth` del `BrandMessagesProvider` — es el mismo texto
48
+ * que el del `Calendar`, así que es el mismo espacio.
48
49
  */
49
50
  previousMonthLabel?: string;
50
51
  /**
51
- * aria-label del botón de mes siguiente. Default: "Mes siguiente" (castellano).
52
- * Una app multiidioma debe pasarla traducida.
52
+ * aria-label del botón de mes siguiente. **Sin default**: sin él, sale de
53
+ * `calendar.nextMonth` del `BrandMessagesProvider`.
53
54
  */
54
55
  nextMonthLabel?: string;
55
56
  /**
@@ -62,13 +62,14 @@ export interface CalendarRosterProps {
62
62
  */
63
63
  legendLabel?: string;
64
64
  /**
65
- * aria-label del botón de mes anterior. Default: "Mes anterior" (castellano).
66
- * Una app multiidioma debe pasarla traducida.
65
+ * aria-label del botón de mes anterior. **Sin default**: sin él, sale de
66
+ * `calendar.previousMonth` del `BrandMessagesProvider` — es el mismo texto
67
+ * que el del `Calendar`, así que es el mismo espacio.
67
68
  */
68
69
  previousMonthLabel?: string;
69
70
  /**
70
- * aria-label del botón de mes siguiente. Default: "Mes siguiente" (castellano).
71
- * Una app multiidioma debe pasarla traducida.
71
+ * aria-label del botón de mes siguiente. **Sin default**: sin él, sale de
72
+ * `calendar.nextMonth` del `BrandMessagesProvider`.
72
73
  */
73
74
  nextMonthLabel?: string;
74
75
  /** Locale para nombres de mes y día. Default: 'es-ES' */
@@ -1,6 +1,25 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import 'react-image-crop/dist/ReactCrop.css';
3
3
  import './ImageCropDialog.css';
4
+ /**
5
+ * El cromo del recortador, y **solo el cromo**: lo que el diálogo dice por su
6
+ * cuenta mientras la imagen va y viene.
7
+ *
8
+ * Aquí se ve la distinción que gobierna la campaña entera. El título, el
9
+ * «Cancelar» y el «Guardar» **no** están en este espacio y siguen siendo props
10
+ * obligatorias sin valor por defecto: el diálogo no sabe qué se está
11
+ * recortando —una foto de perfil, un logo, la portada de un curso— ni qué pasa
12
+ * al confirmar, y eso es contenido de la pantalla que lo abre, no un rótulo
13
+ * del sistema. Lo que sí sabe es que la imagen puede tardar y puede fallar: el
14
+ * aviso de carga y el de error son suyos, valen igual en todas las pantallas y
15
+ * por eso salen del catálogo.
16
+ */
17
+ export interface ImageCropDialogMessages {
18
+ /** Lo que se dice mientras la imagen se descarga y descodifica. Se anuncia y se ve. */
19
+ loading: string;
20
+ /** Lo que se dice cuando la imagen no se puede cargar. */
21
+ error: string;
22
+ }
4
23
  export interface ImageCropDialogProps {
5
24
  /** Object URL del fichero elegido; el diálogo está abierto mientras no sea null. */
6
25
  sourceUrl: string | null;
@@ -16,16 +35,21 @@ export interface ImageCropDialogProps {
16
35
  busy?: boolean;
17
36
  cancelLabel: ReactNode;
18
37
  confirmLabel: ReactNode;
19
- /** Etiqueta del botón de cierre del diálogo. */
38
+ /**
39
+ * Etiqueta del botón de cierre del diálogo. Se reenvía **tal cual** al
40
+ * `Modal`, que todavía no lee del proveedor: mientras no se migre, sin esta
41
+ * prop el aspa sigue diciendo lo que diga `Modal`.
42
+ */
20
43
  closeLabel?: string;
21
44
  /**
22
45
  * Lo que se dice mientras la imagen se descarga y descodifica. Se anuncia y
23
- * se ve. Default castellano: «Cargando imagen…».
46
+ * se ve. **Sin default**: sin él, sale de `imageCropDialog.loading` del
47
+ * `BrandMessagesProvider`.
24
48
  */
25
49
  loadingLabel?: string;
26
50
  /**
27
- * Lo que se dice cuando la imagen no se puede cargar. Default castellano:
28
- * «No hemos podido cargar la imagen. Prueba con otro archivo.».
51
+ * Lo que se dice cuando la imagen no se puede cargar. **Sin default**: sin
52
+ * él, sale de `imageCropDialog.error` del `BrandMessagesProvider`.
29
53
  */
30
54
  errorMessage?: string;
31
55
  onConfirm: (blob: Blob) => void | Promise<void>;