-
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.
* initial CheckboxGroup * feat: control variant of checkboxes * fix: add label to checkboxItem * fix: add flex wrap * fix: add screen reader class * fix: add export * fix: 512 use value for id * fix label for
- Loading branch information
1 parent
00408dd
commit 4729910
Showing
6 changed files
with
216 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
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,11 @@ | ||
.seeds-checkbox-group { | ||
--inner-button-gap: var(--seeds-s3); | ||
display: flex; | ||
gap: var(--inner-button-gap); | ||
flex-wrap: wrap; | ||
} | ||
|
||
input[type="checkbox"]:focus-visible + .seeds-button { | ||
outline: var(--seeds-focus-ring-outline); | ||
box-shadow: var(--seeds-focus-ring-box-shadow); | ||
} |
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,74 @@ | ||
import React from "react" | ||
|
||
import "./CheckboxGroup.scss" | ||
import "../actions/Button.scss" | ||
import { ButtonProps } from "actions/Button" | ||
|
||
export interface CheckboxItem { | ||
label: string | ||
value: string | ||
} | ||
export interface CheckboxGroupProps extends Pick<ButtonProps, "size" | "variant"> { | ||
/** Label content */ | ||
label?: string | ||
/** Current selected values*/ | ||
values: CheckboxItem[] | ||
/** An array of strings representing each item in the group*/ | ||
options: CheckboxItem[] | ||
/** Element ID */ | ||
id: string | ||
/** Additional CSS classes */ | ||
className?: string | ||
/** ID for selecting in tests */ | ||
testId?: string | ||
/** function to call when a checkbox is clicked*/ | ||
onChange: (values: CheckboxItem[]) => void | ||
/** Appearance of the checked input*/ | ||
checkedVariant?: ButtonProps["variant"] | ||
} | ||
|
||
const CheckboxGroup = (props: CheckboxGroupProps) => { | ||
const classNames = ["seeds-checkbox-group"] | ||
if (props.className) classNames.push(props.className) | ||
|
||
const handleCheckboxChange = (label: string, event: React.ChangeEvent<HTMLInputElement>) => { | ||
const { name, checked } = event.target | ||
const newValue = checked | ||
? [...props.values, { label: label, value: name }] | ||
: props.values.filter((v) => v.value !== name) | ||
props.onChange(newValue) | ||
} | ||
|
||
const isChecked = (option: CheckboxItem) => { | ||
return props.values.some((v) => v.value === option.value) | ||
} | ||
|
||
return ( | ||
<div id={props.id} className={classNames.join(" ")} data-testid={props.testId}> | ||
{props.options.map((option) => ( | ||
<div key={`${props.id}-${option.value}-container`}> | ||
<input | ||
type="checkbox" | ||
name={option.value} | ||
id={`${props.id}-${option.value}`} | ||
checked={isChecked(option)} | ||
onChange={(e) => handleCheckboxChange(option.label, e)} | ||
className="seeds-screen-reader-only" | ||
/> | ||
<label | ||
className="seeds-button" | ||
data-variant={ | ||
isChecked(option) ? props.checkedVariant || "primary" : props.variant || "secondary" | ||
} | ||
data-size={props.size || "lg"} | ||
htmlFor={`${props.id}-${option.value}`} | ||
> | ||
{option.label} | ||
</label> | ||
</div> | ||
))} | ||
</div> | ||
) | ||
} | ||
|
||
export default CheckboxGroup |
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,34 @@ | ||
import { ArgsTable } from "@storybook/addon-docs" | ||
import CheckboxGroup from "../CheckboxGroup" | ||
|
||
# <CheckboxGroup /> | ||
|
||
## Properties | ||
|
||
<ArgsTable of={CheckboxGroup} /> | ||
|
||
## Theme Variables | ||
|
||
| Name | Description | Default | | ||
| ------------------------------- | ----------------------------------------- | ----------------------- | | ||
| `--inner-button-gap` | Space between elements | `--seeds-s3` | | ||
|
||
## Theme Variables from Button Styles | ||
|
||
| Name | Description | Default | | ||
| ------------------------------- | ----------------------------------------- | ----------------------- | | ||
| `--button-border-width` | Border width | `--seeds-border-2` | | ||
| `--button-font-family` | Font family | `--seeds-font-alt-sans` | | ||
| `--button-font-weight` | Font weight | `none` | | ||
| `--button-interior-gap` | Space between icons/text | `--seeds-s3` | | ||
| `--button-icon-size-percentage` | Relative size to base font | `75%` | | ||
| `--button-icon-side-padding` | Space between an icon and the button edge | `--seeds-s4` | | ||
| `--button-padding-sm` | Small button padding | | | ||
| `--button-font-size-sm` | Small button font size | `--seeds-font-size-sm` | | ||
| `--button-border-radius-sm` | Small button border radius | `--seeds-rounded` | | ||
| `--button-padding-md` | Medium button padding | | | ||
| `--button-font-size-md` | Medium button font size | `--seeds-font-size-md` | | ||
| `--button-border-radius-md` | Medium button border radius | `--seeds-rounded` | | ||
| `--button-padding-lg` | Large button padding | | | ||
| `--button-font-size-lg` | Large button font size | `--seeds-font-size-lg` | | ||
| `--button-border-radius-lg` | Large button border radius | `--seeds-rounded` | |
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,54 @@ | ||
import { useState } from "react" | ||
import CheckboxGroup, { CheckboxItem } from "../CheckboxGroup" | ||
|
||
import MDXDocs from "./CheckboxGroup.docs.mdx" | ||
|
||
export default { | ||
title: "Forms/CheckboxGroup", | ||
component: CheckboxGroup, | ||
parameters: { | ||
docs: { | ||
page: MDXDocs, | ||
}, | ||
}, | ||
} | ||
|
||
export const Standalone = () => { | ||
const options = [ | ||
{ label: "Option 1", value: "1" }, | ||
{ label: "Option 2", value: "2" }, | ||
{ label: "Option 3", value: "3" }, | ||
] | ||
const [values, setValues] = useState<CheckboxItem[]>([]) | ||
|
||
return ( | ||
<CheckboxGroup | ||
label={"My Checkbox Group"} | ||
values={values} | ||
options={options} | ||
id={"MyCheckboxGroupNew"} | ||
onChange={setValues} | ||
/> | ||
) | ||
} | ||
|
||
export const WithVariant = () => { | ||
const options = [ | ||
{ label: "Option 1", value: "1" }, | ||
{ label: "Option 2", value: "2" }, | ||
{ label: "Option 3", value: "3" }, | ||
] | ||
const [values, setValues] = useState<CheckboxItem[]>([]) | ||
|
||
return ( | ||
<CheckboxGroup | ||
label={"My Checkbox Group"} | ||
values={values} | ||
options={options} | ||
id={"MyCheckboxGroup"} | ||
onChange={setValues} | ||
variant="alert" | ||
checkedVariant="success" | ||
/> | ||
) | ||
} |
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,42 @@ | ||
import { render, cleanup, screen, fireEvent } from "@testing-library/react" | ||
import CheckboxGroup, { CheckboxItem } from "forms/CheckboxGroup" | ||
|
||
afterEach(cleanup) | ||
|
||
describe("<CheckboxGroup>", () => { | ||
it("displays the CheckboxGroup", () => { | ||
const options = [ | ||
{ label: "1", value: "1" }, | ||
{ label: "2", value: "2" }, | ||
{ label: "3", value: "3" }, | ||
] | ||
let values: CheckboxItem[] = [] | ||
const setValues = jest.fn((newValues) => { | ||
values = newValues | ||
}) | ||
|
||
render( | ||
<CheckboxGroup | ||
id="MyCheckboxGroup" | ||
testId="MyCheckboxGroup" | ||
className="test-class" | ||
options={options} | ||
values={values} | ||
onChange={setValues} | ||
/> | ||
) | ||
expect(screen.getByText(options[0].label)).toBeInTheDocument() | ||
expect(screen.getByText(options[1].label)).toBeInTheDocument() | ||
expect(screen.getByText(options[2].label)).toBeInTheDocument() | ||
|
||
expect(screen.getByTestId("MyCheckboxGroup")).not.toBeNull() | ||
expect(screen.getByTestId("MyCheckboxGroup")).toHaveClass("test-class") | ||
|
||
const checkboxOne = screen.getByRole("checkbox", { name: /1/i }) | ||
expect((checkboxOne as HTMLInputElement).checked).toBe(false) | ||
|
||
fireEvent.click(checkboxOne) | ||
expect(setValues).toHaveBeenCalledWith([{label: "1", value: "1"}]) | ||
expect(values).toEqual([{label: "1", value: "1"}]) | ||
}) | ||
}) |