Skip to content

Commit

Permalink
Merge pull request #32 from UrbanInstitute/button-component
Browse files Browse the repository at this point in the history
Add Button component
  • Loading branch information
mitchthorson authored Mar 5, 2024
2 parents ae82fe5 + 38cb681 commit 6d43b98
Show file tree
Hide file tree
Showing 6 changed files with 356 additions and 17 deletions.
39 changes: 22 additions & 17 deletions .storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
/** @type { import('@storybook/sveltekit').StorybookConfig } */
const config = {
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx|svelte)"],
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
"@storybook/addon-svelte-csf",
"@storybook/addon-a11y"
],
framework: {
name: "@storybook/sveltekit",
options: {}
},
core: { disableTelemetry: true },
docs: {
autodocs: "tag"
},
staticDirs: ["../static/"]
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx|svelte)"],
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
"@storybook/addon-svelte-csf",
"@storybook/addon-a11y"
],
framework: {
name: "@storybook/sveltekit",
options: {}
},
core: { disableTelemetry: true },
docs: {
autodocs: "tag"
},
staticDirs: ["../static/"],
build: {
test: {
disableAutoDocs: false
}
}
};
export default config;
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# @UrbanInstitute/dataviz-components Changelog

## Next
- Add Button component

## 0.4.0

Expand Down
164 changes: 164 additions & 0 deletions src/lib/Button/Button.stories.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<script context="module">
import Button from "./Button.svelte";
import IconDownload from "./IconDownload.svelte";
export const meta = {
title: "Components/Button",
description: "A basic button component.",
component: Button,
tags: ["autodocs"],
argTypes: {
variant: {
default: "primary",
options: ["primary", "primary-black", "secondary", "secondary-black", "tertiary"],
control: "select"
},
size: {
default: "standard",
options: ["standard", "small"],
control: "select"
}
},
parameters: {
docs: {
description: {
component: "Basic HTML Button adhering to Urban styles."
}
}
}
};
</script>

<script>
import { Story, Template } from "@storybook/addon-svelte-csf";
import { within, userEvent, expect, fn } from "@storybook/test";
</script>

<Template let:args>
<Button {...args} on:click on:mouseenter on:mouseleave>Button text</Button>
</Template>

<Story name="primary" args={{}} />

<Story
name="primary with event listeners"
args={{
event_click: fn(),
event_mouseenter: fn(),
event_mouseleave: fn()
}}
play={async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole("button");
await userEvent.click(button);
await expect(args.event_click).toHaveBeenCalled();
await userEvent.hover(button);
await expect(args.event_mouseenter).toHaveBeenCalled();
await userEvent.unhover(button);
await expect(args.event_mouseleave).toHaveBeenCalled();
}}
/>

<Story name="primary with icon">
<Button
>Button text <svelte:fragment slot="icon" let:iconColor
><IconDownload size={16} fill={iconColor} /></svelte:fragment
></Button
>
</Story>

<Story
name="primary small"
args={{
size: "small"
}}
/>

<Story
name="primary-black"
args={{
variant: "primary-black"
}}
/>

<Story name="primary-black with icon">
<Button variant="primary-black"
>Button text <svelte:fragment slot="icon" let:iconColor
><IconDownload size={16} fill={iconColor} /></svelte:fragment
></Button
>
</Story>

<Story
name="primary-black-small"
args={{
variant: "primary-black",
size: "small"
}}
/>

<Story
name="secondary"
args={{
variant: "secondary"
}}
/>
<Story name="secondary with icon">
<Button variant="secondary"
>Button text <svelte:fragment slot="icon" let:iconColor
><IconDownload size={16} fill={iconColor} /></svelte:fragment
></Button
>
</Story>

<Story
name="secondary-small"
args={{
variant: "secondary",
size: "small"
}}
/>

<Story
name="secondary-black"
args={{
variant: "secondary-black"
}}
/>

<Story name="secondary-black with icon">
<Button variant="secondary-black"
>Button text <svelte:fragment slot="icon" let:iconColor
><IconDownload size={16} fill={iconColor} /></svelte:fragment
></Button
>
</Story>
<Story
name="secondary-black-small"
args={{
variant: "secondary-black",
size: "small"
}}
/>

<Story
name="tertiary"
args={{
variant: "tertiary"
}}
/>

<Story name="tertiary with icon">
<Button variant="tertiary"
>Button text <svelte:fragment slot="icon" let:iconColor
><IconDownload size={16} fill={iconColor} /></svelte:fragment
></Button
>
</Story>
<Story
name="tertiary-small"
args={{
variant: "tertiary",
size: "small"
}}
/>
156 changes: 156 additions & 0 deletions src/lib/Button/Button.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<!-- @component Button a basic HTML button with Urban styling-->
<script>
import "../style/app.css";
import { urbanColors } from "../utils";
import { createEventDispatcher } from "svelte";
/**
* Which variant of button to use
* @type {"primary" | "primary-black" | "secondary" | "secondary-black" | "tertiary"}
*/
export let variant = "primary";
/**
* Which size of button to use
* @type {"standard" | "small" }
*/
export let size = "standard"
/**
* Is the button disabled?
* @type { boolean }
*/
export let disabled = false;
let hovered = false;
let dispatch = createEventDispatcher();
function getIconColor(_variant, _hovered) {
// hovered colors
if (!_hovered) {
if (_variant === "primary" || _variant === "primary-black") {
return urbanColors.white;
}
if (_variant === "secondary") {
return urbanColors.blue;
}
if (_variant === "secondary-black" || _variant === "tertiary") {
return urbanColors.black;
}
}
if (_variant === "primary") {
return urbanColors.white;
}
if (_variant === "primary-black") {
return urbanColors.black;
}
// not hovered colors
if (_variant === "secondary" || _variant == "secondary-black" || _variant === "tertiary") {
return urbanColors.white;
}
return urbanColors.black;
}
function onMouseEnter(e) {
hovered = true;
dispatch("mouseenter", e);
}
function onMouseLeave(e) {
hovered = false;
dispatch("mouseleave", e);
}
$: iconColor = getIconColor(variant, hovered);
</script>
<button class="variant-{variant} size-{size}" on:click {disabled} on:mouseenter={onMouseEnter} on:mouseleave={onMouseLeave}>
<slot>Default button text</slot>
{#if $$slots.icon}
<span class="button-icon"><slot name="icon" {iconColor}></slot></span>
{/if}
</button>
<style>
button {
appearance: none;
border: none;
cursor: pointer;
font-family: var(--font-family-sans);
font-size: var(--font-size-large);
font-weight: var(--font-weight-bold);
text-transform: uppercase;
--border-size: 2px;
}
.button-icon {
display: inline-block;
margin-left: 0.5rem;
}
/* sizes */
button.size-standard {
padding: calc(1rem - var(--border-size) * 2);
}
button.size-small {
padding: calc(0.75rem - var(--border-size) * 2);
}
/* primary variant */
button.variant-primary {
background-color: var(--color-blue);
border: solid var(--border-size) var(--color-blue);
color: var(--color-white);
}
button.variant-primary:hover {
background-color: var(--color-blue-shade-dark);
border: solid var(--border-size) var(--color-blue-shade-dark);
}
/* primary-black variant */
button.variant-primary-black {
background-color: var(--color-black);
border: solid var(--border-size) var(--color-black);
color: var(--color-white);
}
button.variant-primary-black:hover {
background-color: var(--color-white);
color: var(--color-black);
border: solid var(--border-size) var(--color-black);
}
/* secondary variant */
button.variant-secondary {
background-color: var(--color-white);
border: solid var(--border-size) var(--color-blue);
color: var(--color-blue);
}
button.variant-secondary:hover {
background-color: var(--color-blue);
color: var(--color-white);
border: solid var(--border-size) var(--color-blue);
}
/* secondary-black variant */
button.variant-secondary-black {
background-color: var(--color-white);
border: solid var(--border-size) var(--color-black);
color: var(--color-black);
}
button.variant-secondary-black:hover {
background-color: var(--color-black);
color: var(--color-white);
border: solid var(--border-size) var(--color-black);
}
/* tertiary variant */
button.variant-tertiary {
background-color: var(--color-yellow);
border: solid var(--border-size) var(--color-yellow);
color: var(--color-black);
}
button.variant-tertiary:hover {
background-color: var(--color-black);
border: solid var(--border-size) var(--color-black);
color: var(--color-white);
}
</style>
12 changes: 12 additions & 0 deletions src/lib/Button/IconDownload.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script>
export let fill = "#FFFFFF";
export let size = 48;
</script>

<svg width={size} height={size} viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
<path
d="M43.6933 42.4229C44.0667 42.4229 44.3467 42.56 44.6267 42.7886C44.9067 43.0171 45 43.3371 45 43.7029V46.72C45 47.0857 44.86 47.36 44.6267 47.6343C44.3933 47.9086 44.0667 48 43.6933 48H4.30667C3.93333 48 3.65333 47.8629 3.37333 47.6343C3.09333 47.4057 3 47.0857 3 46.72V43.7029C3 43.3371 3.14 43.0629 3.37333 42.7886C3.60667 42.5143 3.93333 42.4229 4.30667 42.4229H43.6933ZM41.1733 21.44C41.4067 21.2114 41.5 20.9371 41.5 20.5714C41.5 20.2057 41.36 19.8857 41.08 19.6114L38.98 17.4629C38.7 17.2343 38.3733 17.1429 38 17.1429C37.6267 17.1429 37.3467 17.28 37.1133 17.5543L26.8467 27.9314V1.28C26.8467 0.914286 26.7067 0.64 26.4733 0.365714C26.24 0.0914286 25.9133 0 25.54 0H22.46C22.0867 0 21.8067 0.137143 21.5267 0.365714C21.2467 0.594286 21.1533 0.914286 21.1533 1.28V27.9771L10.8867 17.6C10.6533 17.28 10.3733 17.1429 10 17.1429C9.62667 17.1429 9.3 17.2343 9.02 17.4629L6.82667 19.6114C6.59333 19.8857 6.5 20.2057 6.5 20.5714C6.5 20.9371 6.64 21.2114 6.92 21.44L23.02 37.3029C23.3 37.5771 23.6267 37.7143 24 37.7143C24.3733 37.7143 24.7 37.5771 24.98 37.3029L41.1733 21.44Z"
{fill}
/>
</svg>
1 change: 1 addition & 0 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export { default as ReturnTop } from "./ReturnTop/ReturnTop.svelte";
export { default as Scorecard } from "./Scorecard/Scorecard.svelte";
export { default as SocialShare } from "./SocialShare/SocialShare.svelte";
export { default as TextBlock } from "./TextBlock/TextBlock.svelte";
export { default as Button } from "./Button/Button.svelte";

0 comments on commit 6d43b98

Please sign in to comment.