From c8c39e0155cafed8ca2faad1413011408babf92a Mon Sep 17 00:00:00 2001 From: lwih Date: Mon, 15 Apr 2024 10:50:43 +0200 Subject: [PATCH] feat(elements): introduce LinkButton component --- src/elements/LinkButton.tsx | 75 ++++++++++++++ src/index.ts | 2 + stories/elements/LinkButton.stories.tsx | 128 ++++++++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 src/elements/LinkButton.tsx create mode 100644 stories/elements/LinkButton.stories.tsx diff --git a/src/elements/LinkButton.tsx b/src/elements/LinkButton.tsx new file mode 100644 index 000000000..3b418e5e0 --- /dev/null +++ b/src/elements/LinkButton.tsx @@ -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 & { + Icon?: FunctionComponent + children?: string | ReactNode + size: Size +} + +const FONT_SIZE: Record = { + [Size.LARGE]: '16px', + [Size.NORMAL]: '13px', + [Size.SMALL]: '11px' +} +const ICON_SIZE: Record = { + [Size.LARGE]: 16, + [Size.NORMAL]: 13, + [Size.SMALL]: 11 +} + +const StyledLinkButton = styled.button` + 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) { + return ( + + <> + {Icon && } + {isString(children) ?

{children}

: <>{children}} + +
+ ) +} + +LinkButton.displayName = 'LinkButton' + +export { LinkButton } diff --git a/src/index.ts b/src/index.ts index 00f0d469a..0e01f3941 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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' @@ -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' diff --git a/stories/elements/LinkButton.stories.tsx b/stories/elements/LinkButton.stories.tsx new file mode 100644 index 000000000..d7ef756e2 --- /dev/null +++ b/stories/elements/LinkButton.stories.tsx @@ -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 = { + ...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 ( + <> +

A LinkButton which you can play with:

+
+ + + + + + + Small + Normal + Large + + + + + Just text + + a dummy text + + + a dummy text + + + a dummy text + + + + Funky Text + + + text in italic + + + + + + text with bold emphasis + + + + + + + text with bold and italic emphasis + + + + + + Text with icon + + + a dummy text + + + + + a dummy text + + + + + a dummy text + + + + + Disabled + + + a dummy text + + + + + a dummy text + + + + + a dummy text + + + + + + + + ) +}