@alveole/components 2.0.0-alpha → 2.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.d.ts.map +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/stories/index.d.ts +1 -1
- package/dist/stories/index.d.ts.map +1 -1
- package/dist/stories/index.js +1 -1
- package/dist/ui/Button/Button.d.ts.map +1 -1
- package/dist/ui/Button/Button.js +22 -2
- package/dist/ui/Button/Button.stories.d.ts +12 -0
- package/dist/ui/Button/Button.stories.d.ts.map +1 -1
- package/dist/ui/Button/Button.stories.js +20 -0
- package/dist/ui/Button/Button.stories.sources.d.ts +2 -0
- package/dist/ui/Button/Button.stories.sources.d.ts.map +1 -1
- package/dist/ui/Button/Button.stories.sources.js +3 -0
- package/dist/ui/Button/Button.types.d.ts +4 -0
- package/dist/ui/Button/Button.types.d.ts.map +1 -1
- package/dist/ui/Checkbox/Checkbox.js +2 -2
- package/dist/ui/FileDropZone/FileDropZone.d.ts +10 -0
- package/dist/ui/FileDropZone/FileDropZone.d.ts.map +1 -0
- package/dist/ui/FileDropZone/FileDropZone.js +3 -0
- package/dist/ui/FileDropZone/FileDropZone.stories.d.ts +50 -0
- package/dist/ui/FileDropZone/FileDropZone.stories.d.ts.map +1 -0
- package/dist/ui/FileDropZone/FileDropZone.stories.js +29 -0
- package/dist/ui/FileDropZone/FileDropZone.stories.sources.d.ts +10 -0
- package/dist/ui/FileDropZone/FileDropZone.stories.sources.d.ts.map +1 -0
- package/dist/ui/FileDropZone/FileDropZone.stories.sources.js +10 -0
- package/dist/ui/FileDropZone/FileDropZone.styles.d.ts +37 -0
- package/dist/ui/FileDropZone/FileDropZone.styles.d.ts.map +1 -0
- package/dist/ui/FileDropZone/FileDropZone.styles.js +35 -0
- package/dist/ui/FileDropZone/FileDropZone.web.d.ts +4 -0
- package/dist/ui/FileDropZone/FileDropZone.web.d.ts.map +1 -0
- package/dist/ui/FileDropZone/FileDropZone.web.js +11 -0
- package/dist/ui/FileDropZone/fichiersDuDataTransfer.d.ts.map +1 -0
- package/dist/ui/FileDropZone/index.d.ts +2 -0
- package/dist/ui/FileDropZone/index.d.ts.map +1 -0
- package/dist/ui/FileDropZone/index.js +1 -0
- package/dist/ui/FileDropZone/useDepotFichier.d.ts +17 -0
- package/dist/ui/FileDropZone/useDepotFichier.d.ts.map +1 -0
- package/dist/ui/FileDropZone/useDepotFichier.js +89 -0
- package/dist/ui/FormControl/FileInput.d.ts +10 -12
- package/dist/ui/FormControl/FileInput.d.ts.map +1 -1
- package/dist/ui/FormControl/FileInput.js +15 -53
- package/dist/ui/FormControl/FileInput.stories.d.ts +8 -40
- package/dist/ui/FormControl/FileInput.stories.d.ts.map +1 -1
- package/dist/ui/FormControl/FileInput.stories.js +46 -4
- package/dist/ui/FormControl/FileInput.stories.sources.d.ts +10 -0
- package/dist/ui/FormControl/FileInput.stories.sources.d.ts.map +1 -1
- package/dist/ui/FormControl/FileInput.stories.sources.js +11 -1
- package/dist/ui/FormControl/FileInput.styles.d.ts +2 -39
- package/dist/ui/FormControl/FileInput.styles.d.ts.map +1 -1
- package/dist/ui/FormControl/FileInput.styles.js +3 -32
- package/dist/ui/FormControl/FileInputListe.d.ts +11 -0
- package/dist/ui/FormControl/FileInputListe.d.ts.map +1 -0
- package/dist/ui/FormControl/FileInputListe.js +24 -0
- package/dist/ui/FormControl/fichierCorrespondAuType.d.ts +1 -0
- package/dist/ui/FormControl/fichierCorrespondAuType.d.ts.map +1 -1
- package/dist/ui/FormControl/fichierCorrespondAuType.js +5 -1
- package/dist/ui/FormControl/fichiersDuChamp.d.ts +43 -0
- package/dist/ui/FormControl/fichiersDuChamp.d.ts.map +1 -0
- package/dist/ui/FormControl/fichiersDuChamp.js +63 -0
- package/dist/ui/FormControl/useChoixDeFichier.d.ts +15 -0
- package/dist/ui/FormControl/useChoixDeFichier.d.ts.map +1 -0
- package/dist/ui/FormControl/useChoixDeFichier.js +87 -0
- package/dist/ui/FormControl/valideLeType.d.ts +1 -1
- package/dist/ui/FormControl/valideLeType.js +1 -1
- package/dist/ui/LucideIcon/catalogueLucide.d.ts +117 -0
- package/dist/ui/LucideIcon/catalogueLucide.d.ts.map +1 -1
- package/dist/ui/LucideIcon/vendor/lab.js +1 -1
- package/dist/ui/LucideIcon/vendor/lucide.d.ts +2233 -1722
- package/dist/ui/LucideIcon/vendor/lucide.js +3 -3
- package/dist/ui/RadioGroup/RadioGroup.d.ts +3 -1
- package/dist/ui/RadioGroup/RadioGroup.d.ts.map +1 -1
- package/dist/ui/RadioGroup/RadioGroup.js +5 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +1 -1
- package/package.json +10 -8
- package/dist/ui/DragAndDropFile/DragAndDropFile.d.ts +0 -10
- package/dist/ui/DragAndDropFile/DragAndDropFile.d.ts.map +0 -1
- package/dist/ui/DragAndDropFile/DragAndDropFile.js +0 -13
- package/dist/ui/DragAndDropFile/DragAndDropFile.stories.d.ts +0 -56
- package/dist/ui/DragAndDropFile/DragAndDropFile.stories.d.ts.map +0 -1
- package/dist/ui/DragAndDropFile/DragAndDropFile.stories.js +0 -17
- package/dist/ui/DragAndDropFile/DragAndDropFile.stories.sources.d.ts +0 -10
- package/dist/ui/DragAndDropFile/DragAndDropFile.stories.sources.d.ts.map +0 -1
- package/dist/ui/DragAndDropFile/DragAndDropFile.stories.sources.js +0 -10
- package/dist/ui/DragAndDropFile/DragAndDropFile.styles.d.ts +0 -43
- package/dist/ui/DragAndDropFile/DragAndDropFile.styles.d.ts.map +0 -1
- package/dist/ui/DragAndDropFile/DragAndDropFile.styles.js +0 -43
- package/dist/ui/DragAndDropFile/DragAndDropFile.web.d.ts +0 -3
- package/dist/ui/DragAndDropFile/DragAndDropFile.web.d.ts.map +0 -1
- package/dist/ui/DragAndDropFile/DragAndDropFile.web.js +0 -18
- package/dist/ui/DragAndDropFile/fichiersDuDataTransfer.d.ts.map +0 -1
- package/dist/ui/DragAndDropFile/index.d.ts +0 -2
- package/dist/ui/DragAndDropFile/index.d.ts.map +0 -1
- package/dist/ui/DragAndDropFile/index.js +0 -1
- package/dist/ui/DragAndDropFile/useDepotFichier.d.ts +0 -21
- package/dist/ui/DragAndDropFile/useDepotFichier.d.ts.map +0 -1
- package/dist/ui/DragAndDropFile/useDepotFichier.js +0 -77
- /package/dist/ui/{DragAndDropFile → FileDropZone}/fichiersDuDataTransfer.d.ts +0 -0
- /package/dist/ui/{DragAndDropFile → FileDropZone}/fichiersDuDataTransfer.js +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export const libellesParDefaut = {
|
|
2
|
+
addFile: 'Ajouter un fichier',
|
|
3
|
+
selectFile: 'Sélectionner un fichier',
|
|
4
|
+
gallery: 'Galerie',
|
|
5
|
+
camera: 'Appareil photo',
|
|
6
|
+
document: 'Document',
|
|
7
|
+
cancel: 'Annuler',
|
|
8
|
+
chooseImageTitle: 'Choisir une image',
|
|
9
|
+
chooseDocumentTitle: 'Choisir un fichier',
|
|
10
|
+
chooseImageMessage: 'Prendre une photo ou en choisir une dans la galerie.',
|
|
11
|
+
permissionRequired: 'Autorisation requise',
|
|
12
|
+
cameraPermissionMessage: "Autorisez l'accès à l'appareil photo dans les réglages pour prendre une photo.",
|
|
13
|
+
galleryPermissionMessage: "Autorisez l'accès à la galerie dans les réglages pour choisir une image.",
|
|
14
|
+
unnamed: 'Fichier sans nom',
|
|
15
|
+
remove: 'Retirer',
|
|
16
|
+
};
|
|
17
|
+
const listeDe = (value) => value == null ? [] : Array.isArray(value) ? value : [value];
|
|
18
|
+
export const fichiersVisibles = (value) => listeDe(value).filter(fichier => !fichier.removed);
|
|
19
|
+
// Le champ multiple accumule ; le champ simple ne recoit un fichier que s'il n'en montre aucun.
|
|
20
|
+
export const ajoute = (value, nouveaux, multiple) => {
|
|
21
|
+
if (!multiple)
|
|
22
|
+
return nouveaux[0] ?? value;
|
|
23
|
+
return [...listeDe(value), ...nouveaux];
|
|
24
|
+
};
|
|
25
|
+
const memeFichier = (a, b) => a.id != null && b.id != null ? a.id === b.id : a.uri === b.uri;
|
|
26
|
+
// Un fichier enregistre reste dans la valeur, marque `removed`, pour que l'appelant sache quoi
|
|
27
|
+
// supprimer cote serveur ; un fichier ajoute disparait simplement.
|
|
28
|
+
export const retire = (value, cible) => {
|
|
29
|
+
const retirer = (fichier) => {
|
|
30
|
+
if (!memeFichier(fichier, cible))
|
|
31
|
+
return [fichier];
|
|
32
|
+
return fichier.persisted ? [{ ...fichier, removed: true }] : [];
|
|
33
|
+
};
|
|
34
|
+
if (!Array.isArray(value))
|
|
35
|
+
return value == null ? null : (retirer(value)[0] ?? null);
|
|
36
|
+
const suivants = value.flatMap(retirer);
|
|
37
|
+
return suivants.length === 0 ? null : suivants;
|
|
38
|
+
};
|
|
39
|
+
const typesDe = (type) => (type == null ? [] : Array.isArray(type) ? type : [type]);
|
|
40
|
+
const estUnTypeImage = (t) => t === 'image' || t.startsWith('image/');
|
|
41
|
+
export const imagesSeulement = (type) => {
|
|
42
|
+
const types = typesDe(type);
|
|
43
|
+
return types.length > 0 && types.every(estUnTypeImage);
|
|
44
|
+
};
|
|
45
|
+
const accepteLesImages = (type) => {
|
|
46
|
+
const types = typesDe(type);
|
|
47
|
+
return types.length === 0 || types.some(t => t === '*/*' || estUnTypeImage(t));
|
|
48
|
+
};
|
|
49
|
+
/** Les sources que la feuille d'actions propose sur natif, dans l'ordre. Sur grand ecran, le document passe en tete. */
|
|
50
|
+
export const sourcesProposees = (type, grandEcran) => {
|
|
51
|
+
const images = accepteLesImages(type) ? ['gallery', 'camera'] : [];
|
|
52
|
+
if (imagesSeulement(type))
|
|
53
|
+
return images;
|
|
54
|
+
return grandEcran ? ['document', ...images] : [...images, 'document'];
|
|
55
|
+
};
|
|
56
|
+
/** Sur grand ecran, l'option qui ouvre l'explorateur de fichiers s'annonce comme telle. */
|
|
57
|
+
export const libelleDeLaSource = (source, labels, { type, grandEcran }) => {
|
|
58
|
+
if (source === 'document')
|
|
59
|
+
return grandEcran ? labels.selectFile : labels.document;
|
|
60
|
+
if (source === 'gallery')
|
|
61
|
+
return grandEcran && imagesSeulement(type) ? labels.selectFile : labels.gallery;
|
|
62
|
+
return labels.camera;
|
|
63
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FileInputProps } from './FileInput';
|
|
2
|
+
import { FileInputLabels } from './fichiersDuChamp';
|
|
3
|
+
type Options = Pick<FileInputProps, 'value' | 'onChange' | 'type' | 'disabled' | 'onPickStart'> & {
|
|
4
|
+
multiple: boolean;
|
|
5
|
+
cameraQuality: number;
|
|
6
|
+
labels: FileInputLabels;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Tout ce que le bouton du champ declenche : le selecteur de documents sur le web ; sur natif, une
|
|
10
|
+
* feuille d'actions galerie / appareil photo / document, avec les demandes d'autorisation. Les
|
|
11
|
+
* fichiers recus passent le controle de type, puis s'ajoutent a la valeur.
|
|
12
|
+
*/
|
|
13
|
+
export declare const useChoixDeFichier: (options: Options) => () => Promise<void>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=useChoixDeFichier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useChoixDeFichier.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/useChoixDeFichier.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAGL,eAAe,EAKhB,MAAM,mBAAmB,CAAC;AAmC3B,KAAK,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,aAAa,CAAC,GAAG;IAChG,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,eAAe,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,OAAO,wBAuDjD,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useTheme } from '@alveole/theme';
|
|
2
|
+
import * as DocumentPicker from 'expo-document-picker';
|
|
3
|
+
import * as ImagePicker from 'expo-image-picker';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { Platform } from 'react-native';
|
|
6
|
+
import { Alert } from '../../core/Alert';
|
|
7
|
+
import { ajoute, imagesSeulement, libelleDeLaSource, sourcesProposees, } from './fichiersDuChamp';
|
|
8
|
+
import { valideLeType } from './valideLeType';
|
|
9
|
+
const enFichier = (asset) => ({
|
|
10
|
+
uri: asset.uri,
|
|
11
|
+
name: asset.fileName ?? 'image.jpg',
|
|
12
|
+
size: asset.fileSize ?? 0,
|
|
13
|
+
mimeType: asset.mimeType ?? 'image/jpeg',
|
|
14
|
+
lastModified: Date.now(),
|
|
15
|
+
});
|
|
16
|
+
/** Demande l'autorisation, puis ouvre la galerie ou l'appareil photo. Rend les fichiers choisis, ou aucun. */
|
|
17
|
+
const prendreUneImage = async (source, { labels, cameraQuality, multiple }) => {
|
|
18
|
+
const camera = source === 'camera';
|
|
19
|
+
const demande = camera ? ImagePicker.requestCameraPermissionsAsync : ImagePicker.requestMediaLibraryPermissionsAsync;
|
|
20
|
+
const { status } = await demande();
|
|
21
|
+
if (status !== 'granted') {
|
|
22
|
+
const message = camera ? labels.cameraPermissionMessage : labels.galleryPermissionMessage;
|
|
23
|
+
Alert.alert({ title: labels.permissionRequired, message });
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
const result = camera
|
|
27
|
+
? await ImagePicker.launchCameraAsync({ mediaTypes: ['images'], quality: cameraQuality })
|
|
28
|
+
: await ImagePicker.launchImageLibraryAsync({
|
|
29
|
+
mediaTypes: ['images'],
|
|
30
|
+
quality: 1,
|
|
31
|
+
allowsMultipleSelection: multiple,
|
|
32
|
+
});
|
|
33
|
+
return result.canceled ? [] : result.assets.map(enFichier);
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Tout ce que le bouton du champ declenche : le selecteur de documents sur le web ; sur natif, une
|
|
37
|
+
* feuille d'actions galerie / appareil photo / document, avec les demandes d'autorisation. Les
|
|
38
|
+
* fichiers recus passent le controle de type, puis s'ajoutent a la valeur.
|
|
39
|
+
*/
|
|
40
|
+
export const useChoixDeFichier = (options) => {
|
|
41
|
+
const { value, onChange, type, disabled, onPickStart, multiple, cameraQuality, labels } = options;
|
|
42
|
+
const { isVariant } = useTheme();
|
|
43
|
+
const grandEcran = isVariant('desktop');
|
|
44
|
+
const isPickingRef = React.useRef(false);
|
|
45
|
+
const recevoir = React.useCallback((nouveaux) => {
|
|
46
|
+
if (nouveaux.length === 0)
|
|
47
|
+
return;
|
|
48
|
+
const transmettre = () => onChange(ajoute(value, nouveaux, multiple));
|
|
49
|
+
valideLeType({ type, onChange: transmettre })(multiple ? nouveaux : nouveaux[0]);
|
|
50
|
+
}, [onChange, value, multiple, type]);
|
|
51
|
+
const choisirUnDocument = React.useCallback(async () => {
|
|
52
|
+
const result = await DocumentPicker.getDocumentAsync({ copyToCacheDirectory: true, multiple, type });
|
|
53
|
+
recevoir(result.assets ?? []);
|
|
54
|
+
}, [multiple, type, recevoir]);
|
|
55
|
+
const choisirUneImage = React.useCallback(async (source) => recevoir(await prendreUneImage(source, { labels, cameraQuality, multiple })), [labels, cameraQuality, multiple, recevoir]);
|
|
56
|
+
const ouvrirLaFeuille = React.useCallback(() => {
|
|
57
|
+
const lancer = (source) => (source === 'document' ? choisirUnDocument() : choisirUneImage(source));
|
|
58
|
+
const images = imagesSeulement(type);
|
|
59
|
+
Alert.alert({
|
|
60
|
+
title: images ? labels.chooseImageTitle : labels.chooseDocumentTitle,
|
|
61
|
+
message: images ? labels.chooseImageMessage : undefined,
|
|
62
|
+
buttons: [
|
|
63
|
+
...sourcesProposees(type, grandEcran).map(source => ({
|
|
64
|
+
text: libelleDeLaSource(source, labels, { type, grandEcran }),
|
|
65
|
+
onPress: () => lancer(source),
|
|
66
|
+
})),
|
|
67
|
+
{ text: labels.cancel, style: 'cancel' },
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
}, [type, labels, grandEcran, choisirUnDocument, choisirUneImage]);
|
|
71
|
+
return React.useCallback(async () => {
|
|
72
|
+
if (isPickingRef.current)
|
|
73
|
+
return;
|
|
74
|
+
onPickStart?.();
|
|
75
|
+
if (disabled)
|
|
76
|
+
return;
|
|
77
|
+
if (Platform.OS !== 'web')
|
|
78
|
+
return ouvrirLaFeuille();
|
|
79
|
+
isPickingRef.current = true;
|
|
80
|
+
try {
|
|
81
|
+
await choisirUnDocument();
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
isPickingRef.current = false;
|
|
85
|
+
}
|
|
86
|
+
}, [onPickStart, disabled, ouvrirLaFeuille, choisirUnDocument]);
|
|
87
|
+
};
|
|
@@ -4,7 +4,7 @@ import type { FileInputProps } from './FileInput';
|
|
|
4
4
|
* et prevenir l'utilisateur sinon. Un fichier dont le type MIME est inconnu passe : c'est au
|
|
5
5
|
* selecteur, qui filtre deja, d'avoir eu le dernier mot.
|
|
6
6
|
*
|
|
7
|
-
* Les trois champs de fichier (l'ancien FileField, DragAndDropFile natif et web) faisaient ce filtrage
|
|
7
|
+
* Les trois champs de fichier (l'ancien FileField, l'ancien DragAndDropFile natif et web) faisaient ce filtrage
|
|
8
8
|
* chacun dans son coin, et avaient deja diverge : FileField reconnaissait les types avec ses
|
|
9
9
|
* propres comparaisons de chaines, plus laches que celles des deux autres, et ne verifiait que
|
|
10
10
|
* le premier fichier d'une selection multiple. Un meme fichier pouvait donc etre accepte ici et
|
|
@@ -11,7 +11,7 @@ const refuser = (plusieurs) => Alert.alert({
|
|
|
11
11
|
* et prevenir l'utilisateur sinon. Un fichier dont le type MIME est inconnu passe : c'est au
|
|
12
12
|
* selecteur, qui filtre deja, d'avoir eu le dernier mot.
|
|
13
13
|
*
|
|
14
|
-
* Les trois champs de fichier (l'ancien FileField, DragAndDropFile natif et web) faisaient ce filtrage
|
|
14
|
+
* Les trois champs de fichier (l'ancien FileField, l'ancien DragAndDropFile natif et web) faisaient ce filtrage
|
|
15
15
|
* chacun dans son coin, et avaient deja diverge : FileField reconnaissait les types avec ses
|
|
16
16
|
* propres comparaisons de chaines, plus laches que celles des deux autres, et ne verifiait que
|
|
17
17
|
* le premier fichier d'une selection multiple. Un meme fichier pouvait donc etre accepte ici et
|