Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(CountDown): new count-down #481

Merged
merged 5 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion site/mobile/mobile.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export default {
{
title: 'CountDown 倒计时',
name: 'count-down',
component: () => import('tdesign-mobile-react/count-down/_example/index.jsx'),
component: () => import('tdesign-mobile-react/count-down/_example/index.tsx'),
},
{
title: 'Message 消息通知',
Expand Down
2 changes: 1 addition & 1 deletion src/_common
4 changes: 3 additions & 1 deletion src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { ReactElement, ReactNode, CSSProperties, FormEvent, DragEvent, Synthetic
// TElement 表示 API 只接受传入组件
export type TElement<T = undefined> = T extends undefined ? ReactElement : (props: T) => ReactElement;
// 1. TNode = ReactNode; 2. TNode<T> = (props: T) => ReactNode
export type TNode<T = undefined> = T extends undefined ? ReactNode : (props: T) => ReactNode;
export type TNode<T = undefined> = T extends undefined
? ReactNode | (() => ReactNode)
: ReactNode | ((props: T) => ReactNode);

export type AttachNodeReturnValue = HTMLElement | Element | Document;
export type AttachNode = CSSSelector | ((triggerNode?: HTMLElement) => AttachNodeReturnValue);
Expand Down
89 changes: 57 additions & 32 deletions src/count-down/CountDown.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React, { Fragment, ReactNode, memo, useImperativeHandle, forwardRef } from 'react';
import cls from 'classnames';
import useCountDown from './hooks/useCountDown';
import useConfig from '../_util/useConfig';
import withNativeProps, { NativeProps } from '../_util/withNativeProps';
import React, { Fragment, useImperativeHandle, forwardRef } from 'react';
import classNames from 'classnames';
import type { StyledProps } from '../common';
import { TdCountDownProps } from './type';
import { countDownDefaultProps } from './defaultProps';
import parseTNode from '../_util/parseTNode';
import useDefaultProps from '../hooks/useDefaultProps';
import { usePrefixClass } from '../hooks/useClass';
import useCountDown from './hooks/useCountDown';

import './style';

Expand All @@ -13,20 +16,26 @@ export interface CountDownRef {
pause: () => void;
}

export interface CountDownProps extends TdCountDownProps, NativeProps {}

const defaultProps = {
autoStart: true,
size: 'small',
splitWithUnit: false,
format: 'HH:mm:ss',
theme: 'default',
};
export interface CountDownProps extends TdCountDownProps, StyledProps {}

const CountDown = forwardRef<CountDownRef, CountDownProps>((props, ref) => {
const { autoStart, content, millisecond, size, splitWithUnit, time, format, theme, onChange, onFinish } = props;
const { classPrefix } = useConfig();
const name = `${classPrefix}-countdown`;
const {
className,
style,
autoStart,
content,
children,
millisecond,
size,
splitWithUnit,
time,
format,
theme,
onChange,
onFinish,
} = useDefaultProps<CountDownProps>(props, countDownDefaultProps);

const countDownClass = usePrefixClass('count-down');

const { timeText, timeList, start, reset, pause } = useCountDown({
autoStart,
Expand All @@ -41,26 +50,42 @@ const CountDown = forwardRef<CountDownRef, CountDownProps>((props, ref) => {

if (!timeText) return null;

let contentNode: ReactNode = null;
if (content) {
contentNode = content;
} else {
contentNode = timeList.map(({ digit, unit, match }) => (
const rootClasses = classNames(
countDownClass,
`${countDownClass}--${theme}`,
`${countDownClass}--${size}`,
className,
);

const renderContent = () => {
if (content !== 'default') {
return parseTNode(content || children);
}

return timeList.map(({ digit, unit, match }) => (
<Fragment key={match}>
<span className={`${name}__digit ${name}__digit-${match}`}>{digit}</span>
{unit && <span className={`${name}__unit ${name}__unit-${match}`}>{unit}</span>}
<span className={`${countDownClass}__item`}>{digit}</span>
{unit && (
<span
className={classNames([
`${countDownClass}__split`,
`${countDownClass}__split--${splitWithUnit ? 'text' : 'dot'}`,
])}
>
{unit}
</span>
)}
</Fragment>
));
}

const classNames = cls(name, `${name}--${theme}`, `${name}--${size}`, {
[`${name}--split-with-unit`]: splitWithUnit,
});
};

return withNativeProps(props, <span className={classNames}>{contentNode}</span>);
return (
<div className={rootClasses} style={style}>
{renderContent()}
</div>
);
});

CountDown.defaultProps = defaultProps as CountDownProps;
CountDown.displayName = 'CountDown';

export default memo(CountDown);
export default CountDown;
43 changes: 0 additions & 43 deletions src/count-down/_example/base.jsx

This file was deleted.

52 changes: 52 additions & 0 deletions src/count-down/_example/base.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import { CountDown } from 'tdesign-mobile-react';

const time = 96 * 60 * 1000;

export default function BaseCountDown() {
return (
<>
<div className="demo-count-down">
<text className="demo-count-down-desc"> 时分秒 </text>
<div className="demo-count-down-content">
<CountDown time={time} />
</div>
</div>

<div className="demo-count-down">
<text className="demo-count-down-desc"> 带毫秒 </text>
<div className="demo-count-down-content">
<CountDown time={time} millisecond />
</div>
</div>

<div className="demo-count-down">
<text className="demo-count-down-desc"> 带方形底 </text>
<div className="demo-count-down-content">
<CountDown content="default" time={time} theme="square" />
</div>
</div>

<div className="demo-count-down">
<text className="demo-count-down-desc"> 带圆形底 </text>
<div className="demo-count-down-content">
<CountDown time={time} theme="round" />
</div>
</div>

<div className="demo-count-down">
<text className="demo-count-down-desc"> 带单位 </text>
<div className="demo-count-down-content">
<CountDown time={time} split-with-unit theme="round" />
</div>
</div>

<div className="demo-count-down">
<text className="demo-count-down-desc"> 无底色带单位 </text>
<div className="demo-count-down-content">
<CountDown className="custom" time={time} split-with-unit />
</div>
</div>
</>
);
}
14 changes: 0 additions & 14 deletions src/count-down/_example/index.jsx

This file was deleted.

21 changes: 21 additions & 0 deletions src/count-down/_example/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import TDemoHeader from '../../../site/mobile/components/DemoHeader';
import TDemoBlock from '../../../site/mobile/components/DemoBlock';
import BaseCountDown from './base';
import SizeCountDown from './size';

import './style/index.less';

export default function CountDownDemo() {
return (
<div className="tdesign-mobile-demo">
<TDemoHeader title="CountDown倒计时" summary="用于实时展示倒计时数值。" />
<TDemoBlock title="01 组件类型" padding={true}>
<BaseCountDown />
</TDemoBlock>
<TDemoBlock title="02 组件尺寸" summary="倒计时 large/medium/small 尺寸" padding={true}>
<SizeCountDown />
</TDemoBlock>
</div>
);
}
75 changes: 75 additions & 0 deletions src/count-down/_example/size.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';
import { CountDown } from 'tdesign-mobile-react';

const time = 96 * 60 * 1000;

export default function SizeCountDown() {
return (
<>
<div className="demo-count-down">
<text className="demo-count-down-desc"> 时分秒 </text>
<div className="demo-count-down-content">
<CountDown size="small" time={time} />
</div>
<div className="demo-count-down-content">
<CountDown time={time} />
</div>
<div className="demo-count-down-content">
<CountDown size="large" time={time} />
</div>
</div>

<div className="demo-count-down">
<text className="demo-count-down-desc"> 带毫秒 </text>
<div className="demo-count-down-content">
<CountDown size="small" time={time} millisecond />
</div>
<div className="demo-count-down-content">
<CountDown format="HH:mm:ss:SSS" time={time} />
</div>
<div className="demo-count-down-content">
<CountDown size="large" time={time} millisecond />
</div>
</div>

<div className="demo-count-down">
<text className="demo-count-down-desc"> 带方形底 </text>
<div className="demo-count-down-content">
<CountDown size="small" time={time} theme="square" />
</div>
<div className="demo-count-down-content">
<CountDown time={time} theme="square" />
</div>
<div className="demo-count-down-content">
<CountDown size="large" time={time} theme="square" />
</div>
</div>

<div className="demo-count-down">
<text className="demo-count-down-desc"> 带圆形底 </text>
<div className="demo-count-down-content">
<CountDown size="small" time={time} theme="round" />
</div>
<div className="demo-count-down-content">
<CountDown time={time} theme="round" />
</div>
<div className="demo-count-down-content">
<CountDown size="large" time={time} theme="round" />
</div>
</div>

<div className="demo-count-down">
<text className="demo-count-down-desc"> 带单位 </text>
<div className="demo-count-down-content">
<CountDown size="small" time={time} split-with-unit theme="round" />
</div>
<div className="demo-count-down-content">
<CountDown time={time} split-with-unit theme="round" />
</div>
<div className="demo-count-down-content">
<CountDown size="large" time={time} split-with-unit theme="round" />
</div>
</div>
</>
);
}
Loading
Loading