Skip to content

Commit 60bed2d

Browse files
committed
refactor: unify component file structure so index.tsx only re-exports
Move implementation from index.tsx into dedicated files (e.g. link/link.tsx) for 44 components, making index.tsx a pure re-export barrel file.
1 parent c0defe6 commit 60bed2d

90 files changed

Lines changed: 4134 additions & 3997 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

components/alert/alert.tsx

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React, { useState, useRef, useContext } from 'react';
2+
import classNames from 'classnames';
3+
import { ConfigContext } from '../config-provider/config-context';
4+
import { getPrefixCls } from '../_utils/general';
5+
import { CheckCircle, CloseCircle, InfoCircle, WarningCircle } from '../_utils/components';
6+
import { AlertProps } from './types';
7+
import Transition from '../transition';
8+
9+
const setClosedStyle = (node: HTMLElement): void => {
10+
node.style.borderTopWidth = '0';
11+
node.style.paddingTop = '0';
12+
node.style.marginTop = '0';
13+
node.style.height = '0';
14+
node.style.paddingBottom = '0';
15+
node.style.borderBottomWidth = '0';
16+
node.style.marginBottom = '0';
17+
};
18+
19+
const Alert = React.forwardRef<HTMLDivElement, AlertProps>((props, forwardedRef) => {
20+
const {
21+
type = 'info',
22+
iconSize = 14,
23+
prefixCls: customisedCls,
24+
title,
25+
icon,
26+
closeText,
27+
closable,
28+
afterClose,
29+
onClose,
30+
children,
31+
className,
32+
style,
33+
...otherProps
34+
} = props;
35+
const [isShow, setShow] = useState(true);
36+
const ref = useRef<HTMLDivElement | null>(null);
37+
const configContext = useContext(ConfigContext);
38+
const prefixCls = getPrefixCls('alert', configContext.prefixCls, customisedCls);
39+
const cls = classNames(prefixCls, className, [`${prefixCls}_${type}`]);
40+
41+
const closeBtnOnClick = (e: React.MouseEvent<HTMLSpanElement>): void => {
42+
ref.current && setClosedStyle(ref.current as HTMLDivElement);
43+
setShow(false);
44+
onClose && onClose(e);
45+
};
46+
47+
// Setting close text attribute also allows to be closable
48+
const closeIcon = (closable || closeText) && (
49+
<button type="button" className={`${prefixCls}__close-btn`} onClick={closeBtnOnClick} aria-label="Close">
50+
{closeText || '✕'}
51+
</button>
52+
);
53+
54+
const renderIcon = (): React.ReactNode => {
55+
if (typeof icon === 'boolean') {
56+
switch (type) {
57+
case 'success':
58+
return <CheckCircle size={iconSize} className={`${prefixCls}__icon`} />;
59+
case 'info':
60+
return <InfoCircle size={iconSize} className={`${prefixCls}__icon`} />;
61+
case 'warning':
62+
return <WarningCircle size={iconSize} className={`${prefixCls}__icon`} />;
63+
case 'error':
64+
return <CloseCircle size={iconSize} className={`${prefixCls}__icon`} />;
65+
}
66+
}
67+
68+
return icon;
69+
};
70+
71+
return (
72+
<Transition timeout={300} in={isShow} nodeRef={ref} onExited={afterClose}>
73+
<div {...otherProps} role="alert" className={cls} style={style} ref={(node) => {
74+
ref.current = node;
75+
if (typeof forwardedRef === 'function') forwardedRef(node);
76+
else if (forwardedRef) forwardedRef.current = node;
77+
}}>
78+
{icon && renderIcon()}
79+
<div>
80+
{title && <p className={`${prefixCls}__title`}>{title}</p>}
81+
{children}
82+
</div>
83+
{closeIcon}
84+
</div>
85+
</Transition>
86+
);
87+
});
88+
89+
Alert.displayName = 'Alert';
90+
91+
export default Alert;

components/alert/index.tsx

Lines changed: 1 addition & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,3 @@
1-
import React, { useState, useRef, useContext } from 'react';
2-
import classNames from 'classnames';
3-
import { ConfigContext } from '../config-provider/config-context';
4-
import { getPrefixCls } from '../_utils/general';
5-
import { CheckCircle, CloseCircle, InfoCircle, WarningCircle } from '../_utils/components';
6-
import { AlertProps } from './types';
7-
import Transition from '../transition';
8-
9-
const setClosedStyle = (node: HTMLElement): void => {
10-
node.style.borderTopWidth = '0';
11-
node.style.paddingTop = '0';
12-
node.style.marginTop = '0';
13-
node.style.height = '0';
14-
node.style.paddingBottom = '0';
15-
node.style.borderBottomWidth = '0';
16-
node.style.marginBottom = '0';
17-
};
18-
19-
const Alert = React.forwardRef<HTMLDivElement, AlertProps>((props, forwardedRef) => {
20-
const {
21-
type = 'info',
22-
iconSize = 14,
23-
prefixCls: customisedCls,
24-
title,
25-
icon,
26-
closeText,
27-
closable,
28-
afterClose,
29-
onClose,
30-
children,
31-
className,
32-
style,
33-
...otherProps
34-
} = props;
35-
const [isShow, setShow] = useState(true);
36-
const ref = useRef<HTMLDivElement | null>(null);
37-
const configContext = useContext(ConfigContext);
38-
const prefixCls = getPrefixCls('alert', configContext.prefixCls, customisedCls);
39-
const cls = classNames(prefixCls, className, [`${prefixCls}_${type}`]);
40-
41-
const closeBtnOnClick = (e: React.MouseEvent<HTMLSpanElement>): void => {
42-
ref.current && setClosedStyle(ref.current as HTMLDivElement);
43-
setShow(false);
44-
onClose && onClose(e);
45-
};
46-
47-
// Setting close text attribute also allows to be closable
48-
const closeIcon = (closable || closeText) && (
49-
<button type="button" className={`${prefixCls}__close-btn`} onClick={closeBtnOnClick} aria-label="Close">
50-
{closeText || '✕'}
51-
</button>
52-
);
53-
54-
const renderIcon = (): React.ReactNode => {
55-
if (typeof icon === 'boolean') {
56-
switch (type) {
57-
case 'success':
58-
return <CheckCircle size={iconSize} className={`${prefixCls}__icon`} />;
59-
case 'info':
60-
return <InfoCircle size={iconSize} className={`${prefixCls}__icon`} />;
61-
case 'warning':
62-
return <WarningCircle size={iconSize} className={`${prefixCls}__icon`} />;
63-
case 'error':
64-
return <CloseCircle size={iconSize} className={`${prefixCls}__icon`} />;
65-
}
66-
}
67-
68-
return icon;
69-
};
70-
71-
return (
72-
<Transition timeout={300} in={isShow} nodeRef={ref} onExited={afterClose}>
73-
<div {...otherProps} role="alert" className={cls} style={style} ref={(node) => {
74-
ref.current = node;
75-
if (typeof forwardedRef === 'function') forwardedRef(node);
76-
else if (forwardedRef) forwardedRef.current = node;
77-
}}>
78-
{icon && renderIcon()}
79-
<div>
80-
{title && <p className={`${prefixCls}__title`}>{title}</p>}
81-
{children}
82-
</div>
83-
{closeIcon}
84-
</div>
85-
</Transition>
86-
);
87-
});
88-
89-
Alert.displayName = 'Alert';
1+
import Alert from './alert';
902

913
export default Alert;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React, { useContext } from 'react';
2+
import classNames from 'classnames';
3+
import { ConfigContext } from '../config-provider/config-context';
4+
import { getPrefixCls } from '../_utils/general';
5+
import { AspectRatioProps } from './types';
6+
7+
const AspectRatio = React.forwardRef<HTMLDivElement, AspectRatioProps>((props, ref) => {
8+
const {
9+
ratio = 1,
10+
width = '100%',
11+
prefixCls: customisedCls,
12+
className,
13+
style,
14+
children,
15+
...otherProps
16+
} = props;
17+
const configContext = useContext(ConfigContext);
18+
const prefixCls = getPrefixCls('aspect-ratio', configContext.prefixCls, customisedCls);
19+
const cls = classNames(prefixCls, className);
20+
21+
return (
22+
<div {...otherProps} ref={ref} className={cls} style={{ ...style, width }}>
23+
<div className={`${prefixCls}__padding`} style={{ paddingTop: `${(1 / ratio) * 100}%` }} />
24+
<div className={`${prefixCls}__inside`}>{children}</div>
25+
</div>
26+
);
27+
});
28+
29+
AspectRatio.displayName = 'AspectRatio';
30+
31+
export default AspectRatio;

components/aspect-ratio/index.tsx

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,3 @@
1-
import React, { useContext } from 'react';
2-
import classNames from 'classnames';
3-
import { ConfigContext } from '../config-provider/config-context';
4-
import { getPrefixCls } from '../_utils/general';
5-
import { AspectRatioProps } from './types';
6-
7-
const AspectRatio = React.forwardRef<HTMLDivElement, AspectRatioProps>((props, ref) => {
8-
const {
9-
ratio = 1,
10-
width = '100%',
11-
prefixCls: customisedCls,
12-
className,
13-
style,
14-
children,
15-
...otherProps
16-
} = props;
17-
const configContext = useContext(ConfigContext);
18-
const prefixCls = getPrefixCls('aspect-ratio', configContext.prefixCls, customisedCls);
19-
const cls = classNames(prefixCls, className);
20-
21-
return (
22-
<div {...otherProps} ref={ref} className={cls} style={{ ...style, width }}>
23-
<div className={`${prefixCls}__padding`} style={{ paddingTop: `${(1 / ratio) * 100}%` }} />
24-
<div className={`${prefixCls}__inside`}>{children}</div>
25-
</div>
26-
);
27-
});
28-
29-
AspectRatio.displayName = 'AspectRatio';
1+
import AspectRatio from './aspect-ratio';
302

313
export default AspectRatio;

components/back-top/back-top.tsx

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import React, { useCallback, useContext, useEffect, useState } from 'react';
2+
import classNames from 'classnames';
3+
import { Target } from '../_utils/dom';
4+
import { ConfigContext } from '../config-provider/config-context';
5+
import { getPrefixCls } from '../_utils/general';
6+
import { BackTopProps } from './types';
7+
8+
const easeInOutCubic = (t: number, b: number, c: number, d: number): number => {
9+
const cc = c - b;
10+
t /= d / 2;
11+
if (t < 1) {
12+
return (cc / 2) * t * t * t + b;
13+
} else {
14+
return (cc / 2) * ((t -= 2) * t * t + 2) + b;
15+
}
16+
};
17+
18+
const BackTop = (props: BackTopProps): JSX.Element | null => {
19+
const {
20+
visibilityHeight = 300,
21+
target = (): Target => window,
22+
prefixCls: customisedCls,
23+
onClick,
24+
className,
25+
style,
26+
children,
27+
} = props;
28+
const configContext = useContext(ConfigContext);
29+
const prefixCls = getPrefixCls('back-top', configContext.prefixCls, customisedCls);
30+
const cls = classNames(prefixCls, className, {
31+
[`${prefixCls}_custom`]: !!children,
32+
});
33+
const [visible, setVisible] = useState(true);
34+
35+
const getDistanceFromTop = useCallback((): number => {
36+
const targetNode = target();
37+
if (targetNode === window) {
38+
return window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
39+
}
40+
return (targetNode as HTMLElement).scrollTop;
41+
}, [target]);
42+
43+
const setScrollToTop = (distance: number): void => {
44+
const targetNode = target();
45+
if (targetNode === window) {
46+
document.body.scrollTop = distance;
47+
document.documentElement.scrollTop = distance;
48+
} else {
49+
(targetNode as HTMLElement).scrollTop = distance;
50+
}
51+
};
52+
53+
const scrollToTop = (e: React.MouseEvent<HTMLButtonElement>): void => {
54+
const scrollTop = getDistanceFromTop();
55+
const startTime = Date.now();
56+
const step = (): void => {
57+
const timestamp = Date.now();
58+
const time = timestamp - startTime;
59+
setScrollToTop(easeInOutCubic(time, scrollTop, 0, 450));
60+
if (time < 450) {
61+
requestAnimationFrame(step);
62+
} else {
63+
setScrollToTop(0);
64+
}
65+
};
66+
requestAnimationFrame(step);
67+
onClick && onClick(e);
68+
};
69+
70+
const handleOnScroll = useCallback(() => {
71+
if (getDistanceFromTop() > visibilityHeight) {
72+
!visible && setVisible(true);
73+
} else if (visible) {
74+
setVisible(false);
75+
}
76+
}, [getDistanceFromTop, visible, visibilityHeight]);
77+
78+
useEffect(() => {
79+
const targetNode = target();
80+
targetNode.addEventListener('scroll', handleOnScroll);
81+
handleOnScroll();
82+
83+
return (): void => {
84+
targetNode.removeEventListener('scroll', handleOnScroll);
85+
};
86+
}, [target, handleOnScroll]);
87+
88+
if (visible) {
89+
return (
90+
<button type="button" className={cls} style={style} onClick={scrollToTop} aria-label="Back to top">
91+
{children || (
92+
<svg viewBox="0 0 1024 1024" width="18" height="18">
93+
<path
94+
d="M563.2 379.757048 563.2 972.755371C563.2 1001.056998 540.219441 1024 512 1024
95+
483.723021 1024 460.8 1001.019181 460.8 972.755371L460.8 379.740842 272.093167
96+
568.447675C252.13208 588.408762 219.700711 588.340711 199.746554 568.386554 179.75171
97+
548.39171 179.766716 515.958656 199.685432 496.039941L473.973319 221.752055C483.353204
98+
211.343458 496.929524 204.8 512 204.8 527.198527 204.8 540.850334 211.438998 550.227358
99+
221.968936L824.32552 496.0671C844.244236 515.985815 844.259243 548.418868 824.2644
100+
568.413712 804.310241 588.367871 771.878874 588.435921 751.917786 568.474834L563.2
101+
379.757048ZM0 51.2C0 22.923021 22.82342 0 51.130666 0L972.869334 0C1001.108021 0 1024
102+
22.980559 1024 51.2 1024 79.476979 1001.17658 102.4 972.869334 102.4L51.130666
103+
102.4C22.891979 102.4 0 79.419441 0 51.2Z"
104+
fill="#ffffff"
105+
/>
106+
</svg>
107+
)}
108+
</button>
109+
);
110+
}
111+
112+
return null;
113+
};
114+
115+
export default BackTop;

0 commit comments

Comments
 (0)