Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ToggleButton and ToggleButtonGroup components #519

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/react-components/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
TextFieldPage,
SwitchPage,
TooltipPage,
ToggleButtonGroupPage,
} from "@/pages";

// This icon is available as a plain SVG at src/assets/icon-menu.svg
Expand Down Expand Up @@ -169,6 +170,7 @@ function App() {
<TooltipPage />
<TextAreaPage />
<TextFieldPage />
<ToggleButtonGroupPage />
</main>
<Footer />
<Footer
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
.bcds-react-aria-ToggleButton {
display: inline-flex;
flex-direction: row;
flex: 0 1 auto;
gap: var(--layout-margin-xsmall);
align-items: center;
justify-content: center;
padding: var(--layout-padding-hair) var(--layout-padding-small);
color: var(--typography-color-secondary);
background-color: var(--surface-color-secondary-button-disabled);
border: none;
border-radius: var(--layout-border-radius-medium);
box-sizing: content-box;
cursor: pointer;
}

/* Size */
.bcds-react-aria-ToggleButtonGroup.small > .bcds-react-aria-ToggleButton,
.bcds-react-aria-ToggleButton.small {
font: var(--typography-regular-small-body);
}

.bcds-react-aria-ToggleButtonGroup.medium > .bcds-react-aria-ToggleButton,
.bcds-react-aria-ToggleButton.medium {
font: var(--typography-regular-body);
}

/* Icon button */
.bcds-react-aria-ToggleButton.icon {
align-items: center;
justify-content: space-around;
}

.bcds-react-aria-ToggleButton.small.icon {
padding: unset;
align-self: center;
height: var(--icons-size-large);
width: var(--icons-size-large);
min-width: var(--icons-size-large);
}

.bcds-react-aria-ToggleButton.medium.icon {
padding: unset;
height: var(--icons-size-xlarge);
width: var(--icons-size-xlarge);
min-width: var(--icons-size-xlarge);
}

/* Pressed */
.bcds-react-aria-ToggleButton[data-hovered][data-pressed] {
background-color: var(--theme-blue-10);
border: var(--layout-border-width-small) solid var(--theme-blue-10);
}

/* Active */
.bcds-react-aria-ToggleButton[data-selected] {
background-color: var(--surface-color-secondary-button-default);
color: var(--typography-color-primary);
border: var(--layout-border-width-small) solid
var(--surface-color-secondary-button-default);
box-shadow: var(--surface-shadow-small);
}

/* Hover */
.bcds-react-aria-ToggleButton[data-hovered] {
background-color: var(--surface-color-secondary-button-default);
color: var(--typography-color-primary);
border: var(--layout-border-width-small) solid
var(--surface-color-secondary-button-default);
border-radius: var(--layout-border-radius-medium);
}

/* Focused */
.bcds-react-aria-ToggleButton[data-focus-visible] {
outline: solid var(--layout-border-width-medium)
var(--surface-color-border-active);
}

/* Disabled */
.bcds-react-aria-ToggleButton[data-disabled] {
color: var(--typography-color-disabled);
cursor: not-allowed;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
ToggleButton as ReactAriaToggleButton,
ToggleButtonProps as ReactAriaToggleButtonProps,
} from "react-aria-components";

import "./ToggleButton.css";

export interface ToggleButtonProps extends ReactAriaToggleButtonProps {
size?: "small" | "medium";
isIconButton?: boolean;
}

export default function ToggleButton({
size = "medium",
children,
isIconButton = false,
...props
}: ToggleButtonProps) {
return (
<ReactAriaToggleButton
className={`bcds-react-aria-ToggleButton ${size} ${
isIconButton ? "icon" : null
}`}
{...props}
>
{children}
</ReactAriaToggleButton>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from "./ToggleButton";
export type { ToggleButtonProps } from "./ToggleButton";
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.bcds-react-aria-ToggleButtonGroup {
display: inline-flex;
gap: var(--layout-margin-small);
background-color: var(--surface-color-secondary-button-disabled);
border-radius: var(--layout-border-radius-medium);
box-sizing: content-box;
flex-wrap: wrap;
flex-grow: 1;
}

/* Sizing */
.bcds-react-aria-ToggleButtonGroup.small {
padding: var(--layout-padding-hair) var(--layout-padding-xsmall);
}

.bcds-react-aria-ToggleButtonGroup.medium {
padding: var(--layout-padding-xsmall);
}

/* Orientation */
.bcds-react-aria-ToggleButtonGroup[data-orientation="horizontal"] {
flex-direction: row;
height: var(--layout-margin-xlarge);
}

.bcds-react-aria-ToggleButtonGroup[data-orientation="vertical"] {
flex-direction: column;
}

/* Label */
.bcds-react-aria-ToggleButtonGroup--Label {
display: flex;
padding: var(--layout-padding-small) var(--layout-padding-none);
font: var(--typography-regular-small-body);
color: var(--typography-color-secondary);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
ToggleButtonGroup as ReactAriaToggleButtonGroup,
ToggleButtonGroupProps as ReactAriaToggleButtonGroupProps,
Text,
} from "react-aria-components";

import "./ToggleButtonGroup.css";

export interface ToggleButtonGroupProps
extends ReactAriaToggleButtonGroupProps {
label?: string;
size?: "small" | "medium";
}

export default function ToggleButtonGroup({
label,
size = "medium",
children,
...props
}: ToggleButtonGroupProps) {
return (
<>
{label && (
<Text className="bcds-react-aria-ToggleButtonGroup--Label">
{label}
</Text>
)}
<ReactAriaToggleButtonGroup
className={`bcds-react-aria-ToggleButtonGroup ${
size === "small" ? "small" : "medium"
}`}
{...props}
>
{children}
</ReactAriaToggleButtonGroup>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from "./ToggleButtonGroup";
export type { ToggleButtonGroupProps } from "react-aria-components";
2 changes: 2 additions & 0 deletions packages/react-components/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@ export { default as TagGroup } from "./TagGroup";
export { default as TagList } from "./TagList";
export { default as TextArea } from "./TextArea";
export { default as TextField } from "./TextField";
export { default as ToggleButton } from "./ToggleButton";
export { default as ToggleButtonGroup } from "./ToggleButtonGroup";
export { default as Switch } from "./Switch";
export { default as Tooltip, TooltipTrigger } from "./Tooltip";
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import {
ToggleButton,
ToggleButtonGroup,
SvgCheckCircleIcon,
SvgCloseIcon,
SvgExclamationCircleIcon,
} from "@/components";

export default function ToggleButtonGroupPage() {
return (
<>
<h2>Toggle Button Group</h2>
<ToggleButtonGroup label="This is a text label">
<ToggleButton id="1">
<SvgCheckCircleIcon />
Button 1
</ToggleButton>
<ToggleButton id="2">Button 2</ToggleButton>
<ToggleButton id="3">Button 3</ToggleButton>
</ToggleButtonGroup>
<h3>Icon buttons</h3>
<ToggleButtonGroup selectionMode="multiple">
<ToggleButton id="1" isIconButton aria-label="Yes">
<SvgCheckCircleIcon />
</ToggleButton>
<ToggleButton id="2" isIconButton aria-label="Maybe">
<SvgExclamationCircleIcon />
</ToggleButton>
<ToggleButton id="3" isIconButton aria-label="No">
<SvgCloseIcon />
</ToggleButton>
</ToggleButtonGroup>
<h4>Small icon buttons</h4>
<ToggleButtonGroup selectionMode="multiple">
<ToggleButton id="1" size="small" isIconButton aria-label="Yes">
<SvgCheckCircleIcon />
</ToggleButton>
<ToggleButton id="2" size="small" isIconButton aria-label="Maybe">
<SvgExclamationCircleIcon />
</ToggleButton>
<ToggleButton id="3" size="small" isIconButton aria-label="No">
<SvgCloseIcon />
</ToggleButton>
</ToggleButtonGroup>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
}}
>
<div style={{ display: "flex", flexDirection: "column", width: "30%" }}>
<h3>Vertical orientation</h3>
<ToggleButtonGroup
orientation="vertical"
label="This is a text label"
>
<ToggleButton id="1">Button 1</ToggleButton>
<ToggleButton id="2">Button 2</ToggleButton>
<ToggleButton id="3">Button 3</ToggleButton>
</ToggleButtonGroup>
</div>
<div style={{ display: "flex", flexDirection: "column", width: "30%" }}>
<h3>Multiple selection</h3>
<ToggleButtonGroup
selectionMode="multiple"
label="This group allows multiple items to be toggled"
>
<ToggleButton id="1">Button 1</ToggleButton>
<ToggleButton id="2">Button 2</ToggleButton>
<ToggleButton id="3">Button 3</ToggleButton>
<ToggleButton id="4">Button 4</ToggleButton>
<ToggleButton id="5" isDisabled>
Button 5 (disabled)
</ToggleButton>
</ToggleButtonGroup>
</div>
<div
style={{ display: "flex", flexDirection: "column", width: "30%" }}
></div>
</div>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ToggleButtonGroupPage from "./ToggleButtonGroup";

export default ToggleButtonGroupPage;
2 changes: 2 additions & 0 deletions packages/react-components/src/pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import SelectPage from "./Select";
import TagGroupPage from "./TagGroup";
import TextAreaPage from "./TextArea";
import TextFieldPage from "./TextField";
import ToggleButtonGroupPage from "./ToggleButtonGroup";
import SwitchPage from "./Switch";
import TooltipPage from "./Tooltip";

Expand All @@ -28,6 +29,7 @@ export {
TagGroupPage,
TextAreaPage,
TextFieldPage,
ToggleButtonGroupPage,
SwitchPage,
TooltipPage,
};
Loading