Skip to content

Commit

Permalink
feat(elements): introduce LinkButton component
Browse files Browse the repository at this point in the history
  • Loading branch information
lwih committed Apr 17, 2024
1 parent 76c1d53 commit c8c39e0
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 0 deletions.
75 changes: 75 additions & 0 deletions src/elements/LinkButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { type IconProps } from '@types_/definitions'
import { isString } from 'lodash'
import { type ButtonHTMLAttributes, type FunctionComponent, type ReactNode } from 'react'
import styled from 'styled-components'

import { Size } from '../constants'
import { THEME } from '../theme'

export type LinkButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
Icon?: FunctionComponent<IconProps>
children?: string | ReactNode
size: Size
}

const FONT_SIZE: Record<Size, string> = {
[Size.LARGE]: '16px',
[Size.NORMAL]: '13px',
[Size.SMALL]: '11px'
}
const ICON_SIZE: Record<Size, number> = {
[Size.LARGE]: 16,
[Size.NORMAL]: 13,
[Size.SMALL]: 11
}

const StyledLinkButton = styled.button<LinkButtonProps>`
display: flex;
flex-direction: row;
gap: 0.4rem;
align-items: flex-end;
background: transparent;
text-decoration: underline;
cursor: ${({ disabled }: LinkButtonProps) => (disabled ? 'none' : 'pointer')}};
font-size: ${({ size }: LinkButtonProps) => FONT_SIZE[size]}};
color: ${p => p.theme.color.slateGray};
&:hover,
&._hover {
color: ${p => p.theme.color.blueYonder};
svg {
color: ${p => p.theme.color.blueYonder};
}
}
&:active,
&._active {
color: ${p => p.theme.color.blueGray};
svg {
color: ${p => p.theme.color.blueGray};
}
}
&:disabled,
&._disabled {
color: ${p => p.theme.color.lightGray};
svg {
color: ${p => p.theme.color.lightGray};
}
}
`

function LinkButton({ children, Icon, ...props }: Readonly<LinkButtonProps>) {
return (
<StyledLinkButton {...props}>
<>
{Icon && <Icon color={THEME.color.slateGray} size={ICON_SIZE[props.size]} />}
{isString(children) ? <p>{children}</p> : <>{children}</>}
</>
</StyledLinkButton>
)
}

LinkButton.displayName = 'LinkButton'

export { LinkButton }
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export { Fieldset } from './elements/Fieldset'
export { FieldError } from './elements/FieldError'
export { Figure } from './elements/Figure'
export { IconButton } from './elements/IconButton'
export { LinkButton } from './elements/LinkButton'
export { Label } from './elements/Label'
export { Legend } from './elements/Legend'
export { Tag } from './elements/Tag'
Expand Down Expand Up @@ -206,6 +207,7 @@ export type { FigureProps } from './elements/Figure'
export type { IconButtonProps } from './elements/IconButton'
export type { LabelProps } from './elements/Label'
export type { LegendProps } from './elements/Legend'
export type { LinkButtonProps } from './elements/LinkButton'
export type { TagProps } from './elements/Tag'
export type { TagGroupProps } from './elements/TagGroup'

Expand Down
128 changes: 128 additions & 0 deletions stories/elements/LinkButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { Showcase } from '../../.storybook/components/Showcase'
import { ARG_TYPE, META_DEFAULTS } from '../../.storybook/constants'
import { generateStoryDecorator } from '../../.storybook/utils/generateStoryDecorator'
import { Icon, LinkButton, Size } from '../../src'

import type { LinkButtonProps } from '../../src'
import type { Meta } from '@storybook/react'

/* eslint-disable sort-keys-fix/sort-keys-fix */
const meta: Meta<LinkButtonProps> = {
...META_DEFAULTS,

title: 'Elements/LinkButton',
component: LinkButton,

argTypes: {
disabled: ARG_TYPE.OPTIONAL_BOOLEAN,
Icon: ARG_TYPE.ICON,
size: ARG_TYPE.OPTIONAL_SIZE,
children: ARG_TYPE.OPTIONAL_STRING
},

args: {
disabled: false,
Icon: Icon.Close,
size: Size.NORMAL,
children: 'a random text'
},

decorators: [generateStoryDecorator()]
}
/* eslint-enable sort-keys-fix/sort-keys-fix */

export default meta

export function _LinkButton(props: LinkButtonProps) {
return (
<>
<h4>A LinkButton which you can play with:</h4>
<br />
<LinkButton {...props} />
<Showcase>
<Showcase.Table>
<thead>
<tr>
<td />
<th>Small</th>
<th>Normal</th>
<th>Large</th>
</tr>
</thead>
<tbody>
<tr>
<th>Just text</th>
<td>
<LinkButton size={Size.SMALL}>a dummy text</LinkButton>
</td>
<td>
<LinkButton size={Size.NORMAL}>a dummy text</LinkButton>
</td>
<td>
<LinkButton size={Size.LARGE}>a dummy text</LinkButton>
</td>
</tr>
<tr>
<th>Funky Text</th>
<td>
<LinkButton size={Size.SMALL}>
<i>text in italic</i>
</LinkButton>
</td>
<td>
<LinkButton size={Size.NORMAL}>
<span>
text with <b>bold</b> emphasis
</span>
</LinkButton>
</td>
<td>
<LinkButton size={Size.LARGE}>
<span>
text with <b>bold</b> and <i>italic</i> emphasis
</span>
</LinkButton>
</td>
</tr>
<tr>
<th>Text with icon</th>
<td>
<LinkButton Icon={Icon.Reset} size={Size.SMALL}>
a dummy text
</LinkButton>
</td>
<td>
<LinkButton Icon={Icon.Reset} size={Size.NORMAL}>
a dummy text
</LinkButton>
</td>
<td>
<LinkButton Icon={Icon.Reset} size={Size.LARGE}>
a dummy text
</LinkButton>
</td>
</tr>
<tr>
<th>Disabled</th>
<td>
<LinkButton disabled size={Size.SMALL}>
a dummy text
</LinkButton>
</td>
<td>
<LinkButton disabled size={Size.NORMAL}>
a dummy text
</LinkButton>
</td>
<td>
<LinkButton disabled Icon={Icon.Reset} size={Size.LARGE}>
a dummy text
</LinkButton>
</td>
</tr>
</tbody>
</Showcase.Table>
</Showcase>
</>
)
}

0 comments on commit c8c39e0

Please sign in to comment.