-
Notifications
You must be signed in to change notification settings - Fork 178
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(components): listButton and accordion children creation #15967
Merged
Merged
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import * as React from 'react' | ||
|
||
import { ListButton as ListButtonComponent } from './index' | ||
import { | ||
ListButtonAccordion, | ||
ListButtonAccordionContainer, | ||
ListButtonRadioButton, | ||
} from './ListButtonChildren/index' | ||
import { StyledText } from '../..' | ||
import type { Meta, StoryObj } from '@storybook/react' | ||
|
||
const meta: Meta<typeof ListButtonComponent> = { | ||
title: 'Library/Atoms/ListButton', | ||
component: ListButtonComponent, | ||
argTypes: { | ||
type: { | ||
control: { | ||
type: 'select', | ||
options: ['noActive', 'success', 'warning'], | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
export default meta | ||
|
||
type Story = StoryObj<typeof ListButtonComponent> | ||
|
||
const Template = (args: any): JSX.Element => { | ||
jerader marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const [containerExpand, setContainerExpand] = React.useState<boolean>(false) | ||
const [buttonValue, setButtonValue] = React.useState<string | null>(null) | ||
const [nestedButtonValue, setNestedButtonValue] = React.useState< | ||
string | null | ||
>(null) | ||
|
||
return ( | ||
<ListButtonComponent | ||
{...args} | ||
onClick={() => { | ||
setContainerExpand(!containerExpand) | ||
}} | ||
> | ||
<ListButtonAccordion | ||
key="main" | ||
mainHeadline="Main heading" | ||
headline="accordion heading" | ||
isExpanded={containerExpand} | ||
> | ||
<ListButtonAccordionContainer id="mainAccordionContainer"> | ||
<> | ||
<ListButtonRadioButton | ||
key="buttonNested" | ||
isSelected={buttonValue === 'radio button nested'} | ||
buttonValue="radio button nested" | ||
buttonText="Radio button with nested" | ||
onChange={e => { | ||
e.stopPropagation() | ||
setButtonValue('radio button nested') | ||
}} | ||
/> | ||
|
||
{buttonValue === 'radio button nested' ? ( | ||
<ListButtonAccordionContainer id="nestedAccordionContainer"> | ||
<ListButtonAccordion | ||
key="child" | ||
isNested | ||
headline="nested accordion heading" | ||
isExpanded={buttonValue === 'radio button nested'} | ||
> | ||
<> | ||
<ListButtonRadioButton | ||
isSelected={nestedButtonValue === 'radio button1'} | ||
buttonValue="radio button1" | ||
buttonText="nested button" | ||
onChange={() => { | ||
setNestedButtonValue('radio button1') | ||
}} | ||
/> | ||
{nestedButtonValue === 'radio button1' ? ( | ||
<StyledText desktop="bodyDefaultRegular"> | ||
Nested button option | ||
</StyledText> | ||
) : null} | ||
</> | ||
<ListButtonRadioButton | ||
isSelected={nestedButtonValue === 'radio button2'} | ||
buttonValue="radio button2" | ||
buttonText="nested button 2" | ||
onChange={() => { | ||
setNestedButtonValue('radio button2') | ||
}} | ||
/> | ||
<ListButtonRadioButton | ||
isSelected={nestedButtonValue === 'radio button3'} | ||
buttonValue="radio button3" | ||
buttonText="nested button 3" | ||
onChange={() => { | ||
setNestedButtonValue('radio button3') | ||
}} | ||
/> | ||
</ListButtonAccordion> | ||
</ListButtonAccordionContainer> | ||
) : null} | ||
</> | ||
<> | ||
<ListButtonRadioButton | ||
key="buttonNonNested" | ||
isSelected={buttonValue === 'radio button non nest'} | ||
buttonValue="radio button non nest" | ||
buttonText="Radio button without nested" | ||
onChange={() => { | ||
setButtonValue('radio button non nest') | ||
}} | ||
/> | ||
|
||
{buttonValue === 'radio button non nest' ? ( | ||
<StyledText desktop="bodyDefaultRegular"> | ||
Non nested button option | ||
</StyledText> | ||
) : null} | ||
</> | ||
</ListButtonAccordionContainer> | ||
</ListButtonAccordion> | ||
</ListButtonComponent> | ||
) | ||
} | ||
export const ListButton: Story = { | ||
render: Template, | ||
args: { | ||
type: 'noActive', | ||
}, | ||
} |
59 changes: 59 additions & 0 deletions
59
components/src/atoms/ListButton/ListButtonChildren/ListButtonAccordion.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import * as React from 'react' | ||
import { Flex } from '../../../primitives' | ||
import { DIRECTION_COLUMN } from '../../../styles' | ||
import { SPACING } from '../../../ui-style-constants' | ||
import { StyledText } from '../../StyledText' | ||
|
||
interface ListButtonAccordionProps { | ||
headline: string | ||
children: React.ReactNode | ||
// determines if the accordion is expanded or not | ||
jerader marked this conversation as resolved.
Show resolved
Hide resolved
|
||
isExpanded?: boolean | ||
// is it nested into another accordion? | ||
jerader marked this conversation as resolved.
Show resolved
Hide resolved
|
||
isNested?: boolean | ||
// optional main headline for the top level accordion | ||
jerader marked this conversation as resolved.
Show resolved
Hide resolved
|
||
mainHeadline?: string | ||
} | ||
|
||
/* | ||
To be used with ListButton, ListButtonAccordion and ListButtonRadioButton | ||
This is the accordion component to use both as just an accordion or nested accordion | ||
**/ | ||
export function ListButtonAccordion( | ||
props: ListButtonAccordionProps | ||
): JSX.Element { | ||
const { | ||
headline, | ||
children, | ||
mainHeadline, | ||
isExpanded = false, | ||
isNested = false, | ||
} = props | ||
|
||
return ( | ||
<Flex flexDirection={DIRECTION_COLUMN} width="100%"> | ||
{mainHeadline != null ? ( | ||
<Flex marginBottom={isExpanded ? SPACING.spacing40 : '0'}> | ||
<StyledText desktopStyle="bodyDefaultSemiBold"> | ||
{mainHeadline} | ||
</StyledText> | ||
</Flex> | ||
) : null} | ||
{isExpanded ? ( | ||
<Flex | ||
marginTop={isNested ? SPACING.spacing4 : '0'} | ||
flexDirection={DIRECTION_COLUMN} | ||
gridGap={SPACING.spacing4} | ||
marginLeft={isNested ? SPACING.spacing40 : '0'} | ||
> | ||
<Flex marginBottom={SPACING.spacing4}> | ||
<StyledText desktopStyle="bodyDefaultSemiBold"> | ||
{headline} | ||
</StyledText> | ||
</Flex> | ||
<Flex flexDirection={DIRECTION_COLUMN}>{children}</Flex> | ||
</Flex> | ||
) : null} | ||
</Flex> | ||
) | ||
} |
29 changes: 29 additions & 0 deletions
29
components/src/atoms/ListButton/ListButtonChildren/ListButtonAccordionContainer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import * as React from 'react' | ||
import { Flex } from '../../../primitives' | ||
import { DIRECTION_COLUMN } from '../../../styles' | ||
|
||
interface ListButtonAccordionContainerProps { | ||
children: React.ReactNode | ||
id: string | ||
} | ||
/* | ||
To be used with ListButtonAccordion to stop propagation since multiple | ||
layers have a CTA | ||
**/ | ||
export function ListButtonAccordionContainer( | ||
props: ListButtonAccordionContainerProps | ||
): JSX.Element { | ||
const { id, children } = props | ||
|
||
return ( | ||
<Flex | ||
key={id} | ||
flexDirection={DIRECTION_COLUMN} | ||
onClick={(e: React.MouseEvent) => { | ||
e.stopPropagation() | ||
}} | ||
> | ||
{children} | ||
</Flex> | ||
) | ||
} |
84 changes: 84 additions & 0 deletions
84
components/src/atoms/ListButton/ListButtonChildren/ListButtonRadioButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import * as React from 'react' | ||
import styled, { css } from 'styled-components' | ||
import { SPACING } from '../../../ui-style-constants' | ||
import { BORDERS, COLORS } from '../../../helix-design-system' | ||
import { Flex } from '../../../primitives' | ||
import { StyledText } from '../../StyledText' | ||
|
||
import type { StyleProps } from '../../../primitives' | ||
|
||
interface ListButtonRadioButtonProps extends StyleProps { | ||
buttonText: string | ||
buttonValue: string | number | ||
onChange: React.ChangeEventHandler<HTMLInputElement> | ||
disabled?: boolean | ||
isSelected?: boolean | ||
id?: string | ||
} | ||
|
||
// used for helix and as a child button to ListButtonAccordion | ||
export function ListButtonRadioButton( | ||
props: ListButtonRadioButtonProps | ||
): JSX.Element { | ||
const { | ||
buttonText, | ||
buttonValue, | ||
isSelected = false, | ||
onChange, | ||
disabled = false, | ||
id = buttonText, | ||
} = props | ||
|
||
const SettingButton = styled.input` | ||
display: none; | ||
` | ||
|
||
const AVAILABLE_BUTTON_STYLE = css` | ||
background: ${COLORS.white}; | ||
color: ${COLORS.black90}; | ||
|
||
&:hover { | ||
background-color: ${COLORS.grey10}; | ||
} | ||
` | ||
|
||
const SELECTED_BUTTON_STYLE = css` | ||
background: ${COLORS.blue50}; | ||
color: ${COLORS.white}; | ||
|
||
&:active { | ||
background-color: ${COLORS.blue60}; | ||
} | ||
` | ||
|
||
const DISABLED_STYLE = css` | ||
color: ${COLORS.grey40}; | ||
background-color: ${COLORS.grey10}; | ||
` | ||
|
||
const SettingButtonLabel = styled.label` | ||
border-radius: ${BORDERS.borderRadius8}; | ||
cursor: pointer; | ||
padding: 14px ${SPACING.spacing12}; | ||
width: 100%; | ||
|
||
${isSelected ? SELECTED_BUTTON_STYLE : AVAILABLE_BUTTON_STYLE} | ||
${disabled && DISABLED_STYLE} | ||
` | ||
|
||
return ( | ||
<Flex width="100%" margin={SPACING.spacing4}> | ||
<SettingButton | ||
checked={isSelected} | ||
id={id} | ||
disabled={disabled} | ||
onChange={onChange} | ||
type="radio" | ||
value={buttonValue} | ||
/> | ||
<SettingButtonLabel role="label" htmlFor={id}> | ||
<StyledText desktopStyle="bodyDefaultRegular">{buttonText}</StyledText> | ||
</SettingButtonLabel> | ||
</Flex> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './ListButtonAccordion' | ||
export * from './ListButtonAccordionContainer' | ||
export * from './ListButtonRadioButton' |
46 changes: 46 additions & 0 deletions
46
components/src/atoms/ListButton/__tests__/ListButton.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import * as React from 'react' | ||
import { vi, describe, it, expect, beforeEach } from 'vitest' | ||
import '@testing-library/jest-dom/vitest' | ||
import { fireEvent, screen } from '@testing-library/react' | ||
import { renderWithProviders } from '../../../testing/utils' | ||
import { COLORS } from '../../../helix-design-system' | ||
|
||
import { ListButton } from '..' | ||
|
||
const render = (props: React.ComponentProps<typeof ListButton>) => | ||
renderWithProviders(<ListButton {...props} />) | ||
|
||
describe('ListButton', () => { | ||
let props: React.ComponentProps<typeof ListButton> | ||
|
||
beforeEach(() => { | ||
props = { | ||
type: 'noActive', | ||
children: <div>mock ListButton content</div>, | ||
onClick: vi.fn(), | ||
} | ||
}) | ||
|
||
it('should render correct style - noActive', () => { | ||
render(props) | ||
const listButton = screen.getByTestId('ListButton_noActive') | ||
expect(listButton).toHaveStyle(`backgroundColor: ${COLORS.grey35}`) | ||
}) | ||
it('should render correct style - connected', () => { | ||
props.type = 'connected' | ||
render(props) | ||
const listButton = screen.getByTestId('ListButton_connected') | ||
expect(listButton).toHaveStyle(`backgroundColor: ${COLORS.green35}`) | ||
}) | ||
it('should render correct style - notConnected', () => { | ||
props.type = 'notConnected' | ||
render(props) | ||
const listButton = screen.getByTestId('ListButton_notConnected') | ||
expect(listButton).toHaveStyle(`backgroundColor: ${COLORS.yellow35}`) | ||
}) | ||
it('should call on click when pressed', () => { | ||
render(props) | ||
fireEvent.click(screen.getByText('mock ListButton content')) | ||
expect(props.onClick).toHaveBeenCalled() | ||
}) | ||
}) |
35 changes: 35 additions & 0 deletions
35
components/src/atoms/ListButton/__tests__/ListButtonAccordion.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import * as React from 'react' | ||
import { describe, it, beforeEach } from 'vitest' | ||
import { screen } from '@testing-library/react' | ||
import { renderWithProviders } from '../../../testing/utils' | ||
|
||
import { ListButtonAccordion } from '..' | ||
|
||
const render = (props: React.ComponentProps<typeof ListButtonAccordion>) => | ||
renderWithProviders(<ListButtonAccordion {...props} />) | ||
|
||
describe('ListButtonAccordion', () => { | ||
let props: React.ComponentProps<typeof ListButtonAccordion> | ||
|
||
beforeEach(() => { | ||
props = { | ||
children: <div>mock ListButtonAccordion content</div>, | ||
headline: 'mock headline', | ||
isExpanded: true, | ||
} | ||
}) | ||
|
||
it('should render non nested accordion', () => { | ||
render(props) | ||
screen.getByText('mock headline') | ||
screen.getByText('mock ListButtonAccordion content') | ||
}) | ||
it('should render non nested accordion with main headline', () => { | ||
props.isNested = true | ||
props.mainHeadline = 'mock main headline' | ||
render(props) | ||
screen.getByText('mock main headline') | ||
screen.getByText('mock headline') | ||
screen.getByText('mock ListButtonAccordion content') | ||
}) | ||
}) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding text like 'click the button to see Accordion, Radio, Nested' would be user-friendly for the designers.
we can notice that easily since we read code, but they don't check code.
probably adding text might DQA smooth.