Skip to content

Commit

Permalink
♻️ refactor(major): refactored icon text button component
Browse files Browse the repository at this point in the history
  • Loading branch information
e1en0r committed Jun 19, 2021
1 parent 6e933cb commit 80eea5a
Show file tree
Hide file tree
Showing 20 changed files with 1,360 additions and 686 deletions.
10 changes: 7 additions & 3 deletions __tests__/components/Button/IconTextButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ import { AsTypeA } from '__mocks__/AsType.mock';

describe('<IconTextButton />', () => {
it('should render a basic icon tet button', () => {
const { container, getByText } = render(<IconTextButton icon={TimesIcon} text="Click me!" />);
const { container, getByText } = render(<IconTextButton icon={TimesIcon}>Click me!</IconTextButton>);
expect(container.firstChild?.nodeName).toBe('BUTTON');
expect(container.querySelector('svg')).toBeTruthy();
expect(getByText('Click me!')).toBeTruthy();
});

it('should render an icon button as an anchor', () => {
const { container, getByText } = render(
<IconTextButton<'a'> as="a" href="#iconbutton" icon={TimesIcon} text="Click me!" />,
<IconTextButton<'a'> as="a" href="#iconbutton" icon={TimesIcon}>
Click me!
</IconTextButton>,
);
expect(container.firstChild?.nodeName).toBe('A');
expect(container.firstChild).toHaveAttribute('href', '#iconbutton');
Expand All @@ -24,7 +26,9 @@ describe('<IconTextButton />', () => {

it('should render an icon text button using a functional component', () => {
const { container, getByText } = render(
<IconTextButton<'a'> as={AsTypeA} href="#iconbutton" icon={TimesIcon} text="Click me!" />,
<IconTextButton<'a'> as={AsTypeA} href="#iconbutton" icon={TimesIcon}>
Click me!
</IconTextButton>,
);
expect(container.firstChild?.nodeName).toBe('A');
expect(container.firstChild).toHaveAttribute('href', '#iconbutton');
Expand Down
62 changes: 31 additions & 31 deletions src/components/Badge/docs/badge.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Badge, ColoredBadge, StyledBadge } from '../index';

<PageTitle title="Badge" src="components/Badge" />

## Marker badges
## Point badges

<Playground>
<ThemeWrapper>
Expand All @@ -29,32 +29,32 @@ import { Badge, ColoredBadge, StyledBadge } from '../index';
margin: '20px',
}}
>
<Badge position="top-left" shape="marker" color="primary" />
<Badge position="top-right" shape="marker" color="success" />
<Badge position="bottom-left" shape="marker" color="warning" />
<Badge position="bottom-right" shape="marker" color="danger" />
<Badge position="top-left" shape="point" color="primary" />
<Badge position="top-right" shape="point" color="success" />
<Badge position="bottom-left" shape="point" color="warning" />
<Badge position="bottom-right" shape="point" color="danger" />
</div>
<Flex direction="row" alignItems="center" wrap>
<Rhythm m={2}>
<Badge shape="marker" color="primary" />
<Badge shape="marker" color="success" />
<Badge shape="marker" color="warning" />
<Badge shape="marker" color="danger" />
<Badge shape="marker" color="neutral" />
<Badge shape="point" color="primary" />
<Badge shape="point" color="success" />
<Badge shape="point" color="warning" />
<Badge shape="point" color="danger" />
<Badge shape="point" color="neutral" />
</Rhythm>
<Rhythm m={2}>
<Badge shape="marker" color="primary" pulsing />
<Badge shape="marker" color="success" pulsing />
<Badge shape="marker" color="warning" pulsing />
<Badge shape="marker" color="danger" pulsing />
<Badge shape="marker" color="neutral" pulsing />
<Badge shape="point" color="primary" pulsing />
<Badge shape="point" color="success" pulsing />
<Badge shape="point" color="warning" pulsing />
<Badge shape="point" color="danger" pulsing />
<Badge shape="point" color="neutral" pulsing />
</Rhythm>
</Flex>
</Flex>
</ThemeWrapper>
</Playground>

## Point badges
## Marker badges

<Playground>
<ThemeWrapper>
Expand All @@ -68,25 +68,25 @@ import { Badge, ColoredBadge, StyledBadge } from '../index';
margin: '20px',
}}
>
<Badge position="top-left" shape="point" color="primary" />
<Badge position="top-right" shape="point" color="success" />
<Badge position="bottom-left" shape="point" color="warning" />
<Badge position="bottom-right" shape="point" color="danger" />
<Badge position="top-left" shape="marker" color="primary" />
<Badge position="top-right" shape="marker" color="success" />
<Badge position="bottom-left" shape="marker" color="warning" />
<Badge position="bottom-right" shape="marker" color="danger" />
</div>
<Flex direction="row" alignItems="center" wrap>
<Rhythm m={2}>
<Badge shape="point" color="primary" />
<Badge shape="point" color="success" />
<Badge shape="point" color="warning" />
<Badge shape="point" color="danger" />
<Badge shape="point" color="neutral" />
<Badge shape="marker" color="primary" />
<Badge shape="marker" color="success" />
<Badge shape="marker" color="warning" />
<Badge shape="marker" color="danger" />
<Badge shape="marker" color="neutral" />
</Rhythm>
<Rhythm m={2}>
<Badge shape="point" color="primary" pulsing />
<Badge shape="point" color="success" pulsing />
<Badge shape="point" color="warning" pulsing />
<Badge shape="point" color="danger" pulsing />
<Badge shape="point" color="neutral" pulsing />
<Badge shape="marker" color="primary" pulsing />
<Badge shape="marker" color="success" pulsing />
<Badge shape="marker" color="warning" pulsing />
<Badge shape="marker" color="danger" pulsing />
<Badge shape="marker" color="neutral" pulsing />
</Rhythm>
</Flex>
</Flex>
Expand Down Expand Up @@ -336,7 +336,7 @@ import { Badge, ColoredBadge, StyledBadge } from '../index';
position: 'relative',
width: '60px',
height: '40px',
backgroundColor: themes.light['contrast-palette-quietest-color'],
backgroundColor: themes.light['color-BG50-O40'],
margin: '20px',
marginRight: 40,
flex: 'none',
Expand Down
11 changes: 2 additions & 9 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
import { cx } from '@emotion/css';
import React from 'react';
import { SemanticColor, ThemeProps, MergeElementProps, AsReactType } from '../../types';
import { ThemeProps, MergeElementProps, AsReactType } from '../../types';
import { useThemeId } from '../../hooks/useThemeId';
import styles from './styles/Button.module.css';

export type ButtonAlignment = 'left' | 'right' | 'center';
export type ButtonWeight = 'solid' | 'shaded' | 'outlined' | 'ghost' | 'inline';
export type ButtonShape = 'pill' | 'brick';
export type ButtonSize = 'small' | 'medium' | 'large' | 'relative';
export type ButtonColor = SemanticColor | 'neutralAndPrimary' | 'black' | 'white';

export type ButtonElementType = Extract<keyof JSX.IntrinsicElements, 'button' | 'a' | 'div' | 'span'>;
import { ButtonAlignment, ButtonWeight, ButtonShape, ButtonSize, ButtonColor, ButtonElementType } from './types';

export interface LocalButtonProps extends ThemeProps {
/** Manually apply the active styles; this does not actually make it active */
Expand Down
3 changes: 2 additions & 1 deletion src/components/Button/ButtonGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import React, { useCallback } from 'react';
import { MergeElementProps, Orientation, ThemeProps } from '../../types';
import { useThemeId } from '../../hooks/useThemeId';
import { renderFromProp } from '../../utils';
import { Button, ButtonColor, ButtonProps, ButtonSize, ButtonWeight } from './Button';
import { Button, ButtonProps } from './Button';
import styles from './styles/ButtonGroup.module.css';
import { ButtonColor, ButtonSize, ButtonWeight } from './types';

export type ButtonGroupSpacing = 'divided' | 'joined' | 'cozy' | 'comfy';

Expand Down
3 changes: 2 additions & 1 deletion src/components/Button/ColoredButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import React from 'react';
import { MergeProps, Theme } from '../../types';
import { themes, ThemeColors, ThemeColorIds } from '../../config';
import { withTheme } from '../../context/Theme';
import { Button, ButtonElementType, ButtonProps } from './Button';
import { Button, ButtonProps } from './Button';
import { ButtonElementType } from './types';

export type ColoredButtonProps<T extends ButtonElementType = 'button'> = MergeProps<
Omit<ButtonProps<T>, 'width'>,
Expand Down
3 changes: 2 additions & 1 deletion src/components/Button/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { cx } from '@emotion/css';
import React from 'react';
import { AsReactType, MergeElementProps } from '../../types';
import { renderFromPropWithFallback, RenderFromPropElement } from '../../utils/renderFromProp';
import { Button, ButtonElementType, ButtonProps, LocalButtonProps } from './Button';
import { Button, ButtonProps, LocalButtonProps } from './Button';
import styles from './styles/Button.module.css';
import { ButtonElementType } from './types';

export type IconButtonShape = 'round' | 'square';
export type IconButtonElementType = ButtonElementType;
Expand Down
9 changes: 5 additions & 4 deletions src/components/Button/IconTextButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,31 @@ import { cx } from '@emotion/css';
import React from 'react';
import { AsReactType, MergeElementProps } from '../../types';
import { renderFromProp, renderFromPropWithFallback, RenderFromPropElement } from '../../utils/renderFromProp';
import { Button, ButtonElementType, LocalButtonProps, ButtonProps } from './Button';
import { Button, LocalButtonProps, ButtonProps } from './Button';
import styles from './styles/Button.module.css';
import { ButtonElementType } from './types';

export type IconTextButtonElementType = ButtonElementType;

export interface LocalIconTextButtonProps extends Omit<LocalButtonProps, 'children'> {
icon: RenderFromPropElement<{}>;
text: RenderFromPropElement<{}> | string;
children: RenderFromPropElement<{}> | string;
reverse?: boolean;
}

export type IconTextButtonProps<T extends ButtonElementType = 'button'> = AsReactType<T> &
MergeElementProps<T, LocalIconTextButtonProps>;

export function IconTextButtonBase<T extends IconTextButtonElementType = 'button'>(
{ as, className, icon, reverse, text, ...props }: IconTextButtonProps<T>,
{ as, children, className, icon, reverse, ...props }: IconTextButtonProps<T>,
forwardedRef: React.ForwardedRef<HTMLElementTagNameMap[T]>,
): React.ReactElement {
const classes = cx(reverse ? styles['button--iconTextReverse'] : styles['button--iconText'], className);

return (
<Button<T> as={as} className={classes} ref={forwardedRef} {...(props as ButtonProps<T>)}>
<span className={styles.button__icon}>{renderFromProp<{}>(icon)}</span>
<span className={styles.button__text}>{renderFromPropWithFallback<{}>(text)}</span>
<span className={styles.button__text}>{renderFromPropWithFallback<{}>(children)}</span>
</Button>
);
}
Expand Down
3 changes: 2 additions & 1 deletion src/components/Button/StyledButton.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import styled from '@emotion/styled';
import { MergeProps } from '../../types';
import { Button, ButtonElementType, ButtonProps } from './Button';
import { Button, ButtonProps } from './Button';
import { ButtonElementType } from './types';

export type StyledButtonProps<T extends ButtonElementType = 'button'> = MergeProps<
Omit<ButtonProps<T>, 'width'>,
Expand Down
28 changes: 28 additions & 0 deletions src/components/Button/StyledIconButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import styled from '@emotion/styled';
import { MergeProps } from '../../types';
import { IconButton, IconButtonElementType, IconButtonProps } from './IconButton';

export type StyledIconButtonProps<T extends IconButtonElementType = 'button'> = MergeProps<
Omit<IconButtonProps<T>, 'width'>,
{
primaryColor?: string;
inverseColor?: string;
hoveredPrimaryColor?: string;
activePrimaryColor?: string;
width: number | string;
}
>;

// @ts-ignore [TODO:ts] WTF
export const StyledIconButton = styled(IconButton, {
shouldForwardProp: (prop: string) =>
!['primaryColor', 'inverseColor', 'hoveredPrimaryColor', 'activePrimaryColor', 'width'].includes(prop),
})<StyledIconButtonProps>`
${({ primaryColor }) => primaryColor && `--button-primary-color: ${primaryColor};`}
${({ inverseColor }) => inverseColor && `--button-inverse-color: ${inverseColor};`}
${({ hoveredPrimaryColor }) => hoveredPrimaryColor && `--button-hovered-primary-color: ${hoveredPrimaryColor};`}
${({ activePrimaryColor }) => activePrimaryColor && `--button-active-primary-color: ${activePrimaryColor};`}
${({ width }) => width !== undefined && `width: ${Number.isNaN(width) ? width : `${width}px`};`}
`;

StyledIconButton.displayName = 'StyledIconButton';
28 changes: 28 additions & 0 deletions src/components/Button/StyledIconTextButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import styled from '@emotion/styled';
import { MergeProps } from '../../types';
import { IconTextButton, IconTextButtonElementType, IconTextButtonProps } from './IconTextButton';

export type StyledIconTextButtonProps<T extends IconTextButtonElementType = 'button'> = MergeProps<
Omit<IconTextButtonProps<T>, 'width'>,
{
primaryColor?: string;
inverseColor?: string;
hoveredPrimaryColor?: string;
activePrimaryColor?: string;
width: number | string;
}
>;

// @ts-ignore [TODO:ts] WTF
export const StyledIconTextButton = styled(IconTextButton, {
shouldForwardProp: (prop: string) =>
!['primaryColor', 'inverseColor', 'hoveredPrimaryColor', 'activePrimaryColor', 'width'].includes(prop),
})<StyledIconTextButtonProps>`
${({ primaryColor }) => primaryColor && `--button-primary-color: ${primaryColor};`}
${({ inverseColor }) => inverseColor && `--button-inverse-color: ${inverseColor};`}
${({ hoveredPrimaryColor }) => hoveredPrimaryColor && `--button-hovered-primary-color: ${hoveredPrimaryColor};`}
${({ activePrimaryColor }) => activePrimaryColor && `--button-active-primary-color: ${activePrimaryColor};`}
${({ width }) => width !== undefined && `width: ${Number.isNaN(width) ? width : `${width}px`};`}
`;

StyledIconTextButton.displayName = 'StyledIconTextButton';
Loading

0 comments on commit 80eea5a

Please sign in to comment.