@axa-fr/design-system-slash-react 0.2.0-beta.323 → 0.2.0-beta.325

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.
@@ -0,0 +1,23 @@
1
+ import { DropzoneInputProps, DropzoneOptions, FileRejection } from "react-dropzone";
2
+ type Dropzone = DropzoneInputProps & DropzoneOptions;
3
+ type Props = Omit<Dropzone, "onDrop" | "onChange"> & {
4
+ classModifier?: string;
5
+ label?: string;
6
+ icon?: string;
7
+ onChange: (data: onChangeProps) => void;
8
+ };
9
+ export type FilePreview = File & {
10
+ preview: string;
11
+ };
12
+ export type CustomFile<T = FilePreview> = {
13
+ id: string;
14
+ file: T;
15
+ };
16
+ type onChangeProps = {
17
+ id?: string;
18
+ name?: string;
19
+ values: CustomFile[];
20
+ errors?: CustomFile<FileRejection>[];
21
+ };
22
+ declare const File: ({ className, classModifier, id, name, disabled, onChange, multiple, maxSize, minSize, accept, readOnly, placeholder, label, icon, ...otherProps }: Props) => import("react/jsx-runtime").JSX.Element;
23
+ export { File };
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useDropzone, } from "react-dropzone";
3
+ import { useId } from "react";
4
+ import { getComponentClassName } from "../../utilities";
5
+ import { Button } from "../../Button/Button";
6
+ const File = ({ className, classModifier, id, name, disabled, onChange, multiple = true, maxSize = 20000000, minSize = 0, accept, readOnly, placeholder = "Glissez/déposez vos fichiers", label = "Parcourir", icon = "open", ...otherProps }) => {
7
+ const valueId = useId();
8
+ const errorsId = useId();
9
+ const handleOnChange = (acceptedFiles, rejectedFiles) => {
10
+ if (!onChange)
11
+ return;
12
+ const values = acceptedFiles.map((file) => ({
13
+ id: valueId,
14
+ file: {
15
+ ...file,
16
+ lastModified: file.lastModified,
17
+ name: file.name,
18
+ type: file.type,
19
+ size: file.size,
20
+ stream: file.stream,
21
+ arrayBuffer: file.arrayBuffer,
22
+ slice: file.slice,
23
+ text: file.text,
24
+ preview: URL.createObjectURL(file),
25
+ },
26
+ }));
27
+ const errors = rejectedFiles.map((error) => ({
28
+ id: errorsId,
29
+ file: {
30
+ errors: error.errors,
31
+ file: {
32
+ ...error.file,
33
+ lastModified: error.file.lastModified,
34
+ name: error.file.name,
35
+ type: error.file.type,
36
+ size: error.file.size,
37
+ },
38
+ },
39
+ }));
40
+ const onChangeProps = {
41
+ values,
42
+ errors,
43
+ name,
44
+ id,
45
+ };
46
+ onChange(onChangeProps);
47
+ };
48
+ const { getRootProps, getInputProps, open } = useDropzone({
49
+ onDrop: handleOnChange,
50
+ minSize,
51
+ maxSize,
52
+ multiple,
53
+ accept,
54
+ disabled,
55
+ });
56
+ const componentClassName = getComponentClassName(className, classModifier, "af-form__file-input");
57
+ return (_jsxs("div", { className: componentClassName, children: [_jsxs("div", { ...getRootProps({ className: "drop-box" }), children: [_jsx("input", { ...getInputProps({ id, name, readOnly, ...otherProps }) }), _jsx("div", { children: placeholder })] }), _jsxs(Button, { type: "button", className: "af-btn", classModifier: "file hasIconLeft", onClick: open, disabled: disabled, children: [_jsx("i", { className: `glyphicon glyphicon-${icon}` }), " ", label] })] }));
58
+ };
59
+ export { File };
@@ -0,0 +1,6 @@
1
+ import { FileRejection } from "react-dropzone";
2
+ type Props = {
3
+ errors?: FileRejection[];
4
+ };
5
+ declare const FileErrors: ({ errors }: Props) => import("react/jsx-runtime").JSX.Element;
6
+ export { FileErrors };
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const FileErrors = ({ errors }) => (_jsxs("div", { className: "af-form__file-errors", children: [_jsx("span", { children: "Le chargement de certains fichiers a \u00E9chou\u00E9 : " }), _jsx("ul", { className: "af-form__file-errors-list", children: errors &&
3
+ errors.map((err) => (_jsxs("li", { children: [err.file.name, " (", err.file.size, ")"] }, err.file.name))) })] }));
4
+ export { FileErrors };
@@ -0,0 +1,14 @@
1
+ import { ComponentPropsWithoutRef, ReactNode } from "react";
2
+ import { Field } from "../core";
3
+ import { FileTable } from "./FileTable";
4
+ import { File } from "./File";
5
+ import "@axa-fr/design-system-slash-css/dist/Form/File/File.scss";
6
+ type FieldProps = ComponentPropsWithoutRef<typeof Field>;
7
+ type FileProps = ComponentPropsWithoutRef<typeof File>;
8
+ type FileTableProps = ComponentPropsWithoutRef<typeof FileTable>;
9
+ type Props = FieldProps & FileProps & Pick<FileTableProps, "values" | "errors"> & {
10
+ fileLabel?: string;
11
+ helpMessage?: ReactNode;
12
+ };
13
+ declare const FileInput: ({ values, name, onChange, classModifier, message, children, helpMessage, id, forceDisplayMessage, messageType, classNameContainerLabel, classNameContainerInput, label, isVisible, className, errors, fileLabel, disabled, ...otherFileProps }: Props) => import("react/jsx-runtime").JSX.Element;
14
+ export { FileInput };
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId } from "react";
3
+ import { Field, FieldInput, HelpMessage, useInputClassModifier } from "../core";
4
+ import { FileTable } from "./FileTable";
5
+ import { File } from "./File";
6
+ import "@axa-fr/design-system-slash-css/dist/Form/File/File.scss";
7
+ const FileInput = ({ values = [], name = "", onChange, classModifier = "", message, children, helpMessage, id = "", forceDisplayMessage, messageType, classNameContainerLabel, classNameContainerInput, label, isVisible, className, errors, fileLabel, disabled = false, ...otherFileProps }) => {
8
+ const onDeleteClick = (selectedId, selectInputId) => {
9
+ const newValues = values.filter((element) => element.id !== selectedId);
10
+ onChange({
11
+ values: newValues,
12
+ name,
13
+ id: selectInputId,
14
+ });
15
+ };
16
+ const rowModifier = `${classModifier} label-top`;
17
+ const inputUseId = useId();
18
+ const inputId = id ?? inputUseId;
19
+ const { inputClassModifier, inputFieldClassModifier } = useInputClassModifier(classModifier, disabled, Boolean(children));
20
+ return (_jsxs(Field, { label: label, id: inputId, message: message, messageType: messageType, isVisible: isVisible, forceDisplayMessage: forceDisplayMessage, className: className, classModifier: rowModifier, classNameContainerLabel: classNameContainerLabel, classNameContainerInput: classNameContainerInput, children: [_jsxs(FieldInput, { className: "af-form__file", classModifier: inputFieldClassModifier, children: [_jsx(File, { id: inputId, name: name, onChange: onChange, disabled: disabled, classModifier: inputClassModifier, label: fileLabel, required: classModifier?.includes("required"), ...otherFileProps }), children] }), _jsx(HelpMessage, { message: helpMessage, isVisible: !message }), _jsx(FileTable, { errors: errors, values: values, onClick: (selectedId) => onDeleteClick(selectedId, inputId), classModifier: classModifier })] }));
21
+ };
22
+ export { FileInput };
@@ -0,0 +1,9 @@
1
+ import { Meta, StoryObj } from "@storybook/react";
2
+ import { FileInput } from "./FileInput";
3
+ declare const meta: Meta<typeof FileInput>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof FileInput>;
6
+ export declare const FileInputStory: Story;
7
+ export declare const FileStory: Story;
8
+ export declare const FileWithValuesStory: Story;
9
+ export declare const FileWithErrorsStory: Story;
@@ -0,0 +1,103 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { HelpMessage, MessageTypes } from "../core";
3
+ import { FileInput } from "./FileInput";
4
+ import { File } from "./File";
5
+ import { FileTable } from "./FileTable";
6
+ const meta = {
7
+ component: FileInput,
8
+ title: "Components/Form/Input/File",
9
+ argTypes: {
10
+ onChange: { action: "onChange" },
11
+ },
12
+ };
13
+ export default meta;
14
+ export const FileInputStory = {
15
+ name: "FileInput",
16
+ render: ({ onChange, ...args }) => (_jsx(FileInput, { onChange: onChange, ...args })),
17
+ args: {
18
+ classModifier: "required",
19
+ label: "Image",
20
+ fileLabel: "Browse",
21
+ name: "placeImage",
22
+ id: "inputuniqueid",
23
+ accept: "image/jpeg, image/png, application/*",
24
+ helpMessage: "Take a photo af a place",
25
+ messageType: MessageTypes.error,
26
+ multiple: true,
27
+ isVisible: true,
28
+ classNameContainerLabel: "col-md-2",
29
+ classNameContainerInput: "col-md-10",
30
+ },
31
+ };
32
+ export const FileStory = {
33
+ name: "File",
34
+ render: ({ onChange, ...args }) => _jsx(File, { onChange: onChange, ...args }),
35
+ args: {
36
+ label: "Image",
37
+ name: "placeImage",
38
+ id: "inputuniqueid",
39
+ accept: "image/jpeg, image/png, application/*",
40
+ multiple: true,
41
+ isVisible: true,
42
+ icon: "open",
43
+ },
44
+ };
45
+ const errors = [
46
+ {
47
+ file: {
48
+ name: "refused-extension-file.svg",
49
+ preview: "",
50
+ size: 100,
51
+ },
52
+ },
53
+ {
54
+ file: {
55
+ name: "too-big-file.jpg",
56
+ size: 100,
57
+ },
58
+ errors: {},
59
+ },
60
+ {
61
+ file: {
62
+ name: "error-file.jpg",
63
+ preview: "",
64
+ size: 100,
65
+ },
66
+ },
67
+ ];
68
+ const values = [
69
+ {
70
+ id: "000003",
71
+ file: {
72
+ name: "error-file.jpg",
73
+ size: 100,
74
+ preview: "https://via.placeholder.com/150Cx50",
75
+ type: "image",
76
+ },
77
+ },
78
+ {
79
+ id: "000004",
80
+ file: {
81
+ name: "fichier.png",
82
+ size: 100,
83
+ preview: "https://via.placeholder.com/150Cx50",
84
+ type: "image",
85
+ },
86
+ },
87
+ {
88
+ id: "000005",
89
+ file: {
90
+ name: "fichier.csv",
91
+ preview: "https://via.placeholder.com/150Cx50",
92
+ size: 100,
93
+ },
94
+ },
95
+ ];
96
+ export const FileWithValuesStory = {
97
+ name: "File with values",
98
+ render: ({ onChange, ...args }) => (_jsxs(_Fragment, { children: [_jsx(File, { onChange: onChange, ...args }), _jsx(HelpMessage, { message: "Enter the place name, ex : Webcenter" }), _jsx(FileTable, { errors: [], values: values, onClick: () => { }, classModifier: "" })] })),
99
+ };
100
+ export const FileWithErrorsStory = {
101
+ name: "File with errors",
102
+ render: ({ onChange, ...args }) => (_jsxs(_Fragment, { children: [_jsx(File, { onChange: onChange, ...args }), _jsx(HelpMessage, { message: "Enter the place name, ex : Webcenter" }), _jsx(FileTable, { errors: errors, values: values, onClick: () => { }, classModifier: "" })] })),
103
+ };
@@ -0,0 +1,9 @@
1
+ import { CustomFile } from "./File";
2
+ type Props = CustomFile & {
3
+ onClick: (id: string) => void;
4
+ className?: string;
5
+ classModifier?: string;
6
+ disabled?: boolean;
7
+ };
8
+ declare const FileLine: ({ className, classModifier, file, disabled, id, onClick, }: Props) => import("react/jsx-runtime").JSX.Element;
9
+ export { FileLine };
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { getComponentClassName } from "../../utilities";
3
+ const FileLine = ({ className, classModifier, file, disabled, id, onClick, }) => {
4
+ const componentClassName = getComponentClassName(className, classModifier, "af-form__file-line");
5
+ return (_jsxs("li", { className: componentClassName, children: [file && file.type && file.type.startsWith("image") ? (_jsx("i", { className: "glyphicon glyphicon-picture" })) : (_jsx("i", { className: "glyphicon glyphicon-file" })), _jsx("span", { children: file.name }), _jsx("span", { children: file.size }), _jsx("button", { disabled: disabled, type: "button", className: "af-link af-link--delete-file", onClick: () => onClick(id), children: _jsx("span", { className: "af-link__text", children: "Supprimer" }) })] }));
6
+ };
7
+ export { FileLine };
@@ -0,0 +1,14 @@
1
+ import { ComponentPropsWithoutRef } from "react";
2
+ import { FileRejection } from "react-dropzone";
3
+ import { FileLine } from "./FileLine";
4
+ import { CustomFile } from "./File";
5
+ type FileLineProps = ComponentPropsWithoutRef<typeof FileLine>;
6
+ type Props = Pick<FileLineProps, "onClick"> & {
7
+ errors?: FileRejection[];
8
+ values?: CustomFile[];
9
+ className?: string;
10
+ classModifier?: string;
11
+ disabled?: boolean;
12
+ };
13
+ declare const FileTable: ({ errors, values, className, classModifier, disabled, onClick, }: Props) => import("react/jsx-runtime").JSX.Element;
14
+ export { FileTable };
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { FileLine } from "./FileLine";
3
+ import { FileErrors } from "./FileErrors";
4
+ import { getComponentClassName } from "../../utilities";
5
+ const FileTable = ({ errors, values, className, classModifier, disabled, onClick, }) => {
6
+ const componentClassName = getComponentClassName(className, classModifier, "custom-table-file af-file-table");
7
+ return (_jsxs("div", { className: componentClassName, children: [errors && errors.length > 0 && _jsx(FileErrors, { errors: errors }), values && values.length > 0 && (_jsx("ul", { className: "af-form__file-list", children: values.map(({ file, id }) => (_jsx(FileLine, { disabled: disabled, file: file, onClick: onClick, id: id }, id))) }))] }));
8
+ };
9
+ export { FileTable };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render } from "@testing-library/react";
3
+ import { File } from "../File";
4
+ describe("<File.File>", () => {
5
+ it("renders File.File correctly", () => {
6
+ const { asFragment } = render(_jsx(File, { label: "File *", id: "id", name: "file", onChange: () => { }, accept: "image/jpeg, image/png, application/*", multiple: true }));
7
+ expect(asFragment()).toMatchSnapshot();
8
+ });
9
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render } from "@testing-library/react";
3
+ import { FileInput } from "../FileInput";
4
+ import { MessageTypes } from "../../core";
5
+ describe("<FileInput>", () => {
6
+ it("renders FileInput correctly", () => {
7
+ const { asFragment } = render(_jsx(FileInput, { label: "File *", id: "id", name: "file", onChange: () => { }, accept: "image/jpeg, image/png, application/*", messageType: MessageTypes.error, message: null }));
8
+ expect(asFragment()).toMatchSnapshot();
9
+ });
10
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { fireEvent, render } from "@testing-library/react";
3
+ import { FileLine } from "../FileLine";
4
+ describe("<File.FileInput>", () => {
5
+ it("renders File.FileInput correctly", () => {
6
+ const { asFragment } = render(_jsx(FileLine, { file: {
7
+ ...new File([], "name"),
8
+ name: "name",
9
+ size: 1,
10
+ preview: "#",
11
+ }, id: "id", onClick: () => { } }));
12
+ expect(asFragment()).toMatchSnapshot();
13
+ });
14
+ it("Should called onClick function when button have been clicked", () => {
15
+ const onClickMock = vi.fn();
16
+ const { getByRole } = render(_jsx(FileLine, { file: {
17
+ ...new File([], "name"),
18
+ name: "name",
19
+ size: 1,
20
+ preview: "#",
21
+ }, id: "id", onClick: onClickMock }));
22
+ fireEvent.click(getByRole("button"));
23
+ expect(onClickMock).toHaveBeenCalled();
24
+ });
25
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render } from "@testing-library/react";
3
+ import { FileTable } from "../FileTable";
4
+ describe("<File.FileTable>", () => {
5
+ it("renders File.FileTable correctly", () => {
6
+ const { asFragment } = render(_jsx(FileTable, { errors: [
7
+ {
8
+ file: {
9
+ ...new File([], "youhou.txt"),
10
+ name: "youhou.txt",
11
+ size: 2,
12
+ },
13
+ errors: [],
14
+ },
15
+ ], values: [
16
+ {
17
+ file: {
18
+ ...new File([], "superfile.pdf"),
19
+ name: "superfile.pdf",
20
+ preview: "",
21
+ size: 2,
22
+ },
23
+ id: "id",
24
+ },
25
+ ], onClick: () => { } }));
26
+ expect(asFragment()).toMatchSnapshot();
27
+ });
28
+ it("renders File.FileTable correctly when no have values", () => {
29
+ const { asFragment, queryByRole } = render(_jsx(FileTable, { errors: [
30
+ {
31
+ file: {
32
+ ...new File([], "youhou.txt"),
33
+ name: "youhou.txt",
34
+ size: 2,
35
+ },
36
+ errors: [],
37
+ },
38
+ ], values: [], onClick: () => { } }));
39
+ expect(asFragment()).toMatchSnapshot();
40
+ expect(queryByRole("list")).toHaveClass("af-form__file-errors-list");
41
+ expect(queryByRole("list")).toBeInTheDocument();
42
+ });
43
+ it("renders Errors correctly with empty errors", () => {
44
+ const { asFragment, queryByRole } = render(_jsx(FileTable, { values: [
45
+ {
46
+ file: {
47
+ ...new File([], "youhou.txt"),
48
+ name: "youhou.txt",
49
+ size: 2,
50
+ preview: "",
51
+ },
52
+ id: "id",
53
+ },
54
+ ], onClick: () => { } }));
55
+ expect(asFragment()).toMatchSnapshot();
56
+ expect(queryByRole("list")).not.toHaveClass("af-form__file-errors-list");
57
+ });
58
+ });
@@ -0,0 +1,5 @@
1
+ export { FileInput } from "./FileInput";
2
+ export { File } from "./File";
3
+ export { FileTable } from "./FileTable";
4
+ export { FileLine } from "./FileLine";
5
+ export { FileErrors } from "./FileErrors";
@@ -0,0 +1,5 @@
1
+ export { FileInput } from "./FileInput";
2
+ export { File } from "./File";
3
+ export { FileTable } from "./FileTable";
4
+ export { FileLine } from "./FileLine";
5
+ export { FileErrors } from "./FileErrors";
package/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export { Select, SelectBase, SelectInput } from "./Form/Select";
16
16
  export { Slider, SliderInput } from "./Form/Slider";
17
17
  export { Text, TextInput } from "./Form/Text";
18
18
  export { Textarea, TextareaInput } from "./Form/Textarea";
19
+ export { File, FileInput, FileTable } from "./Form/File";
19
20
  export { Footer } from "./Layout/Footer";
20
21
  export { Header, Infos, Name, NavBar, NavBarBase, NavBarItem, NavBarItemBase, NavBarItemLink, TitleHeader, ToggleButton, User, } from "./Layout/Header";
21
22
  export { BooleanModal, Modal, ModalBody, ModalFooter, ModalHeader, ModalHeaderBase, } from "./ModalAgent";
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ export { Select, SelectBase, SelectInput } from "./Form/Select";
16
16
  export { Slider, SliderInput } from "./Form/Slider";
17
17
  export { Text, TextInput } from "./Form/Text";
18
18
  export { Textarea, TextareaInput } from "./Form/Textarea";
19
+ export { File, FileInput, FileTable } from "./Form/File";
19
20
  export { Footer } from "./Layout/Footer";
20
21
  export { Header, Infos, Name, NavBar, NavBarBase, NavBarItem, NavBarItemBase, NavBarItemLink, TitleHeader, ToggleButton, User, } from "./Layout/Header";
21
22
  export { BooleanModal, Modal, ModalBody, ModalFooter, ModalHeader, ModalHeaderBase, } from "./ModalAgent";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axa-fr/design-system-slash-react",
3
- "version": "0.2.0-beta.323",
3
+ "version": "0.2.0-beta.325",
4
4
  "description": "",
5
5
  "exports": {
6
6
  ".": {
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "homepage": "https://github.com/AxaFrance/design-system#readme",
43
43
  "peerDependencies": {
44
- "@axa-fr/design-system-slash-css": "0.2.0-beta.323",
44
+ "@axa-fr/design-system-slash-css": "0.2.0-beta.325",
45
45
  "@material-symbols/svg-400": ">= 0.19.0",
46
46
  "react": ">= 18"
47
47
  },
@@ -56,6 +56,7 @@
56
56
  "classnames": "^2.5.1",
57
57
  "dompurify": "^3.1.5",
58
58
  "rc-slider": "^10.5.0",
59
+ "react-dropzone": "^11.5.3",
59
60
  "react-select": "^5.8.0"
60
61
  },
61
62
  "devDependencies": {