@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,89 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Alert } from '../../core/Alert';
|
|
3
|
+
import { ajoute, fichierCorrespondAuType, fichiersVisibles } from '../FormControl';
|
|
4
|
+
import { fichiersDuDataTransfer } from './fichiersDuDataTransfer';
|
|
5
|
+
const enAsset = (file) => ({
|
|
6
|
+
uri: URL.createObjectURL(file),
|
|
7
|
+
name: file.name,
|
|
8
|
+
size: file.size,
|
|
9
|
+
mimeType: file.type || 'application/octet-stream',
|
|
10
|
+
lastModified: file.lastModified,
|
|
11
|
+
file,
|
|
12
|
+
});
|
|
13
|
+
const urisBlob = (value) => (Array.isArray(value) ? value : [value]).map(fichier => fichier?.uri).filter(uri => uri?.startsWith('blob:'));
|
|
14
|
+
const revoquer = (uris) => uris.forEach(uri => {
|
|
15
|
+
try {
|
|
16
|
+
URL.revokeObjectURL(uri);
|
|
17
|
+
}
|
|
18
|
+
catch { }
|
|
19
|
+
});
|
|
20
|
+
const contientDesFichiers = (e) => Array.from(e.dataTransfer?.types ?? []).includes('Files');
|
|
21
|
+
/**
|
|
22
|
+
* Le comportement de la zone de depot : s'allumer quand un glissement de fichiers la survole,
|
|
23
|
+
* convertir les fichiers lâches en valeurs du champ, et liberer les URL d'objet. Chaque
|
|
24
|
+
* evenement traite s'arrete a la zone : entre zones imbriquees, seule la plus proche reagit.
|
|
25
|
+
*/
|
|
26
|
+
export const useDepotFichier = ({ value, type, multiple, onChange, disabled }) => {
|
|
27
|
+
const [actif, setActif] = React.useState(false);
|
|
28
|
+
// `dragenter`/`dragleave` se declenchent a chaque enfant traverse : on compte les entrees pour
|
|
29
|
+
// ne s'eteindre qu'en quittant vraiment la zone.
|
|
30
|
+
const entreesRef = React.useRef(0);
|
|
31
|
+
// Meme regle que le bouton du champ : un champ simple qui montre deja un fichier n'en recoit pas.
|
|
32
|
+
const accepte = !disabled && (!!multiple || fichiersVisibles(value).length === 0);
|
|
33
|
+
const concerne = (e) => accepte && contientDesFichiers(e);
|
|
34
|
+
// Les gestionnaires ne sont pas memoises : un formulaire controle passe un `onChange` neuf a
|
|
35
|
+
// chaque rendu, et une memoisation figerait celui du premier rendu.
|
|
36
|
+
const deposer = (files) => {
|
|
37
|
+
const valides = files.filter(file => fichierCorrespondAuType(file.type || '', file.name, type));
|
|
38
|
+
if (valides.length < files.length) {
|
|
39
|
+
Alert.alert({ title: 'Type de fichier incorrect', message: 'Certains fichiers ne sont pas pris en charge' });
|
|
40
|
+
}
|
|
41
|
+
if (valides.length === 0)
|
|
42
|
+
return;
|
|
43
|
+
onChange(ajoute(value, (multiple ? valides : [valides[0]]).map(enAsset), !!multiple));
|
|
44
|
+
};
|
|
45
|
+
const arreter = (e) => {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
};
|
|
49
|
+
const onDragEnter = (e) => {
|
|
50
|
+
if (!concerne(e))
|
|
51
|
+
return;
|
|
52
|
+
arreter(e);
|
|
53
|
+
entreesRef.current += 1;
|
|
54
|
+
setActif(true);
|
|
55
|
+
};
|
|
56
|
+
const onDragOver = (e) => {
|
|
57
|
+
if (concerne(e))
|
|
58
|
+
arreter(e);
|
|
59
|
+
};
|
|
60
|
+
const onDragLeave = (e) => {
|
|
61
|
+
if (!concerne(e))
|
|
62
|
+
return;
|
|
63
|
+
arreter(e);
|
|
64
|
+
entreesRef.current = Math.max(0, entreesRef.current - 1);
|
|
65
|
+
if (entreesRef.current === 0)
|
|
66
|
+
setActif(false);
|
|
67
|
+
};
|
|
68
|
+
const onDrop = (e) => {
|
|
69
|
+
if (!concerne(e))
|
|
70
|
+
return;
|
|
71
|
+
arreter(e);
|
|
72
|
+
entreesRef.current = 0;
|
|
73
|
+
setActif(false);
|
|
74
|
+
const files = fichiersDuDataTransfer(e.dataTransfer);
|
|
75
|
+
if (files.length > 0)
|
|
76
|
+
deposer(multiple ? files : [files[0]]);
|
|
77
|
+
};
|
|
78
|
+
// Chaque fichier depose est publie derriere une URL d'objet, que le navigateur garde en memoire
|
|
79
|
+
// tant qu'on ne la revoque pas. La valeur s'accumule : on ne libere que les URL qui en sortent,
|
|
80
|
+
// et toutes au demontage.
|
|
81
|
+
const urisRef = React.useRef([]);
|
|
82
|
+
React.useEffect(() => {
|
|
83
|
+
const actuelles = urisBlob(value);
|
|
84
|
+
revoquer(urisRef.current.filter(uri => !actuelles.includes(uri)));
|
|
85
|
+
urisRef.current = actuelles;
|
|
86
|
+
}, [value]);
|
|
87
|
+
React.useEffect(() => () => revoquer(urisRef.current), []);
|
|
88
|
+
return { actif, onDragEnter, onDragOver, onDragLeave, onDrop };
|
|
89
|
+
};
|
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import * as DocumentPicker from 'expo-document-picker';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
|
|
3
|
+
import { FileInputLabels, FileInputValue } from './fichiersDuChamp';
|
|
4
|
+
export * from './fichiersDuChamp';
|
|
4
5
|
export type FileInputProps = {
|
|
5
6
|
value: FileInputValue;
|
|
6
|
-
|
|
7
|
-
placeholder?: string;
|
|
8
|
-
forcePlaceholder?: boolean;
|
|
9
|
-
hideButton?: boolean;
|
|
10
|
-
hideFilename?: boolean;
|
|
11
|
-
canChange?: boolean;
|
|
12
|
-
disabled?: boolean;
|
|
7
|
+
onChange: (value: FileInputValue) => void;
|
|
13
8
|
type?: DocumentPicker.DocumentPickerOptions['type'];
|
|
14
9
|
multiple?: boolean;
|
|
15
|
-
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
removable?: boolean;
|
|
12
|
+
hideButton?: boolean;
|
|
13
|
+
labels?: Partial<FileInputLabels>;
|
|
14
|
+
/** Qualite des photos prises avec l'appareil photo, de 0 a 1. */
|
|
15
|
+
cameraQuality?: number;
|
|
16
16
|
reopen?: boolean;
|
|
17
17
|
onPickStart?: () => void;
|
|
18
18
|
};
|
|
19
|
-
export declare const
|
|
20
|
-
export declare const choisis: (assets: DocumentPicker.DocumentPickerAsset[] | null, multiple: boolean) => DocumentPicker.DocumentPickerAsset | DocumentPicker.DocumentPickerAsset[] | null;
|
|
21
|
-
export declare const FileInput: (props: FileInputProps) => React.JSX.Element | null;
|
|
19
|
+
export declare const FileInput: (props: FileInputProps) => React.JSX.Element;
|
|
22
20
|
//# sourceMappingURL=FileInput.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileInput.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/FileInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,cAAc,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"FileInput.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/FileInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,cAAc,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,eAAe,EAAE,cAAc,EAA+C,MAAM,mBAAmB,CAAC;AAKjH,cAAc,mBAAmB,CAAC;AAElC,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1C,IAAI,CAAC,EAAE,cAAc,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAClC,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,OAAO,cAAc,sBAmC9C,CAAC"}
|
|
@@ -1,62 +1,24 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import * as DocumentPicker from 'expo-document-picker';
|
|
3
2
|
import React from 'react';
|
|
4
|
-
import {
|
|
3
|
+
import { Platform } from 'react-native';
|
|
5
4
|
import { Box } from '../../core/Box';
|
|
6
|
-
import {
|
|
5
|
+
import { Button } from '../Button';
|
|
6
|
+
import { fichiersVisibles, libellesParDefaut, retire } from './fichiersDuChamp';
|
|
7
7
|
import { useStyles } from './FileInput.styles';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// depend que de la valeur.
|
|
12
|
-
export const nomAffiche = (value, placeholder, forcePlaceholder) => {
|
|
13
|
-
if (value == null || forcePlaceholder)
|
|
14
|
-
return placeholder;
|
|
15
|
-
if (!Array.isArray(value))
|
|
16
|
-
return value.name || '1 fichier';
|
|
17
|
-
if (value.length === 0)
|
|
18
|
-
return placeholder;
|
|
19
|
-
if (value.length === 1)
|
|
20
|
-
return value[0].name ?? '1 fichier';
|
|
21
|
-
return `${value.length} fichiers`;
|
|
22
|
-
};
|
|
23
|
-
// Le selecteur rend toujours une liste ; le champ simple n'en veut que le premier element, et
|
|
24
|
-
// une liste vide vaut une absence de choix dans les deux cas.
|
|
25
|
-
export const choisis = (assets, multiple) => {
|
|
26
|
-
if (!multiple)
|
|
27
|
-
return assets?.[0] ?? null;
|
|
28
|
-
return assets && assets.length > 0 ? assets : null;
|
|
29
|
-
};
|
|
8
|
+
import { FileInputListe } from './FileInputListe';
|
|
9
|
+
import { useChoixDeFichier } from './useChoixDeFichier';
|
|
10
|
+
export * from './fichiersDuChamp';
|
|
30
11
|
export const FileInput = (props) => {
|
|
31
|
-
const { value, disabled, onChange,
|
|
12
|
+
const { value, disabled, onChange, reopen = false, multiple = false, hideButton = false, removable = true } = props;
|
|
32
13
|
const styles = useStyles();
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
onPickStart?.();
|
|
39
|
-
if (disabled)
|
|
40
|
-
return;
|
|
41
|
-
isPickingRef.current = true;
|
|
42
|
-
try {
|
|
43
|
-
const result = await DocumentPicker.getDocumentAsync({ copyToCacheDirectory: true, multiple, type });
|
|
44
|
-
valideLeType({ type, onChange })(choisis(result.assets, multiple));
|
|
45
|
-
}
|
|
46
|
-
finally {
|
|
47
|
-
isPickingRef.current = false;
|
|
48
|
-
}
|
|
49
|
-
}, [onPickStart, disabled, multiple, type, onChange]);
|
|
14
|
+
const labels = React.useMemo(() => ({ ...libellesParDefaut, ...props.labels }), [props.labels]);
|
|
15
|
+
const choisir = useChoixDeFichier({ ...props, multiple, cameraQuality: props.cameraQuality ?? 0.8, labels });
|
|
16
|
+
// Le champ simple ne remplace pas un fichier en silence : il faut d'abord retirer celui qu'il montre.
|
|
17
|
+
const visibles = fichiersVisibles(value);
|
|
18
|
+
const boutonDesactive = disabled || (!multiple && visibles.length > 0);
|
|
50
19
|
React.useEffect(() => {
|
|
51
20
|
if (reopen)
|
|
52
|
-
|
|
53
|
-
}, [reopen,
|
|
54
|
-
|
|
55
|
-
return null;
|
|
56
|
-
return (_jsx(Pressable, { accessibilityRole: "button", onPress: handlePickFile, children: _jsxs(Box, { tag: "form-control-file-input-inner", style: {
|
|
57
|
-
...styles.fileInputContainer,
|
|
58
|
-
}, children: [_jsx(Box, { tag: "file-input-button", hoverStyle: { ...(!disabled && styles.fileInputButtonHovered) }, style: {
|
|
59
|
-
...styles.fileInputButton,
|
|
60
|
-
...(disabled && styles.fileInputButtonDisabled),
|
|
61
|
-
}, children: _jsx(Typography, { style: styles.inputFileText, children: "Choisir un fichier" }) }), _jsx(Box, { tag: "file-input-text", children: _jsx(Typography, { mt: 'auto', mb: 'auto', style: styles.placeholderText, children: displayValue }) })] }) }));
|
|
21
|
+
choisir();
|
|
22
|
+
}, [reopen, choisir]);
|
|
23
|
+
return (_jsxs(Box, { tag: "file-input", style: styles.container, children: [!hideButton && (_jsx(Button, { fullWidth: Platform.OS !== 'web', onPress: choisir, disabled: boutonDesactive, variant: "secondary", title: labels.addFile, leading: "Paperclip" })), _jsx(FileInputListe, { fichiers: visibles, labels: labels, retirable: !disabled && removable, onRetirer: fichier => onChange(retire(value, fichier)) })] }));
|
|
62
24
|
};
|
|
@@ -3,54 +3,22 @@ declare const _default: {
|
|
|
3
3
|
tags: "ui"[];
|
|
4
4
|
experimental: false;
|
|
5
5
|
description: string;
|
|
6
|
-
component: (props: import("./FileInput").FileInputProps) => import("react").JSX.Element
|
|
6
|
+
component: (props: import("./FileInput").FileInputProps) => import("react").JSX.Element;
|
|
7
7
|
styleFn: () => {
|
|
8
|
-
|
|
8
|
+
container: {
|
|
9
9
|
display: "flex";
|
|
10
|
-
flexDirection: "
|
|
10
|
+
flexDirection: "column";
|
|
11
11
|
gap: string | number;
|
|
12
|
-
alignItems: "center";
|
|
13
|
-
};
|
|
14
|
-
fileInputButton: {
|
|
15
|
-
borderWidth: number;
|
|
16
|
-
borderColor: string;
|
|
17
|
-
backgroundColor: string;
|
|
18
|
-
transition: "background-color 0.1s ease-in-out";
|
|
19
|
-
display: "flex";
|
|
20
|
-
alignItems: "center";
|
|
21
|
-
justifyContent: "center";
|
|
22
|
-
paddingLeft: string | number;
|
|
23
|
-
paddingRight: string | number;
|
|
24
|
-
paddingTop: string | number;
|
|
25
|
-
paddingBottom: string | number;
|
|
26
|
-
};
|
|
27
|
-
fileInputButtonHovered: {
|
|
28
|
-
backgroundColor: string;
|
|
29
|
-
};
|
|
30
|
-
fileInputButtonDisabled: {
|
|
31
|
-
cursor: "not-allowed";
|
|
32
|
-
backgroundColor: string;
|
|
33
|
-
};
|
|
34
|
-
inputFileText: {
|
|
35
|
-
color: string;
|
|
36
|
-
fontSize: 12;
|
|
37
|
-
lineHeight: 20;
|
|
38
|
-
letterSpacing: 0;
|
|
39
|
-
fontFamily: string;
|
|
40
|
-
fontWeight?: import("react-native").TextStyle["fontWeight"];
|
|
41
|
-
};
|
|
42
|
-
placeholderText: {
|
|
43
|
-
color: string;
|
|
44
|
-
fontSize: 12;
|
|
45
|
-
lineHeight: 20;
|
|
46
|
-
letterSpacing: 0;
|
|
47
|
-
fontFamily: string;
|
|
48
|
-
fontWeight?: import("react-native").TextStyle["fontWeight"];
|
|
49
12
|
};
|
|
50
13
|
};
|
|
51
14
|
};
|
|
52
15
|
export default _default;
|
|
53
16
|
export declare const Default: () => import("react").JSX.Element;
|
|
54
17
|
export declare const Multiple: () => import("react").JSX.Element;
|
|
18
|
+
export declare const ImagesSeulement: () => import("react").JSX.Element;
|
|
19
|
+
export declare const AvecFichiersEnregistres: () => import("react").JSX.Element;
|
|
20
|
+
export declare const LibellesPersonnalises: () => import("react").JSX.Element;
|
|
21
|
+
export declare const Desactive: () => import("react").JSX.Element;
|
|
22
|
+
export declare const NonRetirable: () => import("react").JSX.Element;
|
|
55
23
|
export * as Sources from './FileInput.stories.sources';
|
|
56
24
|
//# sourceMappingURL=FileInput.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileInput.stories.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/FileInput.stories.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FileInput.stories.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/FileInput.stories.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;AAMA,wBAQkB;AAElB,eAAO,MAAM,OAAO,mCAOnB,CAAC;AAEF,eAAO,MAAM,QAAQ,mCAOpB,CAAC;AAEF,eAAO,MAAM,eAAe,mCAO3B,CAAC;AAEF,eAAO,MAAM,uBAAuB,mCAwBnC,CAAC;AAEF,eAAO,MAAM,qBAAqB,mCAWjC,CAAC;AAEF,eAAO,MAAM,SAAS,mCAarB,CAAC;AAEF,eAAO,MAAM,YAAY,mCAexB,CAAC;AAEF,OAAO,KAAK,OAAO,MAAM,6BAA6B,CAAC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
|
-
import { Box } from '../../core/Box';
|
|
4
3
|
import { FileInput } from './FileInput';
|
|
5
4
|
import { useStyles } from './FileInput.styles';
|
|
6
5
|
import { FormControl } from './FormControl';
|
|
@@ -8,16 +7,59 @@ export default {
|
|
|
8
7
|
title: 'FileInput',
|
|
9
8
|
tags: ['ui'],
|
|
10
9
|
experimental: false,
|
|
11
|
-
description:
|
|
10
|
+
description: "Sélection de fichiers avec validation MIME et liste des fichiers choisis. Sur natif, propose galerie, appareil photo ou document. Nue : on la place dans un FormControl pour son libellé, son aide et sa validation. Pour déposer des fichiers sur tout un formulaire (web), l'envelopper dans une [FileDropZone](/components/FileDropZone).",
|
|
12
11
|
component: FileInput,
|
|
13
12
|
styleFn: useStyles,
|
|
14
13
|
};
|
|
15
14
|
export const Default = () => {
|
|
16
15
|
const [file, setFile] = useState(null);
|
|
17
|
-
return (
|
|
16
|
+
return (_jsx(FormControl, { label: "Document", children: _jsx(FileInput, { value: file, onChange: setFile }) }));
|
|
18
17
|
};
|
|
19
18
|
export const Multiple = () => {
|
|
20
19
|
const [files, setFiles] = useState(null);
|
|
21
20
|
return (_jsx(FormControl, { label: "Documents", children: _jsx(FileInput, { value: files, onChange: setFiles, multiple: true }) }));
|
|
22
21
|
};
|
|
22
|
+
export const ImagesSeulement = () => {
|
|
23
|
+
const [files, setFiles] = useState(null);
|
|
24
|
+
return (_jsx(FormControl, { label: "Photos", hint: "Formats accept\u00E9s : JPG, PNG", children: _jsx(FileInput, { type: "image/*", value: files, onChange: setFiles, multiple: true }) }));
|
|
25
|
+
};
|
|
26
|
+
export const AvecFichiersEnregistres = () => {
|
|
27
|
+
const [files, setFiles] = useState([
|
|
28
|
+
{
|
|
29
|
+
id: '1',
|
|
30
|
+
persisted: true,
|
|
31
|
+
uri: 'https://picsum.photos/id/10/200',
|
|
32
|
+
name: 'photo-chantier.jpg',
|
|
33
|
+
mimeType: 'image/jpeg',
|
|
34
|
+
lastModified: 0,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: '2',
|
|
38
|
+
persisted: true,
|
|
39
|
+
uri: 'https://example.com/devis.pdf',
|
|
40
|
+
name: 'devis.pdf',
|
|
41
|
+
mimeType: 'application/pdf',
|
|
42
|
+
lastModified: 0,
|
|
43
|
+
},
|
|
44
|
+
]);
|
|
45
|
+
return (_jsx(FormControl, { label: "Pi\u00E8ces jointes", hint: "Un fichier enregistr\u00E9 retir\u00E9 reste dans la valeur, marqu\u00E9 removed.", children: _jsx(FileInput, { value: files, onChange: setFiles, multiple: true }) }));
|
|
46
|
+
};
|
|
47
|
+
export const LibellesPersonnalises = () => {
|
|
48
|
+
const [file, setFile] = useState(null);
|
|
49
|
+
return (_jsx(FormControl, { label: "Attachment", children: _jsx(FileInput, { value: file, onChange: setFile, labels: { addFile: 'Add a file', gallery: 'Gallery', camera: 'Camera', document: 'Document', cancel: 'Cancel' } }) }));
|
|
50
|
+
};
|
|
51
|
+
export const Desactive = () => (_jsx(FormControl, { label: "Document", disabled: true, children: _jsx(FileInput, { value: {
|
|
52
|
+
uri: 'https://example.com/contrat.pdf',
|
|
53
|
+
name: 'contrat.pdf',
|
|
54
|
+
mimeType: 'application/pdf',
|
|
55
|
+
lastModified: 0,
|
|
56
|
+
}, onChange: () => { }, disabled: true }) }));
|
|
57
|
+
export const NonRetirable = () => (_jsx(FormControl, { label: "Justificatif", children: _jsx(FileInput, { value: {
|
|
58
|
+
id: '3',
|
|
59
|
+
persisted: true,
|
|
60
|
+
uri: 'https://example.com/justificatif.pdf',
|
|
61
|
+
name: 'justificatif.pdf',
|
|
62
|
+
mimeType: 'application/pdf',
|
|
63
|
+
lastModified: 0,
|
|
64
|
+
}, onChange: () => { }, removable: false }) }));
|
|
23
65
|
export * as Sources from './FileInput.stories.sources';
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
export declare const Default: () => string;
|
|
2
2
|
export declare const Multiple: () => string;
|
|
3
|
+
export declare const ImagesSeulement: () => string;
|
|
4
|
+
export declare const AvecFichiersEnregistres: () => string;
|
|
5
|
+
export declare const LibellesPersonnalises: () => string;
|
|
6
|
+
export declare const Desactive: () => string;
|
|
7
|
+
export declare const NonRetirable: () => string;
|
|
3
8
|
export declare const storySources: {
|
|
4
9
|
readonly Default: () => string;
|
|
5
10
|
readonly Multiple: () => string;
|
|
11
|
+
readonly ImagesSeulement: () => string;
|
|
12
|
+
readonly AvecFichiersEnregistres: () => string;
|
|
13
|
+
readonly LibellesPersonnalises: () => string;
|
|
14
|
+
readonly Desactive: () => string;
|
|
15
|
+
readonly NonRetirable: () => string;
|
|
6
16
|
};
|
|
7
17
|
export type StorySourceName = keyof typeof storySources;
|
|
8
18
|
//# sourceMappingURL=FileInput.stories.sources.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileInput.stories.sources.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/FileInput.stories.sources.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"FileInput.stories.sources.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/FileInput.stories.sources.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,cAAyO,CAAC;AAE9P,eAAO,MAAM,QAAQ,cAAwP,CAAC;AAE9Q,eAAO,MAAM,eAAe,cAAkT,CAAC;AAE/U,eAAO,MAAM,uBAAuB,cAAotB,CAAC;AAEzvB,eAAO,MAAM,qBAAqB,cAA4Y,CAAC;AAE/a,eAAO,MAAM,SAAS,cAA0V,CAAC;AAEjX,eAAO,MAAM,YAAY,cAAuZ,CAAC;AAEjb,eAAO,MAAM,YAAY;;;;;;;;CAQf,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,YAAY,CAAC"}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
// This file is generated. Do not edit manually.
|
|
2
2
|
// Source: src/ui/FormControl/FileInput.stories.tsx
|
|
3
|
-
export const Default = () => "export const Default = () => {\n const [file, setFile] = useState<FileInputValue>(null);\n return (\n <
|
|
3
|
+
export const Default = () => "export const Default = () => {\n const [file, setFile] = useState<FileInputValue>(null);\n return (\n <FormControl label=\"Document\">\n <FileInput value={file} onChange={setFile} />\n </FormControl>\n );\n};";
|
|
4
4
|
export const Multiple = () => "export const Multiple = () => {\n const [files, setFiles] = useState<FileInputValue>(null);\n return (\n <FormControl label=\"Documents\">\n <FileInput value={files} onChange={setFiles} multiple />\n </FormControl>\n );\n};";
|
|
5
|
+
export const ImagesSeulement = () => "export const ImagesSeulement = () => {\n const [files, setFiles] = useState<FileInputValue>(null);\n return (\n <FormControl label=\"Photos\" hint=\"Formats acceptés : JPG, PNG\">\n <FileInput type=\"image/*\" value={files} onChange={setFiles} multiple />\n </FormControl>\n );\n};";
|
|
6
|
+
export const AvecFichiersEnregistres = () => "export const AvecFichiersEnregistres = () => {\n const [files, setFiles] = useState<FileInputValue>([\n {\n id: '1',\n persisted: true,\n uri: 'https://picsum.photos/id/10/200',\n name: 'photo-chantier.jpg',\n mimeType: 'image/jpeg',\n lastModified: 0,\n },\n {\n id: '2',\n persisted: true,\n uri: 'https://example.com/devis.pdf',\n name: 'devis.pdf',\n mimeType: 'application/pdf',\n lastModified: 0,\n },\n ]);\n return (\n <FormControl label=\"Pièces jointes\" hint=\"Un fichier enregistré retiré reste dans la valeur, marqué removed.\">\n <FileInput value={files} onChange={setFiles} multiple />\n </FormControl>\n );\n};";
|
|
7
|
+
export const LibellesPersonnalises = () => "export const LibellesPersonnalises = () => {\n const [file, setFile] = useState<FileInputValue>(null);\n return (\n <FormControl label=\"Attachment\">\n <FileInput\n value={file}\n onChange={setFile}\n labels={{ addFile: 'Add a file', gallery: 'Gallery', camera: 'Camera', document: 'Document', cancel: 'Cancel' }}\n />\n </FormControl>\n );\n};";
|
|
8
|
+
export const Desactive = () => "export const Desactive = () => (\n <FormControl label=\"Document\" disabled>\n <FileInput\n value={{\n uri: 'https://example.com/contrat.pdf',\n name: 'contrat.pdf',\n mimeType: 'application/pdf',\n lastModified: 0,\n }}\n onChange={() => {}}\n disabled\n />\n </FormControl>\n);";
|
|
9
|
+
export const NonRetirable = () => "export const NonRetirable = () => (\n <FormControl label=\"Justificatif\">\n <FileInput\n value={{\n id: '3',\n persisted: true,\n uri: 'https://example.com/justificatif.pdf',\n name: 'justificatif.pdf',\n mimeType: 'application/pdf',\n lastModified: 0,\n }}\n onChange={() => {}}\n removable={false}\n />\n </FormControl>\n);";
|
|
5
10
|
export const storySources = {
|
|
6
11
|
Default,
|
|
7
12
|
Multiple,
|
|
13
|
+
ImagesSeulement,
|
|
14
|
+
AvecFichiersEnregistres,
|
|
15
|
+
LibellesPersonnalises,
|
|
16
|
+
Desactive,
|
|
17
|
+
NonRetirable,
|
|
8
18
|
};
|
|
@@ -1,45 +1,8 @@
|
|
|
1
1
|
export declare const useStyles: () => {
|
|
2
|
-
|
|
2
|
+
container: {
|
|
3
3
|
display: "flex";
|
|
4
|
-
flexDirection: "
|
|
4
|
+
flexDirection: "column";
|
|
5
5
|
gap: string | number;
|
|
6
|
-
alignItems: "center";
|
|
7
|
-
};
|
|
8
|
-
fileInputButton: {
|
|
9
|
-
borderWidth: number;
|
|
10
|
-
borderColor: string;
|
|
11
|
-
backgroundColor: string;
|
|
12
|
-
transition: "background-color 0.1s ease-in-out";
|
|
13
|
-
display: "flex";
|
|
14
|
-
alignItems: "center";
|
|
15
|
-
justifyContent: "center";
|
|
16
|
-
paddingLeft: string | number;
|
|
17
|
-
paddingRight: string | number;
|
|
18
|
-
paddingTop: string | number;
|
|
19
|
-
paddingBottom: string | number;
|
|
20
|
-
};
|
|
21
|
-
fileInputButtonHovered: {
|
|
22
|
-
backgroundColor: string;
|
|
23
|
-
};
|
|
24
|
-
fileInputButtonDisabled: {
|
|
25
|
-
cursor: "not-allowed";
|
|
26
|
-
backgroundColor: string;
|
|
27
|
-
};
|
|
28
|
-
inputFileText: {
|
|
29
|
-
color: string;
|
|
30
|
-
fontSize: 12;
|
|
31
|
-
lineHeight: 20;
|
|
32
|
-
letterSpacing: 0;
|
|
33
|
-
fontFamily: string;
|
|
34
|
-
fontWeight?: import("react-native").TextStyle["fontWeight"];
|
|
35
|
-
};
|
|
36
|
-
placeholderText: {
|
|
37
|
-
color: string;
|
|
38
|
-
fontSize: 12;
|
|
39
|
-
lineHeight: 20;
|
|
40
|
-
letterSpacing: 0;
|
|
41
|
-
fontFamily: string;
|
|
42
|
-
fontWeight?: import("react-native").TextStyle["fontWeight"];
|
|
43
6
|
};
|
|
44
7
|
};
|
|
45
8
|
//# sourceMappingURL=FileInput.styles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileInput.styles.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/FileInput.styles.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS
|
|
1
|
+
{"version":3,"file":"FileInput.styles.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/FileInput.styles.tsx"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS;;;;;;CAMnB,CAAC"}
|
|
@@ -1,37 +1,8 @@
|
|
|
1
1
|
import { makeStyles } from '@alveole/theme';
|
|
2
|
-
export const useStyles = makeStyles(({
|
|
3
|
-
|
|
2
|
+
export const useStyles = makeStyles(({ spacing }) => ({
|
|
3
|
+
container: {
|
|
4
4
|
display: 'flex',
|
|
5
|
-
flexDirection: '
|
|
5
|
+
flexDirection: 'column',
|
|
6
6
|
gap: spacing('1W'),
|
|
7
|
-
alignItems: 'center',
|
|
8
|
-
},
|
|
9
|
-
fileInputButton: {
|
|
10
|
-
borderWidth: 1,
|
|
11
|
-
borderColor: color.border['default-grey'],
|
|
12
|
-
backgroundColor: color.background['alt-grey'],
|
|
13
|
-
transition: 'background-color 0.1s ease-in-out',
|
|
14
|
-
display: 'flex',
|
|
15
|
-
alignItems: 'center',
|
|
16
|
-
justifyContent: 'center',
|
|
17
|
-
paddingLeft: spacing('1W'),
|
|
18
|
-
paddingRight: spacing('1W'),
|
|
19
|
-
paddingTop: spacing('1,5V'),
|
|
20
|
-
paddingBottom: spacing('1,5V'),
|
|
21
|
-
},
|
|
22
|
-
fileInputButtonHovered: {
|
|
23
|
-
backgroundColor: color.background['contrast-grey'],
|
|
24
|
-
},
|
|
25
|
-
fileInputButtonDisabled: {
|
|
26
|
-
cursor: 'not-allowed',
|
|
27
|
-
backgroundColor: color.background['disabled-grey'],
|
|
28
|
-
},
|
|
29
|
-
inputFileText: {
|
|
30
|
-
...text['Corps de texte'].XS.Regular,
|
|
31
|
-
color: color.text['default-grey'],
|
|
32
|
-
},
|
|
33
|
-
placeholderText: {
|
|
34
|
-
...text['Corps de texte'].XS.Regular,
|
|
35
|
-
color: color.text['default-grey'],
|
|
36
7
|
},
|
|
37
8
|
}));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FileInputFile, FileInputLabels } from './fichiersDuChamp';
|
|
2
|
+
type FileInputListeProps = {
|
|
3
|
+
fichiers: FileInputFile[];
|
|
4
|
+
labels: FileInputLabels;
|
|
5
|
+
retirable: boolean;
|
|
6
|
+
onRetirer: (fichier: FileInputFile) => void;
|
|
7
|
+
};
|
|
8
|
+
/** Les fichiers montres par le champ : apercu ou icone, ouverture au clic, bouton de retrait. */
|
|
9
|
+
export declare const FileInputListe: ({ fichiers, labels, retirable, onRetirer }: FileInputListeProps) => import("react").JSX.Element | null;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=FileInputListe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileInputListe.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/FileInputListe.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAYnE,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;CAC7C,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,cAAc,GAAI,4CAA4C,mBAAmB,uCA6B7F,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Linking } from 'react-native';
|
|
3
|
+
import { Box } from '../../core/Box';
|
|
4
|
+
import { ButtonIcon } from '../Button';
|
|
5
|
+
import { ListItem } from '../ListItem';
|
|
6
|
+
const estUneImage = (fichier) => fichier.mimeType?.startsWith('image/') || /\.(jpe?g|png|gif|webp|bmp|svg)$/i.test(fichier.name ?? '');
|
|
7
|
+
const iconeDe = (fichier) => {
|
|
8
|
+
if (fichier.persisted)
|
|
9
|
+
return 'FileCheckCorner';
|
|
10
|
+
if (fichier.mimeType?.includes('pdf') || fichier.name?.endsWith('.pdf'))
|
|
11
|
+
return 'FileText';
|
|
12
|
+
if (estUneImage(fichier))
|
|
13
|
+
return 'FileImage';
|
|
14
|
+
return 'File';
|
|
15
|
+
};
|
|
16
|
+
/** Les fichiers montres par le champ : apercu ou icone, ouverture au clic, bouton de retrait. */
|
|
17
|
+
export const FileInputListe = ({ fichiers, labels, retirable, onRetirer }) => {
|
|
18
|
+
if (fichiers.length === 0)
|
|
19
|
+
return null;
|
|
20
|
+
return (_jsx(Box, { tag: "file-input-list", children: fichiers.map((fichier, index) => {
|
|
21
|
+
const nom = fichier.name ?? labels.unnamed;
|
|
22
|
+
return (_jsx(ListItem, { title: nom, preview_url: estUneImage(fichier) ? fichier.uri : undefined, IconProps: { name: iconeDe(fichier) }, showSeparateur: index !== 0, onPress: () => Linking.openURL(fichier.uri).catch(() => { }), trailing: () => (_jsx(ButtonIcon, { accessibilityLabel: `${labels.remove} ${nom}`, disabled: !retirable, variant: "tertiary", icon: "CircleX", onPress: () => onRetirer(fichier) })) }, fichier.id ?? fichier.uri));
|
|
23
|
+
}) }));
|
|
24
|
+
};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Vrai si le fichier (reconnu a son type MIME, avec repli sur l'extension du nom pour le CSV)
|
|
3
3
|
* fait partie des types autorises. Sans type exige, tout fichier passe. Un seul type peut etre
|
|
4
4
|
* fourni sous forme de chaine plutot que de tableau. Semantique stricte : `image/…`, pdf propre.
|
|
5
|
+
* Les types MIME du selecteur (`image/*`, `application/pdf`) sont aussi reconnus.
|
|
5
6
|
*/
|
|
6
7
|
export declare const fichierCorrespondAuType: (mimeType: string, fileName: string | undefined, types: string | readonly string[] | undefined) => boolean;
|
|
7
8
|
//# sourceMappingURL=fichierCorrespondAuType.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fichierCorrespondAuType.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/fichierCorrespondAuType.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fichierCorrespondAuType.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/fichierCorrespondAuType.ts"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAClC,UAAU,MAAM,EAChB,UAAU,MAAM,GAAG,SAAS,EAC5B,OAAO,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,KAC5C,OASF,CAAC"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
const estUneImage = (mimeType) => mimeType.startsWith('image/');
|
|
2
2
|
const estUnPdf = (mimeType) => mimeType === 'application/pdf' || mimeType.endsWith('/pdf');
|
|
3
|
+
// Un type MIME exact (`image/png`) ou generique (`image/*`, `*/*`), comme ceux du selecteur.
|
|
4
|
+
const correspondAuMime = (mimeType, type) => type === mimeType || type === '*/*' || (type.endsWith('/*') && mimeType.startsWith(type.slice(0, -1)));
|
|
3
5
|
const estUnCsv = (mimeType, fileName) => mimeType === 'text/csv' || mimeType === 'application/csv' || (fileName?.endsWith('.csv') ?? false);
|
|
4
6
|
/**
|
|
5
7
|
* Vrai si le fichier (reconnu a son type MIME, avec repli sur l'extension du nom pour le CSV)
|
|
6
8
|
* fait partie des types autorises. Sans type exige, tout fichier passe. Un seul type peut etre
|
|
7
9
|
* fourni sous forme de chaine plutot que de tableau. Semantique stricte : `image/…`, pdf propre.
|
|
10
|
+
* Les types MIME du selecteur (`image/*`, `application/pdf`) sont aussi reconnus.
|
|
8
11
|
*/
|
|
9
12
|
export const fichierCorrespondAuType = (mimeType, fileName, types) => {
|
|
10
13
|
const liste = typeof types === 'string' ? [types] : types;
|
|
@@ -12,5 +15,6 @@ export const fichierCorrespondAuType = (mimeType, fileName, types) => {
|
|
|
12
15
|
return true;
|
|
13
16
|
return ((liste.includes('image') && estUneImage(mimeType)) ||
|
|
14
17
|
(liste.includes('pdf') && estUnPdf(mimeType)) ||
|
|
15
|
-
(liste.includes('csv') && estUnCsv(mimeType, fileName))
|
|
18
|
+
(liste.includes('csv') && estUnCsv(mimeType, fileName)) ||
|
|
19
|
+
liste.some(type => correspondAuMime(mimeType, type)));
|
|
16
20
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as DocumentPicker from 'expo-document-picker';
|
|
2
|
+
/**
|
|
3
|
+
* Un fichier du champ. `persisted` signale un fichier enregistré (deja cote serveur, reconnu a
|
|
4
|
+
* son `id`) ; `removed` marque un fichier enregistre que l'utilisateur a retire.
|
|
5
|
+
*/
|
|
6
|
+
export type FileInputFile = DocumentPicker.DocumentPickerAsset & {
|
|
7
|
+
id?: string;
|
|
8
|
+
persisted?: boolean;
|
|
9
|
+
removed?: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type FileInputValue = FileInputFile | FileInputFile[] | null;
|
|
12
|
+
export type FileInputLabels = {
|
|
13
|
+
addFile: string;
|
|
14
|
+
selectFile: string;
|
|
15
|
+
gallery: string;
|
|
16
|
+
camera: string;
|
|
17
|
+
document: string;
|
|
18
|
+
cancel: string;
|
|
19
|
+
chooseImageTitle: string;
|
|
20
|
+
chooseDocumentTitle: string;
|
|
21
|
+
chooseImageMessage: string;
|
|
22
|
+
permissionRequired: string;
|
|
23
|
+
cameraPermissionMessage: string;
|
|
24
|
+
galleryPermissionMessage: string;
|
|
25
|
+
unnamed: string;
|
|
26
|
+
remove: string;
|
|
27
|
+
};
|
|
28
|
+
export declare const libellesParDefaut: FileInputLabels;
|
|
29
|
+
type TypesAcceptes = DocumentPicker.DocumentPickerOptions['type'];
|
|
30
|
+
export type Source = 'document' | 'gallery' | 'camera';
|
|
31
|
+
export declare const fichiersVisibles: (value: FileInputValue) => FileInputFile[];
|
|
32
|
+
export declare const ajoute: (value: FileInputValue, nouveaux: FileInputFile[], multiple: boolean) => FileInputValue;
|
|
33
|
+
export declare const retire: (value: FileInputValue, cible: FileInputFile) => FileInputValue;
|
|
34
|
+
export declare const imagesSeulement: (type: TypesAcceptes) => boolean;
|
|
35
|
+
/** Les sources que la feuille d'actions propose sur natif, dans l'ordre. Sur grand ecran, le document passe en tete. */
|
|
36
|
+
export declare const sourcesProposees: (type: TypesAcceptes, grandEcran: boolean) => Source[];
|
|
37
|
+
/** Sur grand ecran, l'option qui ouvre l'explorateur de fichiers s'annonce comme telle. */
|
|
38
|
+
export declare const libelleDeLaSource: (source: Source, labels: FileInputLabels, { type, grandEcran }: {
|
|
39
|
+
type: TypesAcceptes;
|
|
40
|
+
grandEcran: boolean;
|
|
41
|
+
}) => string;
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=fichiersDuChamp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fichiersDuChamp.d.ts","sourceRoot":"","sources":["../../../src/ui/FormControl/fichiersDuChamp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,cAAc,MAAM,sBAAsB,CAAC;AAEvD;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,mBAAmB,GAAG;IAC/D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,aAAa,EAAE,GAAG,IAAI,CAAC;AAEpE,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,uBAAuB,EAAE,MAAM,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,eAe/B,CAAC;AAEF,KAAK,aAAa,GAAG,cAAc,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAElE,MAAM,MAAM,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAKvD,eAAO,MAAM,gBAAgB,GAAI,OAAO,cAAc,oBAAuD,CAAC;AAG9G,eAAO,MAAM,MAAM,GAAI,OAAO,cAAc,EAAE,UAAU,aAAa,EAAE,EAAE,UAAU,OAAO,KAAG,cAG5F,CAAC;AAOF,eAAO,MAAM,MAAM,GAAI,OAAO,cAAc,EAAE,OAAO,aAAa,KAAG,cAUpE,CAAC;AAMF,eAAO,MAAM,eAAe,GAAI,MAAM,aAAa,YAGlD,CAAC;AAOF,wHAAwH;AACxH,eAAO,MAAM,gBAAgB,GAAI,MAAM,aAAa,EAAE,YAAY,OAAO,KAAG,MAAM,EAIjF,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,EACd,QAAQ,eAAe,EACvB,sBAAsB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,WAKnE,CAAC"}
|