From 70df7c843c05dba9c34f04ea0e09501b9a17a545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=B8egh?= Date: Fri, 13 Dec 2024 16:40:57 +0100 Subject: [PATCH] fix(Upload): display files without anchor when their size is not given (#4390) --- .../forms/Value/Upload/Examples.tsx | 26 +++++++++ .../extensions/forms/Value/Upload/demos.mdx | 6 +++ .../components/upload/UploadFileListCell.tsx | 2 +- .../components/upload/UploadFileListLink.tsx | 13 +++-- .../__tests__/UploadFileListCell.test.tsx | 51 +++++++++++++++++- .../extensions/forms/Value/Upload/Upload.tsx | 2 +- .../__tests__/Upload.screenshot.test.ts | 8 +++ .../Value/Upload/__tests__/Upload.test.tsx | 23 +++++++- ...e-to-match-files-as-non-clickable.snap.png | Bin 0 -> 6347 bytes 9 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-match-files-as-non-clickable.snap.png diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/Examples.tsx index 529e0f109dc..65b06f8f08c 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/Examples.tsx @@ -524,3 +524,29 @@ export const OnFileClick = () => { ) } + +export const DisplayFileAsNonClickable = () => { + return ( + + + + ) +} diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/demos.mdx index 023e79d3970..50d7455139c 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/demos.mdx @@ -54,6 +54,12 @@ import * as Examples from './Examples' +### Display files as non-clickable + +When file size is 0 or not given (`new File([], name, { type })`), the file is displayed as a span instead of an anchor. How ever, when `onFileClick` is given, the file will be clickable as a button. + + + diff --git a/packages/dnb-eufemia/src/components/upload/UploadFileListCell.tsx b/packages/dnb-eufemia/src/components/upload/UploadFileListCell.tsx index 6f0b787eea9..a2583b1fd40 100644 --- a/packages/dnb-eufemia/src/components/upload/UploadFileListCell.tsx +++ b/packages/dnb-eufemia/src/components/upload/UploadFileListCell.tsx @@ -91,7 +91,7 @@ const UploadFileListCell = ({ const { file, errorMessage, isLoading } = uploadFile const hasWarning = errorMessage != null - const imageUrl = URL.createObjectURL(file) + const imageUrl = file?.size > 0 ? URL.createObjectURL(file) : null const cellRef = useRef() const exists = useExistsHighlight(id, file) diff --git a/packages/dnb-eufemia/src/components/upload/UploadFileListLink.tsx b/packages/dnb-eufemia/src/components/upload/UploadFileListLink.tsx index 015ed24284a..6f95d5083ee 100644 --- a/packages/dnb-eufemia/src/components/upload/UploadFileListLink.tsx +++ b/packages/dnb-eufemia/src/components/upload/UploadFileListLink.tsx @@ -1,18 +1,25 @@ import React from 'react' - +import classNames from 'classnames' import Anchor from '../../components/Anchor' import Button from '../button/Button' +import Span from '../../elements/Span' import { SpacingProps } from '../space/types' import { createSpacingClasses } from '../space/SpacingUtils' -import classNames from 'classnames' export type UploadFileLinkProps = UploadFileAnchorProps & UploadFileButtonProps export const UploadFileLink = (props: UploadFileLinkProps) => { const { onClick, text, href, download, ...rest } = props - if (onClick) + + if (!onClick && !href) { + return {text} + } + + if (onClick) { return + } + return ( { }) }) + it('renders a span when file size is 0', () => { + const fileName = 'file.png' + + render( + + ) + expect(screen.queryByText(fileName).tagName).toBe('SPAN') + expect(screen.queryByText(fileName)).toHaveClass('dnb-span') + }) + + it('renders a span when file size is not given', () => { + const fileName = 'file.png' + + render( + + ) + expect(screen.queryByText(fileName).tagName).toBe('SPAN') + expect(screen.queryByText(fileName)).toHaveClass('dnb-span') + }) + + it('renders a button when file size is invalid, but onClick is given', () => { + const fileName = 'file.png' + + render( + + ) + + expect(screen.queryByText(fileName).parentElement.tagName).toBe( + 'BUTTON' + ) + }) + describe('File Anchor', () => { it('renders the anchor', () => { const fileName = 'file.png' @@ -216,13 +262,14 @@ describe('UploadFileListCell', () => { uploadFile={{ file: createMockFile(fileName, 100, 'image/png') }} /> ) - expect(screen.queryByText(fileName)).toBeInTheDocument() + expect(screen.queryByText(fileName).tagName).toBe('A') }) it('renders the anchor href', () => { const fileName = 'file.png' const mockUrl = 'mock-url' + const originalCreateObjectURL = global.URL.createObjectURL global.URL.createObjectURL = jest.fn().mockReturnValueOnce(mockUrl) render( @@ -237,6 +284,8 @@ describe('UploadFileListCell', () => { fileName ) as HTMLAnchorElement expect(anchorElement.href).toMatch(mockUrl) + + global.URL.createObjectURL = originalCreateObjectURL }) it('renders the download attribute', () => { diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/Upload.tsx b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/Upload.tsx index b6230b80d05..d12447ce4a5 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/Upload.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/Upload.tsx @@ -125,7 +125,7 @@ function UploadFileItem( } } - const imageUrl = URL.createObjectURL(file) + const imageUrl = file?.size > 0 ? URL.createObjectURL(file) : null const text = file.name + (displaySize ? ' ' + getSize(file.size) : '') const isLoading = fileIsLoading || loading diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.screenshot.test.ts b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.screenshot.test.ts index 62a07ad84c5..24a01119b78 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.screenshot.test.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.screenshot.test.ts @@ -57,4 +57,12 @@ describe('Value.Upload', () => { }) expect(screenshot).toMatchImageSnapshot() }) + + it('have to match files as non-clickable', async () => { + const screenshot = await makeScreenshot({ + selector: + '[data-visual-test="upload-value-display-file-as-non-clickable"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) }) diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.test.tsx index 00979aa7b22..b727da994fb 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.test.tsx @@ -322,6 +322,24 @@ describe('Value.Upload', () => { }) }) + it('renders a span when file size is 0', () => { + const fileName = 'file.png' + + render( + + ) + expect(screen.queryByText(fileName).tagName).toBe('SPAN') + expect(screen.queryByText(fileName)).toHaveClass('dnb-span') + }) + describe('File Anchor', () => { it('renders the anchor', () => { const fileName = 'file.png' @@ -337,7 +355,7 @@ describe('Value.Upload', () => { ]} /> ) - expect(screen.queryByText(fileName)).toBeInTheDocument() + expect(screen.queryByText(fileName).tagName).toBe('A') }) it('executes onFileClick event when button is clicked', () => { @@ -415,6 +433,7 @@ describe('Value.Upload', () => { const fileName = 'file.png' const mockUrl = 'mock-url' + const originalCreateObjectURL = global.URL.createObjectURL global.URL.createObjectURL = jest.fn().mockReturnValueOnce(mockUrl) render( @@ -432,6 +451,8 @@ describe('Value.Upload', () => { fileName ) as HTMLAnchorElement expect(anchorElement.href).toMatch(mockUrl) + + global.URL.createObjectURL = originalCreateObjectURL }) it('renders the download attribute', () => { diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-match-files-as-non-clickable.snap.png b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-match-files-as-non-clickable.snap.png new file mode 100644 index 0000000000000000000000000000000000000000..8adad6e159f793749c94e7664b6dd762828fef3b GIT binary patch literal 6347 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