Skip to content

Commit

Permalink
Add inline alert component (#437)
Browse files Browse the repository at this point in the history
* basic scaffold of alert component

* roughing out component functionality

* theming

* function to get icon based on theme

* add success and error icons

* export and import new icons

* styling

* close button

* CSS comments

* remove icon from props

* add children block

* refining children slot, add examples

* clean up imports

* rename component to InlineAlert

* add gap rule for children

* icon refinement and storybook cleanup

* clean up prop names

* fix mangled SVG paths and naming

* fix SvgExclamationCircleIcon path

* aria labelling

* remove non-functional aria labels, see #436

* add alertRole prop to set role attribute

* add inline alert examples to vite kitchen sink

* flex-grow main content container

* fleshing out vite example

* fleshing out storybook docs

* set default ARIA role to "note"

* storybook docs

* make description field optional

* storybook docs

* change showIcon to hideIcon

* storybook docs

* fix button spacing

* clean up examples on vite

* alternative implementation of ARIA roles

* fix icon and close button alignment

* move icons into new subfolder and update imports in other components

* TagGroup - add warning icon to error message (#429)

* add warning icon to taggroup error message

* min-width error icon

* Select - expose description field (#431)

* expose description field on select component

* add errorMessage to argTypes in storybook

* fix icon import in TagGroup from #429

* typo in vite example

* add ID and aria-labelledby to alert title

* styling and props cleanup

* add onClose handling

* children slot and docs update

---------

Co-authored-by: Tyler Krys <[email protected]>
  • Loading branch information
mkernohanbc and ty2k authored Aug 9, 2024
1 parent b4a4487 commit d174a25
Show file tree
Hide file tree
Showing 27 changed files with 561 additions and 7 deletions.
2 changes: 2 additions & 0 deletions packages/react-components/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Button, Footer, FooterLinks, Header } from "@/components";
import useWindowDimensions from "@/hooks/useWindowDimensions";
import {
ButtonPage,
InlineAlertPage,
SelectPage,
TagGroupPage,
TooltipPage,
Expand Down Expand Up @@ -146,6 +147,7 @@ function App() {
<main>
<h1>Components</h1>
<ButtonPage />
<InlineAlertPage />
<SelectPage />
<TagGroupPage />
<TooltipPage />
Expand Down
2 changes: 1 addition & 1 deletion packages/react-components/src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";

import SvgBcLogo from "../SvgBcLogo";
import SvgBcLogo from "../Icons/SvgBcLogo";

import "./Footer.css";

Expand Down
2 changes: 1 addition & 1 deletion packages/react-components/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";

import SvgBcLogo from "../SvgBcLogo";
import SvgBcLogo from "../Icons/SvgBcLogo";

import "./Header.css";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default function SvgCheckCircleIcon({ id = "check-icon" }) {
return (
<svg
id={id}
width="20"
height="20"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<path
d="M12.4688 7.46875C12.75 7.1875 13.2188 7.1875 13.5 7.5C13.8125 7.78125 13.8125 8.25 13.5 8.53125L9.5 12.5312C9.375 12.6875 9.1875 12.75 9 12.75C8.78125 12.75 8.59375 12.6875 8.4375 12.5312L6.4375 10.5312C6.125 10.25 6.125 9.78125 6.4375 9.46875C6.71875 9.1875 7.1875 9.1875 7.5 9.46875L9 10.9688L12.4688 7.46875ZM10 2C14.4062 2 18 5.59375 18 10C18 14.4375 14.4062 18 10 18C5.5625 18 2 14.4375 2 10C2 5.59375 5.5625 2 10 2ZM10 16.5C13.5625 16.5 16.5 13.5938 16.5 10C16.5 6.4375 13.5625 3.5 10 3.5C6.40625 3.5 3.5 6.4375 3.5 10C3.5 13.5938 6.40625 16.5 10 16.5Z"
fill="currentColor"
/>
</g>
</svg>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./SvgCheckCircleIcon";
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default function SvgCloseIcon({ id = "close-icon" }) {
return (
<svg
id={id}
width="20"
height="20"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<path
d="M16 5.21286L14.7871 4L10 8.78714L5.21286 4L4 5.21286L8.78714 10L4 14.7871L5.21286 16L10 11.2129L14.7871 16L16 14.7871L11.2129 10L16 5.21286Z"
fill="currentColor"
/>
</g>
</svg>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./SvgCloseIcon";
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export default function SvgExclamationCircleIcon({
id = "exclamation-icon-circle",
}) {
return (
<svg
id={id}
width="20"
height="20"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<path
d="M9.99999 2C14.4062 2 18 5.59375 18 10C18 14.4375 14.4062 18 9.99999 18C5.56249 18 1.99998 14.4375 1.99998 10C1.99998 5.59375 5.56249 2 9.99999 2ZM9.99999 16.5C13.5625 16.5 16.5 13.5938 16.5 10C16.5 6.4375 13.5625 3.5 9.99999 3.5C6.40624 3.5 3.49999 6.4375 3.49999 10C3.49999 13.5938 6.40624 16.5 9.99999 16.5ZM9.99999 11.5C9.56249 11.5 9.24999 11.1875 9.24999 10.75V6.75C9.24999 6.34375 9.56249 6 9.99999 6C10.4062 6 10.75 6.34375 10.75 6.75V10.75C10.75 11.1875 10.4062 11.5 9.99999 11.5ZM9.99999 12.5625C10.5312 12.5625 10.9687 13 10.9687 13.5312C10.9687 14.0625 10.5312 14.5 9.99999 14.5C9.43749 14.5 8.99999 14.0625 8.99999 13.5312C8.99999 13 9.43749 12.5625 9.99999 12.5625Z"
fill="currentColor"
/>
</g>
</svg>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./SvgExclamationCircleIcon";
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default function SvgInfoIcon({ id = "information-icon" }) {
return (
<svg
id={id}
width="20"
height="20"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<path
d="M9.99999 2C14.4062 2 18 5.59375 18 10C18 14.4375 14.4062 18 9.99999 18C5.56249 18 1.99998 14.4375 1.99998 10C1.99998 5.59375 5.56249 2 9.99999 2ZM9.99999 16.5C13.5625 16.5 16.5 13.5938 16.5 10C16.5 6.4375 13.5625 3.5 9.99999 3.5C6.40624 3.5 3.49999 6.4375 3.49999 10C3.49999 13.5938 6.40624 16.5 9.99999 16.5ZM11.25 12.5C11.6562 12.5 12 12.8438 12 13.25C12 13.6875 11.6562 14 11.25 14H8.74999C8.31249 14 7.99999 13.6875 7.99999 13.25C7.99999 12.8438 8.31249 12.5 8.74999 12.5H9.24999V10.5H8.99999C8.56249 10.5 8.24999 10.1875 8.24999 9.75C8.24999 9.34375 8.56249 9 8.99999 9H9.99999C10.4062 9 10.75 9.34375 10.75 9.75V12.5H11.25ZM9.99999 8C9.43749 8 8.99999 7.5625 8.99999 7C8.99999 6.46875 9.43749 6 9.99999 6C10.5312 6 11 6.46875 11 7C11 7.5625 10.5312 8 9.99999 8Z"
fill="currentColor"
/>
</g>
</svg>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./SvgInfoIcon";
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
.bcds-Inline-Alert {
display: flex;
flex-direction: row;
align-items: flex-start;
gap: var(--layout-margin-small);
padding: var(--layout-padding-medium) var(--layout-padding-large);
}

/* Alert content */
.bcds-Inline-Alert--container {
display: flex;
flex-direction: column;
flex-grow: 1;
}

.bcds-Inline-Alert--container > .title {
font: var(--typography-bold-body);
color: var(--typography-color-primary);
}

.bcds-Inline-Alert--container > .description {
font: var(--typography-regular-body);
color: var(--typography-color-primary);
}

/* Left icon */
.bcds-Inline-Alert--icon {
display: inline-flex;
align-self: flex-start;
padding-top: var(--layout-padding-xsmall);
}

.bcds-Inline-Alert--icon > svg {
min-width: var(--icons-size-medium);
height: var(--icons-size-medium);
}

/* Close icon button */
.bcds-Inline-Alert--closeIcon {
display: inline-flex;
align-self: first baseline;
color: var(--icons-color-primary);
}

.bcds-Inline-Alert--closeIcon > svg {
min-width: var(--icons-size-medium);
height: var(--icons-size-medium);
}

/* Info variant */
.bcds-Inline-Alert.info {
background-color: var(--support-surface-color-info);
border: var(--layout-border-width-small) solid
var(--support-border-color-info);
border-radius: var(--layout-border-radius-medium);
}

.bcds-Inline-Alert.info > .bcds-Inline-Alert--icon {
color: var(--icons-color-info);
}

/* Success variant */
.bcds-Inline-Alert.success {
background-color: var(--suport-surface-color-success);
border: var(--layout-border-width-small) solid
var(--support-border-color-success);
border-radius: var(--layout-border-radius-medium);
}

.bcds-Inline-Alert.success > .bcds-Inline-Alert--icon {
color: var(--icons-color-success);
}

/* Warning variant */
.bcds-Inline-Alert.warning {
background-color: var(--support-surface-color-warning);
border: var(--layout-border-width-small) solid
var(--support-border-color-warning);
border-radius: var(--layout-border-radius-medium);
}

.bcds-Inline-Alert.warning > .bcds-Inline-Alert--icon {
color: var(--icons-color-warning);
}

/* Danger variant */
.bcds-Inline-Alert.danger {
background-color: var(--support-surface-color-danger);
border: var(--layout-border-width-small) solid
var(--support-border-color-danger);
border-radius: var(--layout-border-radius-medium);
}

.bcds-Inline-Alert.danger > .bcds-Inline-Alert--icon {
color: var(--icons-color-danger);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from "react";
import "./InlineAlert.css";
import {
Button,
SvgInfoIcon,
SvgCheckCircleIcon,
SvgExclamationIcon,
SvgExclamationCircleIcon,
SvgCloseIcon,
} from "@/components";

export interface InlineAlertProps extends React.PropsWithChildren {
/* Alert theme */
variant?: "info" | "success" | "warning" | "danger";
/* Alert title */
title?: string;
/* Alert description */
description?: string;
/* Alert closeable state */
isCloseable?: boolean;
/* Show or hide left icon */
isIconHidden?: boolean;
/* ARIA role */
role?: React.AriaRole | undefined;
/* Close button handling */
onClose?: () => void;
}

function getIcon(variant: string) {
switch (variant) {
case "info":
return <SvgInfoIcon />;
case "success":
return <SvgCheckCircleIcon />;
case "warning":
return <SvgExclamationIcon />;
case "danger":
return <SvgExclamationCircleIcon />;
default:
return;
}
}

export default function InlineAlert({
variant = "info",
title,
description,
isIconHidden = false,
isCloseable = false,
role = "note",
children,
onClose,
...props
}: InlineAlertProps) {
return (
<div className={`bcds-Inline-Alert ${variant}`} {...props}>
{!isIconHidden && (
<span className="bcds-Inline-Alert--icon">{getIcon(variant)}</span>
)}
<div
className="bcds-Inline-Alert--container"
role={role}
aria-labelledby="alert-title"
>
{children ? (
children
) : (
<>
{title && (
<span className="title" id="alert-title">
{title}
</span>
)}
{description && <span className="description">{description}</span>}
</>
)}
</div>
{isCloseable && (
<span className="bcds-Inline-Alert--closeIcon">
<Button
variant="tertiary"
isIconButton
size="small"
aria-label="Close this alert"
type="button"
onPress={onClose}
>
<SvgCloseIcon />
</Button>
</span>
)}
</div>
);
}
2 changes: 2 additions & 0 deletions packages/react-components/src/components/InlineAlert/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from "./InlineAlert";
export type { InlineAlertProps } from "./InlineAlert";
2 changes: 1 addition & 1 deletion packages/react-components/src/components/Select/Select.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
color: var(--typography-color-disabled);
}

/* Rext description below select input */
/* Text description below select input */
.bcds-react-aria-Select--Description {
font: var(--typography-regular-small-body);
color: var(--typography-color-secondary);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
} from "react-aria-components";

import "./TagGroup.css";
import SvgExclamationIcon from "../SvgExclamationIcon";

import SvgExclamationIcon from "../Icons/SvgExclamationIcon";

export interface TagGroupProps extends ReactAriaTagGroupProps {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from "react-aria-components";

import "./TextArea.css";
import SvgExclamationIcon from "../SvgExclamationIcon";
import SvgExclamationIcon from "../Icons/SvgExclamationIcon";

export interface TextAreaProps extends ReactAriaTextFieldProps {
/* Sets text label above text input field */
Expand Down
8 changes: 7 additions & 1 deletion packages/react-components/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import "@bcgov/design-tokens/css/variables.css";

export { default as InlineAlert } from "./InlineAlert";
export { default as Button } from "./Button";
export { default as Header } from "./Header";
export { default as Footer, FooterLinks } from "./Footer";
export { default as Form } from "./Form";
export { default as Select } from "./Select";
export { default as SvgBcLogo } from "./SvgBcLogo";
export { default as SvgBcLogo } from "./Icons/SvgBcLogo";
export { default as SvgCheckCircleIcon } from "./Icons/SvgCheckCircleIcon";
export { default as SvgExclamationIcon } from "./Icons/SvgExclamationIcon";
export { default as SvgExclamationCircleIcon } from "./Icons/SvgExclamationCircleIcon";
export { default as SvgCloseIcon } from "./Icons/SvgCloseIcon";
export { default as SvgInfoIcon } from "./Icons/SvgInfoIcon";
export { default as Tag } from "./Tag";
export { default as TagGroup } from "./TagGroup";
export { default as TagList } from "./TagList";
Expand Down
Loading

0 comments on commit d174a25

Please sign in to comment.