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

feat(Accordion): sbanken theme #2586

Merged
merged 10 commits into from
Sep 4, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
title: 'Accordion'
description: 'The Accordion component is a combination of an accessible button (header area) and a content container.'
showTabs: true
theme: 'sbanken'
---

import AccordionInfo from 'Docs/uilib/components/accordion/info'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
add_medium as AddIcon,
subtract_medium as SubtractIcon,
} from '@dnb/eufemia/src/icons'
import { Accordion, P, IconPrimary, ToggleButton } from '@dnb/eufemia/src'
import { Accordion, P, IconPrimary } from '@dnb/eufemia/src'

export const AccordionDefaultExample = () => (
<ComponentBox data-visual-test="accordion-default">
Expand Down Expand Up @@ -86,118 +86,6 @@ export const AccordionCustomisationExample = () => (
</ComponentBox>
)

export const AccordionContainerExample = () => (
<ComponentBox
hideCode
data-visual-test="accordion-container"
scope={{ ChangingContent }}
>
{() => {
function AccordionWithContainer() {
const ref1 = React.useRef(null)
const ref2 = React.useRef(null)
const [changeHeight] = React.useState(() => ({ ref1, ref2 }))
return (
<Accordion.Group
prevent_rerender
single_container
remember_state
id="remembered-state"
>
<Accordion
bottom
id="remembered-state-1"
title="Title1"
description="Description1"
expanded={true}
>
<Accordion.Header title="Title2" description="Description2">
{/* Title 3 string */}
<Accordion.Header.Title key="title">
Title 3
</Accordion.Header.Title>
<Accordion.Header.Description>
Description 3
</Accordion.Header.Description>
{/* <Accordion.Header.Icon key="icon" /> */}
</Accordion.Header>
<Accordion.Content
left="xx-large"
top="medium"
instance={changeHeight.ref1}
>
<ChangingContent changeHeight={changeHeight.ref1}>
<div
style={{
height: '10rem',
background: 'var(--color-sea-green-30)',
}}
>
<P top bottom="xx-large">
Simulation of content height
</P>
</div>
</ChangingContent>
</Accordion.Content>
</Accordion>
<Accordion icon_position="right" id="remembered-state-2">
<Accordion.Header>
<Accordion.Header.Container>
<IconPrimary icon="bell" />
</Accordion.Header.Container>
<Accordion.Header.Title>
Accordion title
</Accordion.Header.Title>
</Accordion.Header>
<Accordion.Content
left="xx-large"
top="medium"
instance={changeHeight.ref2}
>
<ChangingContent changeHeight={changeHeight.ref2}>
<div
style={{
height: '20rem',
background: 'var(--color-sand-yellow)',
}}
>
<P top bottom="xx-large">
Simulation of content height
</P>
</div>
</ChangingContent>
</Accordion.Content>
</Accordion>
</Accordion.Group>
)
}

return <AccordionWithContainer />
}}
</ComponentBox>
)

function ChangingContent({ changeHeight, children }) {
const [contentSize, changeContentSize] = React.useState(false)
React.useEffect(() => {
changeHeight.current.setContainerHeight()
}, [changeHeight, contentSize])
return (
<>
<ToggleButton
checked={contentSize}
on_change={() => {
changeContentSize((s) => !s)
}}
bottom
>
Toggle content size
</ToggleButton>
{contentSize ? children : null}
</>
)
}

export const AccordionGroupExample = () => (
<ComponentBox data-visual-test="accordion-group">
<Accordion.Group expanded allow_close_all>
Expand Down Expand Up @@ -282,3 +170,27 @@ export const AccordionNestedExample = () => {
</ComponentBox>
)
}

export const AccordionDisabledExample = () => (
<ComponentBox data-visual-test="accordion-disabled">
<Accordion
expanded
disabled
remember_state
title="Disabled (expanded)"
>
<P>I am expanded, but disabled, so I can't be closed</P>
</Accordion>
<Accordion.Provider
top
disabled
remember_state
icon="chevron_down"
icon_position="right"
>
<Accordion title="Disabled (closed)">
<P>You can't see this text because I am disabled and closed.</P>
</Accordion>
</Accordion.Provider>
</ComponentBox>
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
AccordionGroupExample,
AccordionNestedExample,
AccordionPlainVariant,
AccordionDisabledExample,
} from 'Docs/uilib/components/accordion/Examples'

## Demos
Expand All @@ -36,12 +37,12 @@ import {

<AccordionNestedExample />

### Accordion with a single container

A single container is only used for wider screens (desktop). When the users' screen is narrower (mobile), it will change to a normal accordion. The change happens with CSS only, so it will not interrupt any React render.

<AccordionContainerExample />

<VisibleWhenVisualTest>
<AccordionPlainVariant />
</VisibleWhenVisualTest>

### Disabled

Accordion can be disabled, though is not exactly defined what the use case is.

<AccordionDisabledExample />
29 changes: 24 additions & 5 deletions packages/dnb-eufemia/src/components/accordion/AccordionHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
validateDOMAttributes,
extendPropsWithContext,
} from '../../shared/component-helper'
import { useTheme } from '../../shared'
import IconPrimary from '../icon-primary/IconPrimary'
import classnames from 'classnames'
import AccordionContext from './AccordionContext'
Expand All @@ -19,11 +20,10 @@ import {
createSkeletonClass,
} from '../skeleton/SkeletonHelper'

import type { ButtonIconPosition } from '../Button'
import type { HeadingLevel } from '../Heading'
import type { IconSize } from '../Icon'
import type { SkeletonShow } from '../Skeleton'
import type { AccordionIcon } from './Accordion'
import type { AccordionIcon, AccordionIconPosition } from './Accordion'

export type AccordionHeaderTitleProps = SpacingProps & {
children?: React.ReactNode
Expand Down Expand Up @@ -97,15 +97,33 @@ export type AccordionHeaderIconProps = {
icon?: AccordionHeaderIconIcon
size?: IconSize
expanded?: boolean
icon_position?: AccordionIconPosition
}

function AccordionHeaderIcon({
icon,
expanded,
size = 'medium',
icon_position,
}: AccordionHeaderIconProps) {
const theme = useTheme()
let animateIcon = true
if (!icon && theme?.name === 'sbanken') {
animateIcon = false
icon = {
expanded: 'subtract-medium',
closed: 'add-medium',
}
}

return (
<span className="dnb-accordion__header__icon">
<span
className={classnames(
'dnb-accordion__header__icon',
!animateIcon && 'dnb-accordion__header__icon--no-animation',
icon_position && `dnb-accordion__header__icon--${icon_position}`,
)}
>
<IconPrimary
size={size}
// There has to be a better way than to do so much casting
Expand Down Expand Up @@ -163,7 +181,7 @@ export type AccordionHeaderProps = React.HTMLProps<HTMLElement> &
heading?: AccordionHeaderHeading
heading_level?: HeadingLevel
icon?: AccordionIcon
icon_position?: ButtonIconPosition
icon_position?: AccordionIconPosition
icon_size?: IconSize
disabled?: boolean
skeleton?: SkeletonShow
Expand Down Expand Up @@ -273,6 +291,7 @@ export const AccordionHeader = ({
icon={icon}
size={icon_size}
expanded={context.expanded}
icon_position={icon_position}
/>,
<AccordionHeaderContainer key="container">
{left_component as React.ReactNode}
Expand Down Expand Up @@ -360,7 +379,7 @@ export const AccordionHeader = ({
tabIndex: 0,
className: classnames(
'dnb-accordion__header',
icon_position && `dnb-accordion__header__icon--${icon_position}`,
icon_position && `dnb-accordion__header--icon-${icon_position}`,
isHoverring && hasClicked && 'dnb-accordion--hover',
!canClick() && 'dnb-accordion__header--prevent-click',
description && 'dnb-accordion__header--description',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import {
setupPageScreenshot,
} from '../../../core/jest/jestSetupScreenshots'

describe('Accordion', () => {
describe.each(['ui', 'sbanken'])('Accordion for %s', (themeName) => {
setupPageScreenshot({
themeName,
url: '/uilib/components/accordion/demos',
each: true,
})
Expand Down Expand Up @@ -92,14 +93,6 @@ describe('Accordion', () => {
expect(screenshot).toMatchImageSnapshot()
})

it('have to match in desktop mode', async () => {
const screenshot = await makeScreenshot({
style: { width: '40rem', 'min-height': '15rem' },
selector: '[data-visual-test="accordion-container"]',
})
expect(screenshot).toMatchImageSnapshot()
})

it('have to match in first state', async () => {
const screenshot = await makeScreenshot({
style: { width: '30rem', height: '20rem' },
Expand All @@ -126,21 +119,11 @@ describe('Accordion', () => {
})
expect(screenshot).toMatchImageSnapshot()
})
})

describe('Accordion container', () => {
setupPageScreenshot({
url: '/uilib/components/accordion/demos',
pageViewport: {
width: 400,
height: 600,
},
})

it('have to match in mobile mode', async () => {
it('have to match disabled state', async () => {
const screenshot = await makeScreenshot({
style: { width: '22rem', 'min-height': '15rem' },
selector: '[data-visual-test="accordion-container"]',
style: { width: '20rem', height: '15rem' },
selector: '[data-visual-test="accordion-disabled"]',
})
expect(screenshot).toMatchImageSnapshot()
})
Expand Down
Binary file not shown.
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.
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.
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.
Binary file not shown.
Loading