Skip to content

Commit

Permalink
feat(Forms): add variant to Iterate.Toolbar for hiding the buttons wh…
Browse files Browse the repository at this point in the history
…en there is only one item in the array
  • Loading branch information
tujoworker committed Sep 12, 2024
1 parent 52326bf commit dd48787
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -378,41 +378,19 @@ export const InitialOpen = () => {

<Card align="stretch">
<Iterate.Array path="/countries" defaultValue={[null]}>
<Iterate.ViewContainer>
<Iterate.ViewContainer toolbarVariant="minimumOneItem">
<Value.SelectCountry
label="Land du er statsborger i"
itemPath="/"
/>
<Iterate.Toolbar>
{({ items }) =>
items.length === 1 ? (
<Iterate.ViewContainer.EditButton />
) : (
<>
<Iterate.ViewContainer.EditButton />
<Iterate.ViewContainer.RemoveButton />
</>
)
}
</Iterate.Toolbar>
</Iterate.ViewContainer>

<Iterate.EditContainer>
<Iterate.EditContainer toolbarVariant="minimumOneItem">
<Field.SelectCountry
label="Land du er statsborger i"
itemPath="/"
required
/>
<Iterate.Toolbar>
{({ items }) =>
items.length === 1 ? null : (
<>
<Iterate.EditContainer.DoneButton />
<Iterate.EditContainer.CancelButton />
</>
)
}
</Iterate.Toolbar>
</Iterate.EditContainer>
</Iterate.Array>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ With an optional `title` and [Iterate.Toolbar](/uilib/extensions/forms/Iterate/T

### Initially open

This example uses a customized [Iterate.Toolbar](/uilib/extensions/forms/Iterate/Toolbar/).
This example uses the container `toolbarVariant` prop with `minimumOneItem`.

It hides the toolbar in the `EditContainer` when there is only one item in the array. And it hides the remove button in the `ViewContainer` when there is only one item in the array.
It hides the toolbar from the `EditContainer` when there is only one item in the array. And it hides the remove button from the `ViewContainer` when there is only one item in the array.

<Examples.InitialOpen />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,27 @@ render(
)
```

## Get the internal item object

You can get the internal item object by using the `Iterate.useItem` hook.

```tsx
import { Iterate, Field, Value } from '@dnb/eufemia/extensions/forms'

const MyItemForm = () => {
const item = Iterate.useItem()
console.log('index:', item.index)

return <Field.String itemPath="/" />
}

render(
<Iterate.Array value={['foo', 'bar']}>
<MyItemForm />
</Iterate.Array>,
)
```

## Customize the Toolbar

```tsx
Expand All @@ -65,23 +86,22 @@ render(
)
```

## Get the internal item object
### Variants

You can get the internal item object by using the `Iterate.useItem` hook.
#### `minimumOneItem`

```tsx
import { Iterate, Field, Value } from '@dnb/eufemia/extensions/forms'
This variant has the following behavior:

const MyItemForm = () => {
const item = Iterate.useItem()
console.log('index:', item.index)
- When `EditContainer` is visible, and the number of items in the array is one, the entire toolbar will be hidden.

return <Field.String itemPath="/" />
}
```tsx
import { Iterate } from '@dnb/eufemia/extensions/forms'

render(
<Iterate.Array value={['foo', 'bar']}>
<MyItemForm />
<Iterate.Array>
<Iterate.EditContainer toolbarVariant="minimumOneItem">
Item Content
</Iterate.EditContainer>
</Iterate.Array>,
)
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ hideInMenu: true

Use `Iterate.Toolbar` to enhance each item in the array with additional functionality. It's particularly useful within components like [Iterate.AnimatedContainer](/uilib/extensions/forms/Iterate/AnimatedContainer) to incorporate a toolbar with extra tools.

The Toolbar is integrated into the containers [Iterate.ViewContainer](/uilib/extensions/forms/Iterate/ViewContainer/) and [Iterate.EditContainer](/uilib/extensions/forms/Iterate/EditContainer/).
The Toolbar is integrated into the [Iterate.ViewContainer](/uilib/extensions/forms/Iterate/ViewContainer/) and the [Iterate.EditContainer](/uilib/extensions/forms/Iterate/EditContainer/).

```tsx
import { Iterate } from '@dnb/eufemia/extensions/forms'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,26 @@ render(
)
```

### Variants

#### `minimumOneItem`

This variant has the following behavior:

- When `ViewContainer` is visible, and the number of items in the array is one, the remove button will be hidden.

```tsx
import { Iterate } from '@dnb/eufemia/extensions/forms'

render(
<Iterate.Array>
<Iterate.ViewContainer toolbarVariant="minimumOneItem">
Item Content
</Iterate.ViewContainer>
</Iterate.Array>,
)
```

## Accessibility

The `Iterate.ViewContainer` component has an `aria-label` attribute, which is set to the `title` prop value. It uses a section element to wrap the content, which helps users with screen readers to get the needed announcement.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Change log for the Eufemia Forms extension.

## v10.48

- Make [Iterate.Toolbar](/uilib/extensions/forms/Iterate/Toolbar/) customizable.
- Make [Iterate.Toolbar](/uilib/extensions/forms/Iterate/Toolbar/) customizable when used inside [Iterate.Array](/uilib/extensions/forms/Iterate/Array/).
- Add new `toolbarVariant` to [Iterate.ViewContainer](/uilib/extensions/forms/Iterate/ViewContainer/) and [Iterate.EditContainer](/uilib/extensions/forms/Iterate/EditContainer/) for hiding the buttons when there is only one item in the array.

## v10.46

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,25 @@ export type Props = {
* An alternative toolbar to be shown in the EditContainer.
*/
toolbar?: React.ReactNode
/**
* The variant of the toolbar.
*/
toolbarVariant?: 'minimumOneItem'
}

export type AllProps = Props & FlexContainerProps & ArrayItemAreaProps

export default function EditContainer(props: AllProps) {
const { toolbar, children, ...rest } = props
const { toolbar, toolbarVariant, children, ...rest } = props
const { arrayValue } = useContext(IterateItemContext)

let toolbarElement = toolbar
if (toolbarVariant === 'minimumOneItem' && arrayValue.length <= 1) {
toolbarElement = <></>
}

const hasToolbar =
!toolbar &&
!toolbarElement &&
React.Children.toArray(children).some((child) => {
return child?.['type'] === Toolbar
})
Expand All @@ -48,7 +58,7 @@ export default function EditContainer(props: AllProps) {
toolbar={
hasToolbar
? null
: toolbar ?? (
: toolbarElement ?? (
<Toolbar>
<DoneButton />
<CancelButton />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export const EditContainerProperties: PropertiesTableProps = {
type: 'React.Node',
status: 'optional',
},
toolbarVariant: {
doc: 'Use variants to render the toolbar differently. Currently there is only the `minimumOneItem` variant. See the info section for more info.',
type: 'string',
status: 'optional',
},
open: {
doc: 'If the container should be open or not. This is taken care of internally by default.',
type: 'boolean',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -589,11 +589,13 @@ describe('EditContainer and ViewContainer', () => {

const { rerender } = render(
<Iterate.Array value={['foo']}>
<Iterate.ViewContainer toolbar={viewToolbar}>
<Iterate.ViewContainer>
View Content
{viewToolbar}
</Iterate.ViewContainer>
<Iterate.EditContainer toolbar={editToolbar}>
<Iterate.EditContainer>
Edit Content
{editToolbar}
</Iterate.EditContainer>
</Iterate.Array>
)
Expand All @@ -617,10 +619,67 @@ describe('EditContainer and ViewContainer', () => {

rerender(
<Iterate.Array value={['foo', 'bar']}>
<Iterate.ViewContainer toolbar={viewToolbar}>
<Iterate.ViewContainer>
View Content
{viewToolbar}
</Iterate.ViewContainer>
<Iterate.EditContainer toolbar={editToolbar}>
<Iterate.EditContainer>
Edit Content
{editToolbar}
</Iterate.EditContainer>
</Iterate.Array>
)

{
const elements = document.querySelectorAll(
'.dnb-forms-iterate__element'
)
expect(elements).toHaveLength(2)

const [firstElement] = Array.from(elements)
const [viewBlock, editBlock] = Array.from(
firstElement.querySelectorAll('.dnb-forms-section-block')
)
expect(editBlock.querySelectorAll('button')).toHaveLength(2)
expect(viewBlock.querySelectorAll('button')).toHaveLength(2)
}
})

it('should render toolbarVariant="minimumOneItem" with correct buttons', () => {
const { rerender } = render(
<Iterate.Array value={['foo']}>
<Iterate.ViewContainer toolbarVariant="minimumOneItem">
View Content
</Iterate.ViewContainer>
<Iterate.EditContainer toolbarVariant="minimumOneItem">
Edit Content
</Iterate.EditContainer>
</Iterate.Array>
)

{
const elements = document.querySelectorAll(
'.dnb-forms-iterate__element'
)
expect(elements).toHaveLength(1)

const [firstElement] = Array.from(elements)
const [viewBlock, editBlock] = Array.from(
firstElement.querySelectorAll('.dnb-forms-section-block')
)
expect(editBlock.querySelectorAll('button')).toHaveLength(0)
expect(viewBlock.querySelectorAll('button')).toHaveLength(1)
expect(viewBlock.querySelectorAll('button')[0]).toHaveTextContent(
tr.viewContainer.editButton
)
}

rerender(
<Iterate.Array value={['foo', 'bar']}>
<Iterate.ViewContainer toolbarVariant="minimumOneItem">
View Content
</Iterate.ViewContainer>
<Iterate.EditContainer toolbarVariant="minimumOneItem">
Edit Content
</Iterate.EditContainer>
</Iterate.Array>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,42 @@ export type Props = {
* An alternative toolbar to be shown in the ViewContainer.
*/
toolbar?: React.ReactNode
/**
* The variant of the toolbar.
*/
toolbarVariant?: 'minimumOneItem'
}

export type AllProps = Props & FlexContainerProps & ArrayItemAreaProps

function ViewContainer(props: AllProps) {
const { children, className, title, toolbar, ...restProps } = props || {}
const { index } = useContext(IterateItemContext)
const {
children,
className,
title,
toolbar,
toolbarVariant,
...restProps
} = props || {}
const { index, arrayValue } = useContext(IterateItemContext)

let itemTitle = title
let ariaLabel = useMemo(() => convertJsxToString(itemTitle), [itemTitle])
if (ariaLabel.includes('{itemNr}')) {
itemTitle = ariaLabel = ariaLabel.replace('{itemNr}', index + 1)
}

let toolbarElement = toolbar
if (toolbarVariant === 'minimumOneItem' && arrayValue.length <= 1) {
toolbarElement = (
<Toolbar>
<EditButton />
</Toolbar>
)
}

const hasToolbar =
!toolbar &&
!toolbarElement &&
React.Children.toArray(children).some((child) => {
return child?.['type'] === Toolbar
})
Expand All @@ -51,7 +71,7 @@ function ViewContainer(props: AllProps) {
{children}
{hasToolbar
? null
: toolbar ?? (
: toolbarElement ?? (
<Toolbar>
<EditButton />
<RemoveButton />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export const ViewContainerProperties: PropertiesTableProps = {
type: 'React.Node',
status: 'optional',
},
toolbarVariant: {
doc: 'Use variants to render the toolbar differently. Currently there is only the `minimumOneItem` variant. See the info section for more info.',
type: 'string',
status: 'optional',
},
'[FlexVertical](/uilib/layout/flex/container/)': {
doc: 'All Flex.Vertical properties.',
type: 'Various',
Expand Down
Loading

0 comments on commit dd48787

Please sign in to comment.