Skip to content

Commit

Permalink
feat(Forms): add transformLabel to Value.Composition (#4207)
Browse files Browse the repository at this point in the history
We do that by moving the `transformLabel` logic from `useValueProps` to
`ValueBlock`.
  • Loading branch information
tujoworker authored Nov 4, 2024
1 parent 59845d0 commit c966bc1
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 115 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { PropertiesTableProps } from '../../../../shared/types'
import { ValueProperties } from '../ValueDocs'

const { label } = ValueProperties
const { label, transformLabel } = ValueProperties

export const CompositionProperties: PropertiesTableProps = {
label,
transformLabel,
maxWidth: {
doc: 'Use `small`, `medium` or `large` for predefined standard max widths. Defaults to `auto`.',
type: 'string',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,22 @@ describe('Value.Composition', () => {
document.querySelector('.dnb-forms-value-block__label strong')
).toBeInTheDocument()
})

describe('transformLabel', () => {
it('renders labels', async () => {
render(
<Value.Composition
label="Label"
transformLabel={(label: string) => label.toUpperCase()}
>
<Value.String path="/foo" />
<Value.String path="/bar" />
</Value.Composition>
)

const label = document.querySelector('.dnb-form-label')

expect(label.textContent).toBe('LABEL')
})
})
})
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { PropertiesTableProps } from '../../../../shared/types'
import { ValueProperties } from '../ValueDocs'

const { transformLabel } = ValueProperties

export const SummaryListProperties: PropertiesTableProps = {
layout: {
doc: 'Use `grid`, `horizontal` or `vertical`.',
type: 'string',
status: 'optional',
},
transformLabel: {
doc: 'Transforms the label before it gets displayed. Receives the label as the first parameter. The second parameter is a object containing the `convertJsxToString` function.',
type: 'function',
status: 'optional',
},
inheritVisibility: {
doc: 'Use this property to propagate the `inheritVisibility` property to all nested values.',
type: 'boolean',
Expand All @@ -21,6 +19,7 @@ export const SummaryListProperties: PropertiesTableProps = {
type: 'boolean',
status: 'optional',
},
transformLabel,
children: {
doc: 'Contents.',
type: 'React.Node',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ function ValueBlock(props: Props) {
const {
className,
label: labelProp,
transformLabel = (label: Props['label']) => label,
inline,
maxWidth = props.composition ? props.maxWidth : 'large',
placeholder,
Expand All @@ -56,14 +57,18 @@ function ValueBlock(props: Props) {
if (inline) {
return null
}

let label = labelProp

if (iterateIndex !== undefined) {
return convertJsxToString(labelProp).replace(
label = convertJsxToString(labelProp).replace(
'{itemNo}',
String(iterateIndex + 1)
)
}
return labelProp
}, [inline, iterateIndex, labelProp])

return transformLabel(label, transformLabelParameters)
}, [inline, iterateIndex, labelProp, transformLabel])

const ref = useRef<HTMLElement>(null)
useNotInSummaryList(valueBlockContext?.composition ? null : ref, label)
Expand Down Expand Up @@ -205,3 +210,7 @@ function useNotInSummaryList(

ValueBlock._supportsSpacingProps = true
export default ValueBlock

const transformLabelParameters = {
convertJsxToString,
} as unknown as Parameters<Props['transformLabel']>[1]
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import { axeComponent } from '../../../../core/jest/jestSetup'
import { render } from '@testing-library/react'
import ValueBlock from '../ValueBlock'
import { Value } from '../..'
import { Form, Value } from '../..'

describe('ValueBlock', () => {
it('renders without crashing', () => {
Expand Down Expand Up @@ -274,4 +274,98 @@ describe('ValueBlock', () => {

log.mockRestore()
})

describe('transformLabel', () => {
it('should transform label', () => {
const transformLabel = jest.fn((label) => label.toUpperCase())
render(
<ValueBlock
label="The label"
transformLabel={transformLabel}
showEmpty
/>
)
expect(transformLabel).toHaveBeenCalledTimes(1)
expect(transformLabel).toHaveBeenLastCalledWith(
'The label',
expect.anything()
)
expect(document.querySelector('.dnb-form-label')).toHaveTextContent(
'THE LABEL'
)
})

it('should transform label in Value.String', () => {
const transformLabel = jest.fn((label) => label.toUpperCase())
render(
<Form.Handler>
<Value.String
label="The label"
transformLabel={transformLabel}
showEmpty
/>
</Form.Handler>
)
expect(transformLabel).toHaveBeenCalledTimes(1)
expect(transformLabel).toHaveBeenLastCalledWith(
'The label',
expect.anything()
)
expect(
document.querySelector('.dnb-forms-value-string')
).toHaveTextContent('THE LABEL')
})

it('should transform a JSX label and return "convertJsxToString"', () => {
const transformLabel = jest.fn((label, { convertJsxToString }) =>
convertJsxToString(label).toUpperCase()
)
render(
<Form.Handler>
<Value.String
label={<span>The label</span>}
transformLabel={transformLabel}
showEmpty
/>
</Form.Handler>
)
expect(transformLabel).toHaveBeenCalledTimes(1)
expect(transformLabel).toHaveBeenLastCalledWith(
<span>The label</span>,
expect.anything()
)
expect(
document.querySelector('.dnb-forms-value-string')
).toHaveTextContent('THE LABEL')
})

it('should transform label using Value.Provider', () => {
const transformLabel = jest.fn((label) => label.toUpperCase())
render(
<Form.Handler>
<Value.Provider transformLabel={transformLabel}>
<Value.SummaryList>
<Value.String label="The label A" showEmpty />
<Value.String label="The label B" showEmpty />
</Value.SummaryList>
</Value.Provider>
</Form.Handler>
)

const [first, second] = Array.from(document.querySelectorAll('dt'))
expect(first).toHaveTextContent('THE LABEL A')
expect(second).toHaveTextContent('THE LABEL B')
expect(transformLabel).toHaveBeenCalledTimes(2)
expect(transformLabel).toHaveBeenNthCalledWith(
1,
'The label A',
expect.anything()
)
expect(transformLabel).toHaveBeenNthCalledWith(
2,
'The label B',
expect.anything()
)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -663,99 +663,4 @@ describe('useValueProps', () => {
}
})
})

describe('transformLabel', () => {
it('should transform label', () => {
const transformLabel = jest.fn((label) => label.toUpperCase())
render(
<Form.Handler>
<Value.String
label="The label"
transformLabel={transformLabel}
showEmpty
/>
</Form.Handler>
)
expect(transformLabel).toHaveBeenCalledTimes(1)
expect(transformLabel).toHaveBeenLastCalledWith(
'The label',
expect.anything()
)
expect(
document.querySelector('.dnb-forms-value-string')
).toHaveTextContent('THE LABEL')
})

it('should transform a JSX label and return "convertJsxToString"', () => {
const transformLabel = jest.fn((label, { convertJsxToString }) =>
convertJsxToString(label).toUpperCase()
)
render(
<Form.Handler>
<Value.String
label={<span>The label</span>}
transformLabel={transformLabel}
showEmpty
/>
</Form.Handler>
)
expect(transformLabel).toHaveBeenCalledTimes(1)
expect(transformLabel).toHaveBeenLastCalledWith(
<span>The label</span>,
expect.anything()
)
expect(
document.querySelector('.dnb-forms-value-string')
).toHaveTextContent('THE LABEL')
})

it('should transform label using inheritLabel', () => {
render(
<Form.Handler>
<Field.String path="/myPath" label="The label" />
<Value.String
path="/myPath"
inheritLabel
transformLabel={(label: string) => label.toUpperCase()}
showEmpty
/>
</Form.Handler>
)
expect(
document.querySelector('.dnb-forms-field-string')
).toHaveTextContent('The label')
expect(
document.querySelector('.dnb-forms-value-string')
).toHaveTextContent('THE LABEL')
})

it('should transform label using Value.Provider', () => {
const transformLabel = jest.fn((label) => label.toUpperCase())
render(
<Form.Handler>
<Value.Provider transformLabel={transformLabel}>
<Value.SummaryList>
<Value.String label="The label A" showEmpty />
<Value.String label="The label B" showEmpty />
</Value.SummaryList>
</Value.Provider>
</Form.Handler>
)

const [first, second] = Array.from(document.querySelectorAll('dt'))
expect(first).toHaveTextContent('THE LABEL A')
expect(second).toHaveTextContent('THE LABEL B')
expect(transformLabel).toHaveBeenCalledTimes(2)
expect(transformLabel).toHaveBeenNthCalledWith(
1,
'The label A',
expect.anything()
)
expect(transformLabel).toHaveBeenNthCalledWith(
2,
'The label B',
expect.anything()
)
})
})
})
12 changes: 2 additions & 10 deletions packages/dnb-eufemia/src/extensions/forms/hooks/useValueProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,13 @@ import {
useRef,
} from 'react'
import { Path, ValueProps } from '../types'
import { convertJsxToString } from '../../../shared/component-helper'
import useExternalValue from './useExternalValue'
import usePath from './usePath'
import DataContext from '../DataContext/Context'
import ValueProviderContext from '../Value/Provider/ValueProviderContext'

export type Props<Value> = ValueProps<Value>

const transformLabelParameters = {
convertJsxToString,
} as unknown as Parameters<Props<unknown>['transformLabel']>[1]

export default function useValueProps<
Value = unknown,
Props extends ValueProps<Value> = ValueProps<Value>,
Expand All @@ -34,7 +29,6 @@ export default function useValueProps<
defaultValue,
inheritVisibility,
inheritLabel,
transformLabel = (label: Props['label']) => label,
transformIn = (value: Value) => value,
toInput = (value: Value) => value,
fromExternal = (value: Value) => value,
Expand Down Expand Up @@ -93,11 +87,9 @@ export default function useValueProps<
? transformIn(toInput(externalValue))
: undefined

const label = transformLabel(
const label =
props.label ??
(inheritLabel ? fieldPropsRef?.current?.[path]?.label : undefined),
transformLabelParameters
)
(inheritLabel ? fieldPropsRef?.current?.[path]?.label : undefined)

return { ...props, label, value }
}

0 comments on commit c966bc1

Please sign in to comment.