Skip to content

Commit

Permalink
Formatting utils and styled files
Browse files Browse the repository at this point in the history
  • Loading branch information
dlnr committed Nov 11, 2024
1 parent e58b54a commit 3706713
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 89 deletions.
33 changes: 32 additions & 1 deletion packages/css/src/components/file-list/file-list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,36 @@
*/

.ams-file-list {
/* Add styles here */
display: flex;
flex-direction: column;
gap: var(--ams-file-list-gap);
padding-block: var(--ams-file-list-padding-block);
}

.ams-file-list__file {
display: flex;
flex-direction: row;
font-family: var(--ams-file-list-file-font-family);
font-size: var(--ams-file-list-file-font-size);
font-weight: var(--ams-file-list-file-font-weight);
gap: var(--ams-file-list-file-gap);
line-height: var(--ams-file-list-file-line-height);
}

.ams-file-list__file-preview {
display: grid;
flex: 0 0 50px;
place-items: center;
}

.ams-file-list__file-name {
flex: 1;
gap: var(--ams-file-list-file-gap);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.ams-file-input__file-details {
color: var(--ams-file-list-file-details-color);
}
28 changes: 23 additions & 5 deletions packages/react/src/FileList/FileList.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { render } from '@testing-library/react'
import { fireEvent, render, screen } from '@testing-library/react'
import { createRef } from 'react'
import { FileList } from './FileList'
import '@testing-library/jest-dom'

const files = [
new File(['sample1'], 'sample1.txt', { type: 'text/plain', lastModified: Date.now() }),
] as unknown as FileList // This is a workaround because jest-dom does not support DataTransfer

describe('FileList', () => {
it('renders', () => {
const { container } = render(<FileList />)
const { container } = render(<FileList files={files} />)

const component = container.querySelector(':only-child')

Expand All @@ -14,15 +18,15 @@ describe('FileList', () => {
})

it('renders a design system BEM class name', () => {
const { container } = render(<FileList />)
const { container } = render(<FileList files={files} />)

const component = container.querySelector(':only-child')

expect(component).toHaveClass('ams-file-list')
})

it('renders an additional class name', () => {
const { container } = render(<FileList className="extra" />)
const { container } = render(<FileList files={files} className="extra" />)

const component = container.querySelector(':only-child')

Expand All @@ -32,10 +36,24 @@ describe('FileList', () => {
it('supports ForwardRef in React', () => {
const ref = createRef<HTMLDivElement>()

const { container } = render(<FileList ref={ref} />)
const { container } = render(<FileList files={files} ref={ref} />)

const component = container.querySelector(':only-child')

expect(ref.current).toBe(component)
})

it('removes a file from the list', () => {
const { container } = render(<FileList files={files} />)

const button = screen.getByRole('button', {
name: 'Verwijder',
})

fireEvent.click(button)

const component = container.querySelector('.ams-file-list__file')

expect(component).not.toBeInTheDocument()
})
})
59 changes: 46 additions & 13 deletions packages/react/src/FileList/FileList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,54 @@
* Copyright Gemeente Amsterdam
*/

import { DocumentIcon } from '@amsterdam/design-system-react-icons'
import clsx from 'clsx'
import { forwardRef } from 'react'
import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react'
import { FileListFile } from './FileListFile'
import { forwardRef, useState } from 'react'
import type { ForwardedRef, HTMLAttributes } from 'react'
import { Button } from '../Button'
import { Icon } from '../Icon'
import { formatFileSize, formatFileType } from '../common'

export type FileListProps = PropsWithChildren<HTMLAttributes<HTMLDivElement>>
export type FileListProps = {
files: FileList
removeable?: boolean
} & HTMLAttributes<HTMLDivElement>

export const FileListRoot = forwardRef(
({ children, className, ...restProps }: FileListProps, ref: ForwardedRef<HTMLDivElement>) => (
<div {...restProps} ref={ref} className={clsx('ams-file-list', className)}>
{children}
</div>
),
)
export const FileList = forwardRef(
({ files, removeable = true, className, ...restProps }: FileListProps, ref: ForwardedRef<HTMLDivElement>) => {
const [fileList, setFileList] = useState(Array.from(files))

const removeFile = (index: number) => {
setFileList((prevFiles) => prevFiles.filter((_, i) => i !== index))
}

FileListRoot.displayName = 'FileList'
return (
<div {...restProps} ref={ref} className={clsx('ams-file-list', className)}>
{fileList.map((file, index) => (
<div key={index} className="ams-file-list__file">
<div className="ams-file-list__file-preview">
{file.type.includes('image') ? (
<img src={URL.createObjectURL(file)} alt={file.name} width={50} height="auto" />
) : (
<Icon svg={DocumentIcon} size="level-3" square />
)}
</div>
<div className="ams-file-list__file-name">
{file.name}
<div className="ams-file-input__file-details">
({formatFileType(file.type)}, {formatFileSize(file.size)})
</div>
</div>
{removeable && (
<Button variant="tertiary" onClick={() => removeFile(index)}>
Verwijder
</Button>
)}
</div>
))}
</div>
)
},
)

export const FileList = Object.assign(FileListRoot, { File: FileListFile })
FileList.displayName = 'FileList'
41 changes: 0 additions & 41 deletions packages/react/src/FileList/FileListFile.test.tsx

This file was deleted.

26 changes: 0 additions & 26 deletions packages/react/src/FileList/FileListFile.tsx

This file was deleted.

20 changes: 20 additions & 0 deletions packages/react/src/common/formatFileSize.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/

/**
*
* @param fileType
* @returns Human readable file size
*/
export const formatFileSize = (fileSize: number, precision = 3) => {
const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']

if (fileSize === 0) return '0 B'

const exponent = Math.floor(Math.log10(fileSize) / 3)
const size = (fileSize / Math.pow(1000, exponent)).toPrecision(precision)

return `${size}${UNITS[exponent]}`
}
38 changes: 38 additions & 0 deletions packages/react/src/common/formatFileType.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/

/**
*
* @param fileType
* @returns Human readable file type
*/
export const formatFileType = (fileType: string) => {
switch (fileType) {
case 'image/gif':
return 'gif'
case 'image/jpeg':
return 'jpg'
case 'image/png':
return 'png'
case 'text/plain':
return 'txt'
case 'application/pdf':
return 'pdf'
case 'application/msword':
return 'Word'
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
return 'Word'
case 'application/vnd.ms-excel':
return 'Excel'
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
return 'Excel'
case 'application/vnd.ms-powerpoint':
return 'PowerPoint'
case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
return 'PowerPoint'
default:
return fileType
}
}
8 changes: 8 additions & 0 deletions packages/react/src/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/

export * from './formatFileType'
export * from './formatFileSize'
export * from './useKeyboardFocus'
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

/* Append here */
export * from './common'
export * from './FileList'
export * from './ActionGroup'
export * from './Breakout'
Expand Down
15 changes: 14 additions & 1 deletion proprietary/tokens/src/components/ams/file-list.tokens.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
{
"ams": {
"file-list": {}
"file-list": {
"gap": { "value": "{ams.space.md}" },
"padding-block": { "value": "{ams.space.md}" },
"file": {
"font-family": { "value": "{ams.text.font-family}" },
"font-size": { "value": "{ams.text.level.6.font-size}" },
"font-weight": { "value": "{ams.text.font-weight.normal}" },
"gap": { "value": "{ams.space.sm}" },
"line-height": { "value": "{ams.text.level.6.line-height}" },
"details": {
"color": { "value": "{ams.color.neutral-grey3}" }
}
}
}
}
}
16 changes: 14 additions & 2 deletions storybook/src/components/FileList/FileList.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,23 @@
import { FileList } from '@amsterdam/design-system-react/src'
import { Meta, StoryObj } from '@storybook/react'

const sampleDataTransfer = new DataTransfer()
sampleDataTransfer.items.add(new File(['sample1'], 'sample1.txt', { type: 'text/plain', lastModified: Date.now() }))
sampleDataTransfer.items.add(new File(['sample2'], 'sample2.txt', { type: 'text/plain', lastModified: Date.now() }))
const sampleFiles = sampleDataTransfer.files

const meta = {
title: 'FileList',
title: 'Components/Forms/File List',
component: FileList,
args: {
children: 'Nieuw component',
files: sampleFiles,
},
argTypes: {
files: {
table: {
disable: true,
},
},
},
} satisfies Meta<typeof FileList>

Expand Down

0 comments on commit 3706713

Please sign in to comment.