|
1 | 1 | import * as React from 'react'; |
2 | 2 | import { clsx } from 'clsx'; |
3 | | -import pickAttrs from '@rc-component/util/lib/pickAttrs'; |
4 | 3 | import useNoticeTimer from './hooks/useNoticeTimer'; |
5 | 4 | import { useEvent } from '@rc-component/util'; |
| 5 | +import useClosable, { type ClosableType } from './hooks/useClosable'; |
6 | 6 |
|
7 | 7 | export interface NotificationClassNames { |
8 | 8 | wrapper?: string; |
@@ -32,9 +32,7 @@ export interface NotificationProps { |
32 | 32 | content?: React.ReactNode; |
33 | 33 | actions?: React.ReactNode; |
34 | 34 | close?: React.ReactNode; |
35 | | - closable?: |
36 | | - | boolean |
37 | | - | ({ closeIcon?: React.ReactNode; onClose?: VoidFunction } & React.AriaAttributes); |
| 35 | + closable?: ClosableType; |
38 | 36 | offset?: { |
39 | 37 | x: number; |
40 | 38 | y: number; |
@@ -90,36 +88,24 @@ const Notification = React.forwardRef<HTMLDivElement, NotificationProps>((props, |
90 | 88 |
|
91 | 89 | // ========================= Close ========================== |
92 | 90 | const onEventClose = useEvent(onClose); |
93 | | - const offsetRef = React.useRef(offset); |
94 | | - const closableObj = React.useMemo(() => { |
95 | | - if (typeof closable === 'object' && closable !== null) { |
96 | | - return closable; |
97 | | - } |
98 | 91 |
|
99 | | - return {}; |
100 | | - }, [closable]); |
101 | | - const closeContent = close === undefined ? (closableObj.closeIcon ?? 'x') : close; |
102 | | - const mergedClosable = close !== undefined ? close !== null : !!closable; |
103 | | - const ariaProps = pickAttrs(closableObj, true); |
104 | | - |
105 | | - if (offset) { |
106 | | - offsetRef.current = offset; |
107 | | - } |
| 92 | + const [closableEnabled, closableConfig, closeBtnAriaProps] = useClosable(closable); |
| 93 | + const closeContent = close === undefined ? closableConfig.closeIcon : close; |
| 94 | + const mergedClosable = close !== undefined ? close !== null : closableEnabled; |
108 | 95 |
|
109 | 96 | // ======================== Duration ======================== |
110 | 97 | const [hovering, setHovering] = React.useState(false); |
111 | 98 |
|
112 | 99 | const [onResume, onPause] = useNoticeTimer( |
113 | 100 | duration, |
114 | 101 | () => { |
115 | | - closableObj.onClose?.(); |
| 102 | + closableConfig.onClose?.(); |
116 | 103 | onEventClose(); |
117 | 104 | }, |
118 | 105 | setPercent, |
119 | 106 | !!showProgress, |
120 | 107 | ); |
121 | 108 |
|
122 | | - const mergedOffset = offset ?? offsetRef.current; |
123 | 109 | const validPercent = 100 - Math.min(Math.max(percent * 100, 0), 100); |
124 | 110 |
|
125 | 111 | React.useEffect(() => { |
@@ -151,6 +137,14 @@ const Notification = React.forwardRef<HTMLDivElement, NotificationProps>((props, |
151 | 137 | onMouseLeave?.(event); |
152 | 138 | } |
153 | 139 |
|
| 140 | + // ======================== Position ======================== |
| 141 | + const offsetRef = React.useRef(offset); |
| 142 | + if (offset) { |
| 143 | + offsetRef.current = offset; |
| 144 | + } |
| 145 | + |
| 146 | + const mergedOffset = offset ?? offsetRef.current; |
| 147 | + |
154 | 148 | // ========================= Render ========================= |
155 | 149 | return ( |
156 | 150 | <div |
@@ -186,18 +180,18 @@ const Notification = React.forwardRef<HTMLDivElement, NotificationProps>((props, |
186 | 180 | <button |
187 | 181 | className={clsx(`${noticePrefixCls}-close`, classNames?.close)} |
188 | 182 | aria-label="Close" |
189 | | - {...ariaProps} |
| 183 | + {...closeBtnAriaProps} |
190 | 184 | style={styles?.close} |
191 | 185 | onKeyDown={(event) => { |
192 | 186 | if (event.key === 'Enter' || event.code === 'Enter') { |
193 | | - closableObj.onClose?.(); |
| 187 | + closableConfig.onClose?.(); |
194 | 188 | onEventClose(); |
195 | 189 | } |
196 | 190 | }} |
197 | 191 | onClick={(e) => { |
198 | 192 | e.preventDefault(); |
199 | 193 | e.stopPropagation(); |
200 | | - closableObj.onClose?.(); |
| 194 | + closableConfig.onClose?.(); |
201 | 195 | onEventClose(); |
202 | 196 | }} |
203 | 197 | > |
|
0 commit comments