Skip to content

Commit

Permalink
feat: button, spinner, icon
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsimao committed Feb 29, 2024
1 parent 81e6afc commit efa0621
Show file tree
Hide file tree
Showing 26 changed files with 401 additions and 145 deletions.
11 changes: 10 additions & 1 deletion packages/components/src/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Meta, StoryObj } from '@storybook/react';
import { XMark } from '@interlay/icons';

import { Button, ButtonProps } from '.';

Expand All @@ -15,7 +16,15 @@ export default {

export const Solid: StoryObj<ButtonProps> = {
args: {
variant: 'solid'
variant: 'solid',
loading: true
}
};

export const Icon: StoryObj<ButtonProps> = {
args: {
isIconOnly: true,
children: <XMark />
}
};

Expand Down
9 changes: 8 additions & 1 deletion packages/components/src/Button/Button.style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type StyledButtonProps = {
$color: ButtonColors;
$variant: ButtonVariants;
$isFocusVisible?: boolean;
$isIconOnly?: boolean;
};

const StyledButton = styled.button<StyledButtonProps>`
Expand All @@ -23,14 +24,20 @@ const StyledButton = styled.button<StyledButtonProps>`
appearance: none;
user-select: none;
${({ theme, $size, $variant, $color, $isFocusVisible }) => {
${({ theme, $size, $variant, $color, $isFocusVisible, $isIconOnly }) => {
const { active, disabled, hover, focus, focusVisible } = theme.button.variant[$variant].color[$color];
return css`
${theme.button.base}
${theme.button.size[$size]}
${theme.button.variant[$variant].color[$color].base}
${$isFocusVisible && focusVisible}
${$isIconOnly &&
css`
padding: 0;
width: ${theme.button.size[$size].height};
`}
&:hover:not([disabled]) {
${hover}
Expand Down
51 changes: 33 additions & 18 deletions packages/components/src/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,41 @@ import { useFocusRing } from '@react-aria/focus';
import { mergeProps } from '@react-aria/utils';
import { PressEvent } from '@react-types/shared';
import { ButtonHTMLAttributes, forwardRef } from 'react';
import { ButtonVariants, ButtonSizes, ButtonColors } from '@interlay/themev2';
import { ButtonVariants, ButtonSizes, ButtonColors, SpinnerSizes, SpinnerColors } from '@interlay/themev2';

import { Flex } from '../Flex';
import { Spinner } from '../Spinner';

import { StyledButton } from './Button.style';

// const loadingSizes: Record<ButtonSizes, IconSize> = {
// 'x-small': 'xs',
// small: 'xs',
// medium: 's',
// large: 's'
// };
const spinnerSizeMap: Record<ButtonSizes, SpinnerSizes> = {
s: 's',
md: 's',
lg: 'md',
xl: 'md',
'2xl': 'lg'
};

const spinnerColorMap: Record<ButtonColors, Record<ButtonVariants, SpinnerColors>> = {
default: {
ghost: 'default',
outline: 'default',
solid: 'default'
},
primary: {
ghost: 'primary',
outline: 'primary',
solid: 'default'
}
};

type Props = {
variant?: ButtonVariants;
fullWidth?: boolean;
size?: ButtonSizes;
color?: ButtonColors;
loading?: boolean;
isIconOnly?: boolean;
onPress?: (e: PressEvent) => void;
};

Expand All @@ -38,6 +56,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
size = 'md',
color = 'default',
fullWidth,
isIconOnly,
onPress,
onClick,
...props
Expand All @@ -57,22 +76,18 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
$color={color}
$fullWidth={fullWidth}
$isFocusVisible={isFocusVisible}
$isIconOnly={isIconOnly}
$size={size}
$variant={variant}
disabled={isDisabled}
{...mergeProps(props, buttonProps, focusProps, { onClick })}
>
{/* {loading && (
<LoadingWrapper>
<StyledSpinner
$variant={variant}
aria-label='Loading...'
size={loadingSizes[size]}
thickness={size === 'large' ? 3 : 2}
/>
</LoadingWrapper>
)} */}
{children}
{loading && (
<Flex elementType='span' marginRight={isIconOnly ? undefined : 'spacing2'}>
<Spinner aria-label='Loading...' color={spinnerColorMap[color][variant]} size={spinnerSizeMap[size]} />
</Flex>
)}
{isIconOnly ? (loading ? undefined : children) : children}
</StyledButton>
);
}
Expand Down
6 changes: 5 additions & 1 deletion packages/components/src/Spinner/Spinner.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Meta, StoryObj } from '@storybook/react';
import { SpinnerSizes } from '@interlay/themev2';

import { Spinner, SpinnerProps } from '.';

Expand All @@ -8,6 +9,9 @@ export default {
parameters: {
layout: 'centered'
},
argTypes: {
size: { control: 'radio', options: ['xs', 's', 'md', 'lg', 'xl', '2xl', '3xl'] as SpinnerSizes[] }
},
decorators: [
(Story) => (
<div style={{ display: 'flex' }}>
Expand All @@ -17,4 +21,4 @@ export default {
]
} as Meta;

export const Default: StoryObj<SpinnerProps> = {};
export const Default: StoryObj<SpinnerProps> = { args: {} };
23 changes: 13 additions & 10 deletions packages/components/src/Spinner/Spinner.style.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import styled from 'styled-components';
import { IconSize, theme } from '@interlay/theme';
import { CTAVariants } from '@interlay/theme';
import { SpinnerColors, SpinnerSizes } from '@interlay/themev2';
import styled, { css } from 'styled-components';

interface StyledSpinnerProps {
$size: IconSize | string;
$size: SpinnerSizes | string;
$thickness: number;
$color: CTAVariants;
$color: SpinnerColors;
}

const StyledSpinner = styled.span<StyledSpinnerProps>`
display: inline-flex;
width: ${({ $size }) => theme.spinner.sizes?.[$size as IconSize] || `${$size}px`};
height: ${({ $size }) => theme.spinner.sizes?.[$size as IconSize] || `${$size}px`};
position: relative;
text-indent: -9999em;
border-style: solid;
border-width: ${(props) => props.$thickness}px;
border-radius: 100%;
border-color: ${({ $color }) =>
`${theme.spinner[$color].color} ${theme.spinner[$color].bg} ${theme.spinner[$color].bg}`};
transform: translateZ(0);
animation: loadIndeterminate 1.1s infinite linear;
${({ theme, $size, $color }) => {
return css`
width: ${theme.spinner.size[$size as SpinnerSizes]?.width || `${$size}px`};
height: ${theme.spinner.size[$size as SpinnerSizes]?.height || `${$size}px`};
${theme.spinner.color[$color]}
`;
}}
@-webkit-keyframes loadIndeterminate {
0% {
transform: rotate(0deg);
Expand All @@ -41,5 +44,5 @@ const StyledSpinner = styled.span<StyledSpinnerProps>`
}
`;

export type { StyledSpinnerProps };
export { StyledSpinner };
export type { StyledSpinnerProps };
26 changes: 21 additions & 5 deletions packages/components/src/Spinner/Spinner.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
import { HTMLAttributes } from 'react';
import { CTAVariants, IconSize } from '@interlay/theme';
import { SpinnerColors, SpinnerSizes } from '@interlay/themev2';

import { StyledSpinner } from './Spinner.style';

const thicknessMap: Record<SpinnerSizes, number> = {
xs: 3,
s: 3,
md: 3,
lg: 4.5,
xl: 5,
'2xl': 6,
'3xl': 7
};

type Props = {
thickness?: number;
color?: CTAVariants;
size?: IconSize | string;
color?: SpinnerColors;
size?: SpinnerSizes | string;
};

type NativeAttrs = Omit<HTMLAttributes<unknown>, keyof Props>;

type SpinnerProps = Props & NativeAttrs;

const Spinner = ({ size = 'md', thickness = 4, color = 'primary', ...props }: SpinnerProps): JSX.Element => (
<StyledSpinner {...props} $color={color} $size={size} $thickness={thickness} role='progressbar' />
const Spinner = ({ size = 'md', thickness, color = 'default', ...props }: SpinnerProps): JSX.Element => (
<StyledSpinner
{...props}
$color={color}
$size={size}
$thickness={thickness || thicknessMap[size as SpinnerSizes] || 4}
role='progressbar'
/>
);

export { Spinner };
Expand Down
18 changes: 9 additions & 9 deletions packages/core/themeV2/src/components/button.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { Styles } from 'styled-components/dist/types';
import { StyledObject } from 'styled-components/dist/types';

type ButtonSizes = 's' | 'md' | 'lg' | 'xl' | '2xl';

type ButtonColors = 'default' | 'primary';

type ButtonColorsParams = {
base: Styles<object>;
hover: Styles<object>;
active: Styles<object>;
focus?: Styles<object>;
focusVisible?: Styles<object>;
disabled: Styles<object>;
base: StyledObject<object>;
hover: StyledObject<object>;
active: StyledObject<object>;
focus?: StyledObject<object>;
focusVisible?: StyledObject<object>;
disabled: StyledObject<object>;
};

type ButtonVariantParams = {
Expand All @@ -20,8 +20,8 @@ type ButtonVariantParams = {
type ButtonVariants = 'solid' | 'outline' | 'ghost';

type ButtonTheme = {
base: Styles<object>;
size: Record<ButtonSizes, Styles<object>>;
base: StyledObject<object>;
size: Record<ButtonSizes, StyledObject<object>>;
variant: Record<ButtonVariants, ButtonVariantParams>;
};

Expand Down
1 change: 1 addition & 0 deletions packages/core/themeV2/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from './drawer';
export * from './list';
export * from './radio';
export * from './switch';
export * from './spinner';
36 changes: 8 additions & 28 deletions packages/core/themeV2/src/components/input.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,14 @@
import { FontSize, Rounded } from '../core';
import { StyledObject } from 'styled-components';

type InputSizes = 's' | 'md' | 'lg';

type InputSizeParams = {
text: FontSize;
};

// TODO: missing paddings
type InputTheme = {
color: string;
bg: string;
rounded: Rounded;
placeholder: string;
hover: {
border: string;
};
focus: {
border: string;
boxShadow: string;
};
error: {
color: string;
border: string;
};
disabled: {
color: string;
bg: string;
border: string;
};
size: Record<InputSizes, InputSizeParams>;
base: StyledObject<object>;
hover: StyledObject<object>;
focus: StyledObject<object>;
error: StyledObject<object>;
disabled: StyledObject<object>;
size: Record<InputSizes, StyledObject<object>>;
};

export type { InputTheme, InputSizes };
export type { InputSizes, InputTheme };
14 changes: 14 additions & 0 deletions packages/core/themeV2/src/components/spinner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { StyledObject } from 'styled-components/dist/types';

type SpinnerSizes = 'xs' | 's' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';

type SpinnerColors = 'default' | 'primary';

type SpinnerColorsParams = StyledObject<object>;

type SpinnerTheme = {
size: Record<SpinnerSizes, StyledObject<object>>;
color: Record<SpinnerColors, SpinnerColorsParams>;
};

export type { SpinnerColors, SpinnerSizes, SpinnerTheme };
13 changes: 12 additions & 1 deletion packages/core/themeV2/src/core/colors.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
type ColorHue = keyof Colors;

type ColorShade = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
type ColorShade = 50 | 75 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;

type Colors = {
light: string;
Expand All @@ -12,4 +12,15 @@ type Colors = {
// error: Color;
};

const color =
(colors: Colors) =>
(hue: ColorHue, shade: ColorShade = 500) => {
if (hue === 'light' || hue === 'dark') {
return colors[hue];
}

return colors[hue][shade];
};

export { color };
export type { Colors, ColorHue, ColorShade };
Loading

0 comments on commit efa0621

Please sign in to comment.