Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Breadcrumb): fix rehydration disturbance #3254

Merged
merged 1 commit into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -757,18 +757,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
Loading