diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Count.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Count.mdx index a0f46dc4df7..9dcaf49444a 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Count.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Count.mdx @@ -1,7 +1,6 @@ --- title: 'Count' description: '`Iterate.Count` is a helper component / function that returns the count of a data array or object.' -order: 11 showTabs: true tabs: - title: Info diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo.mdx new file mode 100644 index 00000000000..b7e8da841b3 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo.mdx @@ -0,0 +1,25 @@ +--- +title: 'ItemNo' +description: '`Iterate.ItemNo` is a helper component that can be used to render the current item number (index) in a given string.' +showTabs: true +tabs: + - title: Info + key: '/info' + - title: Demos + key: '/demos' +breadcrumb: + - text: Forms + href: /uilib/extensions/forms/ + - text: Extended features + href: /uilib/extensions/forms/ + - text: Iterate + href: /uilib/extensions/forms/Iterate/ + - text: ItemNo + href: /uilib/extensions/forms/Iterate/ItemNo/ +--- + +import Info from 'Docs/uilib/extensions/forms/Iterate/ItemNo/info' +import Demos from 'Docs/uilib/extensions/forms/Iterate/ItemNo/demos' + + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo/Examples.tsx new file mode 100644 index 00000000000..270e261dd60 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo/Examples.tsx @@ -0,0 +1,14 @@ +import ComponentBox from '../../../../../../shared/tags/ComponentBox' +import { Form, Iterate } from '@dnb/eufemia/src/extensions/forms' + +export const Default = () => { + return ( + + + + {'Item no. {itemNo}'} + + + + ) +} diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo/demos.mdx new file mode 100644 index 00000000000..13d1e6b62f6 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo/demos.mdx @@ -0,0 +1,11 @@ +--- +showTabs: true +--- + +import * as Examples from './Examples' + +## Demos + +### Default + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo/info.mdx new file mode 100644 index 00000000000..03205372016 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/ItemNo/info.mdx @@ -0,0 +1,21 @@ +--- +showTabs: true +--- + +## Description + +`Iterate.ItemNo` is a helper component that can be used to render the current item number (index) in a given string. It will replace `{itemNo}` with the current item number. + +```tsx +import { Form, Iterate } from '@dnb/eufemia/extensions/forms' + +const myString = 'Item no. {itemNo}' + +render( + + + {myString} + + , +) +``` diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/PushContainer.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/PushContainer.mdx index 2f2b6fe73a7..748b1c55a6c 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/PushContainer.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/PushContainer.mdx @@ -1,7 +1,7 @@ --- title: 'PushContainer' description: '`Iterate.PushContainer` enables users to create a new item in the array.' -order: 9 +order: 7 showTabs: true tabs: - title: Info diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar.mdx index cb6f333183f..8a16d1dc731 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar.mdx @@ -1,7 +1,6 @@ --- title: 'Toolbar' description: '`Iterate.Toolbar` is a helper component to be used within an `Iterate.AnimatedContainer` to add a toolbar to each item in the array.' -order: 10 showTabs: true tabs: - title: Info diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/EditContainer.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/EditContainer.tsx index 7da3dbf8647..72ab1170946 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/EditContainer.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/EditContainer.tsx @@ -9,6 +9,7 @@ import Toolbar from '../Toolbar' import { useSwitchContainerMode } from '../hooks' import DoneButton from './DoneButton' import CancelButton, { useWasNew } from './CancelButton' +import { replaceItemNo } from '../ItemNo' export type Props = { /** @@ -88,18 +89,12 @@ export function EditContainerWithoutToolbar( } = props || {} const wasNew = useWasNew({ isNew, containerMode }) - let itemTitle = wasNew && titleWhenNew ? titleWhenNew : title - let ariaLabel = useMemo(() => convertJsxToString(itemTitle), [itemTitle]) - if (ariaLabel.includes('{itemN')) { - /** - * {itemNr} is deprecated, and can be removed in v11 in favor of {itemNo} - * So in v11 we can use '{itemNo}' instead of a regex - */ - itemTitle = ariaLabel = ariaLabel.replace( - /\{itemN(r|o)\}/g, - String(index + 1) + const itemTitle = useMemo(() => { + return replaceItemNo( + wasNew && titleWhenNew ? titleWhenNew : title, + index ) - } + }, [index, title, titleWhenNew, wasNew]) useSwitchContainerMode({ path }) @@ -107,7 +102,7 @@ export function EditContainerWithoutToolbar( {itemTitle && {itemTitle}} diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/ItemNo/ItemNo.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/ItemNo/ItemNo.tsx new file mode 100644 index 00000000000..6fb99f548f1 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/ItemNo/ItemNo.tsx @@ -0,0 +1,35 @@ +import React, { useMemo } from 'react' +import { useItem } from '../hooks' +import { convertJsxToString } from '../../../../shared/component-helper' + +function ItemNo({ children }) { + const { index } = useItem() + + children = useMemo( + () => replaceItemNo(children, index), + [children, index] + ) + + return <>{replaceItemNo(children, index)} +} + +export function replaceItemNo( + children: React.ReactNode, + index: number +): string | React.ReactNode { + const text = + typeof children !== 'string' ? convertJsxToString(children) : children + + if (text.includes('{itemN')) { + /** + * {itemNr} is deprecated, and can be removed in v11 in favor of {itemNo} + * So in v11 we can use '{itemNo}' instead of a regex + */ + return text.replace(/\{itemN(r|o)\}/g, String(index + 1)) + } + + return children +} + +ItemNo._supportsSpacingProps = false +export default ItemNo diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/ItemNo/__tests__/ItemNo.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/ItemNo/__tests__/ItemNo.test.tsx new file mode 100644 index 00000000000..d34d90d69f7 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/ItemNo/__tests__/ItemNo.test.tsx @@ -0,0 +1,35 @@ +import React from 'react' +import { render } from '@testing-library/react' +import { Iterate } from '../../..' + +describe('Iterate.ItemNo', () => { + it('should replace {itemNo} in children given as a string', () => { + render( + + {'Item no. {itemNo} string'} + + ) + expect(document.body).toHaveTextContent('Item no. 1 string') + }) + + it('should replace several array items', () => { + render( + + {'Item no. {itemNo} string'} + + ) + expect(document.body).toHaveTextContent('Item no. 1 string') + expect(document.body).toHaveTextContent('Item no. 2 string') + }) + + it('should remove jsx and return only a string', () => { + render( + + + {'Item no. {itemNo} string'} + + + ) + expect(document.body).toHaveTextContent('Item no. 1 string') + }) +}) diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/ItemNo/index.ts b/packages/dnb-eufemia/src/extensions/forms/Iterate/ItemNo/index.ts new file mode 100644 index 00000000000..8bfd3c6ca4a --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/ItemNo/index.ts @@ -0,0 +1,2 @@ +export { default } from './ItemNo' +export * from './ItemNo' diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/ViewContainer.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/ViewContainer.tsx index e5002c5ba00..cc49e27fa4c 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/ViewContainer.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/ViewContainer.tsx @@ -9,6 +9,7 @@ import IterateItemContext from '../IterateItemContext' import Toolbar from '../Toolbar' import EditButton from './EditButton' import RemoveButton from './RemoveButton' +import { replaceItemNo } from '../ItemNo' export type Props = { /** @@ -37,19 +38,9 @@ function ViewContainer(props: AllProps) { ...restProps } = props || {} const { index, arrayValue } = useContext(IterateItemContext) - - let itemTitle = title - let ariaLabel = useMemo(() => convertJsxToString(itemTitle), [itemTitle]) - if (ariaLabel.includes('{itemN')) { - /** - * {itemNr} is deprecated, and can be removed in v11 in favor of {itemNo} - * So in v11 we can use '{itemNo}' instead of a regex - */ - itemTitle = ariaLabel = ariaLabel.replace( - /\{itemN(r|o)\}/g, - String(index + 1) - ) - } + const itemTitle = useMemo(() => { + return replaceItemNo(title, index) + }, [index, title]) let toolbarElement = toolbar if (toolbarVariant === 'minimumOneItem' && arrayValue.length <= 1) { @@ -69,7 +60,7 @@ function ViewContainer(props: AllProps) { return ( diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/index.ts b/packages/dnb-eufemia/src/extensions/forms/Iterate/index.ts index 0b045e6969b..4f0a3712380 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/index.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/index.ts @@ -9,6 +9,7 @@ export { default as EditContainer } from './EditContainer' export { default as ViewContainer } from './ViewContainer' export { default as AnimatedContainer } from './AnimatedContainer' export { default as Toolbar } from './Toolbar' +export { default as ItemNo } from './ItemNo' export { useCount, count, Count } from './Count' export { default as useItem } from './hooks/useItem' export { default as IterateItemContext } from './IterateItemContext'