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

refactor: TET-209 button & iconButton #66

Merged
merged 10 commits into from
Sep 15, 2023
22 changes: 8 additions & 14 deletions src/components/AlertBanner/stylesBuilder/stylesBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import { AlertBannerProps } from '../AlertBanner.props';
import { defaultConfig } from '../AlertBanner.styles';
import { AlertBannerIntent } from '../types';

import { ButtonProps } from '@/components/Button';
import { ButtonAppearance } from '@/components/Button/types/ButtonAppearance.type';
import { IconButtonProps } from '@/components/IconButton/IconButton.props';
import { IconButtonAppearance } from '@/components/IconButton/IconButtonAppearance.type';
import { BareButtonProps } from '@/components/Button/Button.props';
import { GhostIconButtonProps } from '@/components/IconButton/IconButton.props';
import { mergeConfigWithCustom } from '@/services';
import { BaseProps } from '@/types/BaseProps';

Expand All @@ -14,8 +12,8 @@ type AlertBannerStylesBuilder = {
iconContainer: BaseProps;
actionContainer: BaseProps;
closeButton: BaseProps;
actionProps: Partial<ButtonProps<'ghost'>>;
closeButtonProps: Partial<IconButtonProps<'ghost'>>;
actionProps: Partial<BareButtonProps>;
closeButtonProps: Partial<GhostIconButtonProps>;
};

export const stylesBuilder = (
Expand All @@ -29,16 +27,12 @@ export const stylesBuilder = (
} = mergeConfigWithCustom({ defaultConfig, custom });

const actionProps = {
appearance: (intent === 'warning'
? 'reverseInverted'
: 'inverted') as ButtonAppearance<'ghost'>,
};
appearance: intent === 'warning' ? 'reverseInverted' : 'inverted',
} as const;

const closeButtonProps = {
appearance: (intent === 'warning'
? 'primary'
: 'inverted') as IconButtonAppearance<'ghost'>,
};
appearance: intent === 'warning' ? 'primary' : 'inverted',
} as const;

return {
container: {
Expand Down
115 changes: 115 additions & 0 deletions src/components/Button/Button.props.case.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { ButtonProps } from '.';

type Props = Partial<ButtonProps>;

const case0: Props = {
variant: 'default',
appearance: 'primary',
intent: 'none',
};
const case1: Props = {
variant: 'default',
appearance: 'primary',
intent: 'success',
};
const case2: Props = {
variant: 'default',
appearance: 'primary',
intent: 'destructive',
};

const case3: Props = {
variant: 'default',
appearance: 'secondary',
intent: 'none',
};
const case4: Props = {
variant: 'default',
appearance: 'secondary',
intent: 'success',
};
const case5: Props = {
variant: 'default',
appearance: 'secondary',
intent: 'destructive',
};

const case6: Props = {
variant: 'default',
appearance: 'inverted',
intent: 'none',
};
// @ts-expect-error - wrong intent
const case7: Props = {
variant: 'default',
appearance: 'inverted',
intent: 'success',
};
// @ts-expect-error - wrong intent
const case8: Props = {
variant: 'default',
appearance: 'inverted',
intent: 'destructive',
};
// @ts-expect-error - wrong appearance
const case9: Props = {
variant: 'default',
appearance: 'reverseInverted',
};

const case10: Props = {
variant: 'ghost',
appearance: 'primary',
intent: 'none',
};
const case11: Props = {
variant: 'ghost',
appearance: 'primary',
intent: 'success',
};
const case12: Props = {
variant: 'ghost',
appearance: 'primary',
intent: 'destructive',
};

const case13: Props = {
variant: 'ghost',
appearance: 'secondary',
intent: 'none',
};
// @ts-expect-error - wrong intent
const case14: Props = {
variant: 'ghost',
appearance: 'secondary',
intent: 'destructive',
};

const case15: Props = {
variant: 'ghost',
appearance: 'inverted',
intent: 'none',
};
const case16: Props = {
variant: 'ghost',
appearance: 'reverseInverted',
intent: 'none',
};

const case17: Props = {
variant: 'bare',
appearance: 'primary',
intent: 'success',
};
const case18: Props = {
variant: 'bare',
appearance: 'primary',
intent: 'destructive',
};
// @ts-expect-error - wrong intent
const case19: Props = {
variant: 'bare',
appearance: 'secondary',
intent: 'destructive',
};
37 changes: 13 additions & 24 deletions src/components/Button/Button.props.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,15 @@
import { ButtonHTMLAttributes } from 'react';
import { CommonButtonProps } from './types/CommonButtonProps.type';
import { PartialBareButtonProps } from './types/PartialBareButtonProps.type';
import { PartialDefaultButtonProps } from './types/PartialDefaultButtonProps';
import { PartialGhostButtonProps } from './types/PartialGhostButtonProps';

import { StylesBuilderProps } from './stylesBuilder/stylesBuilder.props';
import { ButtonAppearance } from './types/ButtonAppearance.type';
import { ButtonIntent } from './types/ButtonIntent.type';
import { ButtonSize } from './types/ButtonSize.type';
import { ButtonState } from './types/ButtonState.type';
import { ButtonVariant } from './types/ButtonType.type';
export type ButtonProps = CommonButtonProps &
(
| PartialDefaultButtonProps
| PartialGhostButtonProps
| PartialBareButtonProps
);

import { IconName } from '@/utility-types/IconName';
import { Or } from '@/utility-types/Or';

export type ButtonProps<
TVariant extends ButtonVariant = 'default',
TAppearance extends ButtonAppearance<TVariant> = ButtonAppearance<TVariant>,
> = {
variant?: TVariant;
appearance?: TAppearance;
size?: ButtonSize<TVariant>;
intent?: ButtonIntent<TVariant, TAppearance>;
label: string;
state?: ButtonState;
custom?: StylesBuilderProps<TVariant, TAppearance>['custom'];
beforeIcon?: IconName<20>;
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'disabled' | 'color'> &
Or<{ afterIcon?: IconName<20> }, { dropdownIndicator?: boolean }>;
export type DefaultButtonProps = CommonButtonProps & PartialDefaultButtonProps;
export type GhostButtonProps = CommonButtonProps & PartialGhostButtonProps;
export type BareButtonProps = CommonButtonProps & PartialBareButtonProps;
38 changes: 10 additions & 28 deletions src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import type { Meta, StoryObj } from '@storybook/react';
import { useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';

import { Button } from './Button';
import { ButtonAppearance } from './types/ButtonAppearance.type';
import { ButtonIntent } from './types/ButtonIntent.type';
import { ButtonSize } from './types/ButtonSize.type';
import { ButtonVariant } from './types/ButtonType.type';
import { ButtonProps } from './Button.props';
import { tet } from '../../tetrisly';

import { ButtonProps } from '.';

const meta = {
title: 'Components/Button',
component: Button,
Expand All @@ -34,13 +29,7 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;

const ButtonWithLoading = <
TVariant extends ButtonVariant,
TAppearance extends ButtonAppearance<TVariant>,
>({
state,
...props
}: ButtonProps<TVariant, TAppearance>) => {
const ButtonWithLoading: FC<ButtonProps> = ({ state, ...props }) => {
const [loading, setLoading] = useState(false);
useEffect(() => {
const timeout = setTimeout(() => {
Expand Down Expand Up @@ -98,7 +87,7 @@ export const DefaultAfterIcon: Story = {
export const DefaultDropdown: Story = {
...Default,
args: {
dropdownIndicator: true,
hasDropdownIndicator: true,
},
};

Expand Down Expand Up @@ -151,13 +140,15 @@ export const BareLoading: Story = {
...Bare,
args: {
state: 'loading',
variant: 'bare',
},
};

export const BareDisabled: Story = {
...Bare,
args: {
state: 'disabled',
variant: 'bare',
},
};

Expand All @@ -168,17 +159,6 @@ const controlDisabled = {
};

const entries = Object.entries as <T>(o: T) => [keyof T, T[keyof T]][];
type Combinations = {
[variant in ButtonVariant]: {
appearance: {
[appearance in ButtonAppearance<variant>]: ButtonIntent<
variant,
appearance
>[];
};
size: ButtonSize<variant>[];
};
};

const combinations = {
default: {
Expand Down Expand Up @@ -207,7 +187,7 @@ const combinations = {
},
size: ['medium', 'large'],
},
} satisfies Combinations;
};

export const AllOptions: Story = {
argTypes: {
Expand Down Expand Up @@ -310,7 +290,9 @@ export const AllOptions: Story = {
key: `${variant}-${appearanceOption}-${intent}-${size}`,
};

return <ButtonWithLoading {...props} />;
return (
<ButtonWithLoading {...(props as ButtonProps)} />
);
})}
</tet.div>
</tet.div>
Expand Down
Loading