Skip to content
This repository was archived by the owner on Jan 20, 2022. It is now read-only.

Commit

Permalink
✨ add `Switch component
Browse files Browse the repository at this point in the history
  • Loading branch information
justinanastos committed Aug 13, 2020
1 parent e166a10 commit ccbf9d9
Show file tree
Hide file tree
Showing 6 changed files with 548 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ tsconfig.tsbuildinfo
/Popover
/shared
/SpaceKitProvider
/Switch
/Table
/TextField
/Tooltip
Expand Down
102 changes: 102 additions & 0 deletions src/Switch/Switch.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import "@testing-library/jest-dom";
import React from "react";
import userEvent from "@testing-library/user-event";
import { act, render, screen } from "@testing-library/react";
import { Switch } from "../Switch";

it("given an unselected switch, should toggle when clicked", () => {
render(<Switch defaultSelected={false}>switch</Switch>);

act(() => {
userEvent.click(screen.getByRole("switch"));
});

expect(screen.getByRole("switch")).toBeChecked();
});

it("given a selected switch, should toggle when clicked", () => {
render(<Switch defaultSelected>switch</Switch>);

act(() => {
userEvent.click(screen.getByRole("switch"));
});

expect(screen.getByRole("switch")).not.toBeChecked();
});

it("given a disabled switch, should not toggle when clicked", () => {
render(
<Switch defaultSelected={false} isDisabled>
switch
</Switch>
);

act(() => {
userEvent.click(screen.getByRole("switch"));
});

expect(screen.getByRole("switch")).not.toBeChecked();
});

it("given an unselected switch with a textual status, status should exist and not be in the label", () => {
render(
<Switch defaultSelected={false} showTextualState>
switch
</Switch>
);

expect(screen.getByText(/off/i)).toBeInTheDocument();
expect(screen.queryByLabelText(/off/i)).toBeInTheDocument();
});

it("given a selected switch with a textual status, status should exist and not be in the label", () => {
render(
<Switch defaultSelected showTextualState>
switch
</Switch>
);

expect(screen.getByText(/on/i)).toBeInTheDocument();
expect(screen.queryByLabelText(/on/i)).toBeInTheDocument();
});

it("given a selected switch without a textual status, textual status should not be found", () => {
render(
<Switch defaultSelected showTextualState={false}>
switch
</Switch>
);

expect(screen.queryByText(/on/i)).not.toBeInTheDocument();
expect(screen.queryByLabelText(/on/i)).not.toBeInTheDocument();
expect(screen.queryByText(/off/i)).not.toBeInTheDocument();
expect(screen.queryByLabelText(/off/i)).not.toBeInTheDocument();
});

it("given an unselected switch without a textual status, textual status should not be found", () => {
render(
<Switch defaultSelected={false} showTextualState={false}>
switch
</Switch>
);

expect(screen.queryByText(/on/i)).not.toBeInTheDocument();
expect(screen.queryByLabelText(/on/i)).not.toBeInTheDocument();
expect(screen.queryByText(/off/i)).not.toBeInTheDocument();
expect(screen.queryByLabelText(/off/i)).not.toBeInTheDocument();
});

it("given an aria-labledby, component should be wired up correctly", () => {
render(
<React.Fragment>
<Switch defaultSelected={false} aria-labelledby="other-element" />
<div id="other-element">label</div>
</React.Fragment>
);

act(() => {
userEvent.click(screen.getByLabelText("label"));
});

expect(screen.getByRole("switch")).toBeChecked();
});
167 changes: 167 additions & 0 deletions src/Switch/Switch.story.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { Wrapper as Switch } from "./switch.story/Wrapper";
import { Switch as OriginalSwitch } from "../Switch";
import { colors } from "../colors";
import { Meta, Story, ArgsTable, Canvas } from "@storybook/addon-docs/blocks";
import noop from "lodash/noop";

<Meta title="Components/Switch" component={OriginalSwitch} />

# Switch

**Switchs** use the same props schema as the underlying library from react-spectrum.

## Uncontrolled

Using the `defaultSelected` props to indicate these components are uncontrolled; meaning their state is not stored externally.

<Canvas>
<Story name="Uncontrolled Deselected">
<Switch>Deslected</Switch>
</Story>
<Story name="Uncontrolled Selected">
<Switch defaultSelected>Selected</Switch>
</Story>
<Story name="Uncontrolled Disabled Deselected">
<Switch isDisabled>Disabled Deslected</Switch>
</Story>
<Story name="Uncontrolled Disabled Selected">
<Switch isDisabled defaultSelected>
Disabled Selected
</Switch>
</Story>
</Canvas>

## Themed

### Dark

<Canvas theme="dark">
<Story name="Dark Themed Uncontrolled Deselected">
<Switch theme="dark">Deslected</Switch>
</Story>
<Story name="Dark Themed Uncontrolled Selected">
<Switch theme="dark" defaultSelected>
Selected
</Switch>
</Story>
<Story name="Dark Themed Uncontrolled Disabled Deselected">
<Switch theme="dark" isDisabled>
Disabled Deslected
</Switch>
</Story>
<Story name="Dark Themed Uncontrolled Disabled Selected">
<Switch theme="dark" isDisabled defaultSelected>
Disabled Selected
</Switch>
</Story>
</Canvas>

## Controlled

Pass `isSelectded` and `onChange` props to indicate these components are controlled; meaning their state held and controlled externally.

<Canvas>
<Story name="Controlled Deselected">
<Switch isSelected={false} onChange={noop}>
Deslected
</Switch>
</Story>
<Story name="Controlled Selected">
<Switch isSelected onChange={noop}>
Selected
</Switch>
</Story>
<Story name="Controlled Disabled Deselected">
<Switch isDisabled isSelected={false} onChange={noop}>
Disabled Deslected
</Switch>
</Story>
<Story name="Controlled Disabled Selected">
<Switch isDisabled isSelected onChange={noop}>
Disabled Selected
</Switch>
</Story>
</Canvas>

## Color

You can customize the color of the checkbox's selected state with the `color` prop

<Canvas>
<Story name="Color Deselected">
<Switch color={colors.green.base}>Deslected</Switch>
</Story>
<Story name="Color Selected">
<Switch color={colors.green.base} defaultSelected>
Selected
</Switch>
</Story>
<Story name="Color Disabled Deselected">
<Switch color={colors.green.base} isDisabled>
Disabled Deslected
</Switch>
</Story>
<Story name="Color Disabled Selected">
<Switch color={colors.green.base} isDisabled defaultSelected>
Disabled Selected
</Switch>
</Story>
</Canvas>

## Focus

Switchs will show a border when focused from keyboard navigation and not from touches or clicks.

<Canvas>
<Story name="Focus Deselected">
<Switch isFocusVisible color={colors.green.base}>
Deslected
</Switch>
</Story>
<Story name="Focus Selected">
<Switch isFocusVisible color={colors.green.base} defaultSelected>
Selected
</Switch>
</Story>
<Story name="Focus Disabled Deselected">
<Switch isFocusVisible color={colors.green.base} isDisabled>
Disabled Deslected
</Switch>
</Story>
<Story name="Focus Disabled Selected">
<Switch isFocusVisible color={colors.green.base} isDisabled defaultSelected>
Disabled Selected
</Switch>
</Story>
</Canvas>

## Size

Switchs support several sizes

### Large

<Canvas>
<Story name="Large, Deselected">
<Switch size="large">Deslected</Switch>
</Story>
<Story name="Large, Selected">
<Switch size="large" defaultSelected>
Selected
</Switch>
</Story>
<Story name="Large, Disabled Deselected">
<Switch size="large" isDisabled>
Disabled Deslected
</Switch>
</Story>
<Story name="Large, Disabled Selected">
<Switch size="large" isDisabled defaultSelected>
Disabled Selected
</Switch>
</Story>
</Canvas>

## Props

<ArgsTable of="." />
Loading

0 comments on commit ccbf9d9

Please sign in to comment.