Skip to content

Commit

Permalink
fix(Breadcrumb): fix rehydration disturbance (#3254)
Browse files Browse the repository at this point in the history
This PR #2762 was originally merged into #2671 – and was with that never
merged into main.
  • Loading branch information
tujoworker authored Jan 22, 2024
1 parent 07e1545 commit dcf3a8b
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 93 deletions.
89 changes: 41 additions & 48 deletions packages/dnb-eufemia/src/components/breadcrumb/Breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import Section, {
import Button from '../button/Button'

// Shared
import { useMediaQuery } from '../../shared'
import Context from '../../shared/Context'
import type { SpacingProps } from '../../shared/types'
import type { SkeletonShow } from '../skeleton/Skeleton'
Expand Down Expand Up @@ -174,15 +173,11 @@ const Breadcrumb = (localProps: BreadcrumbProps & SpacingProps) => {
const spacingClasses = createSpacingClasses(props)

const [isCollapsed, setCollapse] = useState(overrideIsCollapsed)
const isSmallScreen = useMediaQuery({
matchOnSSR: true,
when: { max: 'medium' },
})

let currentVariant = variant
if (!variant) {
if (items || data) {
currentVariant = isSmallScreen ? 'collapse' : 'multiple'
currentVariant = 'multiple'
} else {
currentVariant = 'single'
}
Expand All @@ -201,6 +196,7 @@ const Breadcrumb = (localProps: BreadcrumbProps & SpacingProps) => {
aria-label={convertJsxToString(navText)}
className={classnames(
'dnb-breadcrumb',
`dnb-breadcrumb--variant-${currentVariant}`,
skeletonClasses,
spacingClasses,
className
Expand All @@ -212,23 +208,7 @@ const Breadcrumb = (localProps: BreadcrumbProps & SpacingProps) => {
style_type={styleType || 'transparent'}
spacing={innerSpacing}
>
{currentVariant === 'collapse' && (
<Button
text={backToText}
variant="tertiary"
icon="chevron_left"
icon_position="left"
onClick={
onClick ||
(() => {
setCollapse(!isCollapsed)
})
}
aria-expanded={!isCollapsed}
/>
)}

{currentVariant === 'single' && (
{currentVariant === 'single' ? (
<Button
text={goBackText}
variant="tertiary"
Expand All @@ -237,39 +217,52 @@ const Breadcrumb = (localProps: BreadcrumbProps & SpacingProps) => {
onClick={onClick}
href={href}
/>
)}

{currentVariant === 'multiple' && (
<BreadcrumbMultiple
data={data}
items={items}
isCollapsed={false}
noAnimation={noAnimation}
/>
) : (
<>
<Button
className="dnb-breadcrumb__toggle"
text={backToText}
variant="tertiary"
icon="chevron_left"
icon_position="left"
onClick={
onClick ||
(() => {
setCollapse(!isCollapsed)
})
}
aria-expanded={!isCollapsed}
/>

{currentVariant !== 'collapse' && (
<BreadcrumbMultiple
data={data}
items={items}
isCollapsed={false}
noAnimation={noAnimation}
/>
)}
</>
)}
</Section>

{currentVariant === 'collapse' && (
<Section
variant={collapsedStyleType}
className="dnb-breadcrumb__collapse"
>
<BreadcrumbMultiple
data={data}
items={items}
isCollapsed={isCollapsed}
noAnimation={noAnimation}
/>
</Section>
)}
<Section
variant={collapsedStyleType}
className="dnb-breadcrumb__collapse"
>
<BreadcrumbMultiple
data={data}
items={items}
isCollapsed={isCollapsed}
noAnimation={noAnimation}
/>
</Section>
</nav>
)
}

Breadcrumb.Item = BreadcrumbItem

export { BreadcrumbItem }

Breadcrumb._supportsSpacingProps = true

export { BreadcrumbItem }
export default Breadcrumb
32 changes: 23 additions & 9 deletions packages/dnb-eufemia/src/components/breadcrumb/BreadcrumbItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import {
filterProps,
} from '../../shared/component-helper'

// SSR warning fix: https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85
const useLayoutEffect =
typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect

export type BreadcrumbItemProps = {
/**
* Text displaying the title of the item's corresponding page
Expand Down Expand Up @@ -116,11 +120,19 @@ const BreadcrumbItem = (localProps: BreadcrumbItemProps) => {
when: { max: 'medium' },
})

let currentIcon =
icon || (variant === 'home' && homeIcon) || 'chevron_left'
if (theme?.name === 'sbanken') {
currentIcon = icon || determineSbankenIcon(variant, isSmallScreen)
}
const [currentIcon, setCurrentIcon] = React.useState(null)

useLayoutEffect(() => {
if (!icon && theme?.name === 'sbanken') {
const currentIcon = determineSbankenIcon(variant, isSmallScreen)
setCurrentIcon(currentIcon)
} else {
setCurrentIcon(
icon || (variant === 'home' && homeIcon) || 'chevron_left'
)
}
}, [icon, isSmallScreen, theme?.name, variant])

const currentText = text || (variant === 'home' && homeText) || ''
const isInteractive =
(href || onClick || props.to) && variant !== 'current'
Expand Down Expand Up @@ -149,10 +161,12 @@ const BreadcrumbItem = (localProps: BreadcrumbItemProps) => {
// TODO: Consider deprecating passing down props to span in v11
{...filterProps(props, (key) => !key.includes('-'))}
>
<IconPrimary
icon={currentIcon}
className="dnb-breadcrumb__item__span__icon"
/>
{currentIcon && (
<IconPrimary
icon={currentIcon}
className="dnb-breadcrumb__item__span__icon"
/>
)}
<P space="0">{currentText}</P>
</span>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const BreadcrumbMultiple = ({
<HeightAnimation
open={!isCollapsed}
animate={!noAnimation}
className="dnb-breadcrumb__animation"
className="dnb-breadcrumb__multiple"
>
<Section
className="dnb-breadcrumb__list"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@ import React from 'react'
import { fireEvent, render, screen } from '@testing-library/react'
import Breadcrumb, { BreadcrumbItem, BreadcrumbProps } from '../Breadcrumb'
import { Provider } from '../../../shared'
import MatchMediaMock from 'jest-matchmedia-mock'
import IconPrimary from '../../icon-primary/IconPrimary'
import { loadScss, axeComponent } from '../../../core/jest/jestSetup'
import { BreadcrumbItemProps } from '../BreadcrumbItem'
import { AnchorAllProps } from '../../Anchor'

const matchMedia = new MatchMediaMock()

describe('Breadcrumb', () => {
it('renders without properties', () => {
const props: BreadcrumbProps = {}
Expand Down Expand Up @@ -60,9 +57,7 @@ describe('Breadcrumb', () => {
)

expect(screen.queryByTestId(dataTestId)).toBeInTheDocument()
expect(screen.queryByTestId(dataTestId).className).toMatch(
'dnb-button'
)
expect(screen.queryByTestId(dataTestId)).toHaveClass('dnb-button')
})

// TODO – can be removed in v11 when we deprecate passing down props to dnb-breadcrumb__item__span
Expand All @@ -81,7 +76,7 @@ describe('Breadcrumb', () => {
)

expect(screen.queryByTestId(dataTestId)).toBeInTheDocument()
expect(screen.queryByTestId(dataTestId).className).toMatch(
expect(screen.queryByTestId(dataTestId)).toHaveClass(
'dnb-breadcrumb__item__span'
)
expect(
Expand Down Expand Up @@ -178,13 +173,13 @@ describe('Breadcrumb', () => {
)

expect(
document.querySelector('.dnb-breadcrumb__animation')
document.querySelector('.dnb-breadcrumb__multiple')
).not.toBeInTheDocument()

fireEvent.click(screen.getByRole('button'))

expect(
document.querySelector('.dnb-breadcrumb__animation')
document.querySelector('.dnb-breadcrumb__multiple')
).not.toBeInTheDocument()
})

Expand Down Expand Up @@ -224,8 +219,6 @@ describe('Breadcrumb', () => {
})

it('variant collapse opens the collapsed content on click', () => {
matchMedia.useMediaQuery('(max-width: 60em)')

render(
<Breadcrumb
data={[
Expand All @@ -239,20 +232,18 @@ describe('Breadcrumb', () => {
fireEvent.click(screen.getByRole('button'))

expect(
document.querySelector('.dnb-breadcrumb__animation')
document.querySelector('.dnb-breadcrumb__multiple')
).toBeDefined()
})

it('inherits skeleton prop from provider', () => {
const skeletonClassName = 'dnb-skeleton'

render(
<Provider skeleton>
<Breadcrumb data={[{ onClick: jest.fn(), text: 'Page 1' }]} />
</Provider>
)

expect(screen.getByRole('button').className).toMatch(skeletonClassName)
expect(screen.getAllByRole('button')[0]).toHaveClass('dnb-skeleton')
})

it('should support spacing props', () => {
Expand All @@ -275,6 +266,7 @@ describe('Breadcrumb', () => {
expect(attributes).toEqual(['aria-label', 'class'])
expect(Array.from(element.classList)).toEqual([
'dnb-breadcrumb',
'dnb-breadcrumb--variant-multiple',
'dnb-space__top--large',
])
})
Expand Down Expand Up @@ -365,29 +357,21 @@ describe('Breadcrumb', () => {
})

it('renders a skeleton if skeleton is true', () => {
const skeletonClassName = 'dnb-skeleton'

render(
<BreadcrumbItem skeleton onClick={jest.fn()} text="skeleton" />
)

expect(screen.getByRole('button').className).toMatch(
skeletonClassName
)
expect(screen.getByRole('button')).toHaveClass('dnb-skeleton')
})

it('inherits skeleton prop from provider', () => {
const skeletonClassName = 'dnb-skeleton'

render(
<Provider skeleton>
<BreadcrumbItem onClick={jest.fn()} text="skeleton" />
</Provider>
)

expect(screen.getByRole('button').className).toMatch(
skeletonClassName
)
expect(screen.getByRole('button')).toHaveClass('dnb-skeleton')
})

it('forwards rest props like data-testid, etc, to the breadcrumb item button when interactive', () => {
Expand All @@ -398,9 +382,7 @@ describe('Breadcrumb', () => {

expect(screen.queryByTestId(dataTestId)).toBeInTheDocument()

expect(screen.queryByTestId(dataTestId).className).toMatch(
'dnb-button'
)
expect(screen.queryByTestId(dataTestId)).toHaveClass('dnb-button')
})

// TODO – can be removed in v11 when we deprecate passing down props to dnb-breadcrumb__item__span
Expand All @@ -415,7 +397,7 @@ describe('Breadcrumb', () => {
)

expect(screen.queryByTestId(dataTestId)).toBeInTheDocument()
expect(screen.queryByTestId(dataTestId).className).toMatch(
expect(screen.queryByTestId(dataTestId)).toHaveClass(
'dnb-breadcrumb__item__span'
)
expect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -758,18 +758,28 @@ button.dnb-button::-moz-focus-inner {
.dnb-breadcrumb__item__span__icon {
margin-right: 0.5rem;
}
.dnb-breadcrumb__animation {
.dnb-breadcrumb__multiple {
display: flex;
flex-direction: column;
transition: height 400ms var(--easing-default);
}
.dnb-breadcrumb__animation .dnb-breadcrumb__item {
.dnb-breadcrumb__multiple .dnb-breadcrumb__item {
transition: transform 400ms var(--easing-default) calc(var(--delay) * 50ms);
transform: translateX(-1rem);
}
.dnb-breadcrumb__animation.dnb-height-animation--parallax .dnb-breadcrumb__item {
.dnb-breadcrumb__multiple.dnb-height-animation--parallax .dnb-breadcrumb__item {
transform: translateX(0);
}
@media screen and (max-width: 60em) {
.dnb-breadcrumb__bar .dnb-breadcrumb__multiple {
display: none;
}
}
@media screen and (min-width: 60em) {
.dnb-breadcrumb--variant-multiple .dnb-breadcrumb__toggle {
display: none;
}
}
.dnb-breadcrumb__collapse {
display: flex;
flex-direction: column;
Expand Down
Loading

0 comments on commit dcf3a8b

Please sign in to comment.