Add nav buttons

This commit is contained in:
Bartłomiej Głownia 2022-03-03 12:11:36 +01:00 committed by Matthew Russell
parent 0e9a3c37c5
commit d9444e9aef
5 changed files with 117 additions and 24 deletions

View File

@ -38,6 +38,62 @@ Inline.args = {
variant: 'inline', variant: 'inline',
}; };
export const NavAccent: Story = (args) => (
<>
<div className="mb-8">
<Button variant="accent" className="px-4">
Background
</Button>
</div>
<div className="mb-8">
<Button
variant="accent"
className="pl-8 pr-4"
prependIconName="menu-open"
>
Background
</Button>
</div>
<div className="mb-8">
<Button
variant="accent"
className="pl-4 pr-8"
appendIconName="menu-closed"
>
Background
</Button>
</div>
</>
);
export const NavInline: Story = (args) => (
<>
<div className="mb-8">
<Button variant="inline" className="uppercase">
Background
</Button>
</div>
<div className="mb-8">
<Button
variant="inline"
className="uppercase"
prependIconName="menu-open"
>
Background
</Button>
</div>
<div className="mb-8">
<Button
variant="inline"
className="uppercase"
appendIconName="menu-closed"
>
Background
</Button>
</div>
</>
);
export const IconPrepend = Template.bind({}); export const IconPrepend = Template.bind({});
IconPrepend.args = { IconPrepend.args = {
children: 'Icon prepend', children: 'Icon prepend',

View File

@ -1,7 +1,5 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { Icon, IconName } from '../icon'; import { Icon, IconName } from '../icon';
/* eslint-disable-next-line */
export interface ButtonProps { export interface ButtonProps {
tag?: 'a' | 'button'; tag?: 'a' | 'button';
children?: React.ReactNode; children?: React.ReactNode;
@ -29,10 +27,9 @@ export function Button({
[ [
'inline-flex', 'inline-flex',
'items-center', 'items-center',
'justify-center',
'box-border', 'box-border',
'h-28', 'h-28',
'pl-28',
'pr-28',
'border', 'border',
'text-ui', 'text-ui',
'no-underline', 'no-underline',
@ -43,6 +40,13 @@ export function Button({
'disabled:bg-disabled/25', 'disabled:bg-disabled/25',
], ],
{ {
'pl-28': !(
className?.match(/(^| )p(l|x)-\d+( |$)/) || variant === 'inline'
),
'pr-28': !(
className?.match(/(^| )p(r|x)-\d+( |$)/) || variant === 'inline'
),
'bg-white': variant === 'primary', 'bg-white': variant === 'primary',
'border-light-gray-50': variant === 'primary' || variant === 'secondary', 'border-light-gray-50': variant === 'primary' || variant === 'secondary',
'text-black': variant === 'primary', 'text-black': variant === 'primary',
@ -51,7 +55,6 @@ export function Button({
'active:text-white': variant === 'primary', 'active:text-white': variant === 'primary',
'disabled:text-gray-50': variant === 'primary' || variant === 'secondary', 'disabled:text-gray-50': variant === 'primary' || variant === 'secondary',
'disabled:border-neutral-593': variant === 'primary', 'disabled:border-neutral-593': variant === 'primary',
'disabled:gray-50': variant === 'primary',
'bg-black': variant === 'secondary', 'bg-black': variant === 'secondary',
'text-light-gray-50': variant === 'secondary' || variant === 'inline', 'text-light-gray-50': variant === 'secondary' || variant === 'inline',

View File

@ -1,7 +1,8 @@
import React from 'react'; import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react'; import { ComponentStory, ComponentMeta } from '@storybook/react';
import { Callout } from '.'; import { Callout } from './callout';
import { Button } from '../button';
export default { export default {
title: 'Callout', title: 'Callout',
@ -9,37 +10,61 @@ export default {
} as ComponentMeta<typeof Callout>; } as ComponentMeta<typeof Callout>;
const Template: ComponentStory<typeof Callout> = (args) => ( const Template: ComponentStory<typeof Callout> = (args) => (
<Callout {...args}>Content</Callout> <Callout {...args} />
); );
export const Default = Template.bind({}); export const Default = Template.bind({});
Default.args = {
children: 'Content',
};
export const Danger = Template.bind({}); export const Danger = Template.bind({});
Danger.args = { Danger.args = {
intent: 'danger', intent: 'danger',
children: 'Content',
}; };
export const Warning = Template.bind({}); export const Warning = Template.bind({});
Warning.args = { Warning.args = {
intent: 'warning', intent: 'warning',
children: 'Content',
}; };
export const Prompt = Template.bind({}); export const Prompt = Template.bind({});
Prompt.args = { Prompt.args = {
intent: 'prompt', intent: 'prompt',
children: 'Content',
}; };
export const Progress = Template.bind({}); export const Progress = Template.bind({});
Progress.args = { Progress.args = {
intent: 'progress', intent: 'progress',
children: 'Content',
}; };
export const Success = Template.bind({}); export const Success = Template.bind({});
Success.args = { Success.args = {
intent: 'success', intent: 'success',
children: 'Content',
}; };
export const Help = Template.bind({}); export const Help = Template.bind({});
Help.args = { Help.args = {
intent: 'help', intent: 'help',
children: 'Content',
};
export const IconAndContent = Template.bind({});
IconAndContent.args = {
intent: 'help',
title: 'This is what this thing does',
iconName: 'endorsed',
children: (
<div className="flex flex-col">
<div>With a longer explaination</div>
<Button className="block mt-8" variant="secondary">
Action
</Button>
</div>
),
}; };

View File

@ -8,8 +8,10 @@ test('It renders content within callout', () => {
}); });
test('It renders title and icon', () => { test('It renders title and icon', () => {
render(<Callout icon={<div data-testid="icon" />} title="title" />); render(<Callout iconName="endorsed" title="title" />);
expect(screen.getByTestId('icon')).toBeInTheDocument(); expect(
screen.getByTestId('callout').querySelector('svg')
).toBeInTheDocument();
expect(screen.getByText('title')).toBeInTheDocument(); expect(screen.getByText('title')).toBeInTheDocument();
}); });

View File

@ -1,24 +1,28 @@
import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Icon, IconName } from '../icon';
export const Callout = ({ export interface CalloutProps {
children,
title,
intent = 'help',
icon,
headingLevel,
}: {
children?: React.ReactNode; children?: React.ReactNode;
title?: React.ReactElement | string; title?: React.ReactElement | string;
intent?: 'danger' | 'warning' | 'prompt' | 'progress' | 'success' | 'help'; intent?: 'danger' | 'warning' | 'prompt' | 'progress' | 'success' | 'help';
icon?: React.ReactNode; iconName?: IconName;
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6; headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
}) => { }
export function Callout({
children,
title,
intent = 'help',
iconName,
headingLevel,
}: CalloutProps) {
const className = classNames( const className = classNames(
'shadow-callout', 'shadow-callout',
'border', 'border',
'border-black', 'border-black',
'dark:border-white', 'dark:border-white',
'text-body-large',
'dark:text-white',
'p-8', 'p-8',
{ {
'shadow-intent-danger': intent === 'danger', 'shadow-intent-danger': intent === 'danger',
@ -27,22 +31,25 @@ export const Callout = ({
'shadow-intent-black dark:shadow-intent-progress': intent === 'progress', 'shadow-intent-black dark:shadow-intent-progress': intent === 'progress',
'shadow-intent-success': intent === 'success', 'shadow-intent-success': intent === 'success',
'shadow-intent-help': intent === 'help', 'shadow-intent-help': intent === 'help',
flex: icon, flex: !!iconName,
} }
); );
const TitleTag: keyof JSX.IntrinsicElements = headingLevel const TitleTag: keyof JSX.IntrinsicElements = headingLevel
? `h${headingLevel}` ? `h${headingLevel}`
: 'div'; : 'div';
const icon = iconName && (
<Icon name={iconName} className="fill-current ml-8 mr-16 mt-8" size={20} />
);
const body = ( const body = (
<div className="body-large dark:text-white"> <>
{title && <TitleTag className="text-h5">{title}</TitleTag>} {title && <TitleTag className="text-h5">{title}</TitleTag>}
{children} {children}
</div> </>
); );
return ( return (
<div data-testid="callout" className={className}> <div data-testid="callout" className={className}>
{icon && <div className="">{icon}</div>} {icon}
{icon ? <div className="grow">{body}</div> : body} {icon ? <div className="grow">{body}</div> : body}
</div> </div>
); );
}; }