@navikt/ds-react 6.2.0 → 6.3.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/cjs/form/combobox/ComboboxProvider.js +5 -1
- package/cjs/form/combobox/ComboboxProvider.js.map +1 -1
- package/cjs/form/combobox/FilteredOptions/FilteredOptions.js +14 -12
- package/cjs/form/combobox/FilteredOptions/FilteredOptions.js.map +1 -1
- package/cjs/form/combobox/FilteredOptions/filtered-options-util.d.ts +3 -3
- package/cjs/form/combobox/FilteredOptions/filtered-options-util.js +1 -3
- package/cjs/form/combobox/FilteredOptions/filtered-options-util.js.map +1 -1
- package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.d.ts +8 -5
- package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js +8 -13
- package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
- package/cjs/form/combobox/Input/Input.js +9 -7
- package/cjs/form/combobox/Input/Input.js.map +1 -1
- package/cjs/form/combobox/SelectedOptions/SelectedOptions.d.ts +2 -1
- package/cjs/form/combobox/SelectedOptions/SelectedOptions.js +3 -3
- package/cjs/form/combobox/SelectedOptions/SelectedOptions.js.map +1 -1
- package/cjs/form/combobox/SelectedOptions/selectedOptionsContext.d.ts +10 -7
- package/cjs/form/combobox/SelectedOptions/selectedOptionsContext.js +6 -8
- package/cjs/form/combobox/SelectedOptions/selectedOptionsContext.js.map +1 -1
- package/cjs/form/combobox/combobox-utils.d.ts +10 -0
- package/cjs/form/combobox/combobox-utils.js +27 -0
- package/cjs/form/combobox/combobox-utils.js.map +1 -0
- package/cjs/form/combobox/customOptionsContext.d.ts +5 -4
- package/cjs/form/combobox/customOptionsContext.js +1 -1
- package/cjs/form/combobox/customOptionsContext.js.map +1 -1
- package/cjs/form/combobox/types.d.ts +22 -11
- package/cjs/form/file-upload/FileUpload.context.d.ts +8 -0
- package/cjs/form/file-upload/FileUpload.context.js +7 -0
- package/cjs/form/file-upload/FileUpload.context.js.map +1 -0
- package/cjs/form/file-upload/FileUpload.d.ts +118 -0
- package/cjs/form/file-upload/FileUpload.js +73 -0
- package/cjs/form/file-upload/FileUpload.js.map +1 -0
- package/cjs/form/file-upload/FileUpload.types.d.ts +55 -0
- package/cjs/form/file-upload/FileUpload.types.js +8 -0
- package/cjs/form/file-upload/FileUpload.types.js.map +1 -0
- package/cjs/form/file-upload/i18n/get.d.ts +2 -0
- package/cjs/form/file-upload/i18n/get.js +38 -0
- package/cjs/form/file-upload/i18n/get.js.map +1 -0
- package/cjs/form/file-upload/i18n/i18n.context.d.ts +11 -0
- package/cjs/form/file-upload/i18n/i18n.context.js +39 -0
- package/cjs/form/file-upload/i18n/i18n.context.js.map +1 -0
- package/cjs/form/file-upload/i18n/i18n.types.d.ts +13 -0
- package/cjs/form/file-upload/i18n/i18n.types.js +3 -0
- package/cjs/form/file-upload/i18n/i18n.types.js.map +1 -0
- package/cjs/form/file-upload/i18n/locales/nb.json +20 -0
- package/cjs/form/file-upload/i18n/merge.d.ts +2 -0
- package/cjs/form/file-upload/i18n/merge.js +29 -0
- package/cjs/form/file-upload/i18n/merge.js.map +1 -0
- package/cjs/form/file-upload/index.d.ts +7 -0
- package/cjs/form/file-upload/index.js +16 -0
- package/cjs/form/file-upload/index.js.map +1 -0
- package/cjs/form/file-upload/parts/Trigger.d.ts +7 -0
- package/cjs/form/file-upload/parts/Trigger.js +43 -0
- package/cjs/form/file-upload/parts/Trigger.js.map +1 -0
- package/cjs/form/file-upload/parts/dropzone/Dropzone.d.ts +4 -0
- package/cjs/form/file-upload/parts/dropzone/Dropzone.js +106 -0
- package/cjs/form/file-upload/parts/dropzone/Dropzone.js.map +1 -0
- package/cjs/form/file-upload/parts/dropzone/dropzone.types.d.ts +18 -0
- package/cjs/form/file-upload/parts/dropzone/dropzone.types.js +3 -0
- package/cjs/form/file-upload/parts/dropzone/dropzone.types.js.map +1 -0
- package/cjs/form/file-upload/parts/dropzone/useDropzone.d.ts +13 -0
- package/cjs/form/file-upload/parts/dropzone/useDropzone.js +34 -0
- package/cjs/form/file-upload/parts/dropzone/useDropzone.js.map +1 -0
- package/cjs/form/file-upload/parts/item/Item.d.ts +55 -0
- package/cjs/form/file-upload/parts/item/Item.js +79 -0
- package/cjs/form/file-upload/parts/item/Item.js.map +1 -0
- package/cjs/form/file-upload/parts/item/Item.types.d.ts +5 -0
- package/cjs/form/file-upload/parts/item/Item.types.js +3 -0
- package/cjs/form/file-upload/parts/item/Item.types.js.map +1 -0
- package/cjs/form/file-upload/parts/item/ItemButton.d.ts +12 -0
- package/cjs/form/file-upload/parts/item/ItemButton.js +22 -0
- package/cjs/form/file-upload/parts/item/ItemButton.js.map +1 -0
- package/cjs/form/file-upload/parts/item/ItemIcon.d.ts +9 -0
- package/cjs/form/file-upload/parts/item/ItemIcon.js +51 -0
- package/cjs/form/file-upload/parts/item/ItemIcon.js.map +1 -0
- package/cjs/form/file-upload/parts/item/ItemName.d.ts +9 -0
- package/cjs/form/file-upload/parts/item/ItemName.js +32 -0
- package/cjs/form/file-upload/parts/item/ItemName.js.map +1 -0
- package/cjs/form/file-upload/parts/item/utils/download-file.d.ts +1 -0
- package/cjs/form/file-upload/parts/item/utils/download-file.js +13 -0
- package/cjs/form/file-upload/parts/item/utils/download-file.js.map +1 -0
- package/cjs/form/file-upload/parts/item/utils/file-type-checker.d.ts +2 -0
- package/cjs/form/file-upload/parts/item/utils/file-type-checker.js +6 -0
- package/cjs/form/file-upload/parts/item/utils/file-type-checker.js.map +1 -0
- package/cjs/form/file-upload/parts/item/utils/format-file-size.d.ts +2 -0
- package/cjs/form/file-upload/parts/item/utils/format-file-size.js +24 -0
- package/cjs/form/file-upload/parts/item/utils/format-file-size.js.map +1 -0
- package/cjs/form/file-upload/useFileUpload.d.ts +12 -0
- package/cjs/form/file-upload/useFileUpload.js +33 -0
- package/cjs/form/file-upload/useFileUpload.js.map +1 -0
- package/cjs/form/file-upload/utils/is-accepted-file-type.d.ts +1 -0
- package/cjs/form/file-upload/utils/is-accepted-file-type.js +26 -0
- package/cjs/form/file-upload/utils/is-accepted-file-type.js.map +1 -0
- package/cjs/form/file-upload/utils/is-accepted-size.d.ts +1 -0
- package/cjs/form/file-upload/utils/is-accepted-size.js +11 -0
- package/cjs/form/file-upload/utils/is-accepted-size.js.map +1 -0
- package/cjs/form/file-upload/utils/validate-files.d.ts +8 -0
- package/cjs/form/file-upload/utils/validate-files.js +48 -0
- package/cjs/form/file-upload/utils/validate-files.js.map +1 -0
- package/cjs/index.d.ts +1 -0
- package/cjs/index.js +3 -1
- package/cjs/index.js.map +1 -1
- package/cjs/loader/Loader.d.ts +0 -7
- package/cjs/loader/Loader.js.map +1 -1
- package/cjs/table/DataCell.d.ts +1 -3
- package/cjs/table/DataCell.js.map +1 -1
- package/cjs/util/create-context.d.ts +1 -0
- package/cjs/util/create-context.js.map +1 -1
- package/cjs/util/hooks/useEventListener.d.ts +1 -1
- package/cjs/util/hooks/useMergeRefs.d.ts +1 -1
- package/esm/form/combobox/ComboboxProvider.js +5 -1
- package/esm/form/combobox/ComboboxProvider.js.map +1 -1
- package/esm/form/combobox/FilteredOptions/FilteredOptions.js +14 -12
- package/esm/form/combobox/FilteredOptions/FilteredOptions.js.map +1 -1
- package/esm/form/combobox/FilteredOptions/filtered-options-util.d.ts +3 -3
- package/esm/form/combobox/FilteredOptions/filtered-options-util.js +1 -3
- package/esm/form/combobox/FilteredOptions/filtered-options-util.js.map +1 -1
- package/esm/form/combobox/FilteredOptions/filteredOptionsContext.d.ts +8 -5
- package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js +8 -13
- package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
- package/esm/form/combobox/Input/Input.js +9 -7
- package/esm/form/combobox/Input/Input.js.map +1 -1
- package/esm/form/combobox/SelectedOptions/SelectedOptions.d.ts +2 -1
- package/esm/form/combobox/SelectedOptions/SelectedOptions.js +3 -3
- package/esm/form/combobox/SelectedOptions/SelectedOptions.js.map +1 -1
- package/esm/form/combobox/SelectedOptions/selectedOptionsContext.d.ts +10 -7
- package/esm/form/combobox/SelectedOptions/selectedOptionsContext.js +6 -8
- package/esm/form/combobox/SelectedOptions/selectedOptionsContext.js.map +1 -1
- package/esm/form/combobox/combobox-utils.d.ts +10 -0
- package/esm/form/combobox/combobox-utils.js +22 -0
- package/esm/form/combobox/combobox-utils.js.map +1 -0
- package/esm/form/combobox/customOptionsContext.d.ts +5 -4
- package/esm/form/combobox/customOptionsContext.js +1 -1
- package/esm/form/combobox/customOptionsContext.js.map +1 -1
- package/esm/form/combobox/types.d.ts +22 -11
- package/esm/form/file-upload/FileUpload.context.d.ts +8 -0
- package/esm/form/file-upload/FileUpload.context.js +3 -0
- package/esm/form/file-upload/FileUpload.context.js.map +1 -0
- package/esm/form/file-upload/FileUpload.d.ts +118 -0
- package/esm/form/file-upload/FileUpload.js +44 -0
- package/esm/form/file-upload/FileUpload.js.map +1 -0
- package/esm/form/file-upload/FileUpload.types.d.ts +55 -0
- package/esm/form/file-upload/FileUpload.types.js +5 -0
- package/esm/form/file-upload/FileUpload.types.js.map +1 -0
- package/esm/form/file-upload/i18n/get.d.ts +2 -0
- package/esm/form/file-upload/i18n/get.js +34 -0
- package/esm/form/file-upload/i18n/get.js.map +1 -0
- package/esm/form/file-upload/i18n/i18n.context.d.ts +11 -0
- package/esm/form/file-upload/i18n/i18n.context.js +32 -0
- package/esm/form/file-upload/i18n/i18n.context.js.map +1 -0
- package/esm/form/file-upload/i18n/i18n.types.d.ts +13 -0
- package/esm/form/file-upload/i18n/i18n.types.js +2 -0
- package/esm/form/file-upload/i18n/i18n.types.js.map +1 -0
- package/esm/form/file-upload/i18n/locales/nb.json +20 -0
- package/esm/form/file-upload/i18n/merge.d.ts +2 -0
- package/esm/form/file-upload/i18n/merge.js +25 -0
- package/esm/form/file-upload/i18n/merge.js.map +1 -0
- package/esm/form/file-upload/index.d.ts +7 -0
- package/esm/form/file-upload/index.js +6 -0
- package/esm/form/file-upload/index.js.map +1 -0
- package/esm/form/file-upload/parts/Trigger.d.ts +7 -0
- package/esm/form/file-upload/parts/Trigger.js +18 -0
- package/esm/form/file-upload/parts/Trigger.js.map +1 -0
- package/esm/form/file-upload/parts/dropzone/Dropzone.d.ts +4 -0
- package/esm/form/file-upload/parts/dropzone/Dropzone.js +78 -0
- package/esm/form/file-upload/parts/dropzone/Dropzone.js.map +1 -0
- package/esm/form/file-upload/parts/dropzone/dropzone.types.d.ts +18 -0
- package/esm/form/file-upload/parts/dropzone/dropzone.types.js +2 -0
- package/esm/form/file-upload/parts/dropzone/dropzone.types.js.map +1 -0
- package/esm/form/file-upload/parts/dropzone/useDropzone.d.ts +13 -0
- package/esm/form/file-upload/parts/dropzone/useDropzone.js +30 -0
- package/esm/form/file-upload/parts/dropzone/useDropzone.js.map +1 -0
- package/esm/form/file-upload/parts/item/Item.d.ts +55 -0
- package/esm/form/file-upload/parts/item/Item.js +50 -0
- package/esm/form/file-upload/parts/item/Item.js.map +1 -0
- package/esm/form/file-upload/parts/item/Item.types.d.ts +5 -0
- package/esm/form/file-upload/parts/item/Item.types.js +2 -0
- package/esm/form/file-upload/parts/item/Item.types.js.map +1 -0
- package/esm/form/file-upload/parts/item/ItemButton.d.ts +12 -0
- package/esm/form/file-upload/parts/item/ItemButton.js +17 -0
- package/esm/form/file-upload/parts/item/ItemButton.js.map +1 -0
- package/esm/form/file-upload/parts/item/ItemIcon.d.ts +9 -0
- package/esm/form/file-upload/parts/item/ItemIcon.js +46 -0
- package/esm/form/file-upload/parts/item/ItemIcon.js.map +1 -0
- package/esm/form/file-upload/parts/item/ItemName.d.ts +9 -0
- package/esm/form/file-upload/parts/item/ItemName.js +27 -0
- package/esm/form/file-upload/parts/item/ItemName.js.map +1 -0
- package/esm/form/file-upload/parts/item/utils/download-file.d.ts +1 -0
- package/esm/form/file-upload/parts/item/utils/download-file.js +9 -0
- package/esm/form/file-upload/parts/item/utils/download-file.js.map +1 -0
- package/esm/form/file-upload/parts/item/utils/file-type-checker.d.ts +2 -0
- package/esm/form/file-upload/parts/item/utils/file-type-checker.js +2 -0
- package/esm/form/file-upload/parts/item/utils/file-type-checker.js.map +1 -0
- package/esm/form/file-upload/parts/item/utils/format-file-size.d.ts +2 -0
- package/esm/form/file-upload/parts/item/utils/format-file-size.js +20 -0
- package/esm/form/file-upload/parts/item/utils/format-file-size.js.map +1 -0
- package/esm/form/file-upload/useFileUpload.d.ts +12 -0
- package/esm/form/file-upload/useFileUpload.js +29 -0
- package/esm/form/file-upload/useFileUpload.js.map +1 -0
- package/esm/form/file-upload/utils/is-accepted-file-type.d.ts +1 -0
- package/esm/form/file-upload/utils/is-accepted-file-type.js +22 -0
- package/esm/form/file-upload/utils/is-accepted-file-type.js.map +1 -0
- package/esm/form/file-upload/utils/is-accepted-size.d.ts +1 -0
- package/esm/form/file-upload/utils/is-accepted-size.js +7 -0
- package/esm/form/file-upload/utils/is-accepted-size.js.map +1 -0
- package/esm/form/file-upload/utils/validate-files.d.ts +8 -0
- package/esm/form/file-upload/utils/validate-files.js +44 -0
- package/esm/form/file-upload/utils/validate-files.js.map +1 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/index.js.map +1 -1
- package/esm/loader/Loader.d.ts +0 -7
- package/esm/loader/Loader.js.map +1 -1
- package/esm/table/DataCell.d.ts +1 -3
- package/esm/table/DataCell.js.map +1 -1
- package/esm/util/create-context.d.ts +1 -0
- package/esm/util/create-context.js.map +1 -1
- package/esm/util/hooks/useEventListener.d.ts +1 -1
- package/esm/util/hooks/useMergeRefs.d.ts +1 -1
- package/package.json +13 -3
- package/src/form/combobox/ComboboxProvider.tsx +7 -3
- package/src/form/combobox/FilteredOptions/FilteredOptions.tsx +22 -15
- package/src/form/combobox/FilteredOptions/filtered-options-util.ts +5 -10
- package/src/form/combobox/FilteredOptions/filteredOptionsContext.tsx +19 -29
- package/src/form/combobox/Input/Input.tsx +14 -8
- package/src/form/combobox/SelectedOptions/SelectedOptions.tsx +8 -5
- package/src/form/combobox/SelectedOptions/selectedOptionsContext.tsx +24 -25
- package/src/form/combobox/combobox-utils.test.ts +67 -0
- package/src/form/combobox/combobox-utils.ts +32 -0
- package/src/form/combobox/combobox.stories.tsx +67 -32
- package/src/form/combobox/combobox.test.tsx +32 -1
- package/src/form/combobox/customOptionsContext.tsx +9 -8
- package/src/form/combobox/types.ts +23 -11
- package/src/form/file-upload/FileUpload.context.tsx +9 -0
- package/src/form/file-upload/FileUpload.tsx +142 -0
- package/src/form/file-upload/FileUpload.types.ts +57 -0
- package/src/form/file-upload/file-upload-dropzone.stories.tsx +123 -0
- package/src/form/file-upload/file-upload-item.stories.tsx +136 -0
- package/src/form/file-upload/file-upload.stories.tsx +236 -0
- package/src/form/file-upload/i18n/get.ts +48 -0
- package/src/form/file-upload/i18n/i18n.context.test.tsx +92 -0
- package/src/form/file-upload/i18n/i18n.context.ts +67 -0
- package/src/form/file-upload/i18n/i18n.types.ts +20 -0
- package/src/form/file-upload/i18n/locales/nb.json +20 -0
- package/src/form/file-upload/i18n/merge.ts +35 -0
- package/src/form/file-upload/index.ts +21 -0
- package/src/form/file-upload/parts/Trigger.tsx +48 -0
- package/src/form/file-upload/parts/dropzone/Dropzone.tsx +180 -0
- package/src/form/file-upload/parts/dropzone/dropzone.types.ts +22 -0
- package/src/form/file-upload/parts/dropzone/useDropzone.ts +43 -0
- package/src/form/file-upload/parts/item/Item.tsx +165 -0
- package/src/form/file-upload/parts/item/Item.types.ts +6 -0
- package/src/form/file-upload/parts/item/ItemButton.tsx +52 -0
- package/src/form/file-upload/parts/item/ItemIcon.tsx +74 -0
- package/src/form/file-upload/parts/item/ItemName.tsx +58 -0
- package/src/form/file-upload/parts/item/utils/download-file.ts +9 -0
- package/src/form/file-upload/parts/item/utils/file-type-checker.ts +4 -0
- package/src/form/file-upload/parts/item/utils/format-file-size.test.ts +76 -0
- package/src/form/file-upload/parts/item/utils/format-file-size.ts +25 -0
- package/src/form/file-upload/useFileUpload.ts +54 -0
- package/src/form/file-upload/utils/is-accepted-file-type.test.ts +69 -0
- package/src/form/file-upload/utils/is-accepted-file-type.ts +25 -0
- package/src/form/file-upload/utils/is-accepted-size.test.ts +26 -0
- package/src/form/file-upload/utils/is-accepted-size.ts +7 -0
- package/src/form/file-upload/utils/validate-files.test.ts +132 -0
- package/src/form/file-upload/utils/validate-files.ts +62 -0
- package/src/index.ts +14 -0
- package/src/internal-header/header.stories.tsx +8 -5
- package/src/loader/Loader.tsx +0 -7
- package/src/table/DataCell.tsx +1 -6
- package/src/util/create-context.tsx +1 -0
- package/src/util/hooks/useMergeRefs.ts +1 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import cl from "clsx";
|
|
2
|
+
import React, { MouseEvent, forwardRef } from "react";
|
|
3
|
+
import { ExclamationmarkTriangleIcon } from "@navikt/aksel-icons";
|
|
4
|
+
import { BodyShort } from "../../../../typography";
|
|
5
|
+
import { OverridableComponent } from "../../../../util";
|
|
6
|
+
import { useFileUploadTranslation } from "../../FileUpload.context";
|
|
7
|
+
import { useI18n } from "../../i18n/i18n.context";
|
|
8
|
+
import { ComponentTranslation } from "../../i18n/i18n.types";
|
|
9
|
+
import { FileItem } from "./Item.types";
|
|
10
|
+
import ItemButton from "./ItemButton";
|
|
11
|
+
import ItemIcon from "./ItemIcon";
|
|
12
|
+
import ItemName from "./ItemName";
|
|
13
|
+
import { formatFileSize } from "./utils/format-file-size";
|
|
14
|
+
|
|
15
|
+
export interface FileItemBaseProps {
|
|
16
|
+
/**
|
|
17
|
+
* Overrides html-tag
|
|
18
|
+
* @default "div"
|
|
19
|
+
*/
|
|
20
|
+
as?: "div" | "li";
|
|
21
|
+
/**
|
|
22
|
+
* Either a native File or file metadata.
|
|
23
|
+
*/
|
|
24
|
+
file: FileItem;
|
|
25
|
+
/**
|
|
26
|
+
* onClick on the file name.
|
|
27
|
+
* @note If this and `href` is not set and the `file` prop is a native file, onClick will download the file.
|
|
28
|
+
*/
|
|
29
|
+
onFileClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
|
|
30
|
+
/**
|
|
31
|
+
* href on the file name.
|
|
32
|
+
* @note If this and `onFileClick` is not set and the `file` prop is a native file, onClick will download the file.
|
|
33
|
+
*/
|
|
34
|
+
href?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Error message relating to the item.
|
|
37
|
+
*/
|
|
38
|
+
error?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Status "downloading" and "uploading" displays a loading indicator.
|
|
41
|
+
* @default "idle"
|
|
42
|
+
*/
|
|
43
|
+
status?: "downloading" | "uploading" | "idle";
|
|
44
|
+
/**
|
|
45
|
+
* i18n-API for customizing texts and labels
|
|
46
|
+
*/
|
|
47
|
+
translations?: ComponentTranslation<"FileUpload">["item"];
|
|
48
|
+
onRetry?: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
49
|
+
onDelete?: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type FileItemActionDelete = {
|
|
53
|
+
onDelete: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
54
|
+
itemAction: "delete";
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
type FileItemActionRetry = {
|
|
58
|
+
onRetry: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
59
|
+
itemAction: "retry";
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
type FileItemActionNone = {
|
|
63
|
+
itemAction?: "none";
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
type FileItemConditionalProps =
|
|
67
|
+
| FileItemActionDelete
|
|
68
|
+
| FileItemActionRetry
|
|
69
|
+
| FileItemActionNone;
|
|
70
|
+
|
|
71
|
+
export type FileUploadItemProps = FileItemBaseProps &
|
|
72
|
+
FileItemConditionalProps &
|
|
73
|
+
React.HTMLAttributes<HTMLDivElement>;
|
|
74
|
+
|
|
75
|
+
export const Item: OverridableComponent<FileUploadItemProps, HTMLDivElement> =
|
|
76
|
+
forwardRef(
|
|
77
|
+
(
|
|
78
|
+
{
|
|
79
|
+
as: Component = "div",
|
|
80
|
+
file,
|
|
81
|
+
status = "idle",
|
|
82
|
+
onDelete,
|
|
83
|
+
onRetry,
|
|
84
|
+
error,
|
|
85
|
+
className,
|
|
86
|
+
href,
|
|
87
|
+
onFileClick,
|
|
88
|
+
itemAction = "delete",
|
|
89
|
+
translations,
|
|
90
|
+
...rest
|
|
91
|
+
},
|
|
92
|
+
ref,
|
|
93
|
+
) => {
|
|
94
|
+
const context = useFileUploadTranslation(false);
|
|
95
|
+
const translate = useI18n(
|
|
96
|
+
"FileUpload",
|
|
97
|
+
{ item: translations },
|
|
98
|
+
context?.translations,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const showError = !!error && status === "idle";
|
|
102
|
+
|
|
103
|
+
function getStatusText() {
|
|
104
|
+
if (status === "uploading") {
|
|
105
|
+
return translate("item.uploading");
|
|
106
|
+
}
|
|
107
|
+
if (status === "downloading") {
|
|
108
|
+
return translate("item.downloading");
|
|
109
|
+
}
|
|
110
|
+
return formatFileSize(file);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<Component
|
|
115
|
+
ref={ref}
|
|
116
|
+
{...rest}
|
|
117
|
+
className={cl("navds-file-item", className, {
|
|
118
|
+
"navds-file-item--error": showError,
|
|
119
|
+
})}
|
|
120
|
+
>
|
|
121
|
+
<div className="navds-file-item__inner">
|
|
122
|
+
<ItemIcon
|
|
123
|
+
isLoading={status !== "idle"}
|
|
124
|
+
file={file}
|
|
125
|
+
showError={showError}
|
|
126
|
+
/>
|
|
127
|
+
<div className="navds-file-item__file-info">
|
|
128
|
+
<ItemName file={file} href={href} onClick={onFileClick} />
|
|
129
|
+
<BodyShort as="div" size="small">
|
|
130
|
+
{getStatusText()}
|
|
131
|
+
</BodyShort>
|
|
132
|
+
<div
|
|
133
|
+
className="navds-file-item__error"
|
|
134
|
+
aria-relevant="additions removals"
|
|
135
|
+
aria-live="polite"
|
|
136
|
+
>
|
|
137
|
+
{showError && (
|
|
138
|
+
<BodyShort
|
|
139
|
+
size="small"
|
|
140
|
+
className="navds-file-item__error-content"
|
|
141
|
+
>
|
|
142
|
+
<ExclamationmarkTriangleIcon aria-hidden />
|
|
143
|
+
{error}
|
|
144
|
+
</BodyShort>
|
|
145
|
+
)}
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
{status === "idle" && (
|
|
150
|
+
<ItemButton
|
|
151
|
+
file={file}
|
|
152
|
+
onRetry={onRetry}
|
|
153
|
+
onDelete={onDelete}
|
|
154
|
+
action={itemAction}
|
|
155
|
+
retryTitle={translate("item.retryButtonTitle")}
|
|
156
|
+
deleteTitle={translate("item.deleteButtonTitle")}
|
|
157
|
+
/>
|
|
158
|
+
)}
|
|
159
|
+
</div>
|
|
160
|
+
</Component>
|
|
161
|
+
);
|
|
162
|
+
},
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
export default Item;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ArrowsCirclepathIcon, TrashIcon } from "@navikt/aksel-icons";
|
|
3
|
+
import { Button } from "../../../../button";
|
|
4
|
+
import { FileItem } from "./Item.types";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
file: FileItem;
|
|
8
|
+
onRetry?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
|
9
|
+
onDelete?: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
|
10
|
+
action: "delete" | "retry" | "none";
|
|
11
|
+
retryTitle: string;
|
|
12
|
+
deleteTitle: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const ItemButton = ({
|
|
16
|
+
onRetry,
|
|
17
|
+
onDelete,
|
|
18
|
+
action,
|
|
19
|
+
retryTitle,
|
|
20
|
+
deleteTitle,
|
|
21
|
+
}: Props) => {
|
|
22
|
+
if (action === "none") {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (onRetry && action === "retry") {
|
|
27
|
+
return (
|
|
28
|
+
<Button
|
|
29
|
+
className="navds-file-item__button"
|
|
30
|
+
type="button"
|
|
31
|
+
variant="tertiary-neutral"
|
|
32
|
+
onClick={onRetry}
|
|
33
|
+
icon={<ArrowsCirclepathIcon title={retryTitle} />}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
if (onDelete && action === "delete") {
|
|
38
|
+
return (
|
|
39
|
+
<Button
|
|
40
|
+
className="navds-file-item__button"
|
|
41
|
+
type="button"
|
|
42
|
+
variant="tertiary-neutral"
|
|
43
|
+
onClick={onDelete}
|
|
44
|
+
icon={<TrashIcon title={deleteTitle} />}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default ItemButton;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
FileCsvIcon,
|
|
4
|
+
FileExcelIcon,
|
|
5
|
+
FileIcon,
|
|
6
|
+
FileImageIcon,
|
|
7
|
+
FilePdfIcon,
|
|
8
|
+
FileTextIcon,
|
|
9
|
+
FileWordIcon,
|
|
10
|
+
FileXMarkIcon,
|
|
11
|
+
} from "@navikt/aksel-icons";
|
|
12
|
+
import { Loader } from "../../../../loader";
|
|
13
|
+
import { FileItem } from "./Item.types";
|
|
14
|
+
|
|
15
|
+
interface ItemIconProps {
|
|
16
|
+
isLoading?: boolean;
|
|
17
|
+
file: FileItem;
|
|
18
|
+
showError: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const iconProps = {
|
|
22
|
+
fontSize: "2rem",
|
|
23
|
+
"aria-hidden": true,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function ItemIcon({ isLoading, file, showError }: ItemIconProps) {
|
|
27
|
+
if (isLoading) {
|
|
28
|
+
return (
|
|
29
|
+
<div className="navds-file-item__icon navds-file-item__icon--loading">
|
|
30
|
+
<Loader size="large" />
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
} else if (showError) {
|
|
34
|
+
return (
|
|
35
|
+
<div className="navds-file-item__icon">
|
|
36
|
+
<FileXMarkIcon {...iconProps} />
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
return (
|
|
41
|
+
<div className="navds-file-item__icon">
|
|
42
|
+
<Icon file={file} />
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function Icon({ file }: { file: FileItem }) {
|
|
48
|
+
const extension = file.name.substring(file.name.lastIndexOf(".") + 1);
|
|
49
|
+
|
|
50
|
+
switch (extension) {
|
|
51
|
+
case "jpg":
|
|
52
|
+
case "jpeg":
|
|
53
|
+
case "png":
|
|
54
|
+
case "gif":
|
|
55
|
+
case "webp":
|
|
56
|
+
return <FileImageIcon {...iconProps} />;
|
|
57
|
+
case "pdf":
|
|
58
|
+
return <FilePdfIcon {...iconProps} />;
|
|
59
|
+
case "txt":
|
|
60
|
+
return <FileTextIcon {...iconProps} />;
|
|
61
|
+
case "csv":
|
|
62
|
+
return <FileCsvIcon {...iconProps} />;
|
|
63
|
+
case "xls":
|
|
64
|
+
case "xlsx":
|
|
65
|
+
return <FileExcelIcon {...iconProps} />;
|
|
66
|
+
case "doc":
|
|
67
|
+
case "docx":
|
|
68
|
+
return <FileWordIcon {...iconProps} />;
|
|
69
|
+
default:
|
|
70
|
+
return <FileIcon {...iconProps} />;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default ItemIcon;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Link } from "../../../../link";
|
|
3
|
+
import { FileItem } from "./Item.types";
|
|
4
|
+
import { downloadFile } from "./utils/download-file";
|
|
5
|
+
import { isNativeFile } from "./utils/file-type-checker";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
file: FileItem;
|
|
9
|
+
href?: string;
|
|
10
|
+
onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ItemName = ({ file, href, onClick }: Props) => {
|
|
14
|
+
if (onClick && href) {
|
|
15
|
+
return (
|
|
16
|
+
<Link href={href} onClick={onClick}>
|
|
17
|
+
{file.name}
|
|
18
|
+
</Link>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (onClick) {
|
|
23
|
+
return (
|
|
24
|
+
<Link
|
|
25
|
+
href="#"
|
|
26
|
+
onClick={(event) => {
|
|
27
|
+
event.preventDefault();
|
|
28
|
+
onClick(event);
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
{file.name}
|
|
32
|
+
</Link>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (href) {
|
|
37
|
+
return <Link href={href}>{file.name}</Link>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (isNativeFile(file)) {
|
|
41
|
+
return (
|
|
42
|
+
<Link
|
|
43
|
+
href="#"
|
|
44
|
+
download={file.name}
|
|
45
|
+
onClick={(event) => {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
downloadFile(file);
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
{file.name}
|
|
51
|
+
</Link>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return <span>{file.name}</span>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default ItemName;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { formatFileSize } from "./format-file-size";
|
|
2
|
+
|
|
3
|
+
describe("format-file-size", () => {
|
|
4
|
+
describe("with native File", () => {
|
|
5
|
+
it('returns "0,01 MB" when file size is less than 0,01 MB', () => {
|
|
6
|
+
const file = new File(["abc"], "file.txt");
|
|
7
|
+
|
|
8
|
+
expect(formatFileSize(file)).toBe("0,01 MB");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('returns "0,29 MB" when file size is 0,29 MB', () => {
|
|
12
|
+
const file = new File(["abc".repeat(99_999)], "file.txt");
|
|
13
|
+
|
|
14
|
+
expect(formatFileSize(file)).toBe("0,29 MB");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('returns "> 500 MB" when file size is more than 500 MB', () => {
|
|
18
|
+
const file = createLargeMockFile(600_000_000);
|
|
19
|
+
|
|
20
|
+
expect(formatFileSize(file)).toBe("> 500 MB");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("with MetadataFile", () => {
|
|
25
|
+
it("returns null when file size is undefined", () => {
|
|
26
|
+
const file = {
|
|
27
|
+
name: "myfile.txt",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
expect(formatFileSize(file)).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
it('returns "0,01 MB" when file size is less than 0,01 MB', () => {
|
|
33
|
+
const file = {
|
|
34
|
+
name: "myfile.txt",
|
|
35
|
+
size: 1,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
expect(formatFileSize(file)).toBe("0,01 MB");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('returns "0,96 MB" when file size is 0,96 MB', () => {
|
|
42
|
+
const file = {
|
|
43
|
+
name: "myfile.txt",
|
|
44
|
+
size: 999_999,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
expect(formatFileSize(file)).toBe("0,96 MB");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('returns "> 500 MB" when file size is more than 500 MB', () => {
|
|
51
|
+
const file = {
|
|
52
|
+
name: "myfile.txt",
|
|
53
|
+
size: 600_000_000,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
expect(formatFileSize(file)).toBe("> 500 MB");
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
function createLargeMockFile(sizeInBytes: number): File {
|
|
62
|
+
const chunkSize = 1024 * 1024; // 1MB chunk size
|
|
63
|
+
const chunks: Uint8Array[] = [];
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < sizeInBytes; i += chunkSize) {
|
|
66
|
+
const size = Math.min(chunkSize, sizeInBytes - i);
|
|
67
|
+
const chunk = new Uint8Array(size);
|
|
68
|
+
chunk.fill("a".charCodeAt(0));
|
|
69
|
+
chunks.push(chunk);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const blob = new Blob(chunks, { type: "text/plain" });
|
|
73
|
+
return new File([blob], "largeMockFile.txt", {
|
|
74
|
+
type: "text/plain",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FileItem } from "../Item.types";
|
|
2
|
+
|
|
3
|
+
const MAX_MEGA_BYTES = 500;
|
|
4
|
+
|
|
5
|
+
export function formatFileSize(file: FileItem): string | null {
|
|
6
|
+
if (!file.size) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const megaBytes = file.size / (1024 * 1024);
|
|
10
|
+
|
|
11
|
+
if (megaBytes <= MAX_MEGA_BYTES) {
|
|
12
|
+
return formatter.format(megaBytes);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return `> ${MAX_MEGA_BYTES} MB`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const formatter = new Intl.NumberFormat("nb-NO", {
|
|
19
|
+
style: "unit",
|
|
20
|
+
unit: "megabyte",
|
|
21
|
+
minimumFractionDigits: 2,
|
|
22
|
+
maximumFractionDigits: 2,
|
|
23
|
+
// @ts-expect-error - Looks like roundingMode hasn't been added to TypeScript yet
|
|
24
|
+
roundingMode: "ceil",
|
|
25
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
import { useMergeRefs } from "../../util/hooks";
|
|
3
|
+
import { FileUploadBaseProps } from "./FileUpload.types";
|
|
4
|
+
import { validateFiles } from "./utils/validate-files";
|
|
5
|
+
|
|
6
|
+
export interface UseFileUploadProps
|
|
7
|
+
extends Omit<FileUploadBaseProps, "fileLimit"> {
|
|
8
|
+
ref: React.ForwardedRef<HTMLInputElement>;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const useFileUpload = ({
|
|
13
|
+
ref,
|
|
14
|
+
accept,
|
|
15
|
+
onSelect,
|
|
16
|
+
validator,
|
|
17
|
+
maxSizeInBytes,
|
|
18
|
+
disabled,
|
|
19
|
+
}: UseFileUploadProps) => {
|
|
20
|
+
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
21
|
+
const mergedRef = useMergeRefs(inputRef, ref);
|
|
22
|
+
|
|
23
|
+
const upload = (fileList: FileList) => {
|
|
24
|
+
const { files, partitionedFiles } = validateFiles(
|
|
25
|
+
Array.from(fileList),
|
|
26
|
+
accept,
|
|
27
|
+
validator,
|
|
28
|
+
maxSizeInBytes,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
onSelect(files, partitionedFiles);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
35
|
+
const fileList = event.target.files;
|
|
36
|
+
if (!fileList) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!disabled) {
|
|
41
|
+
upload(fileList);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Resets the value to make it is possible to upload the same file several consecutive times
|
|
45
|
+
event.target.value = "";
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
upload,
|
|
50
|
+
onChange,
|
|
51
|
+
inputRef,
|
|
52
|
+
mergedRef,
|
|
53
|
+
};
|
|
54
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { isAcceptedFileType } from "./is-accepted-file-type";
|
|
2
|
+
|
|
3
|
+
const txtFile = () =>
|
|
4
|
+
new File(["foo"], "foo.txt", {
|
|
5
|
+
type: "text/plain",
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
describe("isAcceptedFileType", () => {
|
|
9
|
+
test("returns true when accept is undefined", () => {
|
|
10
|
+
expect(isAcceptedFileType(txtFile(), undefined)).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("returns true when accept is empty string", () => {
|
|
14
|
+
expect(isAcceptedFileType(txtFile(), "")).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("returns true when file matches accepted extensions", () => {
|
|
18
|
+
expect(isAcceptedFileType(txtFile(), ".txt, .pdf")).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("works as expected when there is no space after comma in accept", () => {
|
|
22
|
+
expect(isAcceptedFileType(txtFile(), ".txt,.pdf")).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("returns false when file does not match the accepted extensions", () => {
|
|
26
|
+
expect(isAcceptedFileType(txtFile(), ".xlsx, .pdf")).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("returns true when file matches the accepted exact mime types", () => {
|
|
30
|
+
expect(isAcceptedFileType(txtFile(), "application/pdf, text/plain")).toBe(
|
|
31
|
+
true,
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("returns false when file does not the accepted exact mime types", () => {
|
|
36
|
+
expect(isAcceptedFileType(txtFile(), "application/pdf, text/csv")).toBe(
|
|
37
|
+
false,
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("returns true when file matches the accepted wildcard mime types", () => {
|
|
42
|
+
expect(isAcceptedFileType(txtFile(), "application/*, text/*")).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("returns false when file does not the accepted wildcard mime types", () => {
|
|
46
|
+
expect(isAcceptedFileType(txtFile(), "application/*, image/*")).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("returns true if matches extension, but not exact or wildcard mime type", () => {
|
|
50
|
+
expect(
|
|
51
|
+
isAcceptedFileType(txtFile(), "application/*, image/*, .txt, audio/mpeg"),
|
|
52
|
+
).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("returns true if matches exact mime type, but not extension or wildcard mime type", () => {
|
|
56
|
+
expect(
|
|
57
|
+
isAcceptedFileType(
|
|
58
|
+
txtFile(),
|
|
59
|
+
"application/*, text/plain, .jpg, audio/mpeg",
|
|
60
|
+
),
|
|
61
|
+
).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("returns true if matches wildcard mime type, but not extension or exact mime type", () => {
|
|
65
|
+
expect(
|
|
66
|
+
isAcceptedFileType(txtFile(), "application/*, text/*, .jpg, audio/mpeg"),
|
|
67
|
+
).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function isAcceptedFileType(
|
|
2
|
+
file: File,
|
|
3
|
+
accept: string | undefined,
|
|
4
|
+
): boolean {
|
|
5
|
+
if (!accept) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
const mimeType = file.type;
|
|
9
|
+
const acceptedTypes = accept.split(",");
|
|
10
|
+
|
|
11
|
+
return acceptedTypes.some((type) => {
|
|
12
|
+
const validType = type.trim();
|
|
13
|
+
const isExtensionType = validType.startsWith(".");
|
|
14
|
+
const isWildcardMimeType = validType.endsWith("/*");
|
|
15
|
+
|
|
16
|
+
if (isExtensionType) {
|
|
17
|
+
return file.name.toLowerCase().endsWith(validType.toLowerCase());
|
|
18
|
+
} else if (isWildcardMimeType) {
|
|
19
|
+
const baseMimeType = mimeType.replace(/\/.*$/, "");
|
|
20
|
+
const baseValidType = validType.replace(/\/.*$/, "");
|
|
21
|
+
return baseMimeType === baseValidType;
|
|
22
|
+
}
|
|
23
|
+
return mimeType === validType;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { isAcceptedSize } from "./is-accepted-size";
|
|
2
|
+
|
|
3
|
+
describe("isAcceptedSize", () => {
|
|
4
|
+
it("should return true if maxSize is less than or equal to 0", () => {
|
|
5
|
+
const file = new File([new Array(5000).join("a")], "filename.txt", {
|
|
6
|
+
type: "text/plain",
|
|
7
|
+
});
|
|
8
|
+
expect(isAcceptedSize(file, -1)).toBe(true);
|
|
9
|
+
expect(isAcceptedSize(file, 0)).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should return true if file size is less than or equal to maxSize", () => {
|
|
13
|
+
const file = new File([new Array(5000).join("a")], "filename.txt", {
|
|
14
|
+
type: "text/plain",
|
|
15
|
+
});
|
|
16
|
+
expect(isAcceptedSize(file, 5000)).toBe(true);
|
|
17
|
+
expect(isAcceptedSize(file, 6000)).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should return false if file size is greater than maxSize", () => {
|
|
21
|
+
const file = new File([new Array(5000).join("a")], "filename.txt", {
|
|
22
|
+
type: "text/plain",
|
|
23
|
+
});
|
|
24
|
+
expect(isAcceptedSize(file, 4000)).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
});
|