Skip to content

Commit

Permalink
Fix propper Wizard and defaultValue support
Browse files Browse the repository at this point in the history
  • Loading branch information
tujoworker committed Sep 25, 2024
1 parent 29dd6f6 commit 7b3bf06
Show file tree
Hide file tree
Showing 13 changed files with 639 additions and 307 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
17 changes: 5 additions & 12 deletions packages/dnb-eufemia/src/extensions/forms/Iterate/Array/Array.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import IterateItemContext, {
import SummaryListContext from '../../Value/SummaryList/SummaryListContext'
import ValueBlockContext from '../../ValueBlock/ValueBlockContext'
import FieldBoundaryProvider from '../../DataContext/FieldBoundary/FieldBoundaryProvider'
import DataContext from '../../DataContext/Context'
import useDataValue from '../../hooks/useDataValue'
import { useArrayLimit, useSwitchContainerMode } from '../hooks'
import { getMessage } from '../../FieldBlock'
Expand Down Expand Up @@ -90,7 +89,6 @@ function ArrayComponent(props: Props) {
value: arrayValue,
limit,
error,
defaultValue,
withoutFlex,
emptyValue,
placeholder,
Expand All @@ -100,7 +98,11 @@ function ArrayComponent(props: Props) {
setChanged,
onChange,
children,
} = useFieldProps(preparedProps)
} = useFieldProps(preparedProps, {
// To ensure the defaultValue set on the Iterate.Array is set in the data context,
// and will not overwrite defaultValues set by fields inside the Iterate.Array.
updateContextDataInSync: true,
})

useMountEffect(() => {
// To ensure the validator is called when a new item is added
Expand Down Expand Up @@ -129,15 +131,6 @@ function ArrayComponent(props: Props) {

const omitFlex = withoutFlex ?? (summaryListContext || valueBlockContext)

// To support React.StrictMode, we inject the defaultValue into the data context this way.
// The routine inside useFieldProps where updateDataValueDataContext is called, does not support React.StrictMode
const { handlePathChange } = useContext(DataContext) || {}
useMountEffect(() => {
if (defaultValue) {
handlePathChange?.(path, defaultValue)
}
})

useEffect(() => {
// Update inside the useEffect, to support React.StrictMode
valueCountRef.current = arrayValue || []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -562,31 +562,133 @@ describe('Iterate.Array', () => {
expect(onChangeIterate).toHaveBeenLastCalledWith(['foo'])
})

it('should handle "defaultValue" with React.StrictMode', () => {
const onSubmit = jest.fn()
describe('defaultValue', () => {
it('should validate required fields', async () => {
const onSubmit = jest.fn()

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

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

expect(input).toHaveValue('')
expect(onSubmit).toHaveLength(0)

fireEvent.submit(form)
await waitFor(() => {
expect(
document.querySelectorAll('.dnb-form-status')
).toHaveLength(1)
})
})

expect(onSubmit).toHaveBeenCalledTimes(1)
expect(onSubmit).toHaveBeenLastCalledWith(
{ myList: [''] },
expect.anything()
)
it('should handle "defaultValue" (empty string) in React.StrictMode', () => {
const onSubmit = jest.fn()

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

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

expect(input).toHaveValue('')

fireEvent.submit(form)

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

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

render(
<React.StrictMode>
<Form.Handler onSubmit={onSubmit}>
<Iterate.Array path="/myList" defaultValue={['foo']}>
<Field.String itemPath="/" />
</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 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 set empty array in the data context', () => {
const onSubmit = jest.fn()

render(
<React.StrictMode>
<Form.Handler onSubmit={onSubmit}>
<Iterate.Array path="/myList" defaultValue={[]}>
content
</Iterate.Array>
</Form.Handler>
</React.StrictMode>
)

const form = document.querySelector('form')
fireEvent.submit(form)

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

describe('with primitive elements', () => {
Expand Down Expand Up @@ -1294,7 +1396,7 @@ describe('Iterate.Array', () => {
<Form.Handler
onSubmit={onSubmit}
data={{
myList: ['', undefined, null, 'something'],
myList: [undefined, null, 'something'],
}}
>
<Iterate.Array path="/myList">
Expand All @@ -1311,26 +1413,20 @@ describe('Iterate.Array', () => {
)

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

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

fireEvent.submit(form)

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

0 comments on commit 7b3bf06

Please sign in to comment.