Skip to content

Commit 7f71294

Browse files
feat(callout): move to stable (#18586)
* feat(callout): move to stable * fix(callout): tests and story formatting * fix: story title/name * fix(notification): test formatting --------- Co-authored-by: Preeti Bansal <146315451+preetibansalui@users.noreply.github.com>
1 parent d3b4a62 commit 7f71294

File tree

9 files changed

+127
-26
lines changed

9 files changed

+127
-26
lines changed

e2e/components/Notifications/Notifications-test.avt.e2e.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,4 +257,15 @@ test.describe('@avt Notifications', () => {
257257
});
258258
await expect(page).toHaveNoACViolations('Notifications toast');
259259
});
260+
261+
test('@avt-advanced-states callout', async ({ page }) => {
262+
await visitStory(page, {
263+
component: 'Notifications',
264+
id: 'components-notifications-callout--default',
265+
globals: {
266+
theme: 'white',
267+
},
268+
});
269+
await expect(page).toHaveNoACViolations('Notifications callout');
270+
});
260271
});

e2e/components/Notifications/Notifications-test.e2e.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ test.describe('Notifications', () => {
3737
theme,
3838
});
3939
});
40+
41+
test('callout @vrt', async ({ page }) => {
42+
await snapshotStory(page, {
43+
component: 'Callout',
44+
id: 'components-notifications-callout--default',
45+
theme,
46+
});
47+
});
4048
});
4149
});
4250
});

packages/react/code-connect/Notification/Notification.figma.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
InlineNotification,
1212
ToastNotification,
1313
ActionableNotification,
14-
unstable__Callout as Callout,
14+
Callout,
1515
} from '@carbon/react';
1616
import figma from '@figma/code-connect';
1717

packages/react/src/components/Notification/Notification.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { Canvas, ArgTypes, Meta } from '@storybook/blocks';
2626

2727
There are 4 different types of notification components:
2828
`ActionableNotification`, `InlineNotification`, `ToastNotification`, and
29-
`unstable__Callout`.
29+
`Callout`.
3030

3131
### ActionableNotification
3232

@@ -43,10 +43,10 @@ focus until the action is acted upon or the notification is dismissed.
4343
elements or rich text. These are announced by screenreaders when rendered. They
4444
don't grab focus. Use them to provide the user with an alert, status, or log.
4545

46-
### unstable\_\_Callout (previously StaticNotification)
46+
### Callout (previously StaticNotification)
4747

48-
`unstable__Callout` is non-modal and should only be used inline with content on
49-
the initial render of the page or modal because it will not be announced to
48+
`Callout` is non-modal and should only be used inline with content on the
49+
initial render of the page or modal because it will not be announced to
5050
screenreader users like the other notification components.
5151

5252
As such, this should not be used for real-time notifications or notifications

packages/react/src/components/Notification/Notification.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,21 +1316,23 @@ export function Callout({
13161316
[`${prefix}--actionable-notification--hide-close-button`]: true,
13171317
});
13181318

1319-
const ref = useRef(null);
1319+
const childrenContainer = useRef(null);
13201320
useInteractiveChildrenNeedDescription(
1321-
ref,
1321+
childrenContainer,
13221322
`interactive child node(s) should have an \`aria-describedby\` property with a value matching the value of \`titleId\``
13231323
);
13241324

13251325
return (
1326-
<div ref={ref} {...rest} className={containerClassName}>
1326+
<div {...rest} className={containerClassName}>
13271327
<div className={`${prefix}--actionable-notification__details`}>
13281328
<NotificationIcon
13291329
notificationType="inline"
13301330
kind={kind}
13311331
iconDescription={statusIconDescription || `${kind} icon`}
13321332
/>
1333-
<div className={`${prefix}--actionable-notification__text-wrapper`}>
1333+
<div
1334+
ref={childrenContainer}
1335+
className={`${prefix}--actionable-notification__text-wrapper`}>
13341336
{title && (
13351337
<Text
13361338
as="div"

packages/react/src/components/Notification/__tests__/Notification-test.js

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,7 @@ describe('ActionableNotification', () => {
343343
});
344344
});
345345

346-
// TODO: Remove StaticNotification tests when Callout moves to stable OR in
347-
// v12, whichever is first. Ensure test parity on Callout.
346+
// TODO: Remove StaticNotification tests when StaticNotification is removed (v12)
348347
describe('StaticNotification', () => {
349348
it('logs a deprecation notice when used', () => {
350349
const spy = jest.spyOn(console, 'warn').mockImplementation(() => {});
@@ -363,6 +362,83 @@ describe('StaticNotification', () => {
363362
});
364363

365364
describe('Callout', () => {
365+
it('should place the `className` prop on the outermost DOM node', () => {
366+
const { container } = render(<Callout className="test" />);
367+
expect(container.firstChild).toHaveClass('test');
368+
});
369+
370+
it('calls `onActionButtonClick` when action button is clicked', async () => {
371+
const onActionButtonClick = jest.fn();
372+
render(
373+
<Callout
374+
title="Notification title"
375+
actionButtonLabel="action-button"
376+
onActionButtonClick={onActionButtonClick}
377+
/>
378+
);
379+
380+
const closeButton = screen.queryByRole('button', {
381+
name: 'action-button',
382+
hidden: true,
383+
});
384+
await userEvent.click(closeButton);
385+
expect(onActionButtonClick).toHaveBeenCalledTimes(1);
386+
});
387+
388+
it('interpolates matching className based on kind prop', () => {
389+
const { rerender, container } = render(
390+
<Callout title="Notification title" />
391+
);
392+
const kinds = ['info', 'warning'];
393+
kinds.forEach((kind) => {
394+
rerender(<Callout title="Notification title" kind={kind} />);
395+
expect(container.firstChild).toHaveClass(
396+
`${prefix}--actionable-notification--${kind}`
397+
);
398+
});
399+
});
400+
401+
it('places low contrast class based on lowContrast prop', () => {
402+
const { container } = render(
403+
<Callout title="Notification title" lowContrast />
404+
);
405+
expect(container.firstChild).toHaveClass(
406+
`${prefix}--actionable-notification--low-contrast`
407+
);
408+
});
409+
410+
it('allows non-interactive elements as children', () => {
411+
render(
412+
<Callout title="Notification title">
413+
<p>Sample text</p>
414+
</Callout>
415+
);
416+
// eslint-disable-next-line testing-library/prefer-presence-queries
417+
expect(screen.queryByText(/Sample text/i)).toBeInTheDocument();
418+
});
419+
420+
it('allows interactive elements as children', () => {
421+
render(
422+
<Callout title="Notification title" titleId="interactive-test">
423+
<button aria-describedby="interactive-test">Sample text</button>
424+
</Callout>
425+
);
426+
// eslint-disable-next-line testing-library/prefer-presence-queries
427+
expect(screen.queryByText(/Sample text/i)).toBeInTheDocument();
428+
});
429+
430+
it('supports `title`, `subtitle`, `titleId` props', () => {
431+
const { container } = render(
432+
<Callout title="A title" subtitle="A subtitle" titleId="aTitleID">
433+
<p>Sample text</p>
434+
</Callout>
435+
);
436+
// eslint-disable-next-line testing-library/prefer-presence-queries
437+
expect(screen.queryByText(/A title/i)).toBeInTheDocument();
438+
expect(screen.queryByText(/A subtitle/i)).toBeInTheDocument();
439+
expect(screen.queryByText(/A title/i)).toHaveAttribute('id', 'aTitleID');
440+
});
441+
366442
it('enforces aria-describedby on interactive children elements', () => {
367443
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
368444

packages/react/src/components/Notification/stories/Callout.stories.js

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Link } from '../../Link';
1111
import mdx from '../Notification.mdx';
1212

1313
export default {
14-
title: 'Experimental/unstable__Callout',
14+
title: 'Components/Notifications/Callout',
1515
component: Callout,
1616
parameters: {
1717
docs: {
@@ -23,11 +23,22 @@ export default {
2323
lowContrast: false,
2424
statusIconDescription: 'notification',
2525
},
26+
argTypes: {
27+
children: {
28+
table: {
29+
disable: true,
30+
},
31+
},
32+
},
2633
};
2734

28-
// export const Default = () => (
29-
// <Callout title="Notification title" subtitle="Subtitle text goes here" />
30-
// );
35+
export const Default = (args) => (
36+
<Callout
37+
title="Notification title"
38+
subtitle="Subtitle text goes here"
39+
{...args}
40+
/>
41+
);
3142

3243
export const WithInteractiveElements = () => (
3344
<Callout
@@ -44,14 +55,6 @@ export const WithInteractiveElements = () => (
4455
</Callout>
4556
);
4657

47-
export const Default = (args) => (
48-
<Callout
49-
title="Notification title"
50-
subtitle="Subtitle text goes here"
51-
{...args}
52-
/>
53-
);
54-
5558
Default.argTypes = {
5659
children: {
5760
table: {

packages/react/src/components/Notification/stories/StaticNotification.stories.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { CodeSnippet } from '../../CodeSnippet';
1212
import mdx from './StaticNotification.mdx';
1313

1414
export default {
15-
title: 'Experimental/unstable__StaticNotification',
15+
title: 'Deprecated/unstable__StaticNotification',
1616
component: StaticNotification,
1717
parameters: {
1818
docs: {

packages/react/src/index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,9 @@ export {
106106
InlineNotification,
107107
NotificationActionButton,
108108
NotificationButton,
109-
Callout as unstable__Callout,
110-
Callout as unstable__StaticNotification,
109+
Callout,
110+
Callout as unstable__Callout, // TODO remove when telemetry shows zero usage, or in v12
111+
Callout as unstable__StaticNotification, // TODO remove when telemetry shows zero usage, or in v12
111112
} from './components/Notification';
112113
export { NumberInput, NumberInputSkeleton } from './components/NumberInput';
113114
export { OrderedList } from './components/OrderedList';

0 commit comments

Comments
 (0)