From b5c5cb2979cbb6e344858b67c4a55cfc75757e6a Mon Sep 17 00:00:00 2001 From: AadneRo Date: Thu, 11 Aug 2022 10:36:41 +0200 Subject: [PATCH] feat(Upload) Add Upload component mvp. Still missing some features: - Drag and drop to upload file --- .../src/docs/uilib/components/upload.md | 12 + .../docs/uilib/components/upload/Examples.tsx | 172 ++++++++ .../src/docs/uilib/components/upload/demos.md | 52 +++ .../src/docs/uilib/components/upload/info.md | 7 + .../uilib/components/upload/properties.md | 23 + packages/dnb-eufemia/src/components/Upload.js | 14 + packages/dnb-eufemia/src/components/index.js | 2 + packages/dnb-eufemia/src/components/lib.js | 3 + .../src/components/upload/Upload.tsx | 166 ++++++++ .../src/components/upload/UploadFileInput.tsx | 110 +++++ .../components/upload/UploadFileListCell.tsx | 167 ++++++++ .../__tests__/Upload.screenshot.test.js | 47 +++ .../upload/__tests__/Upload.test.tsx | 350 ++++++++++++++++ .../upload/__tests__/UploadFileInput.test.tsx | 161 +++++++ .../__tests__/UploadFileListCell.test.tsx | 394 ++++++++++++++++++ .../__snapshots__/Upload.test.tsx.snap | 127 ++++++ ...e-custom-accepted-formats-1-b90e0.snap.png | Bin 0 -> 23438 bytes ...-to-match-the-custom-text-1-e5172.snap.png | Bin 0 -> 21973 bytes ...have-to-match-the-default-1-0bb95.snap.png | Bin 0 -> 23037 bytes ...o-match-the-error-message-1-49b5c.snap.png | Bin 0 -> 26725 bytes ...o-match-the-loading-state-1-f9e4a.snap.png | Bin 0 -> 27358 bytes .../upload/__tests__/testHelpers.ts | 13 + .../upload/__tests__/useUpload.test.tsx | 117 ++++++ .../src/components/upload/index.d.ts | 8 + .../src/components/upload/index.js | 8 + .../upload/stories/Upload.stories.tsx | 78 ++++ .../src/components/upload/style.js | 6 + .../src/components/upload/style/_upload.scss | 95 +++++ .../components/upload/style/dnb-upload.scss | 12 + .../src/components/upload/style/index.d.ts | 6 + .../src/components/upload/style/index.js | 6 + .../src/components/upload/types.ts | 55 +++ .../src/components/upload/useUpload.ts | 25 ++ packages/dnb-eufemia/src/index.js | 2 + packages/dnb-eufemia/src/shared/Context.tsx | 2 + .../dnb-eufemia/src/shared/locales/en-GB.js | 12 + .../dnb-eufemia/src/shared/locales/nb-NO.js | 12 + .../src/style/dnb-ui-components.scss | 1 + 38 files changed, 2265 insertions(+) create mode 100644 packages/dnb-design-system-portal/src/docs/uilib/components/upload.md create mode 100644 packages/dnb-design-system-portal/src/docs/uilib/components/upload/Examples.tsx create mode 100644 packages/dnb-design-system-portal/src/docs/uilib/components/upload/demos.md create mode 100644 packages/dnb-design-system-portal/src/docs/uilib/components/upload/info.md create mode 100644 packages/dnb-design-system-portal/src/docs/uilib/components/upload/properties.md create mode 100644 packages/dnb-eufemia/src/components/Upload.js create mode 100644 packages/dnb-eufemia/src/components/upload/Upload.tsx create mode 100644 packages/dnb-eufemia/src/components/upload/UploadFileInput.tsx create mode 100644 packages/dnb-eufemia/src/components/upload/UploadFileListCell.tsx create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/Upload.screenshot.test.js create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/Upload.test.tsx create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/UploadFileInput.test.tsx create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/UploadFileListCell.test.tsx create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/Upload.test.tsx.snap create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/upload-screenshot-test-js-avatar-screenshot-have-to-match-the-custom-accepted-formats-1-b90e0.snap.png create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/upload-screenshot-test-js-avatar-screenshot-have-to-match-the-custom-text-1-e5172.snap.png create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/upload-screenshot-test-js-avatar-screenshot-have-to-match-the-default-1-0bb95.snap.png create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/upload-screenshot-test-js-avatar-screenshot-have-to-match-the-error-message-1-49b5c.snap.png create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/upload-screenshot-test-js-avatar-screenshot-have-to-match-the-loading-state-1-f9e4a.snap.png create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/testHelpers.ts create mode 100644 packages/dnb-eufemia/src/components/upload/__tests__/useUpload.test.tsx create mode 100644 packages/dnb-eufemia/src/components/upload/index.d.ts create mode 100644 packages/dnb-eufemia/src/components/upload/index.js create mode 100644 packages/dnb-eufemia/src/components/upload/stories/Upload.stories.tsx create mode 100644 packages/dnb-eufemia/src/components/upload/style.js create mode 100644 packages/dnb-eufemia/src/components/upload/style/_upload.scss create mode 100644 packages/dnb-eufemia/src/components/upload/style/dnb-upload.scss create mode 100644 packages/dnb-eufemia/src/components/upload/style/index.d.ts create mode 100644 packages/dnb-eufemia/src/components/upload/style/index.js create mode 100644 packages/dnb-eufemia/src/components/upload/types.ts create mode 100644 packages/dnb-eufemia/src/components/upload/useUpload.ts diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/upload.md b/packages/dnb-design-system-portal/src/docs/uilib/components/upload.md new file mode 100644 index 00000000000..b966d634e99 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/upload.md @@ -0,0 +1,12 @@ +--- +title: 'Upload' +description: 'The Upload widget should be used in scenarios where the customer has to upload files. Files can be uploaded by clicking button. You also have the opportunity to add descriptive texts below the title where you could put max file size, allowed fileformats etc.' +status: 'new' +showTabs: true +--- + +import UploadInfo from 'Docs/uilib/components/upload/info' +import UploadDemos from 'Docs/uilib/components/upload/demos' + + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/upload/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/components/upload/Examples.tsx new file mode 100644 index 00000000000..85d93e1db1e --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/upload/Examples.tsx @@ -0,0 +1,172 @@ +/** + * UI lib Component Example + * + */ + +import React from 'react' +import ComponentBox from 'dnb-design-system-portal/src/shared/tags/ComponentBox' + +export const UploadBasic = () => ( + + { + /* jsx */ ` +const Component = () => { + const {files} = Upload.useUpload('upload-basic') + + return ( + + ) +} +render() + ` + } + +) + +export const UploadMultipleFiles = () => ( + + { + /* jsx */ ` +const Component = () => { + const {files, setFiles} = Upload.useUpload('upload-multiple-files') + return ( + + ) +} +render() + ` + } + +) +export const UploadRemoveFile = () => ( + + { + /* jsx */ ` +const Component = () => { + const {files, setFiles} = Upload.useUpload('upload-remove-files') + return ( + <> + + + + ) +} +render() + ` + } + +) + +export const UploadIsLoading = () => ( + + { + /* jsx */ ` +const Component = () => { + const {files, setFiles} = Upload.useUpload('upload-is-loading') + + return ( + <> + + + + ) +} +render() + ` + } + +) + +export const UploadErrorMessage = () => ( + + { + /* jsx */ ` +const Component = () => { + const {files, setFiles} = Upload.useUpload('upload-error-message') + return ( + <> + + + + ) +} +render() + ` + } + +) + +export const UploadAcceptedFormats = () => ( + + { + /* jsx */ ` +const Component = () => { + const {files, setFiles} = Upload.useUpload('upload-accepted-formats') + + return ( + + ) +} +render() + ` + } + +) + +export const UploadCustomText = () => ( + + { + /* jsx */ ` + + ` + } + +) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/upload/demos.md b/packages/dnb-design-system-portal/src/docs/uilib/components/upload/demos.md new file mode 100644 index 00000000000..58a1709d20a --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/upload/demos.md @@ -0,0 +1,52 @@ +--- +showTabs: true +--- + +import {UploadBasic} from 'Docs/uilib/components/upload/Examples' +import {UploadRemoveFile} from 'Docs/uilib/components/upload/Examples' +import {UploadMultipleFiles} from 'Docs/uilib/components/upload/Examples' +import {UploadIsLoading} from 'Docs/uilib/components/upload/Examples' +import {UploadErrorMessage} from 'Docs/uilib/components/upload/Examples' +import {UploadAcceptedFormats} from 'Docs/uilib/components/upload/Examples' +import {UploadCustomText} from 'Docs/uilib/components/upload/Examples' + + +## Demos + +### Upload (default) + + + +### Upload.useUpload + +using the Upload.useUpload you can remove or add files displayed in the component + + + +### Upload multiple files + + + +### Upload loading state + +When uploading the file you can set the loading state of the request using the Upload.useUpload hook and passing isLoading to the file that is being uploaded. + + + +### Upload error message + +The only checks we do currently is for the file size and the file type. These errors are handled by the HTML element ´input´ so they aren't selectable. If you want any other error messages you can use the Upload.useUpload the same way as with the loading state. + + + +### Upload specific accepted file formats + +You can pass the file formats as a string array. This will restrict which files that can be selected. + + + +### Upload custom text + +All the text can be custom + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/upload/info.md b/packages/dnb-design-system-portal/src/docs/uilib/components/upload/info.md new file mode 100644 index 00000000000..52827966143 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/upload/info.md @@ -0,0 +1,7 @@ +--- +showTabs: true +--- + +## Description + +The Upload should be used in scenarios where the user has to upload files diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/upload/properties.md b/packages/dnb-design-system-portal/src/docs/uilib/components/upload/properties.md new file mode 100644 index 00000000000..ca4d12e7494 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/upload/properties.md @@ -0,0 +1,23 @@ +--- +showTabs: true +--- + +## Properties + + +| Properties | Description | +| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| [Space](/uilib/components/space/properties) | _(optional)_ Spacing properties like `top` or `bottom` are supported. | +| `className` | _(optional)_ Custom className for the component root. | +| `skeleton` | _(optional)_ Skeleton should be applied when loading content Default: null. | +| `acceptedFileTypes` | _(required)_ List of accepted file types. | +| `fileMaxSize` | _(optional)_ fileMaxSize is max size of each file in MB | +| `multipleFiles` | _(optional)_ if set true, accepting multiple files is allowed | +| `title` | _(optional)_ Custom text property. Replaces the default title | +| `text` | _(optional)_ Custom text property. Replaces the default text | +| `formatsDescription` | _(optional)_ Custom text property. Replaces the default accepted format description | +| `fileSizeDescription` | _(optional)_ Custom text property. Replaces the default max file size description | +| `fileSizeContent` | _(optional)_ Custom text property. Replaces the default file size content | +| `uploadButtonText` | _(optional)_ Custom text property. Replaces the default upload button text | +| `uploadLoadingText` | _(optional)_ Custom text property. Replaces the default loading text | +| `deleteButton` | _(optional)_ Custom text property. Replaces the default delete button text | diff --git a/packages/dnb-eufemia/src/components/Upload.js b/packages/dnb-eufemia/src/components/Upload.js new file mode 100644 index 00000000000..90d57a9f132 --- /dev/null +++ b/packages/dnb-eufemia/src/components/Upload.js @@ -0,0 +1,14 @@ +/** + * ATTENTION: This file is auto generated by using "prepareTemplates". + * Do not change the content! + * + */ + +/** + * Library Index upload to autogenerate all the components and extensions + * Used by "prepareUploads" + */ + +import Upload from './upload/Upload' +export * from './upload/Upload' +export default Upload diff --git a/packages/dnb-eufemia/src/components/index.js b/packages/dnb-eufemia/src/components/index.js index 992019406e8..83e8722eddd 100644 --- a/packages/dnb-eufemia/src/components/index.js +++ b/packages/dnb-eufemia/src/components/index.js @@ -54,6 +54,7 @@ import Textarea from './textarea/Textarea' import Timeline from './timeline/Timeline' import ToggleButton from './toggle-button/ToggleButton' import Tooltip from './tooltip/Tooltip' +import Upload from './upload/Upload' import VisuallyHidden from './visually-hidden/VisuallyHidden' // define / export all the available components @@ -102,5 +103,6 @@ export { Timeline, ToggleButton, Tooltip, + Upload, VisuallyHidden, } diff --git a/packages/dnb-eufemia/src/components/lib.js b/packages/dnb-eufemia/src/components/lib.js index a6af619a972..a075f9a7b0a 100644 --- a/packages/dnb-eufemia/src/components/lib.js +++ b/packages/dnb-eufemia/src/components/lib.js @@ -56,6 +56,7 @@ import Textarea from './textarea/Textarea' import Timeline from './timeline/Timeline' import ToggleButton from './toggle-button/ToggleButton' import Tooltip from './tooltip/Tooltip' +import Upload from './upload/Upload' import VisuallyHidden from './visually-hidden/VisuallyHidden' // define / export all the available components @@ -104,6 +105,7 @@ export { Timeline, ToggleButton, Tooltip, + Upload, VisuallyHidden, } @@ -153,6 +155,7 @@ export const getComponents = () => { Timeline, ToggleButton, Tooltip, + Upload, VisuallyHidden, } } diff --git a/packages/dnb-eufemia/src/components/upload/Upload.tsx b/packages/dnb-eufemia/src/components/upload/Upload.tsx new file mode 100644 index 00000000000..253ddada5be --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/Upload.tsx @@ -0,0 +1,166 @@ +import React from 'react' +import classnames from 'classnames' + +// Components +import Lead from '../../elements/Lead' + +// Shared +import { createSpacingClasses } from '../space/SpacingHelper' +import { createSkeletonClass } from '../skeleton/SkeletonHelper' +import Context from '../../shared/Context' +import { extendPropsWithContext } from '../../shared/component-helper' +import { format } from '../number-format/NumberUtils' + +// Internal +import UploadFileInput from './UploadFileInput' +import type { UploadFile, UploadProps } from './types' +import UploadFileListCell from './UploadFileListCell' +import useUpload from './useUpload' + +export const defaultProps = { + fileMaxSize: 5000, +} + +const Upload = (localProps: UploadProps) => { + // Every component should have a context + const context = React.useContext(Context) + // Extract additional props from global context + const { + id, + skeleton, + className, + acceptedFileTypes, + multipleFiles, + fileMaxSize, + title, + text, + formatsDescription, + fileSizeDescription, + fileSizeContent, + uploadButtonText, + uploadLoadingText, + uploadErrorLargeFile, + deleteButton, + ...props + } = extendPropsWithContext( + localProps, + defaultProps, + { skeleton: context?.skeleton }, + context.getTranslation().Upload, + context.Upload + ) + + const skeletonClasses = createSkeletonClass('shape', skeleton, context) + const spacingClasses = createSpacingClasses(props) + + const { files, setFiles } = useUpload(id) + + const prettyfiedAcceptedFileFormats = acceptedFileTypes + .join(', ') + .toUpperCase() + + return ( +
+ + {title} + + + + {text} + + +
+
+ {formatsDescription} +
+
+ {prettyfiedAcceptedFileFormats} +
+ +
+ {fileSizeDescription} +
+
+ {String(fileSizeContent).replace( + '%size', + format(fileMaxSize).toString() + )} +
+
+ +
+ + + +
+
+ ) + + function UploadFileList() { + if (files == null || files.length < 1) return null + + return ( +
+ {files.map((uploadFile: UploadFile, index: number) => { + return ( + onDeleteFile(uploadFile)} + deleteButtonText={deleteButton} + uploadLoadingText={uploadLoadingText} + /> + ) + })} +
+ ) + } + + function onDeleteFile(removeFile: UploadFile) { + const cleanedFiles = files.filter( + (fileListElement) => fileListElement.file != removeFile.file + ) + setFiles(cleanedFiles) + } + + function onInputUpload(addedFiles: UploadFile[]) { + const addedFile = [...files, ...addedFiles] + + setFiles(addedFile) + } +} + +Upload.useUpload = useUpload + +export default Upload diff --git a/packages/dnb-eufemia/src/components/upload/UploadFileInput.tsx b/packages/dnb-eufemia/src/components/upload/UploadFileInput.tsx new file mode 100644 index 00000000000..00f0711b023 --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/UploadFileInput.tsx @@ -0,0 +1,110 @@ +import React, { useEffect, useRef, useState } from 'react' + +// Components +import Button from '../button/Button' +import FormLabel from '../form-label/FormLabel' + +// Icons +import { folder as FolderIcon } from '../../icons' + +// Shared +import { makeUniqueId } from '../../shared/component-helper' +import { format } from '../number-format/NumberUtils' + +// Internal +import { UploadFile } from './types' + +export interface UploadFileInputProps { + acceptedFormats: string[] + onUpload: (files: UploadFile[]) => void + fileMaxSize: number + uploadFileButtonText: React.ReactNode + uploadErrorLargeFile: React.ReactNode + multipleFiles: boolean +} + +const BYTES_IN_A_MEGA_BYTE = 1048576 + +const UploadFileInput = ({ + acceptedFormats, + uploadFileButtonText, + onUpload, + fileMaxSize, + uploadErrorLargeFile, + multipleFiles = false, +}: UploadFileInputProps) => { + const fileInput = useRef(null) + + const accept = acceptedFormats.reduce((accept, format, index) => { + const previus = index === 0 ? '' : `${accept},` + return `${previus} .${format}` + }, '') + + useEffect(() => { + fileInput.current.value = null + fileInput.current.accept = accept + }) + + const [id] = useState(makeUniqueId) + + const openFileDialog = () => fileInput.current?.click() + + return ( +
+ + + + + +
+ ) + + function handleFileInput({ target: { files } }) { + const uploadFile = [...Array(files.length)].map((_item, index) => { + const file: UploadFile = { file: files[index] } + const errorMessage = getErrorMessage(file.file.size) + + if (errorMessage) return { ...file, errorMessage } + return file + }) + onUpload(uploadFile) + } + + function getErrorMessage(fileSize: number) { + const errorMessage = String(uploadErrorLargeFile).replace( + '%size', + format(fileMaxSize).toString() + ) + // Converts from b (binary) to MB (decimal) + return fileSize / BYTES_IN_A_MEGA_BYTE > fileMaxSize + ? errorMessage + : null + } +} + +export default UploadFileInput diff --git a/packages/dnb-eufemia/src/components/upload/UploadFileListCell.tsx b/packages/dnb-eufemia/src/components/upload/UploadFileListCell.tsx new file mode 100644 index 00000000000..fbcdddedbca --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/UploadFileListCell.tsx @@ -0,0 +1,167 @@ +import React from 'react' +import classnames from 'classnames' + +// Components +import Button from '../button/Button' +import Icon from '../../components/Icon' +import FormStatus from '../../components/FormStatus' +import ProgressIndicator from '../../components/progress-indicator' + +// Icons +import { + trash_medium as TrashIcon, + exclamation_medium as ExclamationIcon, + file_pdf_medium, + file_xls_medium, + file_ppt_medium, + file_csv_medium, + file_txt_medium, + file_xml_medium, + file_medium, +} from '../../icons' +import { UploadFile } from './types' + +const images = { + pdf: file_pdf_medium, + xls: file_xls_medium, + ppt: file_ppt_medium, + csv: file_csv_medium, + txt: file_txt_medium, + xml: file_xml_medium, + file: file_medium, +} + +export interface UploadFileListCellProps { + /** + * Uploaded file + */ + uploadFile: UploadFile + /** + * Calls onDelete when clicking the delete button + */ + onDelete: () => void + /** + * Text + */ + uploadLoadingText: React.ReactNode + deleteButtonText: React.ReactNode +} + +const UploadFileListCell = ({ + uploadFile, + onDelete, + uploadLoadingText, + deleteButtonText, +}: UploadFileListCellProps) => { + const { file, errorMessage, isLoading } = uploadFile + const { name, type } = file + + const fileType = type.split('/')[1] + + const hasWarning = errorMessage != null + + const imageUrl = URL.createObjectURL(file) + + return ( +
+
+
+ {getIcon()} + {getTitle()} +
+ + +
+ + {getWarning()} +
+ ) + + function getIcon() { + if (isLoading) { + return + } + + if (hasWarning) + return ( + + ) + + let iconFileType = fileType + + if (!Object.prototype.hasOwnProperty.call(images, fileType)) { + iconFileType = 'file' + } + return ( + + ) + } + + function getTitle() { + return isLoading ? ( +
+ {uploadLoadingText} +
+ ) : ( +
+ + {name} + + + {fileType.toUpperCase()} + +
+ ) + } + + function getWarning() { + return hasWarning ? ( + + ) : null + } +} + +export default UploadFileListCell diff --git a/packages/dnb-eufemia/src/components/upload/__tests__/Upload.screenshot.test.js b/packages/dnb-eufemia/src/components/upload/__tests__/Upload.screenshot.test.js new file mode 100644 index 00000000000..5c52396ae0e --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/__tests__/Upload.screenshot.test.js @@ -0,0 +1,47 @@ +/** + * Screenshot Test + * This file will not run on "test:staged" because we don't require any related files + */ + +import { + testPageScreenshot, + setupPageScreenshot, +} from '../../../core/jest/jestSetupScreenshots' + +describe('Avatar screenshot', () => { + setupPageScreenshot({ url: '/uilib/components/upload/demos' }) + + it('have to match the default', async () => { + const screenshot = await testPageScreenshot({ + selector: '[data-visual-test="upload-basic"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) + + it('have to match the loading state', async () => { + const screenshot = await testPageScreenshot({ + selector: '[data-visual-test="upload-is-loading"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) + + it('have to match the error message', async () => { + const screenshot = await testPageScreenshot({ + selector: '[data-visual-test="upload-error-message"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) + it('have to match the custom accepted formats', async () => { + const screenshot = await testPageScreenshot({ + selector: '[data-visual-test="upload-accepted-formats"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) + + it('have to match the custom text', async () => { + const screenshot = await testPageScreenshot({ + selector: '[data-visual-test="upload-custom-text"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) +}) diff --git a/packages/dnb-eufemia/src/components/upload/__tests__/Upload.test.tsx b/packages/dnb-eufemia/src/components/upload/__tests__/Upload.test.tsx new file mode 100644 index 00000000000..17bab551234 --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/__tests__/Upload.test.tsx @@ -0,0 +1,350 @@ +import React, { useEffect } from 'react' +import { fireEvent, render, screen, waitFor } from '@testing-library/react' +import Upload from '../Upload' +import nbNO from '../../../shared/locales/nb-NO' +import createMockFile from './testHelpers' +import { loadScss, axeComponent } from '../../../core/jest/jestSetup' +import { UploadProps } from '../types' +import useUpload from '../useUpload' + +const nb = nbNO['nb-NO'].Upload + +global.URL.createObjectURL = jest.fn(() => 'url') + +const defaultProps: UploadProps = { + id: 'id', + acceptedFileTypes: ['png'], +} + +describe('Upload', () => { + afterEach(() => { + jest.clearAllMocks() + }) + + it('renders the component', () => { + render() + + expect(screen.queryByTestId('upload')).not.toBeNull() + }) + + it('renders the upload file input section', () => { + render() + + expect(screen.queryByTestId('upload-file-input')).not.toBeNull() + }) + + describe('Text', () => { + it('renders the title', () => { + render() + + const element = screen.queryByTestId('upload-title') + + expect(element).not.toBeNull() + + expect(element.textContent).toMatch(nb.title) + }) + + it('renders the custom title', () => { + const customTitle = 'custom title' + + render() + + const element = screen.queryByTestId('upload-title') + + expect(element.textContent).toMatch(customTitle) + }) + + it('renders the text', () => { + render() + + const element = screen.queryByTestId('upload-text') + + expect(element).not.toBeNull() + + expect(element.textContent).toMatch(nb.text) + }) + + it('renders the custom text', () => { + const customText = 'custom text' + + render() + + const element = screen.queryByTestId('upload-text') + + expect(element.textContent).toMatch(customText) + }) + + it('renders the format description', () => { + render() + + const element = screen.queryByTestId( + 'upload-accepted-formats-description' + ) + + expect(element).not.toBeNull() + + expect(element.textContent).toMatch(nb.formatsDescription) + }) + + it('renders the custom format description', () => { + const customFormatDescription = 'custom formats description' + + render( + + ) + + const element = screen.queryByTestId( + 'upload-accepted-formats-description' + ) + + expect(element.textContent).toMatch(customFormatDescription) + }) + + it('renders the custom accepted format', () => { + const acceptedFileTypes = ['png, jpg'] + + render( + + ) + + const element = screen.queryByTestId('upload-accepted-formats') + + const formattedFileTypes = acceptedFileTypes.join(', ').toUpperCase() + + expect(element).not.toBeNull() + expect(element.textContent).toMatch(formattedFileTypes) + }) + + it('renders the file size description', () => { + render() + + const element = screen.queryByTestId('upload-file-size-description') + + expect(element).not.toBeNull() + }) + + it('renders the custom file size description', () => { + const fileSizeDescription = 'file size description' + + render( + + ) + + const element = screen.queryByTestId('upload-file-size-description') + + expect(element.textContent).toMatch(fileSizeDescription) + }) + + it('renders the file size', () => { + const fileMaxSize = 2 + render() + + const element = screen.queryByTestId('upload-file-size') + + expect(element).not.toBeNull() + expect(element.textContent).toMatch( + String(nb.fileSizeContent).replace('%size', fileMaxSize.toString()) + ) + }) + + it('renders the custom file size', () => { + const fileMaxSize = 2 + const fileSizeContent = '%size custom' + + render( + + ) + + const element = screen.queryByTestId('upload-file-size') + + expect(element.textContent).toMatch( + String(fileMaxSize).replace('%size', `${fileMaxSize}`) + ) + }) + + it('renders the upload file input section button text', () => { + render() + + const element = screen.queryByTestId('upload-file-input-button') + + expect(element.textContent).toMatch(nb.uploadButtonText) + }) + + it('renders the upload file input section button custom text', () => { + const uploadButtonText = 'upload button text' + + render( + + ) + + const element = screen.queryByTestId('upload-file-input-button') + + expect(element.textContent).toMatch(uploadButtonText) + }) + }) + + describe('useUpload', () => { + it('calls uses the useUpload hook to store files', async () => { + const validationFunction = jest.fn() + + const file = createMockFile('fileName.png', 100, 'image/png') + + const id = 'random-id' + + const expectedResult = [{ file }] + + render() + + const inputElement = screen.queryByTestId('upload-file-input-input') + + await waitFor(() => + fireEvent.change(inputElement, { + target: { files: [file] }, + }) + ) + + const MockComponent = () => { + const { files } = useUpload(id) + useEffect(() => validationFunction(files), []) + + return
+ } + + render() + + expect(validationFunction).toHaveBeenCalledWith(expectedResult) + }) + + it('renders the list of files', async () => { + const files = [ + { file: createMockFile('fileName.png', 100, 'image/png') }, + { file: createMockFile('fileName2.png', 100, 'image/png') }, + { file: createMockFile('fileName3.png', 100, 'image/png') }, + ] + + const id = 'random-id' + + render() + + const MockComponent = () => { + const { setFiles } = useUpload(id) + + useEffect(() => setFiles(files), []) + + return
+ } + + render() + + const fileCells = screen.queryAllByTestId('upload-file-list-cell') + + expect(fileCells.length).toBe(files.length) + }) + + it('shows no files', async () => { + const files = [] + + const id = 'random-id3' + + const { queryByTestId } = render( + + ) + + const MockComponent = () => { + const { setFiles } = useUpload(id) + + useEffect(() => setFiles(files), []) + + return
+ } + render() + + const emptyFileCell = queryByTestId('upload-file-list-cell') + + expect(emptyFileCell).toBeNull() + }) + + it('shows the file when the file is added', async () => { + const files = [ + { file: createMockFile('fileName.png', 100, 'image/png') }, + ] + + const id = 'random-id2' + + render() + + const MockComponent = () => { + const { setFiles } = useUpload(id) + + useEffect(() => setFiles(files), []) + + return
+ } + + const emptyFileCell = screen.queryByTestId('upload-file-list-cell') + + expect(emptyFileCell).toBeNull() + + render() + + const fileCell = screen.queryByTestId('upload-file-list-cell') + + expect(fileCell).not.toBeNull() + }) + + it('removes the file from the list when clicking delete', () => { + const files = [ + { file: createMockFile('fileName.png', 100, 'image/png') }, + ] + + const id = 'random-id3' + + const { queryByTestId } = render( + + ) + const MockComponent = () => { + const { setFiles } = useUpload(id) + + useEffect(() => setFiles(files), []) + + return
+ } + + render() + + const fileCell = queryByTestId('upload-file-list-cell') + + expect(fileCell).not.toBeNull() + + const deleteButton = queryByTestId('upload-delete-button') + + fireEvent.click(deleteButton) + + expect(queryByTestId('upload-file-list-cell')).toBeNull() + }) + }) +}) + +describe('Upload aria', () => { + it('should validate', async () => { + const Component = render() + expect(await axeComponent(Component)).toHaveNoViolations() + }) +}) + +describe('Upload scss', () => { + it('have to match snapshot', () => { + const scss = loadScss(require.resolve('../style/dnb-upload.scss')) + expect(scss).toMatchSnapshot() + }) +}) diff --git a/packages/dnb-eufemia/src/components/upload/__tests__/UploadFileInput.test.tsx b/packages/dnb-eufemia/src/components/upload/__tests__/UploadFileInput.test.tsx new file mode 100644 index 00000000000..359223c1715 --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/__tests__/UploadFileInput.test.tsx @@ -0,0 +1,161 @@ +import React from 'react' +import { fireEvent, render, screen, waitFor } from '@testing-library/react' +import UploadFileInput, { UploadFileInputProps } from '../UploadFileInput' +import createMockFile from './testHelpers' + +const defaultProps: UploadFileInputProps = { + acceptedFormats: ['png'], + onUpload: jest.fn(), + uploadFileButtonText: 'upload button text', + fileMaxSize: 1000, + uploadErrorLargeFile: 'error message', + multipleFiles: false, +} + +describe('UploadFileInput', () => { + it('renders the component', () => { + render() + + expect(screen.queryByTestId('upload-file-input')).not.toBeNull() + }) + + it('renders the upload button', () => { + render() + expect(screen.queryByTestId('upload-file-input-button')).not.toBeNull() + }) + + it('renders the upload button text', () => { + const buttonText = 'button text' + render( + + ) + expect( + screen.queryByTestId('upload-file-input-button').textContent + ).toMatch(buttonText) + }) + + it('accepts multiple files when multipleFiles is true', () => { + render() + + const element = screen.queryByTestId('upload-file-input-input') + + expect(element.hasAttribute('multiple')).toBeTruthy() + }) + + it('renders the input', () => { + render() + const element = screen.queryByTestId('upload-file-input-input') + + expect(element).not.toBeNull() + expect(element.getAttribute('class')).toMatch( + 'dnb-upload__button-section__file-input' + ) + }) + + it('renders the sr only label for the input', () => { + render() + + const element = screen.queryByTestId('upload-file-input-sr-label') + + expect(element).not.toBeNull() + }) + + it('renders the correct id for input and input sr label', () => { + render() + + const srLabelElement = screen.queryByTestId( + 'upload-file-input-sr-label' + ) + const inputElement = screen.queryByTestId('upload-file-input-input') + + expect(srLabelElement.getAttribute('for')).toBe( + inputElement.getAttribute('id') + ) + }) + + it('simulates a click on the input when clicking the button', () => { + render() + + const buttonElement = screen.queryByTestId('upload-file-input-button') + + const inputElement = screen.queryByTestId('upload-file-input-input') + + const clickEventListener = jest.fn() + inputElement.addEventListener('click', clickEventListener) + + fireEvent.click(buttonElement) + + expect(clickEventListener).toHaveBeenCalled() + }) + + it('calls the onUpload function', async () => { + const file = createMockFile('fileName.png', 100, 'image/png') + + const onUpload = jest.fn() + + render() + + const inputElement = screen.queryByTestId('upload-file-input-input') + + await waitFor(() => + fireEvent.change(inputElement, { + target: { files: [file] }, + }) + ) + expect(onUpload).toHaveBeenCalledWith([{ file }]) + }) + + it('can upload multiple files', async () => { + const file1 = createMockFile('fileName1.png', 100, 'image/png') + const file2 = createMockFile('fileName2.png', 100, 'image/png') + + const onUpload = jest.fn() + + render() + + const inputElement = screen.queryByTestId('upload-file-input-input') + + await waitFor(() => + fireEvent.change(inputElement, { + target: { files: [file1, file2] }, + }) + ) + expect(onUpload).toHaveBeenCalledWith([ + { file: file1 }, + { file: file2 }, + ]) + }) + + it('returns the file size error message', async () => { + const file1 = createMockFile('fileName1.png', 100000000, 'image/png') + + const fileMaxSize = 1 + const errorMessage = 'error message %size' + const errorMessageFormatted = `error message ${fileMaxSize}` + + const onUpload = jest.fn() + + render( + + ) + + const inputElement = screen.queryByTestId('upload-file-input-input') + + await waitFor(() => + fireEvent.change(inputElement, { + target: { files: [file1] }, + }) + ) + expect(onUpload).toHaveBeenCalledWith([ + { file: file1, errorMessage: errorMessageFormatted }, + ]) + }) +}) diff --git a/packages/dnb-eufemia/src/components/upload/__tests__/UploadFileListCell.test.tsx b/packages/dnb-eufemia/src/components/upload/__tests__/UploadFileListCell.test.tsx new file mode 100644 index 00000000000..5b2725871bc --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/__tests__/UploadFileListCell.test.tsx @@ -0,0 +1,394 @@ +import UploadFileListCell, { + UploadFileListCellProps, +} from '../UploadFileListCell' +import createMockFile from './testHelpers' +import { render, screen } from '@testing-library/react' +import React from 'react' + +global.URL.createObjectURL = jest.fn(() => 'url') + +const defaultProps: UploadFileListCellProps = { + deleteButtonText: 'delete', + onDelete: jest.fn(), + uploadFile: { file: createMockFile('file.png', 100, 'image/png') }, + uploadLoadingText: 'loading', +} + +describe('UploadFileListCell', () => { + it('renders the component', () => { + render() + + const element = screen.queryByTestId('upload-file-list-cell') + + expect(element).not.toBeNull() + }) + + it('renders the error styling', () => { + render( + + ) + + const element = screen.queryByTestId('upload-file-list-cell') + + expect(element.className).toMatch('dnb-upload__file-cell--error') + expect(element.className).not.toMatch( + 'dnb-upload__file-cell--no-error' + ) + }) + + it('renders the no error styling', () => { + render( + + ) + + const element = screen.queryByTestId('upload-file-list-cell') + + expect(element.className).not.toMatch('dnb-upload__file-cell--error') + expect(element.className).toMatch('dnb-upload__file-cell--no-error') + }) + + it('renders the subtitle', () => { + render( + + ) + + const element = screen.queryByTestId('upload-subtitle') + + expect(element).not.toBeNull() + expect(element.textContent).toMatch('PNG') + }) + + it('renders the form errorMessage warning', () => { + render( + + ) + + const element = screen.queryByTestId('upload-warning') + + expect(element).not.toBeNull() + }) + + it('renders the form errorMessage warning message', () => { + const errorMessage = 'error message' + + render( + + ) + + const element = screen.queryByTestId('upload-warning') + + expect(element.textContent).toMatch(errorMessage) + }) + + describe('Icons', () => { + it('renders the exclamation icon', () => { + render( + + ) + + const iconElement = screen.queryByTestId('upload-exclamation-icon') + + expect(iconElement).not.toBeNull() + expect(iconElement.getAttribute('data-test-id')).toBe( + 'exclamation medium icon' + ) + }) + + it('renders the pdf icon', () => { + render( + + ) + + const iconElement = screen.queryByTestId('upload-pdf-icon') + + expect(iconElement).not.toBeNull() + expect(iconElement.getAttribute('data-test-id')).toBe( + 'file pdf medium icon' + ) + }) + + it('renders the xls icon', () => { + render( + + ) + + const iconElement = screen.queryByTestId('upload-xls-icon') + + expect(iconElement).not.toBeNull() + expect(iconElement.getAttribute('data-test-id')).toBe( + 'file xls medium icon' + ) + }) + + it('renders the ppt icon', () => { + render( + + ) + + const iconElement = screen.queryByTestId('upload-ppt-icon') + + expect(iconElement).not.toBeNull() + expect(iconElement.getAttribute('data-test-id')).toBe( + 'file ppt medium icon' + ) + }) + + it('renders the csv icon', () => { + render( + + ) + + const iconElement = screen.queryByTestId('upload-csv-icon') + + expect(iconElement).not.toBeNull() + expect(iconElement.getAttribute('data-test-id')).toBe( + 'file csv medium icon' + ) + }) + + it('renders the txt icon', () => { + render( + + ) + + const iconElement = screen.queryByTestId('upload-txt-icon') + + expect(iconElement).not.toBeNull() + expect(iconElement.getAttribute('data-test-id')).toBe( + 'file txt medium icon' + ) + }) + + it('renders the xml icon', () => { + render( + + ) + + const iconElement = screen.queryByTestId('upload-xml-icon') + + expect(iconElement).not.toBeNull() + expect(iconElement.getAttribute('data-test-id')).toBe( + 'file xml medium icon' + ) + }) + + it('renders the file icon as default', () => { + render( + + ) + + const iconElement = screen.queryByTestId('upload-file-icon') + + expect(iconElement).not.toBeNull() + expect(iconElement.getAttribute('data-test-id')).toBe( + 'file medium icon' + ) + }) + }) + + describe('File Anchor', () => { + it('renders the anchor', () => { + render() + const anchorElement = screen.queryByTestId('upload-file-anchor') + + expect(anchorElement).not.toBeNull() + }) + + it('renders the anchor text', () => { + const fileName = 'file.png' + + render( + + ) + const anchorElement = screen.queryByTestId('upload-file-anchor') + expect(anchorElement.textContent).toMatch(fileName) + }) + + it('renders the anchor href', () => { + const mockUrl = 'mock-url' + + global.URL.createObjectURL = jest.fn().mockReturnValueOnce(mockUrl) + + render( + + ) + const anchorElement = screen.queryByTestId( + 'upload-file-anchor' + ) as HTMLAnchorElement + expect(anchorElement.href).toMatch(mockUrl) + }) + + it('renders with the error style', () => { + render( + + ) + + const anchorElement = screen.queryByTestId('upload-file-anchor') + + expect(anchorElement.className).toMatch( + 'dnb-upload__file-cell--error' + ) + }) + + it('renders without the error style', () => { + render( + + ) + + const anchorElement = screen.queryByTestId('upload-file-anchor') + + expect(anchorElement.className).not.toMatch( + 'dnb-upload__file-cell--error' + ) + }) + }) + + describe('Delete Button', () => { + it('renders the delete button', () => { + render() + + const element = screen.queryByTestId('upload-delete-button') + + expect(element).not.toBeNull() + }) + + it('renders the delete button text', () => { + const deleteButtonText = 'delete' + + render( + + ) + + const element = screen.queryByTestId('upload-delete-button') + + expect(element.textContent).toMatch(deleteButtonText) + }) + + it('renders button as tertiary', () => { + render() + + const element = screen.queryByTestId('upload-delete-button') + + expect(element.className).toMatch('dnb-button--tertiary') + }) + + it('renders the file cell loading state', () => { + render( + + ) + + const element = screen.queryByTestId('upload-progress-indicator') + + expect(element).not.toBeNull() + }) + + it('does not render the loading state when not loading', () => { + render( + + ) + + const element = screen.queryByTestId('upload-progress-indicator') + + expect(element).toBeNull() + }) + }) +}) diff --git a/packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/Upload.test.tsx.snap b/packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/Upload.test.tsx.snap new file mode 100644 index 00000000000..a1fd661f0b8 --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/Upload.test.tsx.snap @@ -0,0 +1,127 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Upload scss have to match snapshot 1`] = ` +"/* +* DNB Upload +* +*/ +/** + * This file is only used to make components independent + * so that they can get imported individually, without the core styles + * + */ +/* + * Utilities + */ +/* + * Scopes + * + */ +/* + * Document Reset + * + */ +.dnb-upload { + font-family: var(--font-family-default); + font-weight: var(--font-weight-basis); + font-size: var(--font-size-small); + font-style: normal; + line-height: var(--line-height-basis); + color: var(--color-black-80, #333); + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + /** + * Ensure consistency and use the same as HTML reset -> html {...} + * between base and code package + */ + -moz-tab-size: 4; + tab-size: 4; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; + word-break: break-word; + /** + * 1. Remove repeating backgrounds in all browsers (opinionated). + * 2. Add border box sizing in all browsers (opinionated). + */ + /** + * 1. Add text decoration inheritance in all browsers (opinionated). + * 2. Add vertical alignment inheritance in all browsers (opinionated). + */ + margin: 0; + padding: 0; } + .dnb-upload *, + .dnb-upload ::before, + .dnb-upload ::after { + background-repeat: no-repeat; + /* 1 */ + box-sizing: border-box; + /* 2 */ } + .dnb-upload ::before, + .dnb-upload ::after { + text-decoration: inherit; + /* 1 */ + vertical-align: inherit; + /* 2 */ } + +/* +* Upload component +* +*/ +.dnb-upload { + display: flex; + flex-direction: column; + border: 0.09375rem dashed var(--color-sea-green); + border-radius: 0.5rem; + padding: var(--spacing-medium); + background: var(--color-white); } + .dnb-upload__condition-list { + display: grid; + grid-gap: 0.5rem 1rem; + grid-template-columns: minmax(1rem, auto) 1fr; + margin-top: var(--spacing-x-small); } + .dnb-upload__condition-list.dnb-dl > dt, + .dnb-upload__condition-list.dnb-dl > dd { + margin: 0; + font-size: var(--font-size-x-small); } + .dnb-upload__condition-list__label { + font-weight: var(--font-weight-medium); + margin-right: var(--spacing-x-small); } + .dnb-upload__text { + color: var(--color-black-55); + font-size: var(--font-size-x-small); + margin-top: var(--spacing-x-small); + margin-bottom: 0.75rem; } + .dnb-upload__button-section__file-input { + visibility: hidden; } + .dnb-upload__file-list { + margin-top: var(--spacing-medium); } + .dnb-upload__file-cell { + border-top: 0.0625rem solid var(--color-black-8); + border-bottom: 0.0625rem solid var(--color-black-8); + padding: var(--spacing-small) 0; } + .dnb-upload__file-cell__content { + display: flex; + flex-direction: row; + justify-content: space-between; } + .dnb-upload__file-cell__content__left { + display: flex; + flex-direction: row; + align-items: center; } + .dnb-upload__file-cell--no-error { + color: var(--color-sea-green); } + .dnb-upload__file-cell--error { + color: var(--color-fire-red); } + .dnb-upload__file-cell__text-container { + display: flex; + flex-direction: column; + margin-left: var(--spacing-small); } + .dnb-upload__file-cell__text-container--loading { + font-size: var(--font-size-basis); } + .dnb-upload__file-cell__title { + font-size: var(--font-size-basis); } + .dnb-upload__file-cell__subtitle { + font-size: var(--font-size-x-small); + color: var(--color-black-55); } +" +`; diff --git a/packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/upload-screenshot-test-js-avatar-screenshot-have-to-match-the-custom-accepted-formats-1-b90e0.snap.png b/packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/upload-screenshot-test-js-avatar-screenshot-have-to-match-the-custom-accepted-formats-1-b90e0.snap.png new file mode 100644 index 0000000000000000000000000000000000000000..1434468def220cc7c90037e7150a8f67d85ae229 GIT binary patch literal 23438 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 UfMFtFgzoh3u;7TtBn0k>2?=ZKbbI5Yi>JT= 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 literal 0 HcmV?d00001 diff --git a/packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/upload-screenshot-test-js-avatar-screenshot-have-to-match-the-default-1-0bb95.snap.png b/packages/dnb-eufemia/src/components/upload/__tests__/__snapshots__/upload-screenshot-test-js-avatar-screenshot-have-to-match-the-default-1-0bb95.snap.png new file mode 100644 index 0000000000000000000000000000000000000000..8ee014b4ef5025b5cadaa196f7615433f18c0de9 GIT binary patch literal 23037 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%0DU?okU$4iMr<2BtqyJ?mDs7I;hg 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 { + afterEach(() => { + jest.clearAllMocks() + }) + + it('return an empty list', () => { + const validationFunction = jest.fn() + + const MockComponents = () => { + const { files } = useUpload('id') + + validationFunction(files) + + return

+ } + + render() + + expect(validationFunction).toHaveBeenCalledWith([]) + }) + + it('return the updateFiles function', () => { + const validationFunction = jest.fn() + + const MockComponents = () => { + const { setFiles } = useUpload('id') + + validationFunction(setFiles) + + return
+ } + + render() + + expect(validationFunction).toHaveBeenCalledWith(expect.any(Function)) + }) + + it('return the added files', () => { + const validationFunction = jest.fn() + + const mockFile = createMockFile('fileName.png', 100, 'image/png') + + const MockComponents = () => { + const { setFiles, files } = useUpload('id') + + useEffect(() => { + setFiles([{ file: mockFile }]) + }, []) + + validationFunction(files) + return
+ } + + render() + act(() => { + expect(validationFunction).toHaveBeenCalledWith([{ file: mockFile }]) + }) + }) + + it('use the event emitter to store a file', () => { + const mockFile = { + file: createMockFile('fileName.png', 100, 'image/png'), + } + const id = 'unique-id-1' + + const MockComponents = () => { + const { setFiles } = useUpload(id) + + useEffect(() => setFiles([mockFile]), []) + + return
+ } + + render() + + const emitter = EventEmitter.createInstance(id) + const emitterFiles = emitter.get().files + + expect(emitterFiles).toMatchObject([mockFile]) + }) + + it('use the event emitter to return a file', () => { + const mockFile = { + file: createMockFile('fileName.png', 100, 'image/png'), + } + const id = 'unique-id-2' + + const validationFunction = jest.fn() + + const MockComponents = () => { + const { files } = useUpload(id) + + useEffect(() => { + validationFunction(files) + }, []) + + return
+ } + + const emitter = EventEmitter.createInstance(id) + const emitterData = { files: [mockFile] } + emitter.update(emitterData) + + render() + + act(() => { + expect(validationFunction).toHaveBeenCalledWith([mockFile]) + }) + }) +}) diff --git a/packages/dnb-eufemia/src/components/upload/index.d.ts b/packages/dnb-eufemia/src/components/upload/index.d.ts new file mode 100644 index 00000000000..2a3ea8fe10d --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/index.d.ts @@ -0,0 +1,8 @@ +/** + * Component Entry + * + */ + +import Upload from './Upload'; +export default Upload; +export * from './Upload'; diff --git a/packages/dnb-eufemia/src/components/upload/index.js b/packages/dnb-eufemia/src/components/upload/index.js new file mode 100644 index 00000000000..67067079c7c --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/index.js @@ -0,0 +1,8 @@ +/** + * Component Entry + * + */ + +import Upload from './Upload' +export default Upload +export * from './Upload' diff --git a/packages/dnb-eufemia/src/components/upload/stories/Upload.stories.tsx b/packages/dnb-eufemia/src/components/upload/stories/Upload.stories.tsx new file mode 100644 index 00000000000..6b729d70759 --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/stories/Upload.stories.tsx @@ -0,0 +1,78 @@ +/** + * @dnb/eufemia Component Story + * + */ + +import React, { useEffect } from 'react' +import { Wrapper, Box } from 'storybook-utils/helpers' +import { Upload } from '../..' +import { UploadFile } from '../types' + +export default { + title: 'Eufemia/Components/Upload', +} + +export const UploadSandbox = () => { + const { files: files1 } = Upload.useUpload('upload-example-1') + Upload.useUpload('upload-example-6') + + useEffect(() => { + console.log(files1) + }, [files1]) + + return ( + + + + + + + + + + + + + + + + + + Two Upload components can be controlled using the same id + + files.map((_file) => { + return { ..._file, isLoading: true } + }) + } + /> + + + + ) +} diff --git a/packages/dnb-eufemia/src/components/upload/style.js b/packages/dnb-eufemia/src/components/upload/style.js new file mode 100644 index 00000000000..a767e2f50a8 --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/style.js @@ -0,0 +1,6 @@ +/** + * Web Style Import + * + */ + +import './style/dnb-upload.scss' diff --git a/packages/dnb-eufemia/src/components/upload/style/_upload.scss b/packages/dnb-eufemia/src/components/upload/style/_upload.scss new file mode 100644 index 00000000000..180b74dfcd1 --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/style/_upload.scss @@ -0,0 +1,95 @@ +/* +* Upload component +* +*/ + +.dnb-upload { + display: flex; + flex-direction: column; + border: 0.09375rem dashed var(--color-sea-green); + border-radius: 0.5rem; + padding: var(--spacing-medium); + + background: var(--color-white); + + &__condition-list { + display: grid; + grid-gap: 0.5rem 1rem; + grid-template-columns: minmax(1rem, auto) 1fr; + + margin-top: var(--spacing-x-small); + + &.dnb-dl > dt, + &.dnb-dl > dd { + margin: 0; + font-size: var(--font-size-x-small); + } + + &__label { + font-weight: var(--font-weight-medium); + margin-right: var(--spacing-x-small); + } + } + + &__text { + color: var(--color-black-55); + font-size: var(--font-size-x-small); + margin-top: var(--spacing-x-small); + margin-bottom: 0.75rem; + } + + &__button-section { + &__file-input { + visibility: hidden; + } + } + + &__file-list { + margin-top: var(--spacing-medium); + } + + &__file-cell { + border-top: 0.0625rem solid var(--color-black-8); + border-bottom: 0.0625rem solid var(--color-black-8); + padding: var(--spacing-small) 0; + + &__content { + display: flex; + flex-direction: row; + + justify-content: space-between; + + &__left { + display: flex; + flex-direction: row; + align-items: center; + } + } + + &--no-error { + color: var(--color-sea-green); + } + + &--error { + color: var(--color-fire-red); + } + + &__text-container { + display: flex; + flex-direction: column; + margin-left: var(--spacing-small); + &--loading { + font-size: var(--font-size-basis); + } + } + + &__title { + font-size: var(--font-size-basis); + } + + &__subtitle { + font-size: var(--font-size-x-small); + color: var(--color-black-55); + } + } +} diff --git a/packages/dnb-eufemia/src/components/upload/style/dnb-upload.scss b/packages/dnb-eufemia/src/components/upload/style/dnb-upload.scss new file mode 100644 index 00000000000..35fbe10272d --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/style/dnb-upload.scss @@ -0,0 +1,12 @@ +/* +* DNB Upload +* +*/ + +@import '../../../style/components/imports.scss'; + +.dnb-upload { + @include componentReset(); +} + +@import './_upload.scss'; diff --git a/packages/dnb-eufemia/src/components/upload/style/index.d.ts b/packages/dnb-eufemia/src/components/upload/style/index.d.ts new file mode 100644 index 00000000000..3fc8cc313a2 --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/style/index.d.ts @@ -0,0 +1,6 @@ +/** + * Web Style Import + * + */ + +import './dnb-upload.scss'; diff --git a/packages/dnb-eufemia/src/components/upload/style/index.js b/packages/dnb-eufemia/src/components/upload/style/index.js new file mode 100644 index 00000000000..4ef8acea2ce --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/style/index.js @@ -0,0 +1,6 @@ +/** + * Web Style Import + * + */ + +import './dnb-upload.scss' diff --git a/packages/dnb-eufemia/src/components/upload/types.ts b/packages/dnb-eufemia/src/components/upload/types.ts new file mode 100644 index 00000000000..76bbe770aba --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/types.ts @@ -0,0 +1,55 @@ +import React from 'react' +import { SkeletonShow } from '../skeleton/Skeleton' + +export interface UploadProps { + /** + * unique id used with the useUpload hook to manage the files + */ + id: string + + /** + * list of accepted file types. + */ + acceptedFileTypes: string[] + + /** + * Custom className on the component root + * Default: null + */ + className?: string + + /** + * Skeleton should be applied when loading content + * Default: null + */ + skeleton?: SkeletonShow + + /** + * If set true, accepting multiple files is allowed + */ + multipleFiles?: boolean + + /** + * fileMaxSize is max size of each file in MB + */ + fileMaxSize?: number + + /** + * Custom text properties + */ + title?: React.ReactNode + text?: React.ReactNode + formatsDescription?: React.ReactNode + fileSizeDescription?: React.ReactNode + fileSizeContent?: React.ReactNode + uploadButtonText?: React.ReactNode + uploadErrorLargeFile?: React.ReactNode + uploadLoadingText?: React.ReactNode + deleteButton?: React.ReactNode +} + +export interface UploadFile { + file: File + errorMessage?: string | React.ReactNode + isLoading?: boolean +} diff --git a/packages/dnb-eufemia/src/components/upload/useUpload.ts b/packages/dnb-eufemia/src/components/upload/useUpload.ts new file mode 100644 index 00000000000..7b9ad643cf2 --- /dev/null +++ b/packages/dnb-eufemia/src/components/upload/useUpload.ts @@ -0,0 +1,25 @@ +import { useEventEmitter } from '../../../src/shared/component-helper' +import type { UploadFile } from './types' + +/** + * Use together with Upload with the same id to manage the files from outside the component. + * @param id string, must match the id of the Upload component + * @returns { files: UploadFile[], setFiles: (file: UploadFile[]) => void } + */ +function useUpload(id: string): { + files: UploadFile[] + setFiles: (files: UploadFile[]) => void +} { + const { data, update } = useEventEmitter(id) + + function setFiles(files: UploadFile[]) { + update({ files }) + } + + return { + files: data?.files || [], + setFiles, + } +} + +export default useUpload diff --git a/packages/dnb-eufemia/src/index.js b/packages/dnb-eufemia/src/index.js index a9c8a5eddcd..6c912c8414c 100644 --- a/packages/dnb-eufemia/src/index.js +++ b/packages/dnb-eufemia/src/index.js @@ -82,6 +82,7 @@ import Textarea from './components/textarea/Textarea' import Timeline from './components/timeline/Timeline' import ToggleButton from './components/toggle-button/ToggleButton' import Tooltip from './components/tooltip/Tooltip' +import Upload from './components/upload/Upload' import VisuallyHidden from './components/visually-hidden/VisuallyHidden' // define / export all the available components @@ -158,6 +159,7 @@ export { Timeline, ToggleButton, Tooltip, + Upload, VisuallyHidden, } diff --git a/packages/dnb-eufemia/src/shared/Context.tsx b/packages/dnb-eufemia/src/shared/Context.tsx index f549ed4c13f..99ff855be68 100644 --- a/packages/dnb-eufemia/src/shared/Context.tsx +++ b/packages/dnb-eufemia/src/shared/Context.tsx @@ -26,6 +26,7 @@ import type { DrawerProps } from '../components/drawer/types' import type { DialogProps } from '../components/dialog/types' import type { TooltipProps } from '../components/tooltip/types' import type { SectionProps } from '../components/section/Section' +import { UploadProps } from '../components/upload/types' // All TypeScript based Eufemia elements import type { AnchorProps } from '../elements/Anchor' @@ -53,6 +54,7 @@ export type ContextProps = { Tooltip?: Partial Section?: Partial ScrollView?: Partial + Upload?: Partial // -- TODO: Not converted yet -- diff --git a/packages/dnb-eufemia/src/shared/locales/en-GB.js b/packages/dnb-eufemia/src/shared/locales/en-GB.js index 05fad95612b..2d5a11839fc 100644 --- a/packages/dnb-eufemia/src/shared/locales/en-GB.js +++ b/packages/dnb-eufemia/src/shared/locales/en-GB.js @@ -119,5 +119,17 @@ export default { Logo: { alt: 'DNB Logo', }, + Upload: { + title: 'Upload documents', + text: 'Drag & drop your files or choose files to upload. Files are converted to PDF after upload.', + formatsDescription: 'Allowed formats:', + fileSizeDescription: 'Max. filesize:', + fileSizeContent: '%size MB', + uploadButtonText: 'Browse files', + uploadLoadingText: 'Uploading', + uploadErrorLargeFile: + 'The file you are trying to upload is too big, the maximum size supported is %size MB. Please try again.', + deleteButton: 'Delete', + }, }, } diff --git a/packages/dnb-eufemia/src/shared/locales/nb-NO.js b/packages/dnb-eufemia/src/shared/locales/nb-NO.js index 3ea88e12e20..01086a115e1 100644 --- a/packages/dnb-eufemia/src/shared/locales/nb-NO.js +++ b/packages/dnb-eufemia/src/shared/locales/nb-NO.js @@ -119,5 +119,17 @@ export default { Logo: { alt: 'DNB Logo', }, + Upload: { + title: 'Last opp dokumenter', + text: 'Dra & slipp eller velg hvilke filer du vil laste opp. Filene konverteres til PDF etter opplasting', + formatsDescription: 'Tilatte formater:', + fileSizeDescription: 'Maks filstørrelse:', + fileSizeContent: '%size MB', + uploadButtonText: 'Utforsk filer', + uploadLoadingText: 'Laster opp', + uploadErrorLargeFile: + 'Filen du prøver å laste opp er for stor, vi støtter ikke filer større enn %size MB. Vennligst prøv igjen.', + deleteButton: 'Slett', + }, }, } diff --git a/packages/dnb-eufemia/src/style/dnb-ui-components.scss b/packages/dnb-eufemia/src/style/dnb-ui-components.scss index 6ca4f51e95d..faf8f352a94 100644 --- a/packages/dnb-eufemia/src/style/dnb-ui-components.scss +++ b/packages/dnb-eufemia/src/style/dnb-ui-components.scss @@ -49,4 +49,5 @@ @import '../components/timeline/style/_timeline.scss'; @import '../components/toggle-button/style/_toggle-button.scss'; @import '../components/tooltip/style/_tooltip.scss'; +@import '../components/upload/style/_upload.scss'; @import '../components/visually-hidden/style/_visually-hidden.scss';