Skip to content

Commit

Permalink
feat(Loading): add new Loading component (#1424)
Browse files Browse the repository at this point in the history
Co-authored-by: Zhang Rui <zhangrui@growingio.com>
  • Loading branch information
Ryan Zhang and Zhang Rui authored Nov 3, 2021
1 parent 52c2000 commit 2aa4034
Show file tree
Hide file tree
Showing 7 changed files with 621 additions and 0 deletions.
67 changes: 67 additions & 0 deletions src/loading/Loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useMemo, forwardRef, useRef } from 'react';
import classNames from 'classnames';
import useDebounceLoading from '../utils/hooks/useDebounceLoading';
import composeRef from '../utils/composeRef';
import usePrefixCls from '../utils/hooks/use-prefix-cls';
import { LoadingProps } from './interface';
import Wheel from './Wheel';

const Loading = forwardRef<HTMLDivElement, LoadingProps>((props, ref) => {
const {
prefixCls: customizePrefixCls,
loading = true,
delay = 0,
indicator,
titlePosition = 'bottom',
title,
size = 'large',
className,
style,
children,
blurColor = 'white',
} = props;
const prefixCls = usePrefixCls('loading-new', customizePrefixCls);
const shouldLoading = useDebounceLoading(loading, delay);
const loadingRef = useRef<HTMLDivElement>(null);

const loadingElementAndTitle: JSX.Element = useMemo(
() =>
shouldLoading ? (
<div
className={classNames(`${prefixCls}`, `${prefixCls}-${size}`, className)}
style={{ ...style }}
ref={composeRef(loadingRef, ref)}
>
<Wheel prefixCls={customizePrefixCls} indicator={indicator} />
{title && (
<span className={classNames(`${prefixCls}-title`, `${prefixCls}-title-${titlePosition}`)}>{title}</span>
)}
</div>
) : (
<>{null}</>
),
[className, customizePrefixCls, indicator, prefixCls, ref, shouldLoading, size, style, title, titlePosition]
);

const result: JSX.Element = useMemo(() => {
if (children) {
return (
<div className={classNames(`${prefixCls}-wrapper-loading`, className)}>
{loadingElementAndTitle}
<div
className={classNames(`${prefixCls}-container`, `${prefixCls}-container-blur-${blurColor}`, {
[`${prefixCls}-container-loading`]: shouldLoading,
})}
>
{children}
</div>
</div>
);
}
return loadingElementAndTitle;
}, [blurColor, children, loadingElementAndTitle, prefixCls, shouldLoading, className]);

return result;
});

export default Loading;
30 changes: 30 additions & 0 deletions src/loading/Wheel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import usePrefixCls from '../utils/hooks/use-prefix-cls';
import { WheelProps } from './interface';

const Wheel: React.FC<WheelProps> = (props: WheelProps) => {
const { indicator, prefixCls: customizePrefixCls } = props;
const prefixCls = usePrefixCls('loading-new', customizePrefixCls);
if (indicator) {
return <span className={`${prefixCls}-indicator`}>{indicator}</span>;
}
return (
<div className={`${prefixCls}-ring`}>
{[1, 2, 3, 4].map((item) => (
<div className={`${prefixCls}-ring-line ${prefixCls}-ring-line-${item}`}>
<div className={`${prefixCls}-ring-line-cog`}>
<div className={`${prefixCls}-ring-line-cog-inner ${prefixCls}-ring-line-cog-inner-left`} />
</div>
<div className={`${prefixCls}-ring-line-ticker`}>
<div className={`${prefixCls}-ring-line-cog-inner ${prefixCls}-ring-line-cog-inner-center`} />
</div>
<div className={`${prefixCls}-ring-line-cog`}>
<div className={`${prefixCls}-ring-line-cog-inner ${prefixCls}-ring-line-cog-inner-right`} />
</div>
</div>
))}
</div>
);
};

export default Wheel;
126 changes: 126 additions & 0 deletions src/loading/demos/Loading.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import React from 'react';
import { Story, Meta } from '@storybook/react/types-6-0';
import { withDesign } from 'storybook-addon-designs';
import { LoadingOutlined } from '@gio-design/icons';
import Loading from '../index';
import Button from '../../button';
import Tabs, { TabPane } from '../../components/tabs';
import { LoadingProps } from '../interface';
import '../style';

export default {
title: 'Upgraded/Loading',
component: Loading,
decorators: [withDesign],
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/kP3A6S2fLUGVVMBgDuUx0f/GrowingIO-Design-Components?node-id=889%3A1142',
allowFullscreen: true,
},
docs: {
page: null,
},
},
} as Meta;

const defaultTabs = (
<Tabs>
<TabPane tab="我的" key="1">
<ul>
<li>Event 1</li>
<li>Event 1</li>
<li>Event 1</li>
<li>Event 1</li>
</ul>
</TabPane>
<TabPane tab="全部" key="2">
<ul>
<li>Event 2</li>
<li>Event 2</li>
<li>Event 2</li>
<li>Event 2</li>
</ul>
</TabPane>
<TabPane tab="共享" key="3">
<ul>
<li>Event 3</li>
<li>Event 3</li>
<li>Event 3</li>
<li>Event 3</li>
</ul>
</TabPane>
</Tabs>
);

const Template: Story<LoadingProps> = (args) => <Loading {...args} />;

export const Default = Template.bind({});
Default.args = {
loading: true,
titlePosition: 'right',
autoCenter: true,
};

export const Container = Template.bind({});
Container.args = {
children: defaultTabs,
};

export const Indicator = Template.bind({});

Indicator.args = {
indicator: <LoadingOutlined rotating />,
title: false,
};

Indicator.story = {
parameters: {
design: {
url: 'https://www.figma.com/file/kP3A6S2fLUGVVMBgDuUx0f/GrowingIO-Design-Components?node-id=889%3A1159',
},
},
};

interface DelayProps {
delay: number;
}

const DelayTemplate: Story<DelayProps> = (args) => {
const { delay } = args;
const [loading, setLoading] = React.useState(true);
return (
<>
<Loading titlePosition="right" loading={loading} delay={delay}>
{defaultTabs}
</Loading>
<br />
<Button onClick={() => setLoading(!loading)}>click me</Button>
</>
);
};

export const Delay = DelayTemplate.bind({});
Delay.args = {
delay: 1000,
};

const SizeTemplate: Story<LoadingProps> = () => {
const styles = { height: 100, border: '1px solid #818181', marginBottom: 8 };
return (
<>
<div style={styles}>
<Loading titlePosition="right" loading size="small" />
</div>
<div style={styles}>
<Loading titlePosition="right" loading size="middle" />
</div>
<div style={styles}>
<Loading titlePosition="right" loading size="large" />
</div>
</>
);
};

export const Size = SizeTemplate.bind({});
Size.args = {};
4 changes: 4 additions & 0 deletions src/loading/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Loading from './Loading';

export { LoadingProps } from './interface';
export default Loading;
51 changes: 51 additions & 0 deletions src/loading/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
export interface LoadingProps {
/**
是否为加载中状态
*/
loading?: boolean;
/**
描述文案相对于指示符号的位置
*/
titlePosition?: 'right' | 'bottom';
/**
自定义描述文案
*/
title?: false | string;
/**
延迟显示加载效果的时间(防止闪烁)
*/
delay?: number;
/**
替换`class`类前缀
*/
prefixCls?: string;
/**
设置被包裹的元素
*/
children?: React.ReactElement[] | React.ReactElement;
/**
自定义 `className`
*/
className?: string;
/**
自定义样式
*/
style?: React.CSSProperties;
/**
设置默认指示符号大小
*/
size?: 'small' | 'middle' | 'large';
/**
自定义指示符号
*/
indicator?: React.ReactElement;
/**
设置模糊蒙层颜色
*/
blurColor?: 'white' | 'black';
}

export interface WheelProps {
indicator?: React.ReactElement;
prefixCls?: string;
}
Loading

1 comment on commit 2aa4034

@vercel
Copy link

@vercel vercel bot commented on 2aa4034 Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.