Skip to content

Commit de7bf8b

Browse files
authored
feat: notification support aria in closable (#321)
1 parent 2813ad6 commit de7bf8b

File tree

4 files changed

+43
-3
lines changed

4 files changed

+43
-3
lines changed

src/Notice.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import classNames from 'classnames';
22
import KeyCode from 'rc-util/lib/KeyCode';
33
import * as React from 'react';
44
import type { NoticeConfig } from './interface';
5+
import pickAttrs from 'rc-util/lib/pickAttrs';
56

67
export interface NoticeProps extends Omit<NoticeConfig, 'onClose'> {
78
prefixCls: string;
@@ -60,6 +61,19 @@ const Notify = React.forwardRef<HTMLDivElement, NoticeProps & { times?: number }
6061
// eslint-disable-next-line react-hooks/exhaustive-deps
6162
}, [duration, mergedHovering, times]);
6263

64+
// ======================== Closable ========================
65+
const closableObj = React.useMemo(() => {
66+
if (typeof closable === 'object' && closable !== null) {
67+
return closable;
68+
}
69+
if (closable) {
70+
return { closeIcon };
71+
}
72+
return {};
73+
}, [closable, closeIcon]);
74+
75+
const ariaProps = pickAttrs(closableObj, true);
76+
6377
// ======================== Render ========================
6478
const noticePrefixCls = `${prefixCls}-notice`;
6579

@@ -90,13 +104,15 @@ const Notify = React.forwardRef<HTMLDivElement, NoticeProps & { times?: number }
90104
tabIndex={0}
91105
className={`${noticePrefixCls}-close`}
92106
onKeyDown={onCloseKeyDown}
107+
aria-label="Close"
108+
{...ariaProps}
93109
onClick={(e) => {
94110
e.preventDefault();
95111
e.stopPropagation();
96112
onInternalClose();
97113
}}
98114
>
99-
{closeIcon}
115+
{closableObj.closeIcon}
100116
</a>
101117
)}
102118
</div>

src/hooks/useNotification.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export interface NotificationConfig {
1414
getContainer?: () => HTMLElement | ShadowRoot;
1515
motion?: CSSMotionProps | ((placement: Placement) => CSSMotionProps);
1616
closeIcon?: React.ReactNode;
17-
closable?: boolean;
17+
closable?: boolean | ({ closeIcon?: React.ReactNode } & React.AriaAttributes);
1818
maxCount?: number;
1919
duration?: number;
2020
/** @private. Config for notification holder style. Safe to remove if refactor */

src/interface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export interface NoticeConfig {
88
content?: React.ReactNode;
99
duration?: number | null;
1010
closeIcon?: React.ReactNode;
11-
closable?: boolean;
11+
closable?: boolean | ({ closeIcon?: React.ReactNode } & React.AriaAttributes);
1212
className?: string;
1313
style?: React.CSSProperties;
1414
classNames?: {

tests/index.test.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,4 +688,28 @@ describe('Notification.Basic', () => {
688688
fireEvent.keyDown(document.querySelector('.rc-notification-notice-close'), { key: 'Enter' }); // origin latest
689689
expect(closeCount).toEqual(1);
690690
});
691+
it('Support aria-* in closable', () => {
692+
const { instance } = renderDemo({
693+
closable: {
694+
closeIcon: 'CloseBtn',
695+
'aria-label': 'close',
696+
'aria-labelledby': 'close',
697+
},
698+
});
699+
700+
act(() => {
701+
instance.open({
702+
content: <p className="test">1</p>,
703+
duration: 0,
704+
});
705+
});
706+
707+
expect(document.querySelector('.rc-notification-notice-close').textContent).toEqual('CloseBtn');
708+
expect(
709+
document.querySelector('.rc-notification-notice-close').getAttribute('aria-label'),
710+
).toEqual('close');
711+
expect(
712+
document.querySelector('.rc-notification-notice-close').getAttribute('aria-labelledby'),
713+
).toEqual('close');
714+
});
691715
});

0 commit comments

Comments
 (0)