@studiolxd/brand 43.0.0 → 44.1.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 +69 -0
- 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/messages/BrandMessages.d.ts +7 -1
- package/dist/_types/messages/index.d.ts +1 -1
- package/dist/_types/molecules/AvatarUpload/AvatarUpload.d.ts +123 -25
- package/dist/_types/molecules/CalendarPlanner/CalendarPlanner.d.ts +5 -4
- package/dist/_types/molecules/CalendarRoster/CalendarRoster.d.ts +5 -4
- package/dist/_types/molecules/ImageCropDialog/ImageCropDialog.d.ts +28 -4
- package/dist/avatar-upload.js +98 -95
- package/dist/brand.css +2 -2
- package/dist/calendar-planner.js +47 -46
- package/dist/calendar-roster.js +62 -61
- package/dist/file-upload.js +120 -117
- package/dist/tokens.css +2 -2
- package/package.json +1 -1
- package/src/tokens/components/star-rating.css +1 -1
|
@@ -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
|
-
*
|
|
39
|
-
*
|
|
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
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Texto visible mientras se arrastra encima. **Sin default**: sin él, sale
|
|
85
|
+
* de `fileUpload.dropzoneActive`.
|
|
86
|
+
*/
|
|
43
87
|
dropzoneActiveLabel?: string;
|
|
44
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Texto visible secundario de la zona. **Sin default**: sin él, sale de
|
|
90
|
+
* `fileUpload.dropzoneHint`.
|
|
91
|
+
*/
|
|
45
92
|
dropzoneHintLabel?: string;
|
|
46
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* aria-label de la lista de archivos. **Sin default**: sin él, sale de
|
|
105
|
+
* `fileUpload.files`.
|
|
106
|
+
*/
|
|
51
107
|
filesLabel?: string;
|
|
52
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* aria-label de la barra de progreso. **Sin default**: sin él, sale de
|
|
110
|
+
* `fileUpload.progress`.
|
|
111
|
+
*/
|
|
53
112
|
progressLabel?: string;
|
|
54
|
-
/**
|
|
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
|
-
/**
|
|
118
|
+
/**
|
|
119
|
+
* Error de archivo demasiado pesado. **Sin default**: sin él, sale de
|
|
120
|
+
* `fileUpload.tooLarge`.
|
|
121
|
+
*/
|
|
57
122
|
tooLargeError?: (maxSize: string) => string;
|
|
58
|
-
/**
|
|
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
|
|
9
|
-
export declare
|
|
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
|
-
*
|
|
40
|
-
*
|
|
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,
|
|
45
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
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.
|
|
68
|
-
* Dice lo que SÍ se acepta: por el botón el
|
|
69
|
-
* diálogo del sistema), pero soltando un
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
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.
|
|
82
|
-
*
|
|
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.
|
|
87
|
-
*
|
|
88
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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.
|
|
47
|
-
*
|
|
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.
|
|
52
|
-
*
|
|
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.
|
|
66
|
-
*
|
|
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.
|
|
71
|
-
*
|
|
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
|
-
/**
|
|
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.
|
|
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.
|
|
28
|
-
*
|
|
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>;
|