Skip to content

Commit

Permalink
feat(CountDown): new count-down (#481)
Browse files Browse the repository at this point in the history
* feat(CountDown): new count-down

* chore: update common

* chore: update common

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
anlyyao and github-actions[bot] authored Aug 23, 2024
1 parent 39b8f64 commit cb70b70
Show file tree
Hide file tree
Showing 21 changed files with 2,024 additions and 234 deletions.
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

0 comments on commit cb70b70

Please sign in to comment.