Add ButtonGroup concept + Soon pill on button + implement in timeline (#551)
* Add ButtonGroup concept * Add soon pill * Fix incorrect wrapping behavior * Implement button group in timeline
This commit is contained in:
@ -0,0 +1,40 @@
|
|||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
|
||||||
|
import { Button } from '@/ui/components/buttons/Button';
|
||||||
|
import { ButtonGroup } from '@/ui/components/buttons/ButtonGroup';
|
||||||
|
import { IconCheckbox, IconNotes, IconTimelineEvent } from '@/ui/icons/index';
|
||||||
|
|
||||||
|
type CommentThreadCreateButtonProps = {
|
||||||
|
onNoteClick?: () => void;
|
||||||
|
onTaskClick?: () => void;
|
||||||
|
onActivityClick?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function CommentThreadCreateButton({
|
||||||
|
onNoteClick,
|
||||||
|
onTaskClick,
|
||||||
|
onActivityClick,
|
||||||
|
}: CommentThreadCreateButtonProps) {
|
||||||
|
const theme = useTheme();
|
||||||
|
return (
|
||||||
|
<ButtonGroup variant="secondary">
|
||||||
|
<Button
|
||||||
|
icon={<IconNotes size={theme.icon.size.sm} />}
|
||||||
|
title="Note"
|
||||||
|
onClick={onNoteClick}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={<IconCheckbox size={theme.icon.size.sm} />}
|
||||||
|
title="Task"
|
||||||
|
soon={true}
|
||||||
|
onClick={onTaskClick}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={<IconTimelineEvent size={theme.icon.size.sm} />}
|
||||||
|
title="Activity"
|
||||||
|
soon={true}
|
||||||
|
onClick={onActivityClick}
|
||||||
|
/>
|
||||||
|
</ButtonGroup>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -6,7 +6,6 @@ import { useOpenCommentThreadRightDrawer } from '@/comments/hooks/useOpenComment
|
|||||||
import { useOpenCreateCommentThreadDrawer } from '@/comments/hooks/useOpenCreateCommentThreadDrawer';
|
import { useOpenCreateCommentThreadDrawer } from '@/comments/hooks/useOpenCreateCommentThreadDrawer';
|
||||||
import { CommentableEntity } from '@/comments/types/CommentableEntity';
|
import { CommentableEntity } from '@/comments/types/CommentableEntity';
|
||||||
import { CommentThreadForDrawer } from '@/comments/types/CommentThreadForDrawer';
|
import { CommentThreadForDrawer } from '@/comments/types/CommentThreadForDrawer';
|
||||||
import { TableActionBarButtonToggleComments } from '@/ui/components/table/action-bar/TableActionBarButtonOpenComments';
|
|
||||||
import { IconCirclePlus, IconNotes } from '@/ui/icons/index';
|
import { IconCirclePlus, IconNotes } from '@/ui/icons/index';
|
||||||
import {
|
import {
|
||||||
beautifyExactDate,
|
beautifyExactDate,
|
||||||
@ -17,6 +16,8 @@ import {
|
|||||||
useGetCommentThreadsByTargetsQuery,
|
useGetCommentThreadsByTargetsQuery,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
|
import { CommentThreadCreateButton } from '../comment-thread/CommentThreadCreateButton';
|
||||||
|
|
||||||
const StyledMainContainer = styled.div`
|
const StyledMainContainer = styled.div`
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
@ -208,8 +209,8 @@ export function Timeline({ entity }: { entity: CommentableEntity }) {
|
|||||||
<StyledTimelineEmptyContainer>
|
<StyledTimelineEmptyContainer>
|
||||||
<StyledEmptyTimelineTitle>No activity yet</StyledEmptyTimelineTitle>
|
<StyledEmptyTimelineTitle>No activity yet</StyledEmptyTimelineTitle>
|
||||||
<StyledEmptyTimelineSubTitle>Create one:</StyledEmptyTimelineSubTitle>
|
<StyledEmptyTimelineSubTitle>Create one:</StyledEmptyTimelineSubTitle>
|
||||||
<TableActionBarButtonToggleComments
|
<CommentThreadCreateButton
|
||||||
onClick={() => openCreateCommandThread(entity)}
|
onNoteClick={() => openCreateCommandThread(entity)}
|
||||||
/>
|
/>
|
||||||
</StyledTimelineEmptyContainer>
|
</StyledTimelineEmptyContainer>
|
||||||
);
|
);
|
||||||
@ -223,8 +224,8 @@ export function Timeline({ entity }: { entity: CommentableEntity }) {
|
|||||||
<IconCirclePlus />
|
<IconCirclePlus />
|
||||||
</StyledIconContainer>
|
</StyledIconContainer>
|
||||||
|
|
||||||
<TableActionBarButtonToggleComments
|
<CommentThreadCreateButton
|
||||||
onClick={() => openCreateCommandThread(entity)}
|
onNoteClick={() => openCreateCommandThread(entity)}
|
||||||
/>
|
/>
|
||||||
</StyledTimelineItemContainer>
|
</StyledTimelineItemContainer>
|
||||||
</StyledTopActionBar>
|
</StyledTopActionBar>
|
||||||
|
|||||||
22
front/src/modules/ui/components/accessories/SoonPill.tsx
Normal file
22
front/src/modules/ui/components/accessories/SoonPill.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledSoonPill = styled.span`
|
||||||
|
align-items: center;
|
||||||
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
|
border-radius: 50px;
|
||||||
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
|
display: flex;
|
||||||
|
font-size: ${({ theme }) => theme.font.size.xs};
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
|
height: ${({ theme }) => theme.spacing(4)};
|
||||||
|
justify-content: flex-end;
|
||||||
|
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
||||||
|
margin-left: auto;
|
||||||
|
padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function SoonPill() {
|
||||||
|
return <StyledSoonPill>Soon</StyledSoonPill>;
|
||||||
|
}
|
||||||
@ -3,7 +3,9 @@ import styled from '@emotion/styled';
|
|||||||
|
|
||||||
import { rgba } from '@/ui/themes/colors';
|
import { rgba } from '@/ui/themes/colors';
|
||||||
|
|
||||||
type Variant =
|
import { SoonPill } from '../accessories/SoonPill';
|
||||||
|
|
||||||
|
export type ButtonVariant =
|
||||||
| 'primary'
|
| 'primary'
|
||||||
| 'secondary'
|
| 'secondary'
|
||||||
| 'tertiary'
|
| 'tertiary'
|
||||||
@ -11,18 +13,22 @@ type Variant =
|
|||||||
| 'tertiaryLight'
|
| 'tertiaryLight'
|
||||||
| 'danger';
|
| 'danger';
|
||||||
|
|
||||||
type Size = 'medium' | 'small';
|
export type ButtonSize = 'medium' | 'small';
|
||||||
|
|
||||||
type Props = {
|
export type ButtonPosition = 'left' | 'middle' | 'right' | undefined;
|
||||||
|
|
||||||
|
export type ButtonProps = {
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
title?: string;
|
title?: string;
|
||||||
fullWidth?: boolean;
|
fullWidth?: boolean;
|
||||||
variant?: Variant;
|
variant?: ButtonVariant;
|
||||||
size?: Size;
|
size?: ButtonSize;
|
||||||
|
position?: ButtonPosition;
|
||||||
|
soon?: boolean;
|
||||||
} & React.ComponentProps<'button'>;
|
} & React.ComponentProps<'button'>;
|
||||||
|
|
||||||
const StyledButton = styled.button<
|
const StyledButton = styled.button<
|
||||||
Pick<Props, 'fullWidth' | 'variant' | 'size' | 'title'>
|
Pick<ButtonProps, 'fullWidth' | 'variant' | 'size' | 'position' | 'title'>
|
||||||
>`
|
>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: ${({ theme, variant, disabled }) => {
|
background: ${({ theme, variant, disabled }) => {
|
||||||
@ -49,7 +55,18 @@ const StyledButton = styled.button<
|
|||||||
return 'none';
|
return 'none';
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
border-radius: 4px;
|
border-radius: ${({ position }) => {
|
||||||
|
switch (position) {
|
||||||
|
case 'left':
|
||||||
|
return '4px 0px 0px 4px';
|
||||||
|
case 'right':
|
||||||
|
return '0px 4px 4px 0px';
|
||||||
|
case 'middle':
|
||||||
|
return '0px';
|
||||||
|
default:
|
||||||
|
return '4px';
|
||||||
|
}
|
||||||
|
}};
|
||||||
box-shadow: ${({ theme, variant }) => {
|
box-shadow: ${({ theme, variant }) => {
|
||||||
switch (variant) {
|
switch (variant) {
|
||||||
case 'primary':
|
case 'primary':
|
||||||
@ -59,6 +76,7 @@ const StyledButton = styled.button<
|
|||||||
return 'none';
|
return 'none';
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
color: ${({ theme, variant, disabled }) => {
|
color: ${({ theme, variant, disabled }) => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
if (variant === 'primary') {
|
if (variant === 'primary') {
|
||||||
@ -105,6 +123,8 @@ const StyledButton = styled.button<
|
|||||||
|
|
||||||
transition: background 0.1s ease;
|
transition: background 0.1s ease;
|
||||||
|
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
width: ${({ fullWidth }) => (fullWidth ? '100%' : 'auto')};
|
width: ${({ fullWidth }) => (fullWidth ? '100%' : 'auto')};
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
@ -144,18 +164,24 @@ export function Button({
|
|||||||
fullWidth = false,
|
fullWidth = false,
|
||||||
variant = 'primary',
|
variant = 'primary',
|
||||||
size = 'medium',
|
size = 'medium',
|
||||||
|
position,
|
||||||
|
soon = false,
|
||||||
|
disabled = false,
|
||||||
...props
|
...props
|
||||||
}: Props) {
|
}: ButtonProps) {
|
||||||
return (
|
return (
|
||||||
<StyledButton
|
<StyledButton
|
||||||
fullWidth={fullWidth}
|
fullWidth={fullWidth}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
size={size}
|
size={size}
|
||||||
|
position={position}
|
||||||
|
disabled={soon || disabled}
|
||||||
title={title}
|
title={title}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{icon}
|
{icon}
|
||||||
{title}
|
{title}
|
||||||
|
{soon && <SoonPill />}
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
43
front/src/modules/ui/components/buttons/ButtonGroup.tsx
Normal file
43
front/src/modules/ui/components/buttons/ButtonGroup.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { ButtonPosition, ButtonProps } from './Button';
|
||||||
|
|
||||||
|
const StyledButtonGroupContainer = styled.div`
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type ButtonGroupProps = Pick<ButtonProps, 'variant' | 'size'> & {
|
||||||
|
children: React.ReactElement[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ButtonGroup({ children, variant, size }: ButtonGroupProps) {
|
||||||
|
return (
|
||||||
|
<StyledButtonGroupContainer>
|
||||||
|
{React.Children.map(children, (child, index) => {
|
||||||
|
let position: ButtonPosition;
|
||||||
|
|
||||||
|
if (index === 0) {
|
||||||
|
position = 'left';
|
||||||
|
} else if (index === children.length - 1) {
|
||||||
|
position = 'right';
|
||||||
|
} else {
|
||||||
|
position = 'middle';
|
||||||
|
}
|
||||||
|
|
||||||
|
const additionalProps: any = { position };
|
||||||
|
|
||||||
|
if (variant) {
|
||||||
|
additionalProps.variant = variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size) {
|
||||||
|
additionalProps.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return React.cloneElement(child, additionalProps);
|
||||||
|
})}
|
||||||
|
</StyledButtonGroupContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@ type Props = {
|
|||||||
title: string;
|
title: string;
|
||||||
fullWidth?: boolean;
|
fullWidth?: boolean;
|
||||||
variant?: Variant;
|
variant?: Variant;
|
||||||
|
soon?: boolean;
|
||||||
} & React.ComponentProps<'button'>;
|
} & React.ComponentProps<'button'>;
|
||||||
|
|
||||||
const StyledButton = styled.button<Pick<Props, 'fullWidth' | 'variant'>>`
|
const StyledButton = styled.button<Pick<Props, 'fullWidth' | 'variant'>>`
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import React from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { text, withKnobs } from '@storybook/addon-knobs';
|
import { text, withKnobs } from '@storybook/addon-knobs';
|
||||||
import { expect, jest } from '@storybook/jest';
|
import { expect, jest } from '@storybook/jest';
|
||||||
@ -8,6 +9,7 @@ import { IconSearch } from '@/ui/icons';
|
|||||||
import { getRenderWrapperForComponent } from '~/testing/renderWrappers';
|
import { getRenderWrapperForComponent } from '~/testing/renderWrappers';
|
||||||
|
|
||||||
import { Button } from '../Button';
|
import { Button } from '../Button';
|
||||||
|
import { ButtonGroup } from '../ButtonGroup';
|
||||||
|
|
||||||
type ButtonProps = React.ComponentProps<typeof Button>;
|
type ButtonProps = React.ComponentProps<typeof Button>;
|
||||||
|
|
||||||
@ -62,8 +64,6 @@ const meta: Meta<typeof Button> = {
|
|||||||
export default meta;
|
export default meta;
|
||||||
type Story = StoryObj<typeof Button>;
|
type Story = StoryObj<typeof Button>;
|
||||||
|
|
||||||
const clickJestFn = jest.fn();
|
|
||||||
|
|
||||||
const variants: ButtonProps['variant'][] = [
|
const variants: ButtonProps['variant'][] = [
|
||||||
'primary',
|
'primary',
|
||||||
'secondary',
|
'secondary',
|
||||||
@ -73,148 +73,157 @@ const variants: ButtonProps['variant'][] = [
|
|||||||
'danger',
|
'danger',
|
||||||
];
|
];
|
||||||
|
|
||||||
const ButtonLine = (props: ButtonProps) => (
|
const clickJestFn = jest.fn();
|
||||||
|
|
||||||
|
const states = {
|
||||||
|
'with-icon': {
|
||||||
|
description: 'With icon',
|
||||||
|
extraProps: (variant: string) => ({
|
||||||
|
'data-testid': `${variant}-button-with-icon`,
|
||||||
|
icon: <IconSearch size={14} />,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
description: 'Default',
|
||||||
|
extraProps: (variant: string) => ({
|
||||||
|
'data-testid': `${variant}-button-default`,
|
||||||
|
onClick: clickJestFn,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
hover: {
|
||||||
|
description: 'Hover',
|
||||||
|
extraProps: (variant: string) => ({
|
||||||
|
id: `${variant}-button-hover`,
|
||||||
|
'data-testid': `${variant}-button-hover`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
pressed: {
|
||||||
|
description: 'Pressed',
|
||||||
|
extraProps: (variant: string) => ({
|
||||||
|
id: `${variant}-button-pressed`,
|
||||||
|
'data-testid': `${variant}-button-pressed`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
description: 'Disabled',
|
||||||
|
extraProps: (variant: string) => ({
|
||||||
|
'data-testid': `${variant}-button-disabled`,
|
||||||
|
disabled: true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
soon: {
|
||||||
|
description: 'Soon',
|
||||||
|
extraProps: (variant: string) => ({
|
||||||
|
'data-testid': `${variant}-button-soon`,
|
||||||
|
soon: true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
focus: {
|
||||||
|
description: 'Focus',
|
||||||
|
extraProps: (variant: string) => ({
|
||||||
|
id: `${variant}-button-focus`,
|
||||||
|
'data-testid': `${variant}-button-focus`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const ButtonLine: React.FC<ButtonProps> = ({ variant, ...props }) => (
|
||||||
<>
|
<>
|
||||||
<StyledButtonContainer>
|
{Object.entries(states).map(([state, { description, extraProps }]) => (
|
||||||
<StyledDescription>With icon</StyledDescription>
|
<StyledButtonContainer key={`${variant}-container-${state}`}>
|
||||||
<Button
|
<StyledDescription>{description}</StyledDescription>
|
||||||
data-testid={`${props.variant}-button-with-icon`}
|
<Button {...props} {...extraProps(variant ?? '')} variant={variant} />
|
||||||
{...props}
|
</StyledButtonContainer>
|
||||||
icon={<IconSearch size={14} />}
|
))}
|
||||||
/>
|
|
||||||
</StyledButtonContainer>
|
|
||||||
<StyledButtonContainer>
|
|
||||||
<StyledDescription>Default</StyledDescription>
|
|
||||||
<Button
|
|
||||||
data-testid={`${props.variant}-button-default`}
|
|
||||||
onClick={clickJestFn}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
</StyledButtonContainer>
|
|
||||||
<StyledButtonContainer>
|
|
||||||
<StyledDescription>Hover</StyledDescription>
|
|
||||||
<Button
|
|
||||||
id={`${props.variant}-button-hover`}
|
|
||||||
data-testid={`${props.variant}-button-hover`}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
</StyledButtonContainer>
|
|
||||||
<StyledButtonContainer>
|
|
||||||
<StyledDescription>Pressed</StyledDescription>
|
|
||||||
<Button
|
|
||||||
id={`${props.variant}-button-pressed`}
|
|
||||||
data-testid={`${props.variant}-button-pressed`}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
</StyledButtonContainer>
|
|
||||||
<StyledButtonContainer>
|
|
||||||
<StyledDescription>Disabled</StyledDescription>
|
|
||||||
<Button
|
|
||||||
data-testid={`${props.variant}-button-disabled`}
|
|
||||||
{...props}
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
</StyledButtonContainer>
|
|
||||||
<StyledButtonContainer>
|
|
||||||
<StyledDescription>Focus</StyledDescription>
|
|
||||||
<Button
|
|
||||||
id={`${props.variant}-button-focus`}
|
|
||||||
data-testid={`${props.variant}-button-focus`}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
</StyledButtonContainer>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
const ButtonContainer = (props: Partial<ButtonProps>) => {
|
const ButtonGroupLine: React.FC<ButtonProps> = ({ variant, ...props }) => (
|
||||||
const title = text('Text', 'A button title');
|
<>
|
||||||
|
{Object.entries(states).map(([state, { description, extraProps }]) => (
|
||||||
|
<StyledButtonContainer key={`${variant}-group-container-${state}`}>
|
||||||
|
<StyledDescription>{description}</StyledDescription>
|
||||||
|
<ButtonGroup>
|
||||||
|
<Button
|
||||||
|
{...props}
|
||||||
|
{...extraProps(`${variant}-left`)}
|
||||||
|
variant={variant}
|
||||||
|
title="Left"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
{...props}
|
||||||
|
{...extraProps(`${variant}-center`)}
|
||||||
|
variant={variant}
|
||||||
|
title="Center"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
{...props}
|
||||||
|
{...extraProps(`${variant}-right`)}
|
||||||
|
variant={variant}
|
||||||
|
title="Right"
|
||||||
|
/>
|
||||||
|
</ButtonGroup>
|
||||||
|
</StyledButtonContainer>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
const generateStory = (
|
||||||
|
size: ButtonProps['size'],
|
||||||
|
type: 'button' | 'group',
|
||||||
|
LineComponent: React.ComponentType<ButtonProps>,
|
||||||
|
): Story => ({
|
||||||
|
render: getRenderWrapperForComponent(
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
{variants.map((variant) => (
|
{variants.map((variant) => (
|
||||||
<div key={variant}>
|
<div key={variant}>
|
||||||
<StyledTitle>{variant}</StyledTitle>
|
<StyledTitle>{variant}</StyledTitle>
|
||||||
<StyledLine>
|
<StyledLine>
|
||||||
<ButtonLine {...props} title={title} variant={variant} />
|
<LineComponent
|
||||||
|
size={size}
|
||||||
|
variant={variant}
|
||||||
|
title={text('Text', 'A button title')}
|
||||||
|
/>
|
||||||
</StyledLine>
|
</StyledLine>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</StyledContainer>
|
</StyledContainer>,
|
||||||
);
|
),
|
||||||
};
|
|
||||||
|
|
||||||
// Medium size
|
|
||||||
export const MediumSize: Story = {
|
|
||||||
render: getRenderWrapperForComponent(<ButtonContainer />),
|
|
||||||
play: async ({ canvasElement }) => {
|
play: async ({ canvasElement }) => {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
|
let button;
|
||||||
|
if (type === 'group') {
|
||||||
|
button = canvas.getByTestId(`primary-left-button-default`);
|
||||||
|
} else {
|
||||||
|
button = canvas.getByTestId(`primary-button-default`);
|
||||||
|
}
|
||||||
|
|
||||||
expect(clickJestFn).toHaveBeenCalledTimes(0);
|
const numberOfClicks = clickJestFn.mock.calls.length;
|
||||||
|
|
||||||
const button = canvas.getByTestId('primary-button-default');
|
|
||||||
await userEvent.click(button);
|
await userEvent.click(button);
|
||||||
|
expect(clickJestFn).toHaveBeenCalledTimes(numberOfClicks + 1);
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
pseudo: Object.keys(states).reduce(
|
||||||
|
(acc, state) => ({
|
||||||
|
...acc,
|
||||||
|
[state]: variants.map(
|
||||||
|
(variant) =>
|
||||||
|
variant &&
|
||||||
|
['#left', '#center', '#right'].map(
|
||||||
|
(pos) => `${pos}-${variant}-${type}-${state}`,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(clickJestFn).toHaveBeenCalledTimes(1);
|
export const MediumSize = generateStory('medium', 'button', ButtonLine);
|
||||||
},
|
export const SmallSize = generateStory('small', 'button', ButtonLine);
|
||||||
};
|
export const MediumSizeGroup = generateStory(
|
||||||
MediumSize.parameters = {
|
'medium',
|
||||||
pseudo: {
|
'group',
|
||||||
hover: [
|
ButtonGroupLine,
|
||||||
'#primary-button-hover',
|
);
|
||||||
'#secondary-button-hover',
|
export const SmallSizeGroup = generateStory('small', 'group', ButtonGroupLine);
|
||||||
'#tertiary-button-hover',
|
|
||||||
'#tertiaryBold-button-hover',
|
|
||||||
'#tertiaryLight-button-hover',
|
|
||||||
'#danger-button-hover',
|
|
||||||
],
|
|
||||||
active: [
|
|
||||||
'#primary-button-pressed',
|
|
||||||
'#secondary-button-pressed',
|
|
||||||
'#tertiary-button-pressed',
|
|
||||||
'#tertiaryBold-button-pressed',
|
|
||||||
'#tertiaryLight-button-pressed',
|
|
||||||
'#danger-button-pressed',
|
|
||||||
],
|
|
||||||
focus: [
|
|
||||||
'#primary-button-focus',
|
|
||||||
'#secondary-button-focus',
|
|
||||||
'#tertiary-button-focus',
|
|
||||||
'#tertiaryBold-button-focus',
|
|
||||||
'#tertiaryLight-button-focus',
|
|
||||||
'#danger-button-focus',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Small size
|
|
||||||
export const SmallSize: Story = {
|
|
||||||
render: getRenderWrapperForComponent(<ButtonContainer size="small" />),
|
|
||||||
};
|
|
||||||
SmallSize.parameters = {
|
|
||||||
pseudo: {
|
|
||||||
hover: [
|
|
||||||
'#primary-button-hover',
|
|
||||||
'#secondary-button-hover',
|
|
||||||
'#tertiary-button-hover',
|
|
||||||
'#tertiaryBold-button-hover',
|
|
||||||
'#tertiaryLight-button-hover',
|
|
||||||
'#danger-button-hover',
|
|
||||||
],
|
|
||||||
active: [
|
|
||||||
'#primary-button-pressed',
|
|
||||||
'#secondary-button-pressed',
|
|
||||||
'#tertiary-button-pressed',
|
|
||||||
'#tertiaryBold-button-pressed',
|
|
||||||
'#tertiaryLight-button-pressed',
|
|
||||||
'#danger-button-pressed',
|
|
||||||
],
|
|
||||||
focus: [
|
|
||||||
'#primary-button-focus',
|
|
||||||
'#secondary-button-focus',
|
|
||||||
'#tertiary-button-focus',
|
|
||||||
'#tertiaryBold-button-focus',
|
|
||||||
'#tertiaryLight-button-focus',
|
|
||||||
'#danger-button-focus',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ type OwnProps = {
|
|||||||
export function TableActionBarButtonToggleComments({ onClick }: OwnProps) {
|
export function TableActionBarButtonToggleComments({ onClick }: OwnProps) {
|
||||||
return (
|
return (
|
||||||
<EntityTableActionBarButton
|
<EntityTableActionBarButton
|
||||||
label="Notes"
|
label="Note"
|
||||||
icon={<IconNotes size={16} />}
|
icon={<IconNotes size={16} />}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -33,3 +33,5 @@ export { IconFileUpload } from '@tabler/icons-react';
|
|||||||
export { IconChevronsRight } from '@tabler/icons-react';
|
export { IconChevronsRight } from '@tabler/icons-react';
|
||||||
export { IconNotes } from '@tabler/icons-react';
|
export { IconNotes } from '@tabler/icons-react';
|
||||||
export { IconCirclePlus } from '@tabler/icons-react';
|
export { IconCirclePlus } from '@tabler/icons-react';
|
||||||
|
export { IconCheckbox } from '@tabler/icons-react';
|
||||||
|
export { IconTimelineEvent } from '@tabler/icons-react';
|
||||||
|
|||||||
@ -65,16 +65,16 @@ const StyledItemLabel = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledSoonPill = styled.div`
|
const StyledSoonPill = styled.div`
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 50px;
|
|
||||||
background-color: ${({ theme }) => theme.background.transparent.light};
|
background-color: ${({ theme }) => theme.background.transparent.light};
|
||||||
|
border-radius: 50px;
|
||||||
|
display: flex;
|
||||||
font-size: ${({ theme }) => theme.font.size.xs};
|
font-size: ${({ theme }) => theme.font.size.xs};
|
||||||
height: 16px;
|
height: 16px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-left: auto;
|
||||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||||
padding-right: ${({ theme }) => theme.spacing(2)};
|
padding-right: ${({ theme }) => theme.spacing(2)};
|
||||||
margin-left: auto; // this aligns the pill to the right
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function NavItem({ label, icon, to, onClick, active, danger, soon }: OwnProps) {
|
function NavItem({ label, icon, to, onClick, active, danger, soon }: OwnProps) {
|
||||||
|
|||||||
@ -32,7 +32,7 @@ export const Default: Story = {
|
|||||||
),
|
),
|
||||||
play: async ({ canvasElement }) => {
|
play: async ({ canvasElement }) => {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
const notesButton = await canvas.findByText('Notes');
|
const notesButton = await canvas.findByText('Note');
|
||||||
await notesButton.click();
|
await notesButton.click();
|
||||||
},
|
},
|
||||||
parameters: {
|
parameters: {
|
||||||
|
|||||||
Reference in New Issue
Block a user