diff --git a/src/Button/Button.stories.tsx b/src/Button/Button.stories.tsx index 2db864d..f0017d6 100644 --- a/src/Button/Button.stories.tsx +++ b/src/Button/Button.stories.tsx @@ -1,11 +1,21 @@ import { action } from "@storybook/addon-actions"; import type { Meta, StoryObj } from "@storybook/react"; -import Button from "./"; +import Button, { ButtonColors, ButtonSizes } from "./"; const meta = { title: "Atoms/Button", component: Button, + argTypes: { + color: { + description: "The button's color scheme", + options: [...ButtonColors], + }, + size: { + description: "The button's size", + option: [...ButtonSizes], + }, + }, } satisfies Meta; export default meta; diff --git a/src/Button/index.scss b/src/Button/index.scss index 1c49e77..a451a63 100644 --- a/src/Button/index.scss +++ b/src/Button/index.scss @@ -8,10 +8,9 @@ align-self: self-start; // Prevents the button from occupying all available space inside a div display: inline-flex; flex-direction: row; + box-sizing: border-box; - margin: 0; border: 0; - border-radius: 0.5rem; font-family: map.get(tokens.$fonts, sans); @@ -37,7 +36,7 @@ } &.button--outlined { - border: 2px solid $color; + outline: 2px solid $color; background-color: map.get(tokens.$brand, white); color: $color; diff --git a/src/Button/index.tsx b/src/Button/index.tsx index 65cea08..dc8aceb 100644 --- a/src/Button/index.tsx +++ b/src/Button/index.tsx @@ -3,14 +3,18 @@ import type { FC, PropsWithChildren } from "react"; import "./index.scss"; import clsx from "clsx"; -export type ButtonSize = "sm" | "base" | "lg"; -export type ButtonColors = - | "primary" - | "secondary" - | "success" - | "info" - | "warning" - | "danger"; +export const ButtonSizes = ["sm", "base", "lg"]; +export type ButtonSize = (typeof ButtonSizes)[number]; + +export const ButtonColors = [ + "primary", + "secondary", + "success", + "info", + "warning", + "danger", +]; +export type ButtonColor = (typeof ButtonColors)[number]; export interface ButtonProps { /** @@ -26,7 +30,7 @@ export interface ButtonProps { /** * The button's color scheme. */ - color?: ButtonColors; + color?: ButtonColor; /** * Whether the button is outlined. diff --git a/src/ButtonGroup/ButtonGroup.stories.tsx b/src/ButtonGroup/ButtonGroup.stories.tsx new file mode 100644 index 0000000..bf4fe0f --- /dev/null +++ b/src/ButtonGroup/ButtonGroup.stories.tsx @@ -0,0 +1,87 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import ButtonGroup from "./"; +import { Button } from ".."; +import { action } from "@storybook/addon-actions"; + +const meta = { + title: "Atoms/ButtonGroup", + component: ButtonGroup, + parameters: { + layout: "centered", + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// Make clicks visible in the inspector +const onClick = action("click"); + +export const Small: Story = { + args: { + size: "sm", + children: ( + <> + + + + + ), + }, +}; + +export const Base: Story = { + args: { + size: "base", + children: ( + <> + + + + + ), + }, +}; + +export const Large: Story = { + args: { + size: "lg", + children: ( + <> + + + + + ), + }, +}; + +export const SmallButtonsWithLargeGap: Story = { + args: { + size: "lg", + children: ( + <> + + + + + ), + }, +}; diff --git a/src/ButtonGroup/index.scss b/src/ButtonGroup/index.scss new file mode 100644 index 0000000..1951287 --- /dev/null +++ b/src/ButtonGroup/index.scss @@ -0,0 +1,14 @@ +@use "sass:map"; + +@use "../sass/tokens"; + +.button-group { + display: flex; + align-items: center; + + @each $size in tokens.$sizes { + &.button-group--#{$size} { + gap: map.get(tokens.$gap, $size); + } + } +} diff --git a/src/ButtonGroup/index.tsx b/src/ButtonGroup/index.tsx new file mode 100644 index 0000000..2594db4 --- /dev/null +++ b/src/ButtonGroup/index.tsx @@ -0,0 +1,32 @@ +import type { FC, PropsWithChildren } from "react"; + +import "./index.scss"; +import clsx from "clsx"; + +export type ButtonGroupSize = "sm" | "base" | "lg"; + +export interface ButtonGroupProps { + /** + * The size of the button group (mostly affects spacing). + */ + size?: ButtonGroupSize; +} + +const ButtonGroup: FC> = ({ + children, + size = "base", +}) => { + return ( +
+ {children} +
+ ); +}; + +export default ButtonGroup; diff --git a/src/CodeBlock/CodeBlock.stories.tsx b/src/CodeBlock/CodeBlock.stories.tsx index 57c3f10..3b5afbd 100644 --- a/src/CodeBlock/CodeBlock.stories.tsx +++ b/src/CodeBlock/CodeBlock.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import CodeBlock from "./"; +import { HighlightLanguages } from "../hooks/useHighlight"; const meta = { title: "Molecules/CodeBlock", @@ -11,7 +12,7 @@ const meta = { argTypes: { language: { control: "select", - options: ["shell", "yaml", "terraform", "text"], + options: [...HighlightLanguages], }, code: { control: "text" }, allowCopy: { control: "boolean" }, diff --git a/src/CodeFile/CodeFile.stories.tsx b/src/CodeFile/CodeFile.stories.tsx index 3d0f7b6..8af17f3 100644 --- a/src/CodeFile/CodeFile.stories.tsx +++ b/src/CodeFile/CodeFile.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import CodeFile from "./"; +import { HighlightLanguages } from "../hooks/useHighlight"; const meta = { title: "Molecules/CodeFile", @@ -11,7 +12,7 @@ const meta = { argTypes: { language: { control: "select", - options: ["shell", "yaml", "terraform", "text"], + options: [...HighlightLanguages], }, code: { control: "text" }, filename: { control: "text" }, diff --git a/src/Highlight/Highlight.stories.tsx b/src/Highlight/Highlight.stories.tsx index 9e7ed9b..0cb7e4a 100644 --- a/src/Highlight/Highlight.stories.tsx +++ b/src/Highlight/Highlight.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import Highlight from "./"; +import { HighlightLanguages } from "../hooks/useHighlight"; const meta = { title: "Atoms/Highlight", @@ -11,7 +12,7 @@ const meta = { argTypes: { language: { control: "select", - options: ["shell", "yaml", "terraform", "text"], + options: [...HighlightLanguages], }, code: { control: "text" }, inline: { control: "boolean" }, diff --git a/src/hooks/useHighlight.ts b/src/hooks/useHighlight.ts index b4a0f10..0568706 100644 --- a/src/hooks/useHighlight.ts +++ b/src/hooks/useHighlight.ts @@ -10,7 +10,8 @@ import { useMemo } from "react"; /** * Languages understood by the UI system's highlighter. The `text` option prevents highlighting. */ -export type HighlightLanguage = "shell" | "yaml" | "terraform" | "text"; +export const HighlightLanguages = ["shell", "yaml", "terraform", "text"]; +export type HighlightLanguage = (typeof HighlightLanguages)[number]; // Lazily instantiate the Shiki renderer to avoid paying (some) startp costs let shiki: ReturnType; diff --git a/src/sass/_tokens.scss b/src/sass/_tokens.scss index 5fc5b2c..57d3cc5 100644 --- a/src/sass/_tokens.scss +++ b/src/sass/_tokens.scss @@ -59,6 +59,12 @@ $border-radius: ( lg: 0.75rem, ); +$gap: ( + sm: 0.25rem, + base: 0.5rem, + lg: 0.75rem, +); + $padding: ( sm: 0.2rem, base: 0.4rem,