Skip to content

Commit

Permalink
chore(useFieldProps): add support for nested schema required declarat…
Browse files Browse the repository at this point in the history
…ion (#3579)

This is an enhancement of this PR #3571 and feature. This way, nested
"required" declarations are supported:


```js
const schema: JSONSchema = {
  type: 'object',
  properties: {
    myObject: {
      type: 'object',
      properties: {
        myField: {
          type: 'string',
        },
      },
      required: ['myField'],
    },
  },
}
```
  • Loading branch information
tujoworker committed May 21, 2024
1 parent c797144 commit dae30d3
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1875,70 +1875,106 @@ describe('useFieldProps', () => {
expect(result.current.htmlAttributes).toEqual({})
})

it('should return aria-required=true when required prop is true', async () => {
const { result } = renderHook(() =>
useFieldProps({
value: undefined,
required: true,
})
)
describe('required', () => {
it('should return aria-required=true when required prop is true', async () => {
const { result } = renderHook(() =>
useFieldProps({
value: undefined,
required: true,
})
)

expect(result.current.error).not.toBeInstanceOf(Error)
expect(result.current.htmlAttributes).toEqual({
'aria-required': 'true',
expect(result.current.error).not.toBeInstanceOf(Error)
expect(result.current.htmlAttributes).toEqual({
'aria-required': 'true',
})
})
})

it('should return aria-required=true when defined in schema', async () => {
const schema: JSONSchema = {
type: 'object',
properties: {
myField: {
type: 'string',
it('should return aria-required=true when defined in schema', async () => {
const schema: JSONSchema = {
type: 'object',
properties: {
myField: {
type: 'string',
},
},
},
required: ['myField'],
}
required: ['myField'],
}

const { result } = renderHook(() =>
useFieldProps({
path: '/myField',
value: undefined,
schema,
})
)
const { result } = renderHook(() =>
useFieldProps({
path: '/myField',
value: undefined,
schema,
})
)

expect(result.current.htmlAttributes).toEqual({
'aria-required': 'true',
expect(result.current.htmlAttributes).toEqual({
'aria-required': 'true',
})
})
})

it('should return aria-required=true when required in context schema', async () => {
const schema: JSONSchema = {
type: 'object',
properties: {
myField: {
type: 'string',
it('should return aria-required=true when required in context schema', async () => {
const schema: JSONSchema = {
type: 'object',
properties: {
myField: {
type: 'string',
},
},
},
required: ['myField'],
}
required: ['myField'],
}

const { result } = renderHook(
() =>
useFieldProps({
path: '/myField',
value: undefined,
}),
{
wrapper: ({ children }) => {
return <Provider schema={schema}>{children}</Provider>
const { result } = renderHook(
() =>
useFieldProps({
path: '/myField',
value: undefined,
}),
{
wrapper: ({ children }) => {
return <Provider schema={schema}>{children}</Provider>
},
}
)

expect(result.current.htmlAttributes).toEqual({
'aria-required': 'true',
})
})

it('should return aria-required=true when required inside nested context schema', async () => {
const schema: JSONSchema = {
type: 'object',
properties: {
myObject: {
type: 'object',
properties: {
myField: {
type: 'string',
},
},
required: ['myField'],
},
},
}
)

expect(result.current.htmlAttributes).toEqual({
'aria-required': 'true',
const { result } = renderHook(
() =>
useFieldProps({
path: '/myObject/myField',
value: undefined,
}),
{
wrapper: ({ children }) => {
return <Provider schema={schema}>{children}</Provider>
},
}
)

expect(result.current.htmlAttributes).toEqual({
'aria-required': 'true',
})
})
})

Expand Down
26 changes: 19 additions & 7 deletions packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,25 @@ export default function useFieldProps<
if (requiredProp) {
return requiredProp
}
const requiredPath = identifier.replace(/^\//, '')
const required = [
schema?.['required'],
dataContext?.schema?.['required'],
].flatMap((v) => v)
if (required.includes(requiredPath)) {
return true

const paths = identifier.split('/')
if (paths.length > 0 && (schema || dataContext?.schema)) {
const requiredList = [schema?.['required']]

if (paths.length > 1) {
const schema = dataContext.schema
const schemaPath = paths.slice(0, -1).join('/properties/')
const schemaPart = pointer.has(schema, schemaPath)
? pointer.get(schema, schemaPath)
: schema

requiredList.push(schemaPart?.required)
}

const collected = requiredList.flatMap((v) => v).filter(Boolean)
if (collected.includes(paths.at(-1))) {
return true
}
}
}, [dataContext?.schema, identifier, requiredProp, schema])

Expand Down

0 comments on commit dae30d3

Please sign in to comment.