diff --git a/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/Examples.tsx
index a7e8ae6d621..8da3852b187 100644
--- a/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/Examples.tsx
+++ b/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/Examples.tsx
@@ -193,3 +193,29 @@ export const LayoutHorizontalFlexGrowItems = () => {
)
}
+
+export const WrappedWithChildren = () => {
+ return (
+
+ {() => {
+ const Wrapper = Flex.withChildren(({ children }) => {
+ return {children}
+ })
+
+ return (
+
+ FlexItem 1
+
+ FlexItem 2
+ FlexItem 3
+
+ FlexItem 4
+
+ )
+ }}
+
+ )
+}
diff --git a/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/demos.mdx
index dc660651479..a16b510a712 100644
--- a/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/demos.mdx
+++ b/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/demos.mdx
@@ -47,3 +47,7 @@ Will wrap on small screens.
### Vertical aligned Field.String
+
+### Flex.withChildren
+
+
diff --git a/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/info.mdx
index 86aa40a8394..3d81bae1abd 100644
--- a/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/info.mdx
+++ b/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/info.mdx
@@ -28,6 +28,27 @@ You may else wrap your custom component in a `Flex.Item` – this way, you still
Technically, `Flex.Container` checks if a nested component has a property called `_supportsSpacingProps`. So if you have a component that supports the [spacing properties](/uilib/layout/space/), you can add this property `ComponentName._supportsSpacingProps = true`.
+If the component is a wrapper component, and you want its children to support spacing, you can add this property `ComponentName._supportsSpacingProps = 'children'`.
+
+But for simplicity, you can use the HOC `Flex.withChildren`:
+
+```tsx
+const Wrapper = Flex.withChildren(({ children }) => {
+ return
{children}
+})
+
+render(
+
+
+
+
+
+
+
+ ,
+)
+```
+
### Horizontal and Vertical aliases
For shortening the usage of `direction="..."`, you can use:
diff --git a/packages/dnb-eufemia/src/components/flex/Container.tsx b/packages/dnb-eufemia/src/components/flex/Container.tsx
index 55e4193bffc..6f1510d19a5 100644
--- a/packages/dnb-eufemia/src/components/flex/Container.tsx
+++ b/packages/dnb-eufemia/src/components/flex/Container.tsx
@@ -94,7 +94,7 @@ function FlexContainer(props: Props) {
...rest
} = props
- const childrenArray = React.Children.toArray(children)
+ const childrenArray = wrapChildren(props, children)
const hasHeading = childrenArray.some((child, i) => {
const previousChild = childrenArray?.[i - 1]
return (
@@ -204,6 +204,23 @@ function FlexContainer(props: Props) {
)
}
+function wrapChildren(props: Props, children: React.ReactNode) {
+ return React.Children.toArray(children).map((child) => {
+ if (
+ React.isValidElement(child) &&
+ child.type['_supportsSpacingProps'] === 'children'
+ ) {
+ return React.cloneElement(
+ child,
+ child.props,
+ {child.props.children}
+ )
+ }
+
+ return child
+ })
+}
+
FlexContainer._supportsSpacingProps = true
export default FlexContainer
diff --git a/packages/dnb-eufemia/src/components/flex/__tests__/Container.screenshot.test.ts b/packages/dnb-eufemia/src/components/flex/__tests__/Container.screenshot.test.ts
index 737cc3a94e0..c53e598834f 100644
--- a/packages/dnb-eufemia/src/components/flex/__tests__/Container.screenshot.test.ts
+++ b/packages/dnb-eufemia/src/components/flex/__tests__/Container.screenshot.test.ts
@@ -15,6 +15,15 @@ describe('Flex.Container', () => {
expect(screenshot).toMatchImageSnapshot()
})
+ it('have to match with children', async () => {
+ const screenshot = await makeScreenshot({
+ url: '/uilib/layout/flex/container/demos',
+ selector:
+ '[data-visual-test="flex-container-with-children"] .dnb-flex-container',
+ })
+ expect(screenshot).toMatchImageSnapshot()
+ })
+
it('have to match field on large viewport', async () => {
const screenshot = await makeScreenshot({
url: '/uilib/layout/flex/container/demos',
diff --git a/packages/dnb-eufemia/src/components/flex/__tests__/Container.test.tsx b/packages/dnb-eufemia/src/components/flex/__tests__/Container.test.tsx
index 241f1d24fcf..87716ff7712 100644
--- a/packages/dnb-eufemia/src/components/flex/__tests__/Container.test.tsx
+++ b/packages/dnb-eufemia/src/components/flex/__tests__/Container.test.tsx
@@ -346,21 +346,8 @@ describe('Flex.Container', () => {
expect(children[2].className).toContain('dnb-space__right--zero')
})
- it('should set element', () => {
- render(content)
-
- const element = document.querySelector('.dnb-flex-container')
-
- expect(element.tagName).toBe('SECTION')
- })
-
it('should not add a wrapper when _supportsSpacingProps is given', () => {
- const { rerender } = render(
-
- content
- content
-
- )
+ const { rerender } = render(<>>)
const TestComponent = (props: SpaceProps) => {
const cn = createSpacingClasses(props)
@@ -417,6 +404,155 @@ describe('Flex.Container', () => {
}
})
+ it('should transform children if _supportsSpacingProps="children" is given', () => {
+ const { rerender } = render(<>>)
+
+ const Wrapper = ({ children }) => {
+ return {children}
+ }
+
+ const TestComponent = (props: SpaceProps) => {
+ const cn = createSpacingClasses(props)
+ cn.push('test-item')
+ return content
+ }
+
+ {
+ rerender(
+
+
+
+
+
+
+ )
+
+ const elements = document.querySelectorAll(
+ '.dnb-flex-container > div'
+ )
+ expect(elements).toHaveLength(1)
+ expect(elements[0].className).toBe(
+ 'dnb-space dnb-space__top--zero dnb-space__bottom--zero'
+ )
+ expect((elements[0].firstChild as HTMLElement).className).toBe(
+ 'wrapper'
+ )
+ }
+
+ {
+ Wrapper._supportsSpacingProps = 'children'
+
+ rerender(
+
+
+
+
+
+
+ )
+
+ {
+ const elements = Array.from(
+ document.querySelectorAll('.dnb-flex-container > div')
+ )
+
+ expect(elements).toHaveLength(3)
+ expect(elements[0]).toHaveClass(
+ 'dnb-space dnb-space__top--zero dnb-space__bottom--zero'
+ )
+ expect(elements[1]).toHaveClass(
+ 'dnb-space dnb-space__top--zero dnb-space__bottom--zero'
+ )
+ expect(elements[2]).toHaveClass(
+ 'dnb-space dnb-space__top--large dnb-space__bottom--zero'
+ )
+ }
+
+ {
+ const elements = Array.from(
+ document.querySelectorAll('.dnb-flex-container > div > div')
+ )
+
+ expect(elements).toHaveLength(3)
+ expect(elements[0]).toHaveClass('wrapper')
+ expect(elements[1]).toHaveClass('test-item')
+ expect(elements[2]).toHaveClass('test-item')
+ }
+
+ {
+ const elements = Array.from(
+ document.querySelectorAll('.dnb-flex-container')
+ )
+
+ expect(elements).toHaveLength(2)
+ }
+
+ {
+ const elements = Array.from(
+ document.querySelectorAll(
+ 'body > div > .dnb-flex-container > div'
+ )
+ )
+
+ expect(elements).toHaveLength(1)
+ expect(elements[0]).toHaveClass(
+ 'dnb-space dnb-space__top--zero dnb-space__bottom--zero'
+ )
+ }
+ }
+
+ {
+ TestComponent._supportsSpacingProps = true
+
+ rerender(
+
+
+
+
+
+
+ )
+
+ {
+ const elements = Array.from(
+ document.querySelectorAll(
+ 'body > div > .dnb-flex-container > div'
+ )
+ )
+
+ expect(elements).toHaveLength(1)
+ expect(elements[0]).toHaveClass(
+ 'dnb-space dnb-space__top--zero dnb-space__bottom--zero'
+ )
+ }
+
+ {
+ const elements = Array.from(
+ document.querySelectorAll('.dnb-flex-container > div')
+ )
+
+ expect(elements).toHaveLength(3)
+ expect(elements[0]).toHaveClass(
+ 'dnb-space dnb-space__top--zero dnb-space__bottom--zero'
+ )
+ expect(elements[1]).toHaveClass(
+ 'dnb-space__top--zero dnb-space__bottom--zero test-item'
+ )
+ expect(elements[2]).toHaveClass(
+ 'dnb-space__top--x-large dnb-space__bottom--zero test-item'
+ )
+ }
+ }
+ })
+
+ it('should set custom element', () => {
+ render(content)
+
+ const element = document.querySelector('.dnb-flex-container')
+
+ expect(element.tagName).toBe('SECTION')
+ })
+
it('gets valid ref element', () => {
let ref: React.RefObject
diff --git a/packages/dnb-eufemia/src/components/flex/__tests__/__image_snapshots__/flexcontainer-have-to-match-with-children.snap.png b/packages/dnb-eufemia/src/components/flex/__tests__/__image_snapshots__/flexcontainer-have-to-match-with-children.snap.png
new file mode 100644
index 00000000000..e2762c6f2b3
Binary files /dev/null and b/packages/dnb-eufemia/src/components/flex/__tests__/__image_snapshots__/flexcontainer-have-to-match-with-children.snap.png differ
diff --git a/packages/dnb-eufemia/src/components/flex/export.ts b/packages/dnb-eufemia/src/components/flex/export.ts
index 3d924cf3197..e2d17f2b69a 100644
--- a/packages/dnb-eufemia/src/components/flex/export.ts
+++ b/packages/dnb-eufemia/src/components/flex/export.ts
@@ -3,3 +3,4 @@ export { default as Item } from './Item'
export { default as Stack } from './Stack'
export { default as Horizontal } from './Horizontal'
export { default as Vertical } from './Vertical'
+export { default as withChildren } from './withChildren'
diff --git a/packages/dnb-eufemia/src/components/flex/stories/Flex.stories.tsx b/packages/dnb-eufemia/src/components/flex/stories/Flex.stories.tsx
new file mode 100644
index 00000000000..4c6dc806966
--- /dev/null
+++ b/packages/dnb-eufemia/src/components/flex/stories/Flex.stories.tsx
@@ -0,0 +1,28 @@
+/**
+ * @dnb/eufemia Component Story
+ *
+ */
+
+import { TestElement } from '../../../extensions/forms'
+import Flex from '../Flex'
+
+export default {
+ title: 'Eufemia/Components/Flex',
+}
+
+const Wrapper = Flex.withChildren(({ children }) => {
+ return {children}
+})
+
+export function FlexWithChildren() {
+ return (
+
+ FlexItem 1
+
+ FlexItem 2
+ FlexItem 3
+
+ FlexItem 4
+
+ )
+}
diff --git a/packages/dnb-eufemia/src/components/flex/withChildren.tsx b/packages/dnb-eufemia/src/components/flex/withChildren.tsx
new file mode 100644
index 00000000000..73b5933789f
--- /dev/null
+++ b/packages/dnb-eufemia/src/components/flex/withChildren.tsx
@@ -0,0 +1,14 @@
+import React from 'react'
+
+type WithChildrenProps = {
+ children?: React.ReactNode
+}
+
+function withChildren(
+ Component: React.ComponentType
+): React.ComponentType {
+ Component['_supportsSpacingProps'] = 'children'
+ return Component
+}
+
+export default withChildren
diff --git a/packages/dnb-eufemia/src/extensions/forms/utils/TestElement/TestElement.tsx b/packages/dnb-eufemia/src/extensions/forms/utils/TestElement/TestElement.tsx
index 15649520bba..c5c924e5a1b 100644
--- a/packages/dnb-eufemia/src/extensions/forms/utils/TestElement/TestElement.tsx
+++ b/packages/dnb-eufemia/src/extensions/forms/utils/TestElement/TestElement.tsx
@@ -10,3 +10,5 @@ export default function TestElement({ className = null, ...props }) {
/>
)
}
+
+TestElement._supportsSpacingProps = true