Skip to content

Commit

Permalink
Merge branch 'main' into ai-chat-button
Browse files Browse the repository at this point in the history
  • Loading branch information
tw15egan committed Feb 6, 2024
2 parents 782a26b + 4ecbf1e commit 9e54db0
Show file tree
Hide file tree
Showing 16 changed files with 346 additions and 19 deletions.
9 changes: 9 additions & 0 deletions .all-contributorsrc
Expand Up @@ -1406,6 +1406,15 @@
"contributions": [
"code"
]
},
{
"login": "jt-helsinki",
"name": "J Thomas",
"avatar_url": "https://avatars.githubusercontent.com/u/20871336?v=4",
"profile": "https://jt-helsinki.github.io/blog/",
"contributions": [
"code"
]
}
],
"commitConvention": "none"
Expand Down
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -271,8 +271,9 @@ check out our [Contributing Guide](/.github/CONTRIBUTING.md) and our
<td align="center"><a href="https://samuelechinellato.com/#/"><img src="https://avatars.githubusercontent.com/u/49278203?v=4?s=100" width="100px;" alt=""/><br /><sub><b>SamChinellato</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=SamChinellato" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/stevenpatrick009"><img src="https://avatars.githubusercontent.com/u/106097350?v=4?s=100" width="100px;" alt=""/><br /><sub><b>stevenpatrick009</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=stevenpatrick009" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/xalc"><img src="https://avatars.githubusercontent.com/u/18441947?v=4?s=100" width="100px;" alt=""/><br /><sub><b>HunterXalc</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=xalc" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/amercury"><img src="https://avatars.githubusercontent.com/u/17834588?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexandr Ovchinnikov</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=amercury" title="Code">💻</a></td>
<td align="center"><a href="https://mattborghi.github.io/"><img src="https://avatars.githubusercontent.com/u/11933424?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matias Borghi</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=mattborghi" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/amercury"><img src="https://avatars.githubusercontent.com/u/17834588?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexandr Ovchinnikov</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=amercury" title="Code">💻</a></td>
<td align="center"><a href="https://jt-helsinki.github.io/blog/"><img src="https://avatars.githubusercontent.com/u/20871336?v=4?s=100" width="100px;" alt=""/><br /><sub><b>J Thomas</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=jt-helsinki" title="Code">💻</a></td>
</tr>
</table>

Expand Down
2 changes: 1 addition & 1 deletion e2e/pictograms-react/__snapshots__/PublicAPI-test.js.snap
Expand Up @@ -1177,4 +1177,4 @@ Array [
"Yoga_04",
"ZeroTrust",
]
`;
`;
38 changes: 38 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Expand Up @@ -7210,6 +7210,44 @@ Map {
},
"render": [Function],
},
"StaticNotification" => Object {
"propTypes": Object {
"children": Object {
"type": "node",
},
"className": Object {
"type": "string",
},
"kind": Object {
"args": Array [
Array [
"error",
"info",
"info-square",
"success",
"warning",
"warning-alt",
],
],
"type": "oneOf",
},
"lowContrast": Object {
"type": "bool",
},
"statusIconDescription": Object {
"type": "string",
},
"subtitle": Object {
"type": "string",
},
"title": Object {
"type": "string",
},
"titleId": Object {
"type": "string",
},
},
},
"StructuredListBody" => Object {
"propTypes": Object {
"children": Object {
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/__tests__/index-test.js
Expand Up @@ -170,6 +170,7 @@ describe('Carbon Components React', () => {
"Slider",
"SliderSkeleton",
"Stack",
"StaticNotification",
"StructuredListBody",
"StructuredListCell",
"StructuredListHead",
Expand Down
5 changes: 3 additions & 2 deletions packages/react/src/components/Button/Button.tsx
Expand Up @@ -195,13 +195,14 @@ const Button = React.forwardRef(function Button<T extends React.ElementType>(

let component: React.ElementType = 'button';
const assistiveId = useId('danger-description');
const { 'aria-pressed': ariaPressed } = rest;
const { 'aria-pressed': ariaPressed, 'aria-describedby': ariaDescribedBy } =
rest;
let otherProps: Partial<ButtonBaseProps> = {
disabled,
type,
'aria-describedby': dangerButtonVariants.includes(kind)
? assistiveId
: undefined,
: ariaDescribedBy || undefined,
'aria-pressed':
ariaPressed ?? (hasIconOnly && kind === 'ghost' ? isSelected : undefined),
};
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/components/ContainedList/ContainedList.js
Expand Up @@ -58,6 +58,7 @@ function ContainedList({
kind = variants[0],
label,
size,
...rest
}) {
const labelId = `${useId('contained-list')}-header`;
const prefix = usePrefix();
Expand All @@ -82,7 +83,7 @@ function ContainedList({
const renderedChildren = renderChildren(children);

return (
<div className={classes}>
<div className={classes} {...rest}>
<div className={`${prefix}--contained-list__header`}>
<div id={labelId} className={`${prefix}--contained-list__label`}>
{label}
Expand Down
Expand Up @@ -18,6 +18,7 @@ function ContainedListItem({
disabled = false,
onClick,
renderIcon: IconElement,
...rest
}) {
const prefix = usePrefix();

Expand All @@ -41,7 +42,7 @@ function ContainedListItem({
);

return (
<li className={classes}>
<li className={classes} {...rest}>
{isClickable ? (
<button
className={`${prefix}--contained-list-item__content`}
Expand Down
6 changes: 5 additions & 1 deletion packages/react/src/components/DatePicker/DatePicker-test.js
Expand Up @@ -224,7 +224,11 @@ describe('Simple date picker', () => {
</React.Suspense>
);

const labeledElement = await screen.findByLabelText('Date Picker label');
const labeledElement = await screen.findByLabelText(
'Date Picker label',
{},
{ timeout: 5000 }
);
expect(labeledElement).toBeInTheDocument();

const input = screen.getByRole('textbox');
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/components/Link/Link.stories.js
Expand Up @@ -6,7 +6,7 @@
*/

import React from 'react';
import { Download } from '@carbon/icons-react';
import { ArrowRight } from '@carbon/icons-react';
import Link from './Link';
import mdx from './Link.mdx';

Expand Down Expand Up @@ -65,7 +65,7 @@ export const Inline = () => (
);

export const PairedWithIcon = () => (
<Link href="#" renderIcon={() => <Download aria-label="Download" />}>
<Link href="#" renderIcon={() => <ArrowRight aria-label="Arrow Right" />}>
Carbon Docs
</Link>
);
Expand Down
36 changes: 27 additions & 9 deletions packages/react/src/components/Notification/Notification.mdx
Expand Up @@ -18,17 +18,35 @@ import { Story, Canvas, ArgsTable, Meta } from '@storybook/blocks';

## Overview

There are 3 different types of notification components:
`ActionableNotification`, `InlineNotification`, and `ToastNotification`.
There are 4 different types of notification components:
`ActionableNotification`, `InlineNotification`, `ToastNotification`, and
`unstable__StaticNotification`.

`InlineNotification` and `ToastNotification` can not contain interactive
elements or rich text.
### ActionableNotification

`ActionableNotification` should be used when user action is required. It can
include an action, other interactive elements or rich text. It uses Toast-like
styling by default, but if you'd like it to be visually similar to an
InlineNotifcation, you can use the `inline` prop. If `actionButtonLabel` is not
provided, an action button will not be rendered. This component grabs and traps
focus until the action is acted upon or the notification is dismissed.

To include an action, interactive elements or rich text in notifications, use
`ActionableNotification`. It uses Toast-like styling by default, but if you'd
like it to be visually similar to an InlineNotifcation, you can use the `inline`
prop. If `actionButtonLabel` is not provided, an action button will not be
rendered.
### InlineNotification & ToastNotification

`InlineNotification` and `ToastNotification` can not contain interactive
elements or rich text. These are announced by screenreaders when rendered. They
don't grab focus. Use them to provide the user with an alert, status, or log.

### unstable\_\_StaticNotification

`unstable__StaticNotification` is non-modal and should only be used inline with
content on the initial render of the page or modal. This should not be used for
real-time notifications or notifications responding to user input (unless the
page is completely refreshing and bumping the users focus back to the first
element in the dom/tab order). This is the most passive notification component
and is essentially just a styled div. If you place actions or interactive
elements within this component, place an `aria-describedby` on the interactive
element with a value that matches the `titleId` prop.

## Component API

Expand Down
164 changes: 163 additions & 1 deletion packages/react/src/components/Notification/Notification.tsx
Expand Up @@ -32,7 +32,10 @@ import {
import { Text } from '../Text';
import Button, { type ButtonProps } from '../Button';
import useIsomorphicEffect from '../../internal/useIsomorphicEffect';
import { useNoInteractiveChildren } from '../../internal/useNoInteractiveChildren';
import {
useNoInteractiveChildren,
useInteractiveChildrenNeedDescription,
} from '../../internal/useNoInteractiveChildren';
import { keys, matches } from '../../internal/keyboard';
import { usePrefix } from '../../internal/usePrefix';
import { useId } from '../../internal/useId';
Expand Down Expand Up @@ -1171,3 +1174,162 @@ ActionableNotification.propTypes = {
*/
title: PropTypes.string,
};

/**
* StaticNotification
* ==================
*/

export interface StaticNotificationProps
extends HTMLAttributes<HTMLDivElement> {
/**
* Specify the content
*/
children?: ReactNode;

/**
* Specify an optional className to be applied to the notification box
*/
className?: string;

/**
* Specify what state the notification represents
*/
kind?:
| 'error'
| 'info'
| 'info-square'
| 'success'
| 'warning'
| 'warning-alt';

/**
* Specify whether you are using the low contrast variant of the StaticNotification.
*/
lowContrast?: boolean;

/**
* Provide a description for "status" icon that can be read by screen readers
*/
statusIconDescription?: string;

/**
* Specify the subtitle
*/
subtitle?: string;

/**
* Specify the title
*/
title?: string;

/**
* Specify the id for the element containing the title
*/
titleId?: string;
}

export function StaticNotification({
children,
title,
titleId,
subtitle,
statusIconDescription,
className,
kind = 'error',
lowContrast,
...rest
}: StaticNotificationProps) {
const prefix = usePrefix();
const containerClassName = cx(className, {
[`${prefix}--inline-notification`]: true,
[`${prefix}--inline-notification--low-contrast`]: lowContrast,
[`${prefix}--inline-notification--${kind}`]: kind,
[`${prefix}--inline-notification--hide-close-button`]: true,
});

const ref = useRef(null);
useInteractiveChildrenNeedDescription(
ref,
`interactive child node(s) should have an \`aria-describedby\` property with a value matching the value of \`titleId\``
);

return (
<div ref={ref} {...rest} className={containerClassName}>
<div className={`${prefix}--inline-notification__details`}>
<NotificationIcon
notificationType="inline"
kind={kind}
iconDescription={statusIconDescription || `${kind} icon`}
/>
<div className={`${prefix}--inline-notification__text-wrapper`}>
{title && (
<Text
as="div"
id={titleId}
className={`${prefix}--inline-notification__title`}>
{title}
</Text>
)}
{subtitle && (
<Text
as="div"
className={`${prefix}--inline-notification__subtitle`}>
{subtitle}
</Text>
)}
{children}
</div>
</div>
</div>
);
}

StaticNotification.propTypes = {
/**
* Specify the content
*/
children: PropTypes.node,

/**
* Specify an optional className to be applied to the notification box
*/
className: PropTypes.string,

/**
* Specify what state the notification represents
*/
kind: PropTypes.oneOf([
'error',
'info',
'info-square',
'success',
'warning',
'warning-alt',
]),

/**
* Specify whether you are using the low contrast variant of the StaticNotification.
*/
lowContrast: PropTypes.bool,

/**
* Provide a description for "status" icon that can be read by screen readers
*/
statusIconDescription: PropTypes.string,

/**
* Specify the subtitle
*/
subtitle: PropTypes.string,

/**
* Specify the title
*/
title: PropTypes.string,

/**
* Specify the id for the element containing the title
*/
titleId: PropTypes.string,
};
2 changes: 2 additions & 0 deletions packages/react/src/components/Notification/index.tsx
Expand Up @@ -16,4 +16,6 @@ export {
type InlineNotificationProps,
ActionableNotification,
type ActionableNotificationProps,
StaticNotification,
type StaticNotificationProps,
} from './Notification';

0 comments on commit 9e54db0

Please sign in to comment.