Skip to content

Commit

Permalink
feat(forms): add Upload field (#3742)
Browse files Browse the repository at this point in the history
  • Loading branch information
tujoworker authored Jul 23, 2024
2 parents 6852368 + 048bfc7 commit 4ea8933
Show file tree
Hide file tree
Showing 46 changed files with 1,558 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ You can also use the file blob in combination with the [FileReader](https://deve

### 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.
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.

<UploadIsLoading />

### 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.
The only file verification the Upload component does 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` hook the same way as with the loading state.

<UploadErrorMessage />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
showTabs: true
---

import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable'
import { UploadEvents } from '@dnb/eufemia/src/components/upload/UploadDocs'

## Events

| Events | Description |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `onChange` | _(optional)_ will be called on `files` changes made by the user. Access the files with `{ files }` (containing each a `fileItem`). |
| `onFileDelete` | _(optional)_ will be called once a file gets deleted by the user. Access the deleted file with `{ fileItem }`. |
<PropertiesTable props={UploadEvents} />

Each `fileItem` will contain a `{ file, id }` (File Object and an unique ID) along with other information.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The Upload component should be used in scenarios where the user has to upload an

- Files selected by the user should be uploaded immediately (temporary location).
- The user should be able to remove them (files) during the session.
- If the Upload component is shown in a submit form, then a [GlobalStatus](/uilib/components/global-status) should be a part of the form.
- The Upload component connects to the [GlobalStatus](/uilib/components/global-status) and displays file error messages there as well.
- Validation messages coming from the "backend" should be displayed for each file via the `useUpload` hook. See [example](/uilib/components/upload/#upload-error-message) below.
- The `useUpload` hook can be placed on any location in your application, and does not need to be where the `Upload` component is used.

Expand All @@ -33,6 +33,10 @@ function YourComponent() {
}
```

## JPG vs JPEG

When `jpg` is defined (most commonly used), then the component will also accept `jpeg` files.

## Backend integration

The "backend" receiving the files is decoupled and can be any existing or new system.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,16 @@
showTabs: true
---

import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable'
import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable'
import { UploadProperties } from '@dnb/eufemia/src/components/upload/UploadDocs'

## Properties

| Properties | Description |
| --------------------------------------- | ----------------------------------------------------------------------------------------- |
| `acceptedFileTypes` | _(required)_ List of accepted file types. More details above. |
| `filesAmountLimit` | _(optional)_ Defines the amount of files the user can select and upload. Defaults to 100. |
| `fileMaxSize` | _(optional)_ `fileMaxSize` is max size of each file in MB. Defaults to 5 MB. |
| `title` | _(optional)_ Custom text property. Replaces the default title. |
| `text` | _(optional)_ Custom text property. Replaces the default text. |
| `fileTypeDescription` | _(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. |
| `buttonText` | _(optional)_ Custom text property. Replaces the default upload button text. |
| `loadingText` | _(optional)_ Custom text property. Replaces the default loading text. |
| `errorLargeFile` | _(optional)_ Custom text property. Replaces the default file size error message. |
| `errorUnsupportedFile` | _(optional)_ Custom text property. Replaces the default file type error message. |
| `errorAmountLimit` | _(optional)_ Custom text property. Replaces the default amount limit error message. |
| `deleteButton` | _(optional)_ Custom text property. Replaces the default delete button text. |
| `fileListAriaLabel` | _(optional)_ Custom text property. Replaces the default list aria label. |
| `skeleton` | _(optional)_ Skeleton should be applied when loading content Default: `null`. |
| [Space](/uilib/layout/space/properties) | _(optional)_ Spacing properties like `top` or `bottom` are supported. |
<PropertiesTable props={UploadProperties} />

## Translations

## JPG vs JPEG
All translation keys listed in the translations table below, can be used as a component property (like `title` or `text`).

When `jpg` is defined (most commonly used), then the component will also accept `jpeg` files.
<TranslationsTable localeKey="Upload" />
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ breadcrumb:

Change log for the Eufemia Forms extension.

## v10.41

- Added [Field.Upload](/uilib/extensions/forms/Field/Upload/) component.

## v10.38

- Added support for nesting fields inside of [Form.Section](/uilib/extensions/forms/Form/Section/) and [Form.ArraySelection](/uilib/extensions/forms/Form/ArraySelection/).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Field } from '@dnb/eufemia/extensions/forms'
render(<Field.Slider />)
```

## Multithub support
## Multithumb support

You can use the `paths` property to define an array with JSON Pointers for multiple thumb buttons.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: 'Upload'
description: '`Field.Upload` is a wrapper for the Upload component to make it easier to use inside a form.'
showTabs: true
theme: 'sbanken'
hideInMenu: true
tabs:
- title: Info
key: '/info'
- title: Demos
key: '/demos'
- title: Properties
key: '/properties'
- title: Events
key: '/events'
breadcrumb:
- text: Forms
href: /uilib/extensions/forms/
- text: Feature fields
href: /uilib/extensions/forms/feature-fields/
- text: Upload
href: /uilib/extensions/forms/feature-fields/Upload/
---

import Info from 'Docs/uilib/extensions/forms/feature-fields/Upload/info'
import Demos from 'Docs/uilib/extensions/forms/feature-fields/Upload/demos'

<Info />
<Demos />
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Flex } from '@dnb/eufemia/src'
import ComponentBox from '../../../../../../shared/tags/ComponentBox'
import { Field, Form } from '@dnb/eufemia/src/extensions/forms'

export const BasicUsage = () => {
return (
<ComponentBox>
<Form.Handler>
<Field.Upload
label="My custom label"
labelDescription="My description"
/>
</Form.Handler>
</ComponentBox>
)
}

export const Required = () => {
return (
<ComponentBox>
<Form.Handler onSubmit={(data) => console.log('onSubmit', data)}>
<Flex.Stack>
<Field.Upload path="/myFiles" required />
<Form.SubmitButton />
</Flex.Stack>
</Form.Handler>
</ComponentBox>
)
}

export const WithHelp = () => {
return (
<ComponentBox>
<Field.Upload
help={{
title: 'Help title',
content: 'Help content',
}}
/>
</ComponentBox>
)
}

export const Customized = () => {
return (
<ComponentBox data-visual-test="upload-field-customized">
<Field.Upload
title="My custom title"
text="My text with a help button"
width="large"
help={{
title: 'Help title',
content: 'Help content',
}}
warning="Warning message"
acceptedFileTypes={['pdf']}
filesAmountLimit={1}
fileMaxSize={1}
/>
</ComponentBox>
)
}

export const WithPath = () => {
const createMockFile = (name: string, size: number, type: string) => {
const file = new File([], name, { type })
Object.defineProperty(file, 'size', {
get() {
return size
},
})
return file
}

return (
<ComponentBox scope={{ createMockFile }}>
<Form.Handler
onChange={(data) => console.log('onChange', data)}
data={{
myFiles: [
{ file: createMockFile('fileName-1.png', 100, 'image/png') },
],
}}
>
<Field.Upload path="/myFiles" />
</Form.Handler>
</ComponentBox>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
showTabs: true
---

import * as Examples from './Examples'

## Demos

### Basic usage

<Examples.BasicUsage />

### Required

<Examples.Required />

### Path usage

<Examples.WithPath />

### With help

<Examples.WithHelp />

### Customized

<Examples.Customized />
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
showTabs: true
---

import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable'
import { UploadFieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/Upload/UploadDocs'

## Events

<PropertiesTable props={UploadFieldEvents} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
showTabs: true
---

## Description

`Field.Upload` is a wrapper for the [Upload](/uilib/components/upload/) component to make it easier to use inside a form.

```jsx
import { Field } from '@dnb/eufemia/extensions/forms'
render(<Field.Upload />)
```

## The data and file format

The returned data is an array of objects containing a file object and a unique ID. The file object contains the file itself and some additional properties like an unique ID.

```tsx
{
id: '1234',
file: {
name: 'file1.jpg',
size: 1234,
type: 'image/jpeg',
},
errorMessage: 'error message ...',
}
```

This data format will be returned by the `onChange` and the `onSubmit` event handlers.

## Validation

The `required` prop will validate if there are valid files present. If there are files with an error, the validation will fail.

If there are invalid files, the `onSubmit` event will not be called and a validation error will be shown.

The `onChange` event handler will return an array with objects containing the file object and some additional properties – regardless of the validity of the file.

## About the `value` and `path` prop

The `path` prop represents an array with an object described above:

```tsx
render(
<Form.Handler defaultData={{ myFiles: files }}>
<Field.Upload path="/myFiles" />
</Form.Handler>,
)
```

The `value` prop represents an array with an object described above:

```tsx
render(<Field.Upload value={files} />)
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
showTabs: true
---

import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable'
import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable'
import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs'
import { UploadFieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/Upload/UploadDocs'

## Properties

### Field-specific props

<PropertiesTable props={UploadFieldProperties} />

### General props

<PropertiesTable
props={fieldProperties}
valueType={['Array<{ file, id }>']}
omit={['layout', 'onBlurValidator', 'contentWidth']}
/>

## Translations

<TranslationsTable localeKey={['Upload']} />
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ export default function PropertiesTable({
omit?: string[]
showDefaultValue: boolean
}) {
const keys = Object.keys(props)
const tableRows = Object.entries(props).map(([key, props]) => {
const keys = Object.keys(props || {})
const tableRows = Object.entries(props || {}).map(([key, props]) => {
if (!props) {
return null
}
Expand Down
1 change: 1 addition & 0 deletions packages/dnb-eufemia/src/components/upload/Upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type { UploadFile, UploadAllProps } from './types'
import UploadFileList from './UploadFileList'
import UploadInfo from './UploadInfo'

export type * from './types'
export { defaultProps }

const Upload = (localProps: UploadAllProps) => {
Expand Down
Loading

0 comments on commit 4ea8933

Please sign in to comment.