-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(storybook): add Button component
- Loading branch information
Showing
2 changed files
with
349 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { Canvas, Controls, Meta, Source } from "@storybook/blocks"; | ||
import * as ButtonStories from "./Button.stories"; | ||
|
||
<Meta of={ButtonStories} /> | ||
|
||
# Button | ||
|
||
## Usage notes | ||
|
||
Please refer to [GOV.UK Design System documentation on | ||
buttons](https://design-system.service.gov.uk/components/button/) for more | ||
information. | ||
|
||
## Example | ||
|
||
<Canvas of={ButtonStories.Default} /> | ||
<Controls of={ButtonStories.Default} /> | ||
|
||
## Variants | ||
|
||
### Small size | ||
|
||
<Canvas of={ButtonStories.Small} /> | ||
|
||
### Large size | ||
|
||
<Canvas of={ButtonStories.Large} /> | ||
|
||
## Icons | ||
|
||
### with left icon | ||
|
||
<Canvas of={ButtonStories.WithIcon} /> | ||
|
||
### with right icon | ||
|
||
<Canvas of={ButtonStories.WithIconRight} /> | ||
|
||
### with icon only | ||
|
||
<Canvas of={ButtonStories.WithIconOnly} /> | ||
|
||
## States | ||
|
||
### Disabled | ||
|
||
<Canvas of={ButtonStories.Disabled} /> | ||
|
||
## Button as link | ||
|
||
<Canvas of={ButtonStories.Link} /> | ||
|
||
## Implementation notes | ||
|
||
- add `ds-button` as base class to a `button` element | ||
- combine with one size modifier: `ds-button-small` or `ds-button-large` | ||
- combine with one appearance modifier: `ds-button-secondary`, `ds-button-tertiary`, `ds-button-ghost` | ||
|
||
<Source of={ButtonStories.Large} /> | ||
|
||
- for full with add `ds-button-full-width` | ||
|
||
<Source of={ButtonStories.FullWidth} /> | ||
|
||
### with icons | ||
|
||
- use `svg` for the icon, add `ds-button-icon` class to the icon | ||
- add `ds-button-with-icon` class to the button | ||
- wrap text in a `span` with the class `ds-button-label` | ||
|
||
<Source of={ButtonStories.WithIcon} /> | ||
|
||
### with icon only | ||
|
||
- add `ds-button-with-icon-only` class | ||
- wrap (invisible) text in a `span` with class `sr-only` | ||
- have a look at [Accessible Icon Buttons](https://www.sarasoueidan.com/blog/accessible-icon-buttons/) | ||
|
||
<Source of={ButtonStories.WithIconOnly} /> | ||
|
||
### links that look like buttons | ||
|
||
- add `role="button"` to the link | ||
- have a look at this [discussion on links styled as buttons and a11y implications](https://github.com/alphagov/govuk_elements/pull/272) | ||
|
||
<Source of={ButtonStories.Link} /> | ||
|
||
### "disabled" buttons | ||
|
||
- use a `div` as tag and add `is-disabled` class | ||
|
||
<Source of={ButtonStories.Disabled} /> | ||
|
||
## Further documentation | ||
|
||
Please check out the code on the given examples and otherwise | ||
refer to [mdn web docs on \<button\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) | ||
for more technical information. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
import type { Meta, StoryObj } from "@storybook/html"; | ||
import { clsx } from "clsx"; | ||
import dedent from "dedent"; | ||
import { | ||
htmlAttrs, | ||
loremSentences, | ||
loremWords, | ||
} from "../../../.storybook/utils"; | ||
|
||
type ButtonArgs = { | ||
label: string; | ||
size?: "default" | "small" | "large"; | ||
appearance?: "default" | "secondary" | "tertiary" | "ghost"; | ||
fullWidth?: boolean; | ||
withIcon?: boolean; | ||
withIconRight?: boolean; | ||
withIconOnly?: boolean; | ||
disabled?: boolean; | ||
isLink?: boolean; | ||
}; | ||
|
||
const meta = { | ||
title: "Components/Button", | ||
render: ({ | ||
label, | ||
size, | ||
appearance, | ||
fullWidth, | ||
withIcon, | ||
withIconRight, | ||
withIconOnly, | ||
disabled, | ||
isLink, | ||
}) => { | ||
const cssClasses = clsx("ds-button", { | ||
"ds-button-large": size === "large", | ||
"ds-button-small": size === "small", | ||
"ds-button-secondary": appearance === "secondary", | ||
"ds-button-tertiary": appearance === "tertiary", | ||
"ds-button-ghost": appearance === "ghost", | ||
"is-disabled": disabled, | ||
"ds-button-with-icon": withIcon || withIconRight, | ||
"ds-button-with-icon-only": withIconOnly, | ||
"ds-button-full-width": fullWidth, | ||
}); | ||
const attrs = htmlAttrs({ className: cssClasses }); | ||
|
||
const icon = dedent` | ||
<svg class="ds-button-icon" width="36" height="36" viewBox="0 0 36 36" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | ||
<path d="M28.5 9.615L26.385 7.5L18 15.885L9.615 7.5L7.5 9.615L15.885 18L7.5 26.385L9.615 28.5L18 20.115L26.385 28.5L28.5 26.385L20.115 18L28.5 9.615Z"></path> | ||
</svg> | ||
`; | ||
|
||
if (disabled) { | ||
return dedent` | ||
<div ${attrs}> | ||
${label} | ||
</div> | ||
`; | ||
} | ||
|
||
if (isLink) { | ||
return dedent` | ||
<a href="https://digitalservice.bund.de" target="_blank" role="button" ${attrs}> | ||
${label} | ||
</a> | ||
`; | ||
} | ||
|
||
if (withIcon || withIconRight) { | ||
return dedent` | ||
<button ${attrs}> | ||
${withIcon ? icon : ""} | ||
<span class="ds-button-label"> | ||
${label} | ||
</span> | ||
${withIconRight ? icon : ""} | ||
</button> | ||
`; | ||
} | ||
|
||
if (withIconOnly) { | ||
return dedent` | ||
<button ${attrs}> | ||
${icon} | ||
<span class="sr-only"> | ||
${label} | ||
</span> | ||
</button> | ||
`; | ||
} | ||
|
||
return dedent` | ||
<button ${attrs}> | ||
${label} | ||
</button> | ||
`; | ||
}, | ||
argTypes: { | ||
disabled: { | ||
description: "Is the button not available for interaction?", | ||
}, | ||
label: { control: "text" }, | ||
withIcon: { control: "boolean" }, | ||
withIconRight: { control: "boolean" }, | ||
withIconOnly: { control: "boolean" }, | ||
size: { | ||
options: ["default", "small", "large"], | ||
control: { type: "radio" }, | ||
}, | ||
appearance: { | ||
options: ["default", "secondary", "tertiary", "ghost"], | ||
control: { type: "radio" }, | ||
}, | ||
}, | ||
args: { | ||
disabled: false, | ||
label: loremWords(4), | ||
size: "default", | ||
appearance: "default", | ||
withIcon: false, | ||
withIconRight: false, | ||
withIconOnly: false, | ||
}, | ||
} satisfies Meta<ButtonArgs>; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<ButtonArgs>; | ||
|
||
export const Default = {} satisfies Story; | ||
export const Small = { args: { size: "small" } } satisfies Story; | ||
export const Large = { args: { size: "large" } } satisfies Story; | ||
export const Disabled = { args: { disabled: true } } satisfies Story; | ||
export const Link = { args: { isLink: true } } satisfies Story; | ||
export const WithIcon = { args: { withIcon: true } } satisfies Story; | ||
export const WithIconRight = { args: { withIconRight: true } } satisfies Story; | ||
export const WithIconOnly = { args: { withIconOnly: true } } satisfies Story; | ||
export const FullWidth = { args: { fullWidth: true } } satisfies Story; | ||
export const FullWidthWithIcon = { | ||
args: { fullWidth: true, withIcon: true }, | ||
} satisfies Story; | ||
export const LongText = { args: { label: loremSentences(4) } } satisfies Story; | ||
export const LongTextWithIcon = { | ||
args: { label: loremSentences(4), withIcon: true }, | ||
} satisfies Story; | ||
|
||
export const Secondary = { args: { appearance: "secondary" } } satisfies Story; | ||
export const SecondarySmall = { | ||
args: { appearance: "secondary", size: "small" }, | ||
} satisfies Story; | ||
export const SecondaryLarge = { | ||
args: { appearance: "secondary", size: "large" }, | ||
} satisfies Story; | ||
export const SecondaryDisabled = { | ||
args: { appearance: "secondary", disabled: true }, | ||
} satisfies Story; | ||
export const SecondaryLink = { | ||
args: { appearance: "secondary", isLink: true }, | ||
} satisfies Story; | ||
export const SecondaryWithIcon = { | ||
args: { appearance: "secondary", withIcon: true }, | ||
} satisfies Story; | ||
export const SecondaryWithIconRight = { | ||
args: { appearance: "secondary", withIconRight: true }, | ||
} satisfies Story; | ||
export const SecondaryWithIconOnly = { | ||
args: { appearance: "secondary", withIconOnly: true }, | ||
} satisfies Story; | ||
export const SecondaryFullWidth = { | ||
args: { appearance: "secondary", fullWidth: true }, | ||
} satisfies Story; | ||
export const SecondaryFullWidthWithIcon = { | ||
args: { appearance: "secondary", fullWidth: true, withIcon: true }, | ||
} satisfies Story; | ||
export const SecondaryLongText = { | ||
args: { appearance: "secondary", label: loremSentences(4) }, | ||
} satisfies Story; | ||
export const SecondaryLongTextWithIcon = { | ||
args: { appearance: "secondary", label: loremSentences(4), withIcon: true }, | ||
} satisfies Story; | ||
|
||
export const Tertiary = { args: { appearance: "tertiary" } } satisfies Story; | ||
export const TertiarySmall = { | ||
args: { appearance: "tertiary", size: "small" }, | ||
} satisfies Story; | ||
export const TertiaryLarge = { | ||
args: { appearance: "tertiary", size: "large" }, | ||
} satisfies Story; | ||
export const TertiaryDisabled = { | ||
args: { appearance: "tertiary", disabled: true }, | ||
} satisfies Story; | ||
export const TertiaryLink = { | ||
args: { appearance: "tertiary", isLink: true }, | ||
} satisfies Story; | ||
export const TertiaryWithIcon = { | ||
args: { appearance: "tertiary", withIcon: true }, | ||
} satisfies Story; | ||
export const TertiaryWithIconRight = { | ||
args: { appearance: "tertiary", withIconRight: true }, | ||
} satisfies Story; | ||
export const TertiaryWithIconOnly = { | ||
args: { appearance: "tertiary", withIconOnly: true }, | ||
} satisfies Story; | ||
export const TertiaryFullWidth = { | ||
args: { appearance: "tertiary", fullWidth: true }, | ||
} satisfies Story; | ||
export const TertiaryFullWidthWithIcon = { | ||
args: { appearance: "tertiary", fullWidth: true, withIcon: true }, | ||
} satisfies Story; | ||
export const TertiaryLongText = { | ||
args: { appearance: "tertiary", label: loremSentences(4) }, | ||
} satisfies Story; | ||
export const TertiaryLongTextWithIcon = { | ||
args: { appearance: "tertiary", label: loremSentences(4), withIcon: true }, | ||
} satisfies Story; | ||
|
||
export const Ghost = { args: { appearance: "ghost" } } satisfies Story; | ||
export const GhostSmall = { | ||
args: { appearance: "ghost", size: "small" }, | ||
} satisfies Story; | ||
export const GhostLarge = { | ||
args: { appearance: "ghost", size: "large" }, | ||
} satisfies Story; | ||
export const GhostDisabled = { | ||
args: { appearance: "ghost", disabled: true }, | ||
} satisfies Story; | ||
export const GhostLink = { | ||
args: { appearance: "ghost", isLink: true }, | ||
} satisfies Story; | ||
export const GhostWithIcon = { | ||
args: { appearance: "ghost", withIcon: true }, | ||
} satisfies Story; | ||
export const GhostWithIconRight = { | ||
args: { appearance: "ghost", withIconRight: true }, | ||
} satisfies Story; | ||
export const GhostWithIconOnly = { | ||
args: { appearance: "ghost", withIconOnly: true }, | ||
} satisfies Story; | ||
export const GhostFullWidth = { | ||
args: { appearance: "ghost", fullWidth: true }, | ||
} satisfies Story; | ||
export const GhostFullWidthWithIcon = { | ||
args: { appearance: "ghost", fullWidth: true, withIcon: true }, | ||
} satisfies Story; | ||
export const GhostLongText = { | ||
args: { appearance: "ghost", label: loremSentences(4) }, | ||
} satisfies Story; | ||
export const GhostLongTextWithIcon = { | ||
args: { appearance: "ghost", label: loremSentences(4), withIcon: true }, | ||
} satisfies Story; |