Skip to content

Commit d58f5c8

Browse files
authored
feat: support stack (#311)
* feat: support stack * feat: support stack * fix: crash * chore: bump rc-motion * chore: update * feat: pause close timeout on hover * feat: support scroll * feat: support placement * feat: stack support offset and gap * chore: fix import * fix: nodeRef * test: add test case * chore: update
1 parent a74f68d commit d58f5c8

File tree

13 files changed

+362
-37
lines changed

13 files changed

+362
-37
lines changed

assets/index.less

Lines changed: 108 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,29 @@
77
display: flex;
88
max-height: 100vh;
99
padding: 10px;
10-
overflow-y: auto;
1110
align-items: flex-end;
11+
width: 340px;
12+
overflow-x: hidden;
13+
overflow-y: auto;
14+
height: 100vh;
15+
box-sizing: border-box;
16+
pointer-events: none;
17+
flex-direction: column;
1218

1319
// Position
1420
&-top,
1521
&-topLeft,
1622
&-topRight {
1723
top: 0;
18-
flex-direction: column;
1924
}
2025

26+
&-bottom,
27+
&-bottomRight,
28+
&-bottomLeft {
29+
bottom: 0;
30+
}
31+
32+
&-bottomRight,
2133
&-topRight {
2234
right: 0;
2335
}
@@ -27,14 +39,22 @@
2739
position: relative;
2840
display: block;
2941
box-sizing: border-box;
30-
width: auto;
31-
margin: 12px 0;
3242
line-height: 1.5;
33-
background: #fff;
34-
border: 1px solid #999;
35-
border: 0px solid rgba(0, 0, 0, 0);
36-
border-radius: 3px 3px;
37-
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
43+
width: 100%;
44+
45+
&-wrapper {
46+
pointer-events: auto;
47+
position: relative;
48+
display: block;
49+
box-sizing: border-box;
50+
border-radius: 3px 3px;
51+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
52+
margin: 0 0 16px;
53+
border: 1px solid #999;
54+
border: 0px solid rgba(0, 0, 0, 0);
55+
background: #fff;
56+
width: 300px;
57+
}
3858

3959
// Content
4060
&-content {
@@ -77,6 +97,11 @@
7797
transition: all 0.3s;
7898
}
7999

100+
&-fade-appear-prepare {
101+
pointer-events: none;
102+
opacity: 0 !important;
103+
}
104+
80105
&-fade-appear-start {
81106
transform: translateX(100%);
82107
opacity: 0;
@@ -133,4 +158,78 @@
133158
// opacity: 0;
134159
// }
135160
// }
161+
162+
// ========================= Stack =========================
163+
&-stack {
164+
& > .@{notificationPrefixCls}-notice {
165+
&-wrapper {
166+
transition: all 0.3s;
167+
position: absolute;
168+
top: 12px;
169+
opacity: 1;
170+
171+
&:not(:nth-last-child(-n + 3)) {
172+
opacity: 0;
173+
right: 34px;
174+
width: 252px;
175+
overflow: hidden;
176+
color: transparent;
177+
pointer-events: none;
178+
}
179+
180+
&:nth-last-child(1) {
181+
right: 10px;
182+
}
183+
184+
&:nth-last-child(2) {
185+
right: 18px;
186+
width: 284px;
187+
color: transparent;
188+
overflow: hidden;
189+
}
190+
191+
&:nth-last-child(3) {
192+
right: 26px;
193+
width: 268px;
194+
color: transparent;
195+
overflow: hidden;
196+
}
197+
}
198+
}
199+
200+
&&-expanded {
201+
& > .@{notificationPrefixCls}-notice {
202+
&-wrapper {
203+
&:not(:nth-last-child(-n + 1)) {
204+
opacity: 1;
205+
width: 300px;
206+
right: 10px;
207+
overflow: unset;
208+
color: inherit;
209+
pointer-events: auto;
210+
}
211+
212+
&::after {
213+
content: "";
214+
position: absolute;
215+
left: 0;
216+
right: 0;
217+
top: -16px;
218+
width: 100%;
219+
height: calc(100% + 32px);
220+
background: transparent;
221+
pointer-events: auto;
222+
color: rgb(0,0,0);
223+
}
224+
}
225+
}
226+
}
227+
228+
&.@{notificationPrefixCls}-bottomRight {
229+
& > .@{notificationPrefixCls}-notice-wrapper {
230+
top: unset;
231+
bottom: 12px;
232+
}
233+
}
234+
}
136235
}

docs/demo/stack.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: stack
3+
nav:
4+
title: Demo
5+
path: /demo
6+
---
7+
8+
<code src="../examples/stack.tsx"></code>

docs/examples/hooks.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import '../../assets/index.less';
44
import { useNotification } from '../../src';
55
import motion from './motion';
66

7-
export default () => {
7+
const App = () => {
88
const [notice, contextHolder] = useNotification({ motion, closable: true });
99

1010
return (
@@ -26,7 +26,25 @@ export default () => {
2626
<button
2727
onClick={() => {
2828
notice.open({
29-
content: `${new Date().toISOString()}`,
29+
content: `${Array(Math.round(Math.random() * 5) + 1)
30+
.fill(1)
31+
.map(() => new Date().toISOString())
32+
.join('\n')}`,
33+
duration: null,
34+
});
35+
}}
36+
>
37+
Not Auto Close
38+
</button>
39+
40+
{/* Not Close */}
41+
<button
42+
onClick={() => {
43+
notice.open({
44+
content: `${Array(5)
45+
.fill(1)
46+
.map(() => new Date().toISOString())
47+
.join('\n')}`,
3048
duration: null,
3149
});
3250
}}
@@ -79,3 +97,9 @@ export default () => {
7997
</>
8098
);
8199
};
100+
101+
export default () => (
102+
<React.StrictMode>
103+
<App />
104+
</React.StrictMode>
105+
);

docs/examples/stack.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* eslint-disable no-console */
2+
import React from 'react';
3+
import '../../assets/index.less';
4+
import { useNotification } from '../../src';
5+
import motion from './motion';
6+
7+
const Context = React.createContext({ name: 'light' });
8+
9+
const getConfig = () => ({
10+
content: `${Array(Math.round(Math.random() * 5) + 1)
11+
.fill(1)
12+
.map(() => new Date().toISOString())
13+
.join('\n')}`,
14+
duration: null,
15+
});
16+
17+
const Demo = () => {
18+
const [{ open }, holder] = useNotification({ motion, stack: true });
19+
20+
return (
21+
<Context.Provider value={{ name: 'bamboo' }}>
22+
<button
23+
type="button"
24+
onClick={() => {
25+
open(getConfig());
26+
}}
27+
>
28+
Top Right
29+
</button>
30+
<button
31+
type="button"
32+
onClick={() => {
33+
open({ ...getConfig(), placement: 'bottomRight' });
34+
}}
35+
>
36+
Bottom Right
37+
</button>
38+
{holder}
39+
</Context.Provider>
40+
);
41+
};
42+
43+
export default Demo;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
"dependencies": {
8080
"@babel/runtime": "^7.10.1",
8181
"classnames": "2.x",
82-
"rc-motion": "^2.6.0",
82+
"rc-motion": "^2.8.0",
8383
"rc-util": "^5.20.1"
8484
},
8585
"lint-staged": {

src/Notice.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export interface NoticeProps extends Omit<NoticeConfig, 'onClose'> {
1111

1212
onClick?: React.MouseEventHandler<HTMLDivElement>;
1313
onNoticeClose?: (key: React.Key) => void;
14+
hovering?: boolean;
1415
}
1516

1617
const Notify = React.forwardRef<HTMLDivElement, NoticeProps & { times?: number }>((props, ref) => {
@@ -29,8 +30,10 @@ const Notify = React.forwardRef<HTMLDivElement, NoticeProps & { times?: number }
2930
onClick,
3031
onNoticeClose,
3132
times,
33+
hovering: forcedHovering,
3234
} = props;
3335
const [hovering, setHovering] = React.useState(false);
36+
const mergedHovering = forcedHovering || hovering;
3437

3538
// ======================== Close =========================
3639
const onInternalClose = () => {
@@ -45,7 +48,7 @@ const Notify = React.forwardRef<HTMLDivElement, NoticeProps & { times?: number }
4548

4649
// ======================== Effect ========================
4750
React.useEffect(() => {
48-
if (!hovering && duration > 0) {
51+
if (!mergedHovering && duration > 0) {
4952
const timeout = setTimeout(() => {
5053
onInternalClose();
5154
}, duration * 1000);
@@ -55,7 +58,7 @@ const Notify = React.forwardRef<HTMLDivElement, NoticeProps & { times?: number }
5558
};
5659
}
5760
// eslint-disable-next-line react-hooks/exhaustive-deps
58-
}, [duration, hovering, times]);
61+
}, [duration, mergedHovering, times]);
5962

6063
// ======================== Render ========================
6164
const noticePrefixCls = `${prefixCls}-notice`;
@@ -68,11 +71,13 @@ const Notify = React.forwardRef<HTMLDivElement, NoticeProps & { times?: number }
6871
[`${noticePrefixCls}-closable`]: closable,
6972
})}
7073
style={style}
71-
onMouseEnter={() => {
74+
onMouseEnter={(e) => {
7275
setHovering(true);
76+
divProps?.onMouseEnter?.(e);
7377
}}
74-
onMouseLeave={() => {
78+
onMouseLeave={(e) => {
7579
setHovering(false);
80+
divProps?.onMouseLeave?.(e);
7681
}}
7782
onClick={onClick}
7883
>

0 commit comments

Comments
 (0)