Skip to content

Commit

Permalink
fix(Tabs): fix error with a single Tabs.Content as children (#2534)
Browse files Browse the repository at this point in the history
  • Loading branch information
langz authored Jul 27, 2023
1 parent 89c3dce commit 215e52c
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -338,3 +338,27 @@ export const TabsNoBorder = () => (
</ComponentBox>
</Wrapper>
)

export const TabsSingleChildrenReactElement = () =>
!globalThis.IS_TEST ? null : (
<Wrapper>
<ComponentBox data-visual-test="tabs-single-children-react-element">
<Tabs>
<Tabs.Content title="First">
<div>hello1</div>
</Tabs.Content>
</Tabs>
</ComponentBox>
</Wrapper>
)

export const TabsSingleElementData = () =>
!globalThis.IS_TEST ? null : (
<Wrapper>
<ComponentBox data-visual-test="tabs-single-element-data">
<Tabs
data={[{ title: 'First', key: 1, content: <div>hello1</div> }]}
/>
</ComponentBox>
</Wrapper>
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
TabsExampleReachRouterNavigation,
TabsNoBorder,
TabsExamplePrerender,
TabsSingleChildrenReactElement,
TabsSingleElementData,
} from 'Docs/uilib/components/tabs/Examples'

## Demos
Expand Down Expand Up @@ -86,3 +88,6 @@ const exampleContent = {
fourth: 'Fourth as a string only',
}
```

<TabsSingleChildrenReactElement />
<TabsSingleElementData />
87 changes: 51 additions & 36 deletions packages/dnb-eufemia/src/components/tabs/Tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,56 +199,71 @@ export default class Tabs extends React.PureComponent {
}

static getData(props) {
const addReactElement = (list, reactElem, reactElemIndex) => {
if (
reactElem.props &&
reactElem.props.displayName === 'CustomContent' // we use this solution, as Component.displayName
) {
// tabs data from main prop
const dataProps =
(props.tabs &&
Array.isArray(props.tabs) &&
props.tabs[reactElemIndex]) ||
{}

// props from the "CustomContent" Component
const componentProps = { ...reactElem.props }
if (componentProps.title === null) {
delete componentProps.title
}

const {
title,
key: _key,
hash,
...rest
} = {
...dataProps,
...componentProps,
...{ children: null }, // remove children, if there is some
}

list.push({
title,
key: (!_key && hash ? hash : _key) || slugify(title),
content: reactElem, // can be a Node or a Function
...rest,
})
}
}

let res = []

// check if we have to use the children prop to prepare our data
const data =
!props.data && props.children ? props.children : props.data

// if it is a React Component - collect data from Tabs.Content component
// if it is an array of React Components - collect data from Tabs.Content component
if (
Array.isArray(props.children) &&
(typeof props.children[0] === 'function' ||
React.isValidElement(props.children[0]))
) {
res = props.children.reduce((acc, content, i) => {
if (
content.props &&
content.props.displayName === 'CustomContent' // we use this solution, as Component.displayName
) {
// tabs data from main prop
const dataProps =
(props.tabs && Array.isArray(props.tabs) && props.tabs[i]) ||
{}

// props from the "CustomContent" Component
const componentProps = { ...content.props }
if (componentProps.title === null) {
delete componentProps.title
}

const {
title,
key: _key,
hash,
...rest
} = {
...dataProps,
...componentProps,
...{ children: null }, // remove children, if there is some
}

acc.push({
title,
key: (!_key && hash ? hash : _key) || slugify(title),
content, // can be a Node or a Function
...rest,
})
}
return acc
res = props.children.reduce((list, reactElem, i) => {
addReactElement(list, reactElem, i)
return list
}, [])
}

// if it is a single React Component - collect data from Tabs.Content component
if (
!Array.isArray(props.children) &&
(typeof props.children === 'function' ||
React.isValidElement(props.children))
) {
addReactElement(res, props.children)
}

// continue, while the children didn't contain our data
if (!(res && res.length > 0)) {
// if data is array, it looks good!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ describe('Tabs', () => {
expect(screenshot).toMatchImageSnapshot()
})

it('have to match when used with a single children as react element', async () => {
const screenshot = await makeScreenshot({
selector: '[data-visual-test="tabs-single-children-react-element"]',
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match when used with a single element in data', async () => {
const screenshot = await makeScreenshot({
selector: '[data-visual-test="tabs-single-element-data"]',
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match a tablist with a click handler', async () => {
const screenshot = await makeScreenshot({
selector: '[data-visual-test="tabs-clickhandler"] .dnb-tabs__tabs',
Expand Down
36 changes: 36 additions & 0 deletions packages/dnb-eufemia/src/components/tabs/__tests__/Tabs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,42 @@ describe('A single Tab component', () => {
expect(testKey).toBe('third')
})

it('has to work with "Tabs.Content" as a single children', () => {
render(
<Tabs>
<Tabs.Content title="single title">
<div>single</div>
</Tabs.Content>
</Tabs>
)

expect(
document.querySelector('div.dnb-tabs__content__inner').textContent
).toBe('single')
expect(
document.querySelector('button span.dnb-tabs__button__title')
.textContent
).toBe('single title')
})

it('has to work with a single element for data property', () => {
render(
<Tabs
data={[
{ title: 'single title', key: 1, content: <div>single</div> },
]}
/>
)

expect(
document.querySelector('div.dnb-tabs__content').textContent
).toBe('single')
expect(
document.querySelector('button span.dnb-tabs__button__title')
.textContent
).toBe('single title')
})

it('should render in StrictMode', () => {
render(
<React.StrictMode>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 12 additions & 2 deletions packages/dnb-eufemia/src/components/tabs/stories/Tabs.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,20 @@ export const TabsSandbox = () => {
<Box>
<Tabs tabs_style="mint-green" content_style="black-3">
<Tabs.Content title="First">
<H2>First</H2>
<div>hello1</div>
</Tabs.Content>
</Tabs>
<Tabs
tabs_style="mint-green"
content_style="black-3"
data={[{ title: 'First', key: 1, content: <div>hello1</div> }]}
/>
<Tabs tabs_style="mint-green" content_style="black-3">
<Tabs.Content title="First">
<div>hello1</div>
</Tabs.Content>
<Tabs.Content title="Second">
<H2>Second</H2>
<div>hello2</div>
</Tabs.Content>
</Tabs>
</Box>
Expand Down

1 comment on commit 215e52c

@vercel
Copy link

@vercel vercel bot commented on 215e52c Jul 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.