Skip to content

Commit

Permalink
feat(Forms): add support for defaultValue (and value) for fields …
Browse files Browse the repository at this point in the history
…used in `Iterate.Array` (#3987)

Fixes #3882
  • Loading branch information
tujoworker authored Oct 5, 2024
1 parent da0c93a commit afbdddf
Show file tree
Hide file tree
Showing 12 changed files with 592 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const PrimitiveItemsFields = () => {
return (
<ComponentBox>
<Iterate.Array
value={['Iron Man', 'Captain America', 'The Hulk']}
defaultValue={['Iron Man', 'Captain America', 'The Hulk']}
onChange={console.log}
>
<Field.String itemPath="/" />
Expand All @@ -26,7 +26,9 @@ export const PrimitiveItemsValues = () => {
return (
<ComponentBox data-visual-test="primitive-element-values">
<Value.SummaryList>
<Iterate.Array value={['Iron Man', 'Captain America', 'The Hulk']}>
<Iterate.Array
defaultValue={['Iron Man', 'Captain America', 'The Hulk']}
>
<Value.String itemPath="/" />
</Iterate.Array>
</Value.SummaryList>
Expand All @@ -39,7 +41,7 @@ export const ValueComposition = () => {
<ComponentBox>
<Value.Composition>
<Iterate.Array
value={[
defaultValue={[
{
label: 'Label A',
value: 'value 1',
Expand Down Expand Up @@ -73,7 +75,7 @@ export const WithTable = () => {
<tbody>
<Iterate.Array
withoutFlex
value={[
defaultValue={[
{ name: 'Iron Man', age: 45 },
{ name: 'Captain America', age: 123 },
{ name: 'The Hulk', age: 3337 },
Expand All @@ -98,7 +100,7 @@ export const ObjectItems = () => {
return (
<ComponentBox>
<Iterate.Array
value={[
defaultValue={[
{
accountName: 'Brukskonto',
accountNumber: '90901134567',
Expand All @@ -123,7 +125,7 @@ export const RenderPropsPrimitiveItems = () => {
return (
<ComponentBox>
<Iterate.Array
value={['foo', 'bar']}
defaultValue={['foo', 'bar']}
onChange={(value) => console.log('onChange', value)}
>
{(elementValue) => <Field.String value={elementValue} />}
Expand All @@ -136,7 +138,7 @@ export const RenderPropsObjectItems = () => {
return (
<ComponentBox>
<Iterate.Array
value={[
defaultValue={[
{ num: 1, txt: 'One' },
{ num: 2, txt: 'Two' },
]}
Expand Down Expand Up @@ -343,7 +345,7 @@ export const WithVisibility = () => {
return (
<ComponentBox>
<Form.Handler>
<Iterate.Array path="/myList" value={[{}]}>
<Iterate.Array path="/myList" defaultValue={[{}]}>
<Flex.Stack>
<Field.Name.First
className="firstName"
Expand Down Expand Up @@ -440,7 +442,7 @@ export const InitialOpen = () => {
export const ToolbarVariantMiniumOneItemOneItem = () => {
return (
<ComponentBox hideCode>
<Iterate.Array value={['foo']}>
<Iterate.Array defaultValue={['foo']}>
<Iterate.ViewContainer toolbarVariant="minimumOneItem">
View Content
</Iterate.ViewContainer>
Expand All @@ -455,7 +457,7 @@ export const ToolbarVariantMiniumOneItemOneItem = () => {
export const ToolbarVariantMiniumOneItemTwoItems = () => {
return (
<ComponentBox hideCode>
<Iterate.Array value={['foo', 'bar']}>
<Iterate.Array defaultValue={['foo', 'bar']}>
<Iterate.ViewContainer toolbarVariant="minimumOneItem">
View Content
</Iterate.ViewContainer>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import { Flex } from '@dnb/eufemia/src'
import ComponentBox from '../../../../../../shared/tags/ComponentBox'
import { Iterate, Field, Form } from '@dnb/eufemia/src/extensions/forms'
import {
Iterate,
Field,
Form,
Value,
} from '@dnb/eufemia/src/extensions/forms'

export const PrimitiveItems = () => {
return (
<ComponentBox>
<Iterate.PushButton
text="Add another item"
value={['foo', 'bar']}
pushValue="new"
onChange={(value) => console.log('onChange', value)}
/>
<Form.Handler>
<Flex.Stack>
<Iterate.Array path="/">
<Value.String itemPath="/" />
</Iterate.Array>
<Iterate.PushButton
text="Add another item"
path="/"
pushValue="new"
/>
</Flex.Stack>
</Form.Handler>
</ComponentBox>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ describe('Visibility', () => {
it('should render with whole path', async () => {
render(
<Form.Handler>
<Iterate.Array path="/myList" value={[{}]}>
<Iterate.Array path="/myList" defaultValue={[{}]}>
<Field.Name.First
className="firstName"
itemPath="/firstName"
Expand All @@ -294,7 +294,7 @@ describe('Visibility', () => {
<Form.Visibility
visibleWhen={{
path: '/myList/0/firstName',
hasValue: (value: string) => value.length > 0,
hasValue: (value: string) => value?.length > 0,
}}
>
<Field.Name.Last
Expand Down Expand Up @@ -322,7 +322,7 @@ describe('Visibility', () => {

render(
<Form.Handler>
<Iterate.Array path="/myList" value={[{}]}>
<Iterate.Array path="/myList" defaultValue={[{}]}>
<Field.Name.First
className="firstName"
itemPath="/firstName"
Expand All @@ -331,7 +331,7 @@ describe('Visibility', () => {
<Form.Visibility
visibleWhen={{
itemPath: '/firstName',
hasValue: (value: string) => value.length > 0,
hasValue: (value: string) => value?.length > 0,
}}
>
<Field.Name.Last
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,61 @@ describe('Iterate.Array', () => {
)
})

it('should handle "defaultValue" (with null) in React.StrictMode', () => {
const onSubmit = jest.fn()

render(
<React.StrictMode>
<Form.Handler onSubmit={onSubmit}>
<Iterate.Array path="/myList" defaultValue={[null]}>
<Field.String itemPath="/" defaultValue="foo" />
</Iterate.Array>
</Form.Handler>
</React.StrictMode>
)

const form = document.querySelector('form')
const input = document.querySelector('input')

expect(input).toHaveValue('foo')

fireEvent.submit(form)

expect(onSubmit).toHaveBeenCalledTimes(1)
expect(onSubmit).toHaveBeenLastCalledWith(
{ myList: ['foo'] },
expect.anything()
)
})

it('should not set defaultValue when item gets removed', () => {
const onSubmit = jest.fn()

render(
<React.StrictMode>
<Form.Handler onSubmit={onSubmit}>
<Iterate.Array path="/myList" defaultValue={[null]}>
<Field.String itemPath="/" defaultValue="foo" />
<Iterate.RemoveButton />
</Iterate.Array>
</Form.Handler>
</React.StrictMode>
)

const form = document.querySelector('form')
const input = document.querySelector('input')

expect(input).toHaveValue('foo')

fireEvent.submit(form)

expect(onSubmit).toHaveBeenCalledTimes(1)
expect(onSubmit).toHaveBeenLastCalledWith(
{ myList: ['foo'] },
expect.anything()
)
})

it('should set empty array in the data context', () => {
const onSubmit = jest.fn()

Expand Down Expand Up @@ -1320,6 +1375,92 @@ describe('Iterate.Array', () => {
})
})

describe('value and defaultValue', () => {
it('should support "value" on fields inside iterate', () => {
const onSubmit = jest.fn()

render(
<Form.Handler
onSubmit={onSubmit}
data={{
myList: ['', undefined, null, 'something'],
}}
>
<Iterate.Array path="/myList">
{(value, index) => {
return (
<Field.String itemPath="/" value={`value ${index + 1}`} />
)
}}
</Iterate.Array>
</Form.Handler>
)

const form = document.querySelector('form')
const [first, second, third, forth] = Array.from(
document.querySelectorAll('input')
)

expect(first).toHaveValue('value 1')
expect(second).toHaveValue('value 2')
expect(third).toHaveValue('value 3')
expect(forth).toHaveValue('value 4')

fireEvent.submit(form)

expect(onSubmit).toHaveBeenCalledTimes(1)
expect(onSubmit).toHaveBeenLastCalledWith(
{
myList: ['value 1', 'value 2', 'value 3', 'value 4'],
},
expect.anything()
)
})

it('should support "defaultValue" on fields inside iterate', () => {
const onSubmit = jest.fn()

render(
<Form.Handler
onSubmit={onSubmit}
data={{
myList: [undefined, null, 'something'],
}}
>
<Iterate.Array path="/myList">
{(value, index) => {
return (
<Field.String
itemPath="/"
defaultValue={`default value ${index + 1}`}
/>
)
}}
</Iterate.Array>
</Form.Handler>
)

const form = document.querySelector('form')
const [first, second, third] = Array.from(
document.querySelectorAll('input')
)

expect(first).toHaveValue('default value 1')
expect(second).toHaveValue('default value 2')
expect(third).toHaveValue('something')

fireEvent.submit(form)

expect(onSubmit).toHaveBeenCalledTimes(1)
expect(onSubmit).toHaveBeenLastCalledWith(
{
myList: ['default value 1', 'default value 2', 'something'],
},
expect.anything()
)
})
})

it('should contain tabindex of -1', () => {
render(<Iterate.Array value={['one']}>content</Iterate.Array>)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,53 @@ describe('EditContainer and ViewContainer', () => {
expect(elements[1]).toHaveFocus()
})
})

it('should removed item from data context', async () => {
const onChange = jest.fn()

render(
<Form.Handler onChange={onChange}>
<Iterate.Array path="/myList" defaultValue={['foo', 'bar']}>
<Iterate.ViewContainer>View Content</Iterate.ViewContainer>
<Iterate.EditContainer>Edit Content</Iterate.EditContainer>
</Iterate.Array>
</Form.Handler>
)

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

const firstElement = elements[0]
const [viewBlock, editBlock] = Array.from(
firstElement.querySelectorAll('.dnb-forms-section-block')
)
const [, removeButton] = Array.from(
viewBlock.querySelectorAll('button')
)

expect(viewBlock).toHaveClass('dnb-forms-section-view-block')
expect(editBlock).toHaveClass('dnb-forms-section-edit-block')

// Remove the element
await userEvent.click(removeButton)

expect(onChange).toHaveBeenCalledTimes(1)
expect(onChange).toHaveBeenLastCalledWith(
{
myList: ['bar'],
},
expect.anything()
)

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

it('should set variant to "outline" when variant is not set', async () => {
Expand Down
Loading

0 comments on commit afbdddf

Please sign in to comment.