Skip to content

Commit

Permalink
add initial styles, story, react component
Browse files Browse the repository at this point in the history
  • Loading branch information
jamiehenson committed Nov 21, 2024
1 parent 05c3165 commit 4b651d3
Show file tree
Hide file tree
Showing 11 changed files with 1,128 additions and 305 deletions.
91 changes: 91 additions & 0 deletions src/core/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { PropsWithChildren } from "react";
import { IconName } from "./Icon/types";
import Icon from "./Icon";
import clsx from "clsx";

export type ButtonType = "priority" | "primary" | "secondary";

type ButtonSize = "lg" | "md" | "sm" | "xs";

type ButtonProps = {
/**
* The type of button: priority, primary, or secondary.
*/
variant?: ButtonType;
/**
* The button size: lg, sm, or xs. Leave empty for md.
*/
size?: ButtonSize;
/**
* An icon to render on the left side of the button label.
*/
leftIcon?: IconName;
/**
* An icon to render on the right side of the button label.
*/
rightIcon?: IconName;
/**
* Optional classes to add to the button element.
*/
className?: string;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;

// got to go the long way round because of ol' mate Taily Waily
const buttonClasses: Record<ButtonType, Record<ButtonSize, string>> = {
priority: {
lg: "ui-button-priority-lg",
md: "ui-button-priority",
sm: "ui-button-priority-sm",
xs: "ui-button-priority-xs",
},
primary: {
lg: "ui-button-primary-lg",
md: "ui-button-primary",
sm: "ui-button-primary-sm",
xs: "ui-button-primary-xs",
},
secondary: {
lg: "ui-button-secondary-lg",
md: "ui-button-secondary",
sm: "ui-button-secondary-sm",
xs: "ui-button-secondary-xs",
},
};

export const iconModifierClasses: Record<
ButtonSize,
{ left: string; right: string }
> = {
lg: { left: "ui-button-lg-left-icon", right: "ui-button-lg-right-icon" },
md: { left: "ui-button-left-icon", right: "ui-button-right-icon" },
sm: { left: "ui-button-sm-left-icon", right: "ui-button-sm-right-icon" },
xs: { left: "", right: "" },
};

const Button: React.FC<PropsWithChildren<ButtonProps>> = ({
variant = "primary",
size,
leftIcon,
rightIcon,
children,
className,
...rest
}) => {
return (
<button
className={clsx(
buttonClasses[variant][size ?? "md"],
{ [iconModifierClasses[size ?? "md"].left]: leftIcon },
{ [iconModifierClasses[size ?? "md"].right]: rightIcon },
className,
)}
{...rest}
>
{leftIcon ? <Icon name={leftIcon} /> : null}
{children}
{rightIcon ? <Icon name={rightIcon} /> : null}
</button>
);
};

export default Button;
1 change: 1 addition & 0 deletions src/core/styles.components.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@import "./styles/layout.css";
@import "./styles/shadows.css";
@import "./styles/text.css";
@import "./styles/gui.css";

@layer components {
/* Basis for icon component */
Expand Down
183 changes: 140 additions & 43 deletions src/core/styles/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,72 +1,169 @@
import React from "react";
import clsx from "clsx";
import Button, { ButtonType, iconModifierClasses } from "../Button";
import Tooltip from "../Tooltip";

export default {
title: "CSS/Button",
};

const buttons = {
priority: {
default: "ui-button-priority",
iconLeft: "",
},
title: "Components/Button",
component: Button,
tags: ["autodocs"],
};

const sizes = [
{ label: "Large", symbol: "lg" },
{ label: "Regular", symbol: "" },
{ label: "Small", symbol: "sm" },
{ label: "Extra small", symbol: "xs" },
{
label: "Large",
key: "lg",
className: {
priority: "ui-button-priority-lg",
primary: "ui-button-primary-lg",
secondary: "ui-button-secondary-lg",
},
},
{
label: "Regular",
className: {
priority: "ui-button-priority",
primary: "ui-button-primary",
secondary: "ui-button-secondary",
},
},
{
label: "Small",
key: "sm",
className: {
priority: "ui-button-priority-sm",
primary: "ui-button-primary-sm",
secondary: "ui-button-secondary-sm",
},
},
{
label: "Extra small",
key: "xs",
className: {
priority: "ui-button-priority-xs",
primary: "ui-button-primary-xs",
secondary: "ui-button-secondary-xs",
},
},
];

type ButtonSetType = "priority" | "primary" | "secondary";

const buttonSet = (type: ButtonSetType) => (
<div className="grid sm:grid-cols-3 gap-16">
{Array(3)
const buttonSet = (type: ButtonType) => (
<div className="grid grid-cols-2 sm:grid-cols-4 gap-16">
{Array(4)
.fill(0)
.map((_, index) => (
<div
key={`button-variant-${index}`}
className="flex flex-col gap-16 max-w-[300px]"
>
<div key={`button-variant-${index}`} className="flex flex-col gap-16">
{sizes.map((size, sizeIndex) => (
<button
type="button"
<Tooltip
key={`button-size-${sizeIndex}`}
className={`ui-button-${type}-${size}`}
>
{index === 1 ? (
<svg
className="text-cool-black hover:text-active-orange"
style={{ width: "1.5rem", height: "1.5rem" }}
triggerProps={{ className: "h-[60px]" }}
triggerElement={
<button
type="button"
className={clsx(
size.className[type],
{
[iconModifierClasses[size.key ?? "md"].left]: index === 1,
},
{
[iconModifierClasses[size.key ?? "md"].right]:
index === 2,
},
)}
disabled={index === 3}
>
<use xlinkHref="#sprite-icon-gui-search"></use>
</svg>
) : null}
{size.label}
{index === 2 ? (
<svg
className="text-cool-black hover:text-active-orange"
style={{ width: "1.5rem", height: "1.5rem" }}
>
<use xlinkHref="#sprite-icon-gui-arrow-right"></use>
</svg>
) : null}
</button>
{index === 1 ? (
<svg style={{ width: "1.5rem", height: "1.5rem" }}>
<use xlinkHref="#sprite-icon-gui-search"></use>
</svg>
) : null}
{size.label}
{index === 2 ? (
<svg style={{ width: "1.5rem", height: "1.5rem" }}>
<use xlinkHref="#sprite-icon-gui-arrow-right"></use>
</svg>
) : null}
</button>
}
>
{clsx(
size.className[type],
{
[iconModifierClasses[size.key ?? "md"].left]: index === 1,
},
{
[iconModifierClasses[size.key ?? "md"].right]: index === 2,
},
)}
</Tooltip>
))}
</div>
))}
</div>
);

export const HighPriority = {
export const ReactComponent = {
render: () => (
<div className="grid sm:grid-cols-3 gap-16">
<div>
<Button variant="priority" size="lg">
Hello React!
</Button>
</div>
<div>
<Button variant="primary" leftIcon="icon-gui-search">
Hello React!
</Button>
</div>
<div>
<Button variant="secondary" size="xs" rightIcon="icon-gui-arrow-right">
Hello React!
</Button>
</div>
</div>
),
parameters: {
docs: {
description: {
story:
"Buttons are available as a React component. The `variant` prop can be set to `priority`, `primary`, or `secondary`. The `size` prop can be set to `lg`, `sm`, or `xs`, or left undefined.\n\nIcons can be added to the left or right of the button text by setting the `leftIcon` or `rightIcon` prop to a valid icon name.",
},
},
},
};

export const Priority = {
render: () => buttonSet("priority"),
parameters: {
docs: {
description: {
story:
"Priority buttons are available as separate CSS classes for use cases outside of React. Classes: `ui-button-priority`, `ui-button-priority-lg`, `ui-button-priority-sm`, `ui-button-priority-xs`. Hover over the icons to see the active classes.\n\nIcons can be set by placing an SVG element inside the button (view the HTML tab in the individual story view for more comprehensive code examples). Adding either `ui-button-{SIZE}-left-icon` or `ui-button-{SIZE}-right-icon` to the button element will adjust the padding to accommodate the icon.",
},
},
},
};

export const Primary = {
render: () => buttonSet("primary"),
parameters: {
docs: {
description: {
story:
"Primary buttons are available as separate CSS classes for use cases outside of React. Classes: `ui-button-primary`, `ui-button-primary-lg`, `ui-button-primary-sm`, `ui-button-primary-xs`. Hover over the icons to see the active classes.\n\nIcons can be set by placing an SVG element inside the button (view the HTML tab in the individual story view for more comprehensive code examples). Adding either `ui-button-{SIZE}-left-icon` or `ui-button-{SIZE}-right-icon` to the button element will adjust the padding to accommodate the icon.",
},
},
},
};

export const Secondary = {
render: () => buttonSet("secondary"),
parameters: {
docs: {
description: {
story:
"Secondary buttons are available as separate CSS classes for use cases outside of React. Classes: `ui-button-secondary`, `ui-button-secondary-lg`, `ui-button-secondary-sm`, `ui-button-secondary-xs`. Hover over the icons to see the active classes.\n\nIcons can be set by placing an SVG element inside the button (view the HTML tab in the individual story view for more comprehensive code examples). Adding either `ui-button-{SIZE}-left-icon` or `ui-button-{SIZE}-right-icon` to the button element will adjust the padding to accommodate the icon.",
},
},
},
};
2 changes: 1 addition & 1 deletion src/core/styles/Forms.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ export const Toggles = {
</div>
<div className="flex gap-16 items-center">
<label className="ui-toggle">
<input type="checkbox" checked />
<input type="checkbox" defaultChecked />
<span className="ui-toggle-slider" />
</label>
<p>Pre-checked</p>
Expand Down
16 changes: 8 additions & 8 deletions src/core/styles/Typography.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ const styles = {
{ label: "Overline 2", className: "ui-text-overline2" },
],
gui: [
{ label: "Button label 1", className: "ui-text-button1" },
{ label: "Button label 2", className: "ui-text-button2" },
{ label: "Button label 3", className: "ui-text-button3" },
{ label: "Button label 4", className: "ui-text-button4" },
{ label: "Menu label 1", className: "ui-text-menu1" },
{ label: "Menu label 2", className: "ui-text-menu2" },
{ label: "Menu label 3", className: "ui-text-menu3" },
{ label: "Menu label 4", className: "ui-text-menu4" },
{ label: "Button label 1", className: "ui-gui-button1" },
{ label: "Button label 2", className: "ui-gui-button2" },
{ label: "Button label 3", className: "ui-gui-button3" },
{ label: "Button label 4", className: "ui-gui-button4" },
{ label: "Menu label 1", className: "ui-gui-menu1" },
{ label: "Menu label 2", className: "ui-gui-menu2" },
{ label: "Menu label 3", className: "ui-gui-menu3" },
{ label: "Menu label 4", className: "ui-gui-menu4" },
{ label: "Link", className: "ui-text" },
],
code: [
Expand Down
Loading

0 comments on commit 4b651d3

Please sign in to comment.