Skip to content

Commit 3b8840d

Browse files
committed
add list content card bounds css vars
1 parent ecadd8c commit 3b8840d

4 files changed

Lines changed: 82 additions & 9 deletions

File tree

src/NotificationList/Content.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { clsx } from 'clsx';
22
import * as React from 'react';
3+
import type { NoticeBounds } from '../hooks/useListPosition';
34

45
export interface ContentProps extends React.HTMLAttributes<HTMLDivElement> {
56
listPrefixCls: string;
67
height: number;
8+
topNoticeBounds?: NoticeBounds;
79
}
810

911
const Content = React.forwardRef<HTMLDivElement, ContentProps>((props, ref) => {
10-
const { listPrefixCls, height, className, style, ...restProps } = props;
12+
const { listPrefixCls, height, topNoticeBounds, className, style, ...restProps } = props;
1113

1214
const contentPrefixCls = `${listPrefixCls}-content`;
1315

@@ -18,15 +20,26 @@ const Content = React.forwardRef<HTMLDivElement, ContentProps>((props, ref) => {
1820

1921
prevHeightRef.current = height;
2022

23+
// ========================= Style ==========================
24+
const contentStyle: React.CSSProperties & {
25+
'--notification-top'?: string;
26+
'--notification-bottom'?: string;
27+
} = {
28+
...style,
29+
height,
30+
};
31+
32+
if (topNoticeBounds) {
33+
contentStyle['--notification-top'] = `${topNoticeBounds.top}px`;
34+
contentStyle['--notification-bottom'] = `${topNoticeBounds.bottom}px`;
35+
}
36+
2137
// ========================= Render =========================
2238
return (
2339
<div
2440
{...restProps}
2541
className={clsx(contentPrefixCls, `${contentPrefixCls}-${heightStatus}`, className)}
26-
style={{
27-
...style,
28-
height,
29-
}}
42+
style={contentStyle}
3043
ref={ref}
3144
/>
3245
);

src/NotificationList/index.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,26 @@ const NotificationList: React.FC<NotificationListProps> = (props) => {
210210
// ====================== List Measure ======================
211211
const [gap, setGap] = React.useState(0);
212212
const contentRef = React.useRef<HTMLDivElement>(null);
213-
const [notificationPosition, setNodeSize, totalHeight] = useListPosition(
213+
const [notificationPosition, setNodeSize, totalHeight, topNoticeBounds] = useListPosition(
214214
configList,
215215
stackPosition,
216216
gap,
217217
);
218218
const hasConfigList = !!configList.length;
219+
const topNoticeContentBounds = React.useMemo(() => {
220+
if (!topNoticeBounds) {
221+
return undefined;
222+
}
223+
224+
if (placement.startsWith('bottom')) {
225+
return {
226+
top: totalHeight - topNoticeBounds.bottom,
227+
bottom: totalHeight - topNoticeBounds.top,
228+
};
229+
}
230+
231+
return topNoticeBounds;
232+
}, [placement, topNoticeBounds, totalHeight]);
219233

220234
React.useEffect(() => {
221235
const listNode = contentRef.current;
@@ -259,6 +273,7 @@ const NotificationList: React.FC<NotificationListProps> = (props) => {
259273
<Content
260274
listPrefixCls={listPrefixCls}
261275
height={totalHeight}
276+
topNoticeBounds={topNoticeContentBounds}
262277
className={classNames?.listContent}
263278
style={styles?.listContent}
264279
ref={contentRef}

src/hooks/useListPosition/index.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ import * as React from 'react';
22
import type { StackConfig } from '../useStack';
33
import useSizes from './useSizes';
44

5+
export interface NoticeBounds {
6+
top: number;
7+
bottom: number;
8+
}
9+
510
/**
611
* Calculates each notification's position and the full list height.
712
*/
@@ -12,11 +17,12 @@ export default function useListPosition(
1217
) {
1318
const [sizeMap, setNodeSize] = useSizes();
1419

15-
const [notificationPosition, totalHeight] = React.useMemo(() => {
20+
const [notificationPosition, totalHeight, topNoticeBounds] = React.useMemo(() => {
1621
let offsetY = 0;
1722
let nextTotalHeight = 0;
1823
const stackThreshold = stack?.threshold ?? 0;
1924
const nextNotificationPosition = new Map<string, number>();
25+
let nextTopNoticeBounds: NoticeBounds | undefined;
2026

2127
configList
2228
.slice()
@@ -29,6 +35,13 @@ export default function useListPosition(
2935

3036
nextNotificationPosition.set(key, y);
3137

38+
if (index === 0) {
39+
nextTopNoticeBounds = {
40+
top: y,
41+
bottom: y + height,
42+
};
43+
}
44+
3245
if (!stack || index < stackThreshold) {
3346
nextTotalHeight = Math.max(nextTotalHeight, y + height);
3447
}
@@ -40,8 +53,8 @@ export default function useListPosition(
4053
}
4154
});
4255

43-
return [nextNotificationPosition, nextTotalHeight] as const;
56+
return [nextNotificationPosition, nextTotalHeight, nextTopNoticeBounds] as const;
4457
}, [configList, gap, sizeMap, stack]);
4558

46-
return [notificationPosition, setNodeSize, totalHeight] as const;
59+
return [notificationPosition, setNodeSize, totalHeight, topNoticeBounds] as const;
4760
}

tests/index.test.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,38 @@ describe('Notification.Basic', () => {
866866
expect(document.querySelector('.rc-notification-list-content')).toHaveClass('bamboo');
867867
});
868868

869+
it('should expose top notice bounds on listContent', () => {
870+
const offsetHeightSpy = vi
871+
.spyOn(HTMLElement.prototype, 'offsetHeight', 'get')
872+
.mockImplementation(function offsetHeight(this: HTMLElement) {
873+
if (this.classList.contains('rc-notification-notice')) {
874+
return this.textContent === 'second' ? 18 : 10;
875+
}
876+
877+
return 0;
878+
});
879+
880+
const { instance } = renderDemo();
881+
882+
act(() => {
883+
instance.open({
884+
description: 'first',
885+
duration: false,
886+
});
887+
instance.open({
888+
description: 'second',
889+
duration: false,
890+
});
891+
});
892+
893+
expect(document.querySelector('.rc-notification-list-content')).toHaveStyle({
894+
'--notification-top': '0px',
895+
'--notification-bottom': '18px',
896+
});
897+
898+
offsetHeightSpy.mockRestore();
899+
});
900+
869901
it('placement', () => {
870902
const { instance } = renderDemo();
871903

0 commit comments

Comments
 (0)