Skip to content

Commit

Permalink
feat: add Tag component (#54)
Browse files Browse the repository at this point in the history
* feat: add Tag component

* feat: continue building out Tag

* test: add Tag tests

* chore: add Tag export

* docs: more theme variables

* docs: add Storybook connection

* tests: simplify Tag test
  • Loading branch information
jaredcwhite authored Jul 19, 2023
1 parent 2b09432 commit af7c7c5
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 6 deletions.
13 changes: 7 additions & 6 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
export * from "./src/expandableText/ExpandableText"

export { default as FieldValue } from "./src/forms/FieldValue"
export { default as FormErrorMessage } from "./src/forms/FormErrorMessage"
export { default as Icon } from "./src/icons/Icon"
export { default as Heading } from "./src/text/Heading"
export { default as HeadingGroup } from "./src/text/HeadingGroup"
export { default as Button } from "./src/actions/Button"
export { default as Alert } from "./src/blocks/Alert"
export { default as Message } from "./src/blocks/Message"
export { default as Toast } from "./src/blocks/Toast"
export { default as Card } from "./src/blocks/Card"
export { default as FieldValue } from "./src/forms/FieldValue"
export { default as FormErrorMessage } from "./src/forms/FormErrorMessage"
export { default as Icon } from "./src/icons/Icon"
export { default as Grid } from "./src/layout/Grid"
export { default as Tabs } from "./src/navigation/Tabs"
export { default as Button } from "./src/actions/Button"
export { default as Heading } from "./src/text/Heading"
export { default as HeadingGroup } from "./src/text/HeadingGroup"
export { default as Tag } from "./src/text/Tag"
87 changes: 87 additions & 0 deletions src/text/Tag.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
.seeds-tag {
--tag-border-radius: var(--seeds-rounded-full);
--tag-padding-inline: var(--seeds-s2_5);
--tag-padding-block: var(--seeds-s0_5);
--tag-interior-gap: var(--seeds-s1);
--tag-font-size: var(--seeds-font-size-sm);
--tag-font-size-lg: var(--seeds-font-size-base);
--tag-font-weight: var(--seeds-font-weight-semibold);
--tag-font-weight-lg: var(--seeds-font-weight-semibold);

display: inline-flex;
border-radius: var(--tag-border-radius);
padding-inline: var(--tag-padding-inline);
padding-block: var(--tag-padding-block);
gap: var(--tag-interior-gap);
font-size: var(--tag-font-size);
font-weight: var(--tag-font-weight);

&[data-variant="primary"] {
background-color: var(--seeds-color-primary-light);
color: var(--seeds-color-primary-dark);
}

&[data-variant="primary-inverse"] {
background-color: var(--seeds-color-primary);
color: var(--seeds-color-white);
}

&[data-variant="secondary"] {
background-color: var(--seeds-color-secondary-light);
color: var(--seeds-color-secondary-dark);
}

&[data-variant="secondary-inverse"] {
background-color: var(--seeds-color-secondary-dark);
color: var(--seeds-color-secondary-light);
}

&[data-variant="success"] {
background-color: var(--seeds-color-success-light);
color: var(--seeds-color-success-darker);
}

&[data-variant="success-inverse"] {
background-color: var(--seeds-color-success);
color: var(--seeds-color-white);
}

&[data-variant="in-process"] {
background-color: var(--seeds-color-highlight-light);
color: var(--seeds-color-highlight-darker);
}

&[data-variant="in-process-inverse"] {
background-color: var(--seeds-color-highlight);
color: var(--seeds-color-secondary-darker);
}

&[data-variant="highlight-cool"] {
background-color: var(--seeds-color-accent-cool-lighter);
color: var(--seeds-color-accent-cool-darker);
}

&[data-variant="highlight-cool-inverse"] {
background-color: var(--seeds-color-accent-cool-darker);
color: var(--seeds-color-white);
}

&[data-variant="highlight-warm"] {
background-color: var(--seeds-color-accent-warm-light);
color: var(--seeds-color-accent-warm-darker);
}

&[data-variant="highlight-warm-inverse"] {
background-color: var(--seeds-color-accent-warm-dark);
color: var(--seeds-color-white);
}

&[data-size="lg"] {
font-size: var(--tag-font-size-lg);
font-weight: var(--tag-font-weight-lg);
}

> .seeds-icon {
align-self: center;
}
}
50 changes: 50 additions & 0 deletions src/text/Tag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from "react"

import "./Tag.scss"

export interface TagProps {
/** Tag text */
children: React.ReactNode
/** Appearance of the component */
variant?:
| "primary"
| "primary-inverse"
| "secondary"
| "secondary-inverse"
| "success"
| "success-inverse"
| "in-process"
| "in-process-inverse"
| "highlight-cool"
| "highlight-cool-inverse"
| "highlight-warm"
| "highlight-warm-inverse"
/** Tag size */
size?: "md" | "lg"
/** Element ID */
id?: string
/** Additional CSS classes */
className?: string
/** Additional ARIA label */
ariaLabel?: string
}

export const Tag = (props: TagProps) => {
const classNames = ["seeds-tag"]

if (props.className) classNames.push(props.className)

return (
<span
id={props.id}
className={classNames.join(" ")}
data-variant={props.variant || "primary"}
data-size={props.size}
aria-label={props.ariaLabel}
>
{props.children}
</span>
)
}

export default Tag
21 changes: 21 additions & 0 deletions src/text/__stories__/Tag.docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ArgsTable } from "@storybook/addon-docs"
import Tag from "../Tag"

# &lt;Tag /&gt;

## Properties

<ArgsTable of={Tag} />

## Theme Variables

| Name | Description | Default |
| ---------------------- | -------------------------- | ------------------------------ |
| `--tag-border-radius` | Radius | `--seeds-rounded-full` |
| `--tag-padding-inline` | Inline padding | `--seeds-s2_5` |
| `--tag-padding-block` | Block padding | `--seeds-s0_5` |
| `--tag-interior-gap` | Gap between icons and text | `--seeds-s1` |
| `--tag-font-size` | Font size | `--seeds-font-size-sm` |
| `--tag-font-size-lg` | Large font size | `--seeds-font-size-base` |
| `--tag-font-weight` | Font weight | `--seeds-font-weight-semibold` |
| `--tag-font-weight-lg` | Large font weight | `--seeds-font-weight-semibold` |
98 changes: 98 additions & 0 deletions src/text/__stories__/Tag.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React from "react"

import Tag from "../Tag"

import Icon from "../../icons/Icon"
import { faFaceSmile } from "@fortawesome/free-solid-svg-icons"

import MDXDocs from "./Tag.docs.mdx"
import HeadingGroup from "../HeadingGroup"

export default {
title: "Text/Tag",
component: Tag,
parameters: {
docs: {
page: MDXDocs,
},
},
}

export const defaultTag = () => <Tag>Default Tag</Tag>

export const tagVariants = () => (
<>
<HeadingGroup size="2xl" heading="md" subheading="Regular Size" />
<div style={{ marginTop: "1rem" }}>
<Tag variant="primary">Primary Tag</Tag>
<Tag variant="secondary">Secondary Tag</Tag>
<Tag variant="success">Success Tag</Tag>
<Tag variant="in-process">In Process Tag</Tag>
<Tag variant="highlight-cool">Highlight Cool Tag</Tag>
<Tag variant="highlight-warm">Highlight Warm Tag</Tag>
</div>
<div style={{ marginBottom: "2rem" }}>
<Tag variant="primary-inverse">Primary Tag</Tag>
<Tag variant="secondary-inverse">Secondary Tag</Tag>
<Tag variant="success-inverse">Success Tag</Tag>
<Tag variant="in-process-inverse">In Process Tag</Tag>
<Tag variant="highlight-cool-inverse">Highlight Cool Tag</Tag>
<Tag variant="highlight-warm-inverse">Highlight Warm Tag</Tag>
</div>
<HeadingGroup size="2xl" heading="lg" subheading="Large Size" />
<div style={{ marginTop: "1rem" }}>
<Tag variant="primary" size="lg">
Primary Tag
</Tag>
<Tag variant="secondary" size="lg">
Secondary Tag
</Tag>
<Tag variant="success" size="lg">
Success Tag
</Tag>
<Tag variant="in-process" size="lg">
In Process Tag
</Tag>
<Tag variant="highlight-cool" size="lg">
Highlight Cool Tag
</Tag>
<Tag variant="highlight-warm" size="lg">
Highlight Warm Tag
</Tag>
</div>
<div style={{ marginBottom: "2rem" }}>
<Tag variant="primary-inverse" size="lg">
Primary Tag
</Tag>
<Tag variant="secondary-inverse" size="lg">
Secondary Tag
</Tag>
<Tag variant="success-inverse" size="lg">
Success Tag
</Tag>
<Tag variant="in-process-inverse" size="lg">
In Process Tag
</Tag>
<Tag variant="highlight-cool-inverse" size="lg">
Highlight Cool Tag
</Tag>
<Tag variant="highlight-warm-inverse" size="lg">
Highlight Warm Tag
</Tag>
</div>
<style>{".seeds-tag { margin: .25rem }"}</style>
</>
)

export const withIcons = () => (
<>
<div style={{ display: "flex", gap: ".5rem" }}>
<Tag>
<Icon icon={faFaceSmile} /> Icon Left
</Tag>
<Tag>
Icon Right <Icon icon={faFaceSmile} />
</Tag>
</div>
</>
)
15 changes: 15 additions & 0 deletions src/text/__tests__/Tag.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { render, cleanup } from "@testing-library/react"
import Tag from "../Tag"

afterEach(cleanup)

describe("<Tag>", () => {
it("displays the tag", () => {
const content = "Tag text here"
const { getByText, container } = render(<Tag id="test-tag" className="test-class">{content}</Tag>)
expect(getByText(content)).toBeInTheDocument()
expect(container.querySelector(".seeds-tag")).not.toBeNull()
expect(container.querySelector("#test-tag")).not.toBeNull()
expect(container.querySelector("#test-tag.test-class")).not.toBeNull()
})
})

0 comments on commit af7c7c5

Please sign in to comment.