-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: TET-854 add header component (#157)
* feat: TET-854 fix input width in SearchInput component * feat: TET-854 fix search width * feat: TET-854 improve search styling * feat: TET-854 add Header component * feat: TET-854 fix build
- Loading branch information
1 parent
06a584e
commit 5c5b46c
Showing
12 changed files
with
426 additions
and
4 deletions.
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,13 @@ | ||
import { HeaderConfig, HeaderType } from './Header.styles'; | ||
|
||
import { ActionProp } from '@/types'; | ||
|
||
export type HeaderProps = { | ||
type?: HeaderType; | ||
counter?: number; | ||
bottomBar?: boolean; | ||
title: string; | ||
description?: string; | ||
custom?: HeaderConfig; | ||
action?: ActionProp; | ||
}; |
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,64 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { Header } from './Header'; | ||
|
||
import { HeaderDocs } from '@/docs-components/HeaderDocs'; | ||
import { TetDocs } from '@/docs-components/TetDocs'; | ||
|
||
const meta = { | ||
title: 'Header', | ||
component: Header, | ||
tags: ['autodocs'], | ||
parameters: { | ||
docs: { | ||
description: { | ||
component: | ||
'A collection of other components that forms the header of a page, used to indicate some subpage or group of content such as a table or listing.', | ||
}, | ||
page: () => ( | ||
<TetDocs docs="https://docs.tetrisly.com/components/in-progress/header"> | ||
<HeaderDocs /> | ||
</TetDocs> | ||
), | ||
}, | ||
}, | ||
} satisfies Meta<typeof Header>; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Complex: Story = { | ||
args: { | ||
title: 'Table title', | ||
counter: 2, | ||
bottomBar: true, | ||
description: 'Description', | ||
type: 'complex', | ||
action: [ | ||
{ | ||
label: 'Add new', | ||
}, | ||
{ | ||
label: 'Export csv', | ||
}, | ||
], | ||
}, | ||
}; | ||
|
||
export const Compact: Story = { | ||
args: { | ||
title: 'Table title', | ||
counter: 0, | ||
bottomBar: true, | ||
description: 'Description', | ||
type: 'compact', | ||
action: [ | ||
{ | ||
label: 'Add new', | ||
}, | ||
{ | ||
label: 'Export csv', | ||
}, | ||
], | ||
}, | ||
}; |
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,93 @@ | ||
import { BaseProps } from '@/types/BaseProps'; | ||
|
||
export type HeaderType = 'complex' | 'compact'; | ||
|
||
export type HeaderConfig = { | ||
table: { type: Record<HeaderType, BaseProps> } & BaseProps; | ||
titleAndDescriptionContainer: BaseProps; | ||
titleContainer: BaseProps; | ||
description: BaseProps; | ||
counter: BaseProps; | ||
actionContainer: BaseProps; | ||
search: { type: Record<HeaderType, BaseProps> } & BaseProps; | ||
bottomBar: { type: Record<HeaderType, BaseProps> } & BaseProps; | ||
} & BaseProps; | ||
|
||
export const defaultConfig = { | ||
display: 'flex', | ||
flexDirection: 'column', | ||
minWidth: 'fit-content', | ||
w: '100%', | ||
h: 'fit-content', | ||
backgroundColor: '$color-background-default', | ||
table: { | ||
w: '100%', | ||
display: 'flex', | ||
padding: '$space-component-padding-large $space-component-padding-2xLarge', | ||
type: { | ||
complex: { | ||
h: '88px', | ||
}, | ||
compact: { | ||
h: '80px', | ||
}, | ||
}, | ||
}, | ||
titleAndDescriptionContainer: { | ||
w: '100%', | ||
text: '$typo-header-xLarge', | ||
display: 'flex', | ||
flexDirection: 'column', | ||
}, | ||
counter: { | ||
w: '$size-2xSmall', | ||
h: '$size-2xSmall', | ||
}, | ||
titleContainer: { | ||
display: 'flex', | ||
alignItems: 'center', | ||
gap: '$space-component-gap-small', | ||
}, | ||
description: { | ||
text: '$typo-body-medium', | ||
color: '$color-content-secondary', | ||
gap: '$space-component-gap-small', | ||
}, | ||
actionContainer: { | ||
display: 'flex', | ||
gap: '$space-component-gap-large', | ||
alignItems: 'center', | ||
}, | ||
bottomBar: { | ||
borderTopWidth: '$border-width-small', | ||
borderStyle: '$border-style-solid', | ||
borderColor: '$color-border-default', | ||
display: 'flex', | ||
type: { | ||
complex: { | ||
padding: | ||
'$space-component-padding-large $space-component-padding-2xLarge', | ||
gap: '$space-component-gap-small', | ||
h: '$size-2xLarge', | ||
}, | ||
compact: { | ||
padding: | ||
'$space-component-padding-small $space-component-padding-large', | ||
h: '$size-large', | ||
}, | ||
}, | ||
}, | ||
search: { | ||
w: '105px', | ||
type: { | ||
complex: { | ||
marginLeft: 'auto', | ||
}, | ||
compact: {}, | ||
}, | ||
}, | ||
} satisfies HeaderConfig; | ||
|
||
export const headerStyles = { | ||
defaultConfig, | ||
}; |
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,80 @@ | ||
import { Header } from './Header'; | ||
import { render } from '../../tests/render'; | ||
|
||
import { customPropTester } from '@/tests/customPropTester'; | ||
|
||
const getHeader = (jsx: JSX.Element) => { | ||
const { getByTestId, queryByTestId } = render(jsx); | ||
|
||
return { | ||
actionContainer: queryByTestId('header-action-container'), | ||
bottomBar: queryByTestId('header-bottom-bar'), | ||
counter: queryByTestId('header-counter'), | ||
description: queryByTestId('header-description'), | ||
header: getByTestId('header'), | ||
search: queryByTestId('header-search'), | ||
title: getByTestId('header-title'), | ||
}; | ||
}; | ||
|
||
describe('Header', () => { | ||
customPropTester(<Header type="complex" title="" />, { | ||
containerId: 'header', | ||
props: {}, | ||
innerElements: {}, | ||
}); | ||
|
||
it('should render the header', () => { | ||
const { header } = getHeader(<Header type="complex" title="" />); | ||
expect(header).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the correct title', () => { | ||
const { title } = getHeader(<Header title="Title" />); | ||
expect(title).toHaveTextContent('Title'); | ||
}); | ||
|
||
it('should render the correct title', () => { | ||
const { title } = getHeader(<Header title="Title" />); | ||
expect(title).toHaveTextContent('Title'); | ||
}); | ||
|
||
it('should render the correct description', () => { | ||
const { description } = getHeader( | ||
<Header description="Description" title="" />, | ||
); | ||
expect(description).toHaveTextContent('Description'); | ||
}); | ||
|
||
it('should not render the description', () => { | ||
const { description } = getHeader(<Header title="" />); | ||
expect(description).toBeNull(); | ||
}); | ||
|
||
it('should render the counter', () => { | ||
const { counter } = getHeader(<Header counter={0} title="" />); | ||
expect(counter).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the bottom bar', () => { | ||
const { bottomBar } = getHeader(<Header bottomBar title="" />); | ||
expect(bottomBar).toBeInTheDocument(); | ||
}); | ||
|
||
it('should not render the bottom bar', () => { | ||
const { bottomBar } = getHeader(<Header title="" />); | ||
expect(bottomBar).toBeNull(); | ||
}); | ||
|
||
it('should render the search', () => { | ||
const { search } = getHeader(<Header bottomBar title="" />); | ||
expect(search).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the action container', () => { | ||
const { actionContainer } = getHeader( | ||
<Header action={[{ label: 'Label' }, { label: 'Label' }]} title="" />, | ||
); | ||
expect(actionContainer).toBeInTheDocument(); | ||
}); | ||
}); |
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,103 @@ | ||
import { MarginProps } from '@xstyled/styled-components'; | ||
import { FC, useMemo } from 'react'; | ||
|
||
import { HeaderProps } from './Header.props'; | ||
import { stylesBuilder } from './stylesBuilder'; | ||
import { Button } from '../Button'; | ||
import { Counter } from '../Counter'; | ||
import { CounterConfig } from '../Counter/Counter.styles'; | ||
import { InlineSearchInput } from '../InlineSearchInput'; | ||
import { SelectablePill } from '../SelectablePill'; | ||
|
||
import { useAction } from '@/hooks'; | ||
import { tet } from '@/tetrisly'; | ||
|
||
export const Header: FC<HeaderProps & MarginProps> = ({ | ||
bottomBar, | ||
counter, | ||
description, | ||
title, | ||
type = 'complex', | ||
action, | ||
custom, | ||
...restProps | ||
}) => { | ||
const styles = useMemo(() => stylesBuilder(type, custom), [custom, type]); | ||
|
||
const [firstAction, secondAction] = useAction(action); | ||
|
||
const isComplexType = type === 'complex'; | ||
const customSearchStyle = { innerElements: { input: { w: '100%' } } }; | ||
|
||
return ( | ||
<tet.div {...styles.container} data-testid="header" {...restProps}> | ||
<tet.div {...styles.table} data-testid="header-table"> | ||
<tet.div | ||
{...styles.titleAndDescriptionContainer} | ||
data-testid="header-title-and-description-container" | ||
> | ||
<tet.div | ||
{...styles.titleContainer} | ||
data-testid="header-title-container" | ||
> | ||
<tet.span data-testid="header-title">{title}</tet.span> | ||
{!(counter === undefined) && ( | ||
<Counter | ||
data-testid="header-counter" | ||
number={counter} | ||
custom={styles.counter as CounterConfig} | ||
/> | ||
)} | ||
</tet.div> | ||
|
||
{!!description && ( | ||
<tet.div {...styles.description} data-testid="header-description"> | ||
{description} | ||
</tet.div> | ||
)} | ||
</tet.div> | ||
{firstAction && ( | ||
<tet.div | ||
{...styles.actionContainer} | ||
data-testid="header-action-container" | ||
> | ||
{/* should it always be like this - first button is primary and second secondary or user decides about it? */} | ||
{secondAction && ( | ||
<Button | ||
variant="default" | ||
appearance="secondary" | ||
size={isComplexType ? 'medium' : 'small'} | ||
{...secondAction} | ||
/> | ||
)} | ||
<Button | ||
variant="default" | ||
appearance="primary" | ||
size={isComplexType ? 'medium' : 'small'} | ||
{...firstAction} | ||
/> | ||
</tet.div> | ||
)} | ||
</tet.div> | ||
{!!bottomBar && ( | ||
<tet.div {...styles.bottomBar} data-testId="header-bottom-bar"> | ||
{type === 'complex' && ( | ||
<> | ||
{/* not sure how it should work, if and how user passes a data about inside components */} | ||
<SelectablePill text="Name" /> | ||
<SelectablePill text="E-mail" /> | ||
<SelectablePill text="Date added" /> | ||
<Button label="Filters" size="small" /> | ||
</> | ||
)} | ||
<InlineSearchInput | ||
{...styles.search} | ||
placeholder="Search..." | ||
custom={customSearchStyle} | ||
data-testId="header-search" | ||
/> | ||
</tet.div> | ||
)} | ||
</tet.div> | ||
); | ||
}; |
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 { Header } from './Header'; | ||
export type { HeaderProps } from './Header.props'; | ||
export { headerStyles } from './Header.styles'; |
Oops, something went wrong.