diff --git a/demo/Button.tsx b/demo/Button.tsx
index 0efd23b..50a7310 100644
--- a/demo/Button.tsx
+++ b/demo/Button.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { Button, FloatLayout } from '../src';
+import { Button } from '../src';
/**
* title: Basic Modal
* title.zh-CN: 基础 Modal
diff --git a/demo/Countdown.tsx b/demo/Countdown.tsx
new file mode 100644
index 0000000..ef9dbf5
--- /dev/null
+++ b/demo/Countdown.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { Countdown } from '../src';
+import './index.less';
+
+function CountdownDemo() {
+ return (
+
+
+
+
+
+
+
+
默认格式:时 : 分 : 秒
+
+ 显示天数
+
+
+
+
自定义格式: 天 : hh : mm : ss
+
+
+
+
倒计时时间到,执行的回调函数
+ {
+ console.log('biu~');
+ }}
+ />
+
+
+ );
+}
+export default CountdownDemo;
diff --git a/demo/index.less b/demo/index.less
index 528cb81..888f4e5 100644
--- a/demo/index.less
+++ b/demo/index.less
@@ -7,3 +7,7 @@
border-radius: 10px;
}
}
+* {
+ margin: 0;
+ padding: 0;
+}
diff --git a/docs/guide/Countdown.md b/docs/guide/Countdown.md
new file mode 100644
index 0000000..e634975
--- /dev/null
+++ b/docs/guide/Countdown.md
@@ -0,0 +1,25 @@
+---
+title: Countdown 倒计时
+---
+
+## Countdown 倒计时
+
+倒计时组件
+
+- 支持自定义格式
+- 支持 天 时 分 秒
+
+
+
+| 参数 | 说明 | 类型 | 可选值 | 默认值 |
+| ---------- | -------------- | ------- | ------ | ------------------------------------------------ |
+| isShowDay | 是否显示天数 | Boolean | - | false |
+| isShowHour | 是否显示小时 | Boolean | - | true |
+| format | 格式化分割符号 | Object | - | day: '天',hours: '时',minutes: '分 seconds : '秒 |
+| day | 天数 | Number | - | 0 |
+| hours | 小时 | Number | - | 0 |
+| minutes | 分钟 | Number | - | 0 |
+| seconds | 秒 | Number | - | 0 |
+
+tip:
+后续考虑设计多定时器样式 依据 type 状态机选择定时器样式
diff --git a/src/.umi/core/routes.ts b/src/.umi/core/routes.ts
index c1c3092..4d812e6 100644
--- a/src/.umi/core/routes.ts
+++ b/src/.umi/core/routes.ts
@@ -197,7 +197,7 @@ export function getRoutes() {
exact: true,
meta: {
filePath: 'docs/guide/ArrowButton.md',
- updatedTime: null,
+ updatedTime: 1617088633000,
title: 'ArrowButton 不规则标签',
slugs: [
{
@@ -207,8 +207,8 @@ export function getRoutes() {
},
{
depth: 2,
- value: 'API文档',
- heading: 'api文档'
+ value: 'API 文档',
+ heading: 'api-文档'
}
],
nav: {
@@ -241,6 +241,29 @@ export function getRoutes() {
},
title: 'Button 按钮'
},
+ {
+ path: '/guide/countdown',
+ component: require('/Users/shide/PROJ/biuUI/docs/guide/Countdown.md')
+ .default,
+ exact: true,
+ meta: {
+ filePath: 'docs/guide/Countdown.md',
+ updatedTime: null,
+ title: 'Countdown 倒计时',
+ slugs: [
+ {
+ depth: 2,
+ value: 'Countdown 倒计时',
+ heading: 'countdown-倒计时'
+ }
+ ],
+ nav: {
+ path: '/guide',
+ title: 'Guide'
+ }
+ },
+ title: 'Countdown 倒计时'
+ },
{
path: '/guide/curtain',
component: require('/Users/shide/PROJ/biuUI/docs/guide/Curtain.md')
@@ -276,7 +299,7 @@ export function getRoutes() {
exact: true,
meta: {
filePath: 'docs/guide/Tag.md',
- updatedTime: null,
+ updatedTime: 1617088633000,
title: 'Tag 标签',
slugs: [
{
@@ -286,8 +309,8 @@ export function getRoutes() {
},
{
depth: 2,
- value: 'API文档',
- heading: 'api文档'
+ value: 'API 文档',
+ heading: 'api-文档'
}
],
nav: {
@@ -304,7 +327,7 @@ export function getRoutes() {
exact: true,
meta: {
filePath: 'docs/guide/index.md',
- updatedTime: 1615798841000,
+ updatedTime: 1617088633000,
title: '指引',
order: 2,
slugs: [
diff --git a/src/.umi/dumi/config.json b/src/.umi/dumi/config.json
index 041e8b9..2b7aff2 100644
--- a/src/.umi/dumi/config.json
+++ b/src/.umi/dumi/config.json
@@ -50,6 +50,11 @@
"title": "Button 按钮",
"meta": {}
},
+ {
+ "path": "/guide/countdown",
+ "title": "Countdown 倒计时",
+ "meta": {}
+ },
{
"path": "/guide/curtain",
"title": "Curtain 幕帘",
diff --git a/src/.umi/dumi/demos/index.ts b/src/.umi/dumi/demos/index.ts
index d1567b7..d5b4475 100644
--- a/src/.umi/dumi/demos/index.ts
+++ b/src/.umi/dumi/demos/index.ts
@@ -3,18 +3,75 @@ import React from 'react';
import { dynamic } from 'dumi';
export default {
+ 'biuui-arrowbutton': {
+ component: require('/Users/shide/PROJ/biuUI/demo/ArrowButton.tsx').default,
+ previewerProps: {
+ sources: {
+ _: {
+ tsx:
+ 'import React from \'react\';\nimport { ArrowButton } from \'../src\';\n\nfunction ArrowButtonDemo() {\n return (\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n );\n}\nexport default ArrowButtonDemo;\n'
+ },
+ 'src/index.ts': {
+ import: '../src',
+ content:
+ "export { default as Button } from './components/Button';\nexport { default as Tag } from './components/Tag';\nexport { default as Curtain } from './components/Curtain';\nexport { default as ArrowButton } from './components/ArrowButton';\nexport { default as Countdown } from './components/Countdown';\n"
+ },
+ 'components/Button/index.tsx': {
+ import: './components/Button',
+ content:
+ "import * as React from 'react';\nimport classnames from 'classnames';\nimport './index.less';\n\n/**\n * @param {onClick} func 对外暴露的点击事件\n * @param {className} string 自定义类名\n * @param {type} string 按钮类型 primary | warning | info | default | pure\n * @param {shape} string 按钮形状 circle | radius(默认)\n */\ntype ButtonType =\n | 'primary'\n | 'warning'\n | 'info'\n | 'default'\n | 'pure'\n | 'slider1'\n | 'slider2';\n\ntype typeModel = 'nomal' | 'slide' | undefined;\n\ninterface IButton {\n typeModel?: typeModel;\n type?: ButtonType;\n children?: React.ReactNode;\n shape?: string;\n block?: string;\n className?: string;\n onClick?: React.MouseEventHandler;\n}\nconst typeModelArr = {\n nomal: 'biu-btn',\n slide: 'bit-btn-slide'\n};\nfunction Button(props: IButton) {\n const { children, onClick, className, type, shape, block, typeModel } = props;\n\n const handTypeModal = (typeModel: typeModel): string => {\n switch (true) {\n case typeModel === 'slide':\n return typeModelArr['slide'];\n default:\n return typeModelArr['nomal'];\n }\n };\n\n return (\n \n );\n}\n\nexport default Button;\n"
+ },
+ 'index.less': {
+ import: './index.less',
+ content:
+ '// @import "../../style/theme/default.scss";\n// @import "../../style/mixins/index.scss";\n\n\n\n\n// $font-size: $font-size-lg;\n\n// .at-count-down {\n// display: inline-block;\n// min-height: $font-size;\n\n// &__item {\n// display: inline-flex;\n// align-items: center;\n// }\n\n// &__time-box {\n// display: inline-block;\n// text-align: center;\n// min-width: $font-size;\n// font: {\n// size: $font-size;\n// family: countDownFont;\n// style: normal;\n// weight: 400;\n// variant: normal;\n// }\n\n// text-transform: none;\n// text-rendering: auto;\n// line-height: 1;\n// -webkit-font-smoothing: antialiased;\n// vertical-align: middle;\n// }\n\n// &__separator {\n// font-size: $font-size-base;\n// display: inline-flex;\n// align-items: center;\n// text-align: justify;\n// padding: 0 $spacing-v-xs;\n// }\n\n// &--card {\n// .at-count-down__time-box {\n// padding: $spacing-v-xs 0;\n// border: 1PX solid $color-border-grey;\n// border-radius: $border-radius-md;\n// color: #FF4949;\n// display: inline-block;\n// background-color: #fff;\n// position: relative;\n\n// .at-count-down__time {\n// position: relative;\n// z-index: $zindex-divider + 1;\n// }\n\n// &::after {\n// position: absolute;\n// content: \'\';\n// width: 100%;\n// height: 1PX;\n// top: 50%;\n// left: 0;\n// z-index: $zindex-divider;\n// background-color: $color-grey-3;\n// }\n// }\n// }\n// }\n.biu-countdown{\n display: inline-block;\n .biu-countdown__item{\n display: inline-flex;\n align-items: center;\n .biu-countdown__time-box{\n color: #333;\n display: inline-block;\n background-color: #fff;\n position: relative;\n .biu-countdown__time{\n \n }\n }\n .biu-countdown__separator{\n display: inline-flex;\n text-align: justify;\n align-items: center;\n }\n }\n}\n\n'
+ },
+ 'components/Tag/index.tsx': {
+ import: './components/Tag',
+ content:
+ "import React from 'react';\nimport classnames from 'classnames';\nimport './index.less';\n\n/**\n * 标签组件\n * @param {closable} boolean 是否可关闭\n * @param {onClose} func 标签关闭时的回调\n * @param {color} string 标签的颜色,不设置则为默认颜色\n */\nfunction Tag(props) {\n let { children, closable, onClose, color } = props;\n let tag = React.createRef();\n let handleClose = () => {\n onClose && onClose();\n tag.current.style.display = 'none';\n };\n return (\n \n {children}\n {closable && (\n \n x\n \n )}\n
\n );\n}\n\nexport default Tag;\n"
+ },
+ 'components/Curtain/index.tsx': {
+ import: './components/Curtain',
+ content:
+ "import React from 'react';\n\nimport './index.less';\n\ninterface IProps {\n visible?: boolean;\n title?: string;\n onClose?: () => void;\n closeBtnPosition?:\n | 'top'\n | 'top-left'\n | 'top-right'\n | 'bottom'\n | 'bottom-left'\n | 'bottom-right'\n | 'none'\n | undefined;\n}\n\ninterface IState {\n _visible?: boolean;\n}\nclass Index extends React.Component {\n public constructor(props: IProps) {\n super(props);\n const { visible } = props;\n this.state = {\n _visible: visible\n };\n }\n\n public componentWillReceiveProps(nextProps: IProps) {\n const { visible } = nextProps;\n if (visible !== this.state._visible) {\n this.setState({\n _visible: visible\n });\n }\n }\n\n private handleClose = () => {\n if (typeof this.props.onClose === 'function') {\n this.props.onClose();\n }\n };\n\n private close = () => {\n this.setState(\n {\n _visible: false\n },\n this.handleClose\n );\n };\n\n render(): JSX.Element | null {\n const { _visible } = this.state;\n const { visible, title, closeBtnPosition = 'bottom' } = this.props;\n if (!visible) return null;\n return (\n \n
\n
\n {this.props.children}\n
\n
\n
\n );\n }\n}\n\nexport default Index;\n"
+ },
+ 'components/ArrowButton/index.tsx': {
+ import: './components/ArrowButton',
+ content:
+ "import React, { Component } from 'react';\nimport classnames from 'classnames';\nimport './index.less';\n\ntype type = 'arc' | 'notching' | 'arrow' | 'arrow2' | 'coupon' | 'notching';\ninterface IProps {\n type: type;\n}\n\nfunction ArrowButton(props: IProps) {\n const { type = 'arrow' } = props;\n\n return (\n \n );\n}\n\nexport default ArrowButton;\n"
+ },
+ 'components/Countdown/index.tsx': {
+ import: './components/Countdown',
+ content:
+ "import React, { Component } from 'react'\nimport classNames from 'classnames'\nimport PropTypes from 'prop-types'\nimport { AtCountDownProps, AtCountdownState } from '@/types/countdown'\nimport AtCountdownItem from './Com'\nimport './index.less'\n\nconst toSeconds = (\n day: number,\n hours: number,\n minutes: number,\n seconds: number): number => day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds\n\n\n\nclass AtCountdown extends Component {\n public static defaultProps: AtCountDownProps\n\n private seconds: number\n private timer: NodeJS.Timeout | number | undefined\n\n public constructor(props: AtCountDownProps) {\n super(props);\n const { day, hours, minutes, seconds } = this.props\n this.seconds = toSeconds(day!, hours!, minutes!, seconds!)\n\n console.log('2232323', this.seconds);\n\n const {\n day: _day,\n hours: _hours,\n minutes: _minutes,\n seconds: _seconds\n } = this.calculateTime();\n this.state = {\n _day,\n _hours,\n _minutes,\n _seconds\n }\n this.timer = undefined\n }\n\n private setTimer(): void {\n if (!this.timer) this.countdonwn()\n }\n\n private clearTimer(): void {\n if (this.timer) {\n clearTimeout(this.timer as number)\n this.timer = undefined\n }\n }\n\n private calculateTime() {\n let [day, hours, minutes, seconds] = [0, 0, 0, 0]\n\n // console.log('this.seconds', this.seconds);\n\n\n if (this.seconds > 0) {\n day = this.props.isShowDay ? Math.floor(this.seconds / (60 * 60 * 24)) : 0\n hours = Math.floor(this.seconds / (60 * 60)) - day * 24\n minutes = Math.floor(this.seconds / 60) - day * 24 * 60 - hours * 60\n seconds =\n Math.floor(this.seconds) -\n day * 24 * 60 * 60 -\n hours * 60 * 60 -\n minutes * 60\n }\n // console.log('hours', hours)\n return {\n day,\n hours,\n minutes,\n seconds\n }\n }\n\n // 倒计时\n private countdonwn(): void {\n // console.log('123')\n const { day, hours, minutes, seconds } = this.calculateTime()\n\n this.setState({\n _day: day,\n _hours: hours,\n _minutes: minutes,\n _seconds: seconds\n })\n this.seconds--\n\n if (this.seconds < 0) {\n this.clearTimer()\n this.props.onTimeUp && this.props.onTimeUp()\n return\n }\n\n this.timer = setTimeout(() => {\n this.countdonwn()\n }, 1000)\n }\n\n public componentWillReceiveProps(nextProps: AtCountDownProps): void {\n if (JSON.stringify(this.props) === JSON.stringify(nextProps)) return\n\n const { day, hours, minutes, seconds } = nextProps\n this.seconds = toSeconds(day!, hours!, minutes!, seconds!)\n this.clearTimer()\n this.setTimer()\n }\n\n public componentDidMount(): void {\n this.setTimer()\n }\n\n public componentWillUnmount(): void {\n this.clearTimer()\n }\n\n\n\n\n render(): JSX.Element {\n\n\n const {\n className,\n customStyle,\n format, // day: '天',hours: '时',minutes: '分',seconds: '秒'\n isShowDay, //\t是否显示天数\n isShowHour, //是否显示小时\n } = this.props\n\n const { _day, _hours, _minutes, _seconds } = this.state\n\n return (\n \n {isShowDay &&
}\n {isShowHour && (
)}\n
\n
\n
\n )\n }\n}\nAtCountdown.defaultProps = {\n customStyle: '',\n className: '',\n isShowDay: false,\n isShowHour: true,\n format: {\n day: '天',\n hours: '时',\n minutes: '分',\n seconds: '秒'\n },\n day: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n onTimeUp() {}\n}\n\n\nexport default AtCountdown\n"
+ },
+ 'Com/index.tsx': {
+ import: './Com',
+ content:
+ "import React, { Component } from 'react'\nimport PropTypes, { InferProps } from 'prop-types'\nimport { AtCountdownItemProps } from '@/types/countdown'\n\n\n\nclass AtCountdownItem extends Component {\n public static defaultProps: AtCountdownItemProps\n public static propTypes: InferProps\n\n private formatNum(num: number): string {\n return num <= 9 ? `0${num}` : `${num}`\n }\n\n public render(): JSX.Element {\n const { num, separator } = this.props\n\n return (\n \n
\n {this.formatNum(num)}\n
\n
{separator}\n
\n )\n }\n}\n\nexport default AtCountdownItem;\n\nAtCountdownItem.defaultProps = {\n num: 0,\n separator: ':'\n}\n\nAtCountdownItem.propTypes = {\n num: PropTypes.number.isRequired,\n separator: PropTypes.string\n}\n"
+ }
+ },
+ dependencies: {
+ react: { version: '17.0.1' },
+ classnames: { version: '2.2.6' },
+ 'prop-types': { version: '15.7.2' }
+ },
+ identifier: 'biuui-arrowbutton'
+ }
+ },
'biuui-button': {
component: require('/Users/shide/PROJ/biuUI/demo/Button.tsx').default,
previewerProps: {
sources: {
_: {
tsx:
- 'import React from \'react\';\nimport { Button, FloatLayout } from \'../src\';\n/**\n * title: Basic Modal\n * title.zh-CN: 基础 Modal\n * desc: This is a basic example of the antd Modal component\n * desc.zh-CN: 这是 antd Modal 组件的基础示例\n */\n\nfunction ButtonDemo() {\n return (\n \n 默认:\n
\n
\n
\n \n \n \n \n \n
\n
\n
PC 悬浮效果
\n
\n
\n \n \n
\n
\n );\n}\n\nexport default ButtonDemo;\n'
+ 'import React from \'react\';\nimport { Button } from \'../src\';\n/**\n * title: Basic Modal\n * title.zh-CN: 基础 Modal\n * desc: This is a basic example of the antd Modal component\n * desc.zh-CN: 这是 antd Modal 组件的基础示例\n */\n\nfunction ButtonDemo() {\n return (\n \n 默认:\n
\n
\n
\n \n \n \n \n \n
\n
\n
PC 悬浮效果
\n
\n
\n \n \n
\n
\n );\n}\n\nexport default ButtonDemo;\n'
},
'src/index.ts': {
import: '../src',
content:
- "export { default as Button } from './components/Button';\nexport { default as Tag } from './components/Tag';\nexport { default as Curtain } from './components/Curtain';\nexport { default as ArrowButton } from './components/ArrowButton';\n\n"
+ "export { default as Button } from './components/Button';\nexport { default as Tag } from './components/Tag';\nexport { default as Curtain } from './components/Curtain';\nexport { default as ArrowButton } from './components/ArrowButton';\nexport { default as Countdown } from './components/Countdown';\n"
},
'components/Button/index.tsx': {
import: './components/Button',
@@ -24,7 +81,7 @@ export default {
'index.less': {
import: './index.less',
content:
- '.btn-wrap {\n margin: auto;\n & > div {\n filter: url(#outline);\n }\n}\n\n.btn {\n content: "";\n width: 200px;\n height: 64px;\n line-height: 64px;\n text-align: center;\n background: linear-gradient(#f49714, #fbe8c8, #f49714);\n color: #be9451;\n font-size: 24px;\n}\n\n.arc {\n width: 200px;\n height: 64px;\n background: radial-gradient(circle at top left, transparent 15px, #f49714 0)\n top left,\n radial-gradient(circle at top right, transparent 15px, #f49714 0) top\n right,\n radial-gradient(circle at bottom right, transparent 15px, #f49714 0)\n bottom right,\n radial-gradient(circle at bottom left, transparent 15px, #f49714 0)\n bottom left;\n background-size: 50% 50%;\n background-repeat: no-repeat;\n // filter: url(#outline);\n}\n\n.notching {\n width: 200px;\n height: 64px;\n background: linear-gradient(135deg, transparent 15px, #f49714 0) top left,\n linear-gradient(-135deg, transparent 15px, #f49714 0) top right,\n linear-gradient(-45deg, transparent 15px, #f49714 0) bottom right,\n linear-gradient(45deg, transparent 15px, #f49714 0) bottom left;\n background-size: 50% 50%;\n background-repeat: no-repeat;\n // filter: url(#outline);\n}\n\n.arrow {\n position: relative;\n width: 180px;\n height: 64px;\n background: #f49714;\n // filter: url(#outline);\n\n &::after {\n content: "";\n position: absolute;\n width: 32px;\n height: 64px;\n top: 0;\n right: -32px;\n background: \n linear-gradient(-45deg, transparent 0, transparent 22px, #f49714 22px, #f49714 100%),\n linear-gradient(-135deg, transparent 0, transparent 22px, #f49714 22px, #f49714 100%);\n background-size: 32px 32px;\n background-repeat: no-repeat;\n background-position: 0 bottom, 0 top;\n }\n}\n\n.arrow2 {\n position: relative;\n width: 150px;\n height: 64px;\n background: #f49714;\n // filter: url(#outline);\n\n &::before {\n content: "";\n position: absolute;\n width: 32px;\n height: 64px;\n top: 0;\n left: -32px;\n background: #000;\n background: \n linear-gradient(-45deg, #f49714 0, #f49714 24px, transparent 24px, transparent),\n linear-gradient(-135deg, #f49714 0, #f49714 24px, transparent 24px, transparent);\n }\n \n &::after {\n content: "";\n position: absolute;\n width: 32px;\n height: 64px;\n top: 0;\n right: -32px;\n background: #000;\n background: \n linear-gradient(-45deg, transparent 0, transparent 22px, #f49714 22px, #f49714 1px),\n linear-gradient(-135deg, transparent 0, transparent 22px, #f49714 22px, #f49714 1px);\n background-size: 32px 32px;\n background-repeat: no-repeat;\n background-position: 0 bottom, 0 top;\n }\n}\n\n.coupon {\n position: relative;\n width: 200px;\n height: 64px;\n background-image: \n radial-gradient(circle at 1px 11px, transparent 8px, #f49714 8px, #f49714 0px),\n radial-gradient(circle at 99px 11px, transparent 8px, #f49714 8px, #f49714 0px);\n background-size: 100px 21px;\n background-position: 0 0, 100px 0;\n background-repeat-x: no-repeat;\n cursor: pointer;\n}\n\n\n\n'
+ '// @import "../../style/theme/default.scss";\n// @import "../../style/mixins/index.scss";\n\n\n\n\n// $font-size: $font-size-lg;\n\n// .at-count-down {\n// display: inline-block;\n// min-height: $font-size;\n\n// &__item {\n// display: inline-flex;\n// align-items: center;\n// }\n\n// &__time-box {\n// display: inline-block;\n// text-align: center;\n// min-width: $font-size;\n// font: {\n// size: $font-size;\n// family: countDownFont;\n// style: normal;\n// weight: 400;\n// variant: normal;\n// }\n\n// text-transform: none;\n// text-rendering: auto;\n// line-height: 1;\n// -webkit-font-smoothing: antialiased;\n// vertical-align: middle;\n// }\n\n// &__separator {\n// font-size: $font-size-base;\n// display: inline-flex;\n// align-items: center;\n// text-align: justify;\n// padding: 0 $spacing-v-xs;\n// }\n\n// &--card {\n// .at-count-down__time-box {\n// padding: $spacing-v-xs 0;\n// border: 1PX solid $color-border-grey;\n// border-radius: $border-radius-md;\n// color: #FF4949;\n// display: inline-block;\n// background-color: #fff;\n// position: relative;\n\n// .at-count-down__time {\n// position: relative;\n// z-index: $zindex-divider + 1;\n// }\n\n// &::after {\n// position: absolute;\n// content: \'\';\n// width: 100%;\n// height: 1PX;\n// top: 50%;\n// left: 0;\n// z-index: $zindex-divider;\n// background-color: $color-grey-3;\n// }\n// }\n// }\n// }\n.biu-countdown{\n display: inline-block;\n .biu-countdown__item{\n display: inline-flex;\n align-items: center;\n .biu-countdown__time-box{\n color: #333;\n display: inline-block;\n background-color: #fff;\n position: relative;\n .biu-countdown__time{\n \n }\n }\n .biu-countdown__separator{\n display: inline-flex;\n text-align: justify;\n align-items: center;\n }\n }\n}\n\n'
},
'components/Tag/index.tsx': {
import: './components/Tag',
@@ -39,28 +96,39 @@ export default {
'components/ArrowButton/index.tsx': {
import: './components/ArrowButton',
content:
- "import React, { Component } from 'react'\nimport classnames from 'classnames';\nimport './index.less';\n\ntype type = 'arc' | 'notching' | 'arrow' | 'arrow2' | 'coupon' | 'notching'\ninterface IProps {\n type: type\n}\n\nfunction ArrowButton(props: IProps) {\n const { type = 'arrow' } = props;\n\n return (\n \n )\n}\n\nexport default ArrowButton;\n"
+ "import React, { Component } from 'react';\nimport classnames from 'classnames';\nimport './index.less';\n\ntype type = 'arc' | 'notching' | 'arrow' | 'arrow2' | 'coupon' | 'notching';\ninterface IProps {\n type: type;\n}\n\nfunction ArrowButton(props: IProps) {\n const { type = 'arrow' } = props;\n\n return (\n \n );\n}\n\nexport default ArrowButton;\n"
+ },
+ 'components/Countdown/index.tsx': {
+ import: './components/Countdown',
+ content:
+ "import React, { Component } from 'react'\nimport classNames from 'classnames'\nimport PropTypes from 'prop-types'\nimport { AtCountDownProps, AtCountdownState } from '@/types/countdown'\nimport AtCountdownItem from './Com'\nimport './index.less'\n\nconst toSeconds = (\n day: number,\n hours: number,\n minutes: number,\n seconds: number): number => day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds\n\n\n\nclass AtCountdown extends Component {\n public static defaultProps: AtCountDownProps\n\n private seconds: number\n private timer: NodeJS.Timeout | number | undefined\n\n public constructor(props: AtCountDownProps) {\n super(props);\n const { day, hours, minutes, seconds } = this.props\n this.seconds = toSeconds(day!, hours!, minutes!, seconds!)\n\n console.log('2232323', this.seconds);\n\n const {\n day: _day,\n hours: _hours,\n minutes: _minutes,\n seconds: _seconds\n } = this.calculateTime();\n this.state = {\n _day,\n _hours,\n _minutes,\n _seconds\n }\n this.timer = undefined\n }\n\n private setTimer(): void {\n if (!this.timer) this.countdonwn()\n }\n\n private clearTimer(): void {\n if (this.timer) {\n clearTimeout(this.timer as number)\n this.timer = undefined\n }\n }\n\n private calculateTime() {\n let [day, hours, minutes, seconds] = [0, 0, 0, 0]\n\n // console.log('this.seconds', this.seconds);\n\n\n if (this.seconds > 0) {\n day = this.props.isShowDay ? Math.floor(this.seconds / (60 * 60 * 24)) : 0\n hours = Math.floor(this.seconds / (60 * 60)) - day * 24\n minutes = Math.floor(this.seconds / 60) - day * 24 * 60 - hours * 60\n seconds =\n Math.floor(this.seconds) -\n day * 24 * 60 * 60 -\n hours * 60 * 60 -\n minutes * 60\n }\n // console.log('hours', hours)\n return {\n day,\n hours,\n minutes,\n seconds\n }\n }\n\n // 倒计时\n private countdonwn(): void {\n // console.log('123')\n const { day, hours, minutes, seconds } = this.calculateTime()\n\n this.setState({\n _day: day,\n _hours: hours,\n _minutes: minutes,\n _seconds: seconds\n })\n this.seconds--\n\n if (this.seconds < 0) {\n this.clearTimer()\n this.props.onTimeUp && this.props.onTimeUp()\n return\n }\n\n this.timer = setTimeout(() => {\n this.countdonwn()\n }, 1000)\n }\n\n public componentWillReceiveProps(nextProps: AtCountDownProps): void {\n if (JSON.stringify(this.props) === JSON.stringify(nextProps)) return\n\n const { day, hours, minutes, seconds } = nextProps\n this.seconds = toSeconds(day!, hours!, minutes!, seconds!)\n this.clearTimer()\n this.setTimer()\n }\n\n public componentDidMount(): void {\n this.setTimer()\n }\n\n public componentWillUnmount(): void {\n this.clearTimer()\n }\n\n\n\n\n render(): JSX.Element {\n\n\n const {\n className,\n customStyle,\n format, // day: '天',hours: '时',minutes: '分',seconds: '秒'\n isShowDay, //\t是否显示天数\n isShowHour, //是否显示小时\n } = this.props\n\n const { _day, _hours, _minutes, _seconds } = this.state\n\n return (\n \n {isShowDay &&
}\n {isShowHour && (
)}\n
\n
\n
\n )\n }\n}\nAtCountdown.defaultProps = {\n customStyle: '',\n className: '',\n isShowDay: false,\n isShowHour: true,\n format: {\n day: '天',\n hours: '时',\n minutes: '分',\n seconds: '秒'\n },\n day: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n onTimeUp() {}\n}\n\n\nexport default AtCountdown\n"
+ },
+ 'Com/index.tsx': {
+ import: './Com',
+ content:
+ "import React, { Component } from 'react'\nimport PropTypes, { InferProps } from 'prop-types'\nimport { AtCountdownItemProps } from '@/types/countdown'\n\n\n\nclass AtCountdownItem extends Component {\n public static defaultProps: AtCountdownItemProps\n public static propTypes: InferProps\n\n private formatNum(num: number): string {\n return num <= 9 ? `0${num}` : `${num}`\n }\n\n public render(): JSX.Element {\n const { num, separator } = this.props\n\n return (\n \n
\n {this.formatNum(num)}\n
\n
{separator}\n
\n )\n }\n}\n\nexport default AtCountdownItem;\n\nAtCountdownItem.defaultProps = {\n num: 0,\n separator: ':'\n}\n\nAtCountdownItem.propTypes = {\n num: PropTypes.number.isRequired,\n separator: PropTypes.string\n}\n"
}
},
dependencies: {
react: { version: '17.0.1' },
- classnames: { version: '2.2.6' }
+ classnames: { version: '2.2.6' },
+ 'prop-types': { version: '15.7.2' }
},
identifier: 'biuui-button'
}
},
- 'biuui-curtain': {
- component: require('/Users/shide/PROJ/biuUI/demo/Curtain.tsx').default,
+ 'biuui-countdown': {
+ component: require('/Users/shide/PROJ/biuUI/demo/Countdown.tsx').default,
previewerProps: {
sources: {
_: {
tsx:
- "import React, { useState } from 'react';\nimport { Curtain } from '../src';\nimport './index.less';\n\nconst Index = () => {\n const [isModalVisible, setIsModalVisible] = useState(true);\n const [closeBtnPosition, setCloseBtnPosition] = useState('bottom');\n\n return (\n \n
{\n setIsModalVisible(true);\n }}\n >\n 点击幕帘\n
\n\n
{\n setIsModalVisible(false);\n }}\n closeBtnPosition=\"bottom\"\n >\n 这是内容这是内容这是内容这是内容
\n \n
\n );\n};\n\nexport default Index;\n"
+ "import React from 'react';\nimport { Countdown } from '../src';\nimport './index.less'\n\nfunction CountdownDemo() {\n return (\n \n
\n
\n
默认格式:时 : 分 : 秒
\n \n 显示天数
\n \n \n
\n
自定义格式: 天 : hh : mm : ss
\n \n \n
\n
\t倒计时时间到,执行的回调函数
\n { console.log('biu~') }}\n />\n \n
\n );\n}\nexport default CountdownDemo;"
},
'src/index.ts': {
import: '../src',
content:
- "export { default as Button } from './components/Button';\nexport { default as Tag } from './components/Tag';\nexport { default as Curtain } from './components/Curtain';\nexport { default as ArrowButton } from './components/ArrowButton';\n\n"
+ "export { default as Button } from './components/Button';\nexport { default as Tag } from './components/Tag';\nexport { default as Curtain } from './components/Curtain';\nexport { default as ArrowButton } from './components/ArrowButton';\nexport { default as Countdown } from './components/Countdown';\n"
},
'components/Button/index.tsx': {
import: './components/Button',
@@ -70,7 +138,7 @@ export default {
'index.less': {
import: './index.less',
content:
- '.page-layout {\n padding-top: 30px;\n .layout {\n width: 200px;\n height: 200px;\n background-color: #fff;\n border-radius: 10px;\n }\n}\n'
+ '.page-layout {\n padding-top: 30px;\n .layout {\n width: 200px;\n height: 200px;\n background-color: #fff;\n border-radius: 10px;\n }\n}\n*{\n margin: 0;\n padding: 0;\n}'
},
'components/Tag/index.tsx': {
import: './components/Tag',
@@ -85,28 +153,39 @@ export default {
'components/ArrowButton/index.tsx': {
import: './components/ArrowButton',
content:
- "import React, { Component } from 'react'\nimport classnames from 'classnames';\nimport './index.less';\n\ntype type = 'arc' | 'notching' | 'arrow' | 'arrow2' | 'coupon' | 'notching'\ninterface IProps {\n type: type\n}\n\nfunction ArrowButton(props: IProps) {\n const { type = 'arrow' } = props;\n\n return (\n \n )\n}\n\nexport default ArrowButton;\n"
+ "import React, { Component } from 'react';\nimport classnames from 'classnames';\nimport './index.less';\n\ntype type = 'arc' | 'notching' | 'arrow' | 'arrow2' | 'coupon' | 'notching';\ninterface IProps {\n type: type;\n}\n\nfunction ArrowButton(props: IProps) {\n const { type = 'arrow' } = props;\n\n return (\n \n );\n}\n\nexport default ArrowButton;\n"
+ },
+ 'components/Countdown/index.tsx': {
+ import: './components/Countdown',
+ content:
+ "import React, { Component } from 'react'\nimport classNames from 'classnames'\nimport PropTypes from 'prop-types'\nimport { AtCountDownProps, AtCountdownState } from '@/types/countdown'\nimport AtCountdownItem from './Com'\nimport './index.less'\n\nconst toSeconds = (\n day: number,\n hours: number,\n minutes: number,\n seconds: number): number => day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds\n\n\n\nclass AtCountdown extends Component {\n public static defaultProps: AtCountDownProps\n\n private seconds: number\n private timer: NodeJS.Timeout | number | undefined\n\n public constructor(props: AtCountDownProps) {\n super(props);\n const { day, hours, minutes, seconds } = this.props\n this.seconds = toSeconds(day!, hours!, minutes!, seconds!)\n\n console.log('2232323', this.seconds);\n\n const {\n day: _day,\n hours: _hours,\n minutes: _minutes,\n seconds: _seconds\n } = this.calculateTime();\n this.state = {\n _day,\n _hours,\n _minutes,\n _seconds\n }\n this.timer = undefined\n }\n\n private setTimer(): void {\n if (!this.timer) this.countdonwn()\n }\n\n private clearTimer(): void {\n if (this.timer) {\n clearTimeout(this.timer as number)\n this.timer = undefined\n }\n }\n\n private calculateTime() {\n let [day, hours, minutes, seconds] = [0, 0, 0, 0]\n\n // console.log('this.seconds', this.seconds);\n\n\n if (this.seconds > 0) {\n day = this.props.isShowDay ? Math.floor(this.seconds / (60 * 60 * 24)) : 0\n hours = Math.floor(this.seconds / (60 * 60)) - day * 24\n minutes = Math.floor(this.seconds / 60) - day * 24 * 60 - hours * 60\n seconds =\n Math.floor(this.seconds) -\n day * 24 * 60 * 60 -\n hours * 60 * 60 -\n minutes * 60\n }\n // console.log('hours', hours)\n return {\n day,\n hours,\n minutes,\n seconds\n }\n }\n\n // 倒计时\n private countdonwn(): void {\n // console.log('123')\n const { day, hours, minutes, seconds } = this.calculateTime()\n\n this.setState({\n _day: day,\n _hours: hours,\n _minutes: minutes,\n _seconds: seconds\n })\n this.seconds--\n\n if (this.seconds < 0) {\n this.clearTimer()\n this.props.onTimeUp && this.props.onTimeUp()\n return\n }\n\n this.timer = setTimeout(() => {\n this.countdonwn()\n }, 1000)\n }\n\n public componentWillReceiveProps(nextProps: AtCountDownProps): void {\n if (JSON.stringify(this.props) === JSON.stringify(nextProps)) return\n\n const { day, hours, minutes, seconds } = nextProps\n this.seconds = toSeconds(day!, hours!, minutes!, seconds!)\n this.clearTimer()\n this.setTimer()\n }\n\n public componentDidMount(): void {\n this.setTimer()\n }\n\n public componentWillUnmount(): void {\n this.clearTimer()\n }\n\n\n\n\n render(): JSX.Element {\n\n\n const {\n className,\n customStyle,\n format, // day: '天',hours: '时',minutes: '分',seconds: '秒'\n isShowDay, //\t是否显示天数\n isShowHour, //是否显示小时\n } = this.props\n\n const { _day, _hours, _minutes, _seconds } = this.state\n\n return (\n \n {isShowDay &&
}\n {isShowHour && (
)}\n
\n
\n
\n )\n }\n}\nAtCountdown.defaultProps = {\n customStyle: '',\n className: '',\n isShowDay: false,\n isShowHour: true,\n format: {\n day: '天',\n hours: '时',\n minutes: '分',\n seconds: '秒'\n },\n day: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n onTimeUp() {}\n}\n\n\nexport default AtCountdown\n"
+ },
+ 'Com/index.tsx': {
+ import: './Com',
+ content:
+ "import React, { Component } from 'react'\nimport PropTypes, { InferProps } from 'prop-types'\nimport { AtCountdownItemProps } from '@/types/countdown'\n\n\n\nclass AtCountdownItem extends Component {\n public static defaultProps: AtCountdownItemProps\n public static propTypes: InferProps\n\n private formatNum(num: number): string {\n return num <= 9 ? `0${num}` : `${num}`\n }\n\n public render(): JSX.Element {\n const { num, separator } = this.props\n\n return (\n \n
\n {this.formatNum(num)}\n
\n
{separator}\n
\n )\n }\n}\n\nexport default AtCountdownItem;\n\nAtCountdownItem.defaultProps = {\n num: 0,\n separator: ':'\n}\n\nAtCountdownItem.propTypes = {\n num: PropTypes.number.isRequired,\n separator: PropTypes.string\n}\n"
}
},
dependencies: {
react: { version: '17.0.1' },
- classnames: { version: '2.2.6' }
+ classnames: { version: '2.2.6' },
+ 'prop-types': { version: '15.7.2' }
},
- identifier: 'biuui-curtain'
+ identifier: 'biuui-countdown'
}
},
- 'biuui-tag': {
- component: require('/Users/shide/PROJ/biuUI/demo/Tag.tsx').default,
+ 'biuui-curtain': {
+ component: require('/Users/shide/PROJ/biuUI/demo/Curtain.tsx').default,
previewerProps: {
sources: {
_: {
tsx:
- 'import React from \'react\';\nimport { Tag, ArrowButton } from \'../src\';\n\n\nfunction TagDemo() {\n return (\n \n 标签\n 标签\n 标签\n 标签
\n 标签\n 标签\n
\n );\n}\n\nexport default TagDemo\n\n\n'
+ "import React, { useState } from 'react';\nimport { Curtain } from '../src';\nimport './index.less';\n\nconst Index = () => {\n const [isModalVisible, setIsModalVisible] = useState(true);\n const [closeBtnPosition, setCloseBtnPosition] = useState('bottom');\n\n return (\n \n
{\n setIsModalVisible(true);\n }}\n >\n 点击幕帘\n
\n\n
{\n setIsModalVisible(false);\n }}\n closeBtnPosition=\"bottom\"\n >\n 这是内容这是内容这是内容这是内容
\n \n
\n );\n};\n\nexport default Index;\n"
},
'src/index.ts': {
import: '../src',
content:
- "export { default as Button } from './components/Button';\nexport { default as Tag } from './components/Tag';\nexport { default as Curtain } from './components/Curtain';\nexport { default as ArrowButton } from './components/ArrowButton';\n\n"
+ "export { default as Button } from './components/Button';\nexport { default as Tag } from './components/Tag';\nexport { default as Curtain } from './components/Curtain';\nexport { default as ArrowButton } from './components/ArrowButton';\nexport { default as Countdown } from './components/Countdown';\n"
},
'components/Button/index.tsx': {
import: './components/Button',
@@ -116,7 +195,7 @@ export default {
'index.less': {
import: './index.less',
content:
- '.btn-wrap {\n margin: auto;\n & > div {\n filter: url(#outline);\n }\n}\n\n.btn {\n content: "";\n width: 200px;\n height: 64px;\n line-height: 64px;\n text-align: center;\n background: linear-gradient(#f49714, #fbe8c8, #f49714);\n color: #be9451;\n font-size: 24px;\n}\n\n.arc {\n width: 200px;\n height: 64px;\n background: radial-gradient(circle at top left, transparent 15px, #f49714 0)\n top left,\n radial-gradient(circle at top right, transparent 15px, #f49714 0) top\n right,\n radial-gradient(circle at bottom right, transparent 15px, #f49714 0)\n bottom right,\n radial-gradient(circle at bottom left, transparent 15px, #f49714 0)\n bottom left;\n background-size: 50% 50%;\n background-repeat: no-repeat;\n // filter: url(#outline);\n}\n\n.notching {\n width: 200px;\n height: 64px;\n background: linear-gradient(135deg, transparent 15px, #f49714 0) top left,\n linear-gradient(-135deg, transparent 15px, #f49714 0) top right,\n linear-gradient(-45deg, transparent 15px, #f49714 0) bottom right,\n linear-gradient(45deg, transparent 15px, #f49714 0) bottom left;\n background-size: 50% 50%;\n background-repeat: no-repeat;\n // filter: url(#outline);\n}\n\n.arrow {\n position: relative;\n width: 180px;\n height: 64px;\n background: #f49714;\n // filter: url(#outline);\n\n &::after {\n content: "";\n position: absolute;\n width: 32px;\n height: 64px;\n top: 0;\n right: -32px;\n background: \n linear-gradient(-45deg, transparent 0, transparent 22px, #f49714 22px, #f49714 100%),\n linear-gradient(-135deg, transparent 0, transparent 22px, #f49714 22px, #f49714 100%);\n background-size: 32px 32px;\n background-repeat: no-repeat;\n background-position: 0 bottom, 0 top;\n }\n}\n\n.arrow2 {\n position: relative;\n width: 150px;\n height: 64px;\n background: #f49714;\n // filter: url(#outline);\n\n &::before {\n content: "";\n position: absolute;\n width: 32px;\n height: 64px;\n top: 0;\n left: -32px;\n background: #000;\n background: \n linear-gradient(-45deg, #f49714 0, #f49714 24px, transparent 24px, transparent),\n linear-gradient(-135deg, #f49714 0, #f49714 24px, transparent 24px, transparent);\n }\n \n &::after {\n content: "";\n position: absolute;\n width: 32px;\n height: 64px;\n top: 0;\n right: -32px;\n background: #000;\n background: \n linear-gradient(-45deg, transparent 0, transparent 22px, #f49714 22px, #f49714 1px),\n linear-gradient(-135deg, transparent 0, transparent 22px, #f49714 22px, #f49714 1px);\n background-size: 32px 32px;\n background-repeat: no-repeat;\n background-position: 0 bottom, 0 top;\n }\n}\n\n.coupon {\n position: relative;\n width: 200px;\n height: 64px;\n background-image: \n radial-gradient(circle at 1px 11px, transparent 8px, #f49714 8px, #f49714 0px),\n radial-gradient(circle at 99px 11px, transparent 8px, #f49714 8px, #f49714 0px);\n background-size: 100px 21px;\n background-position: 0 0, 100px 0;\n background-repeat-x: no-repeat;\n cursor: pointer;\n}\n\n\n\n'
+ '.page-layout {\n padding-top: 30px;\n .layout {\n width: 200px;\n height: 200px;\n background-color: #fff;\n border-radius: 10px;\n }\n}\n*{\n margin: 0;\n padding: 0;\n}'
},
'components/Tag/index.tsx': {
import: './components/Tag',
@@ -131,28 +210,39 @@ export default {
'components/ArrowButton/index.tsx': {
import: './components/ArrowButton',
content:
- "import React, { Component } from 'react'\nimport classnames from 'classnames';\nimport './index.less';\n\ntype type = 'arc' | 'notching' | 'arrow' | 'arrow2' | 'coupon' | 'notching'\ninterface IProps {\n type: type\n}\n\nfunction ArrowButton(props: IProps) {\n const { type = 'arrow' } = props;\n\n return (\n \n )\n}\n\nexport default ArrowButton;\n"
+ "import React, { Component } from 'react';\nimport classnames from 'classnames';\nimport './index.less';\n\ntype type = 'arc' | 'notching' | 'arrow' | 'arrow2' | 'coupon' | 'notching';\ninterface IProps {\n type: type;\n}\n\nfunction ArrowButton(props: IProps) {\n const { type = 'arrow' } = props;\n\n return (\n \n );\n}\n\nexport default ArrowButton;\n"
+ },
+ 'components/Countdown/index.tsx': {
+ import: './components/Countdown',
+ content:
+ "import React, { Component } from 'react'\nimport classNames from 'classnames'\nimport PropTypes from 'prop-types'\nimport { AtCountDownProps, AtCountdownState } from '@/types/countdown'\nimport AtCountdownItem from './Com'\nimport './index.less'\n\nconst toSeconds = (\n day: number,\n hours: number,\n minutes: number,\n seconds: number): number => day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds\n\n\n\nclass AtCountdown extends Component {\n public static defaultProps: AtCountDownProps\n\n private seconds: number\n private timer: NodeJS.Timeout | number | undefined\n\n public constructor(props: AtCountDownProps) {\n super(props);\n const { day, hours, minutes, seconds } = this.props\n this.seconds = toSeconds(day!, hours!, minutes!, seconds!)\n\n console.log('2232323', this.seconds);\n\n const {\n day: _day,\n hours: _hours,\n minutes: _minutes,\n seconds: _seconds\n } = this.calculateTime();\n this.state = {\n _day,\n _hours,\n _minutes,\n _seconds\n }\n this.timer = undefined\n }\n\n private setTimer(): void {\n if (!this.timer) this.countdonwn()\n }\n\n private clearTimer(): void {\n if (this.timer) {\n clearTimeout(this.timer as number)\n this.timer = undefined\n }\n }\n\n private calculateTime() {\n let [day, hours, minutes, seconds] = [0, 0, 0, 0]\n\n // console.log('this.seconds', this.seconds);\n\n\n if (this.seconds > 0) {\n day = this.props.isShowDay ? Math.floor(this.seconds / (60 * 60 * 24)) : 0\n hours = Math.floor(this.seconds / (60 * 60)) - day * 24\n minutes = Math.floor(this.seconds / 60) - day * 24 * 60 - hours * 60\n seconds =\n Math.floor(this.seconds) -\n day * 24 * 60 * 60 -\n hours * 60 * 60 -\n minutes * 60\n }\n // console.log('hours', hours)\n return {\n day,\n hours,\n minutes,\n seconds\n }\n }\n\n // 倒计时\n private countdonwn(): void {\n // console.log('123')\n const { day, hours, minutes, seconds } = this.calculateTime()\n\n this.setState({\n _day: day,\n _hours: hours,\n _minutes: minutes,\n _seconds: seconds\n })\n this.seconds--\n\n if (this.seconds < 0) {\n this.clearTimer()\n this.props.onTimeUp && this.props.onTimeUp()\n return\n }\n\n this.timer = setTimeout(() => {\n this.countdonwn()\n }, 1000)\n }\n\n public componentWillReceiveProps(nextProps: AtCountDownProps): void {\n if (JSON.stringify(this.props) === JSON.stringify(nextProps)) return\n\n const { day, hours, minutes, seconds } = nextProps\n this.seconds = toSeconds(day!, hours!, minutes!, seconds!)\n this.clearTimer()\n this.setTimer()\n }\n\n public componentDidMount(): void {\n this.setTimer()\n }\n\n public componentWillUnmount(): void {\n this.clearTimer()\n }\n\n\n\n\n render(): JSX.Element {\n\n\n const {\n className,\n customStyle,\n format, // day: '天',hours: '时',minutes: '分',seconds: '秒'\n isShowDay, //\t是否显示天数\n isShowHour, //是否显示小时\n } = this.props\n\n const { _day, _hours, _minutes, _seconds } = this.state\n\n return (\n \n {isShowDay &&
}\n {isShowHour && (
)}\n
\n
\n
\n )\n }\n}\nAtCountdown.defaultProps = {\n customStyle: '',\n className: '',\n isShowDay: false,\n isShowHour: true,\n format: {\n day: '天',\n hours: '时',\n minutes: '分',\n seconds: '秒'\n },\n day: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n onTimeUp() {}\n}\n\n\nexport default AtCountdown\n"
+ },
+ 'Com/index.tsx': {
+ import: './Com',
+ content:
+ "import React, { Component } from 'react'\nimport PropTypes, { InferProps } from 'prop-types'\nimport { AtCountdownItemProps } from '@/types/countdown'\n\n\n\nclass AtCountdownItem extends Component {\n public static defaultProps: AtCountdownItemProps\n public static propTypes: InferProps\n\n private formatNum(num: number): string {\n return num <= 9 ? `0${num}` : `${num}`\n }\n\n public render(): JSX.Element {\n const { num, separator } = this.props\n\n return (\n \n
\n {this.formatNum(num)}\n
\n
{separator}\n
\n )\n }\n}\n\nexport default AtCountdownItem;\n\nAtCountdownItem.defaultProps = {\n num: 0,\n separator: ':'\n}\n\nAtCountdownItem.propTypes = {\n num: PropTypes.number.isRequired,\n separator: PropTypes.string\n}\n"
}
},
dependencies: {
react: { version: '17.0.1' },
- classnames: { version: '2.2.6' }
+ classnames: { version: '2.2.6' },
+ 'prop-types': { version: '15.7.2' }
},
- identifier: 'biuui-tag'
+ identifier: 'biuui-curtain'
}
},
- 'biuui-arrowbutton': {
- component: require('/Users/shide/PROJ/biuUI/demo/ArrowButton.tsx').default,
+ 'biuui-tag': {
+ component: require('/Users/shide/PROJ/biuUI/demo/Tag.tsx').default,
previewerProps: {
sources: {
_: {
tsx:
- "import React from 'react';\nimport { ArrowButton } from '../src';\n\n\nfunction ArrowButtonDemo() {\n return (\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n );\n}\nexport default ArrowButtonDemo"
+ 'import React from \'react\';\nimport { Tag, ArrowButton } from \'../src\';\n\nfunction TagDemo() {\n return (\n \n 标签\n 标签\n 标签\n 标签\n
\n \n 标签\n \n 标签\n
\n );\n}\n\nexport default TagDemo;\n'
},
'src/index.ts': {
import: '../src',
content:
- "export { default as Button } from './components/Button';\nexport { default as Tag } from './components/Tag';\nexport { default as Curtain } from './components/Curtain';\nexport { default as ArrowButton } from './components/ArrowButton';\n\n"
+ "export { default as Button } from './components/Button';\nexport { default as Tag } from './components/Tag';\nexport { default as Curtain } from './components/Curtain';\nexport { default as ArrowButton } from './components/ArrowButton';\nexport { default as Countdown } from './components/Countdown';\n"
},
'components/Button/index.tsx': {
import: './components/Button',
@@ -162,7 +252,7 @@ export default {
'index.less': {
import: './index.less',
content:
- '.btn-wrap {\n margin: auto;\n & > div {\n filter: url(#outline);\n }\n}\n\n.btn {\n content: "";\n width: 200px;\n height: 64px;\n line-height: 64px;\n text-align: center;\n background: linear-gradient(#f49714, #fbe8c8, #f49714);\n color: #be9451;\n font-size: 24px;\n}\n\n.arc {\n width: 200px;\n height: 64px;\n background: radial-gradient(circle at top left, transparent 15px, #f49714 0)\n top left,\n radial-gradient(circle at top right, transparent 15px, #f49714 0) top\n right,\n radial-gradient(circle at bottom right, transparent 15px, #f49714 0)\n bottom right,\n radial-gradient(circle at bottom left, transparent 15px, #f49714 0)\n bottom left;\n background-size: 50% 50%;\n background-repeat: no-repeat;\n // filter: url(#outline);\n}\n\n.notching {\n width: 200px;\n height: 64px;\n background: linear-gradient(135deg, transparent 15px, #f49714 0) top left,\n linear-gradient(-135deg, transparent 15px, #f49714 0) top right,\n linear-gradient(-45deg, transparent 15px, #f49714 0) bottom right,\n linear-gradient(45deg, transparent 15px, #f49714 0) bottom left;\n background-size: 50% 50%;\n background-repeat: no-repeat;\n // filter: url(#outline);\n}\n\n.arrow {\n position: relative;\n width: 180px;\n height: 64px;\n background: #f49714;\n // filter: url(#outline);\n\n &::after {\n content: "";\n position: absolute;\n width: 32px;\n height: 64px;\n top: 0;\n right: -32px;\n background: \n linear-gradient(-45deg, transparent 0, transparent 22px, #f49714 22px, #f49714 100%),\n linear-gradient(-135deg, transparent 0, transparent 22px, #f49714 22px, #f49714 100%);\n background-size: 32px 32px;\n background-repeat: no-repeat;\n background-position: 0 bottom, 0 top;\n }\n}\n\n.arrow2 {\n position: relative;\n width: 150px;\n height: 64px;\n background: #f49714;\n // filter: url(#outline);\n\n &::before {\n content: "";\n position: absolute;\n width: 32px;\n height: 64px;\n top: 0;\n left: -32px;\n background: #000;\n background: \n linear-gradient(-45deg, #f49714 0, #f49714 24px, transparent 24px, transparent),\n linear-gradient(-135deg, #f49714 0, #f49714 24px, transparent 24px, transparent);\n }\n \n &::after {\n content: "";\n position: absolute;\n width: 32px;\n height: 64px;\n top: 0;\n right: -32px;\n background: #000;\n background: \n linear-gradient(-45deg, transparent 0, transparent 22px, #f49714 22px, #f49714 1px),\n linear-gradient(-135deg, transparent 0, transparent 22px, #f49714 22px, #f49714 1px);\n background-size: 32px 32px;\n background-repeat: no-repeat;\n background-position: 0 bottom, 0 top;\n }\n}\n\n.coupon {\n position: relative;\n width: 200px;\n height: 64px;\n background-image: \n radial-gradient(circle at 1px 11px, transparent 8px, #f49714 8px, #f49714 0px),\n radial-gradient(circle at 99px 11px, transparent 8px, #f49714 8px, #f49714 0px);\n background-size: 100px 21px;\n background-position: 0 0, 100px 0;\n background-repeat-x: no-repeat;\n cursor: pointer;\n}\n\n\n\n'
+ '// @import "../../style/theme/default.scss";\n// @import "../../style/mixins/index.scss";\n\n\n\n\n// $font-size: $font-size-lg;\n\n// .at-count-down {\n// display: inline-block;\n// min-height: $font-size;\n\n// &__item {\n// display: inline-flex;\n// align-items: center;\n// }\n\n// &__time-box {\n// display: inline-block;\n// text-align: center;\n// min-width: $font-size;\n// font: {\n// size: $font-size;\n// family: countDownFont;\n// style: normal;\n// weight: 400;\n// variant: normal;\n// }\n\n// text-transform: none;\n// text-rendering: auto;\n// line-height: 1;\n// -webkit-font-smoothing: antialiased;\n// vertical-align: middle;\n// }\n\n// &__separator {\n// font-size: $font-size-base;\n// display: inline-flex;\n// align-items: center;\n// text-align: justify;\n// padding: 0 $spacing-v-xs;\n// }\n\n// &--card {\n// .at-count-down__time-box {\n// padding: $spacing-v-xs 0;\n// border: 1PX solid $color-border-grey;\n// border-radius: $border-radius-md;\n// color: #FF4949;\n// display: inline-block;\n// background-color: #fff;\n// position: relative;\n\n// .at-count-down__time {\n// position: relative;\n// z-index: $zindex-divider + 1;\n// }\n\n// &::after {\n// position: absolute;\n// content: \'\';\n// width: 100%;\n// height: 1PX;\n// top: 50%;\n// left: 0;\n// z-index: $zindex-divider;\n// background-color: $color-grey-3;\n// }\n// }\n// }\n// }\n.biu-countdown{\n display: inline-block;\n .biu-countdown__item{\n display: inline-flex;\n align-items: center;\n .biu-countdown__time-box{\n color: #333;\n display: inline-block;\n background-color: #fff;\n position: relative;\n .biu-countdown__time{\n \n }\n }\n .biu-countdown__separator{\n display: inline-flex;\n text-align: justify;\n align-items: center;\n }\n }\n}\n\n'
},
'components/Tag/index.tsx': {
import: './components/Tag',
@@ -177,14 +267,25 @@ export default {
'components/ArrowButton/index.tsx': {
import: './components/ArrowButton',
content:
- "import React, { Component } from 'react'\nimport classnames from 'classnames';\nimport './index.less';\n\ntype type = 'arc' | 'notching' | 'arrow' | 'arrow2' | 'coupon' | 'notching'\ninterface IProps {\n type: type\n}\n\nfunction ArrowButton(props: IProps) {\n const { type = 'arrow' } = props;\n\n return (\n \n )\n}\n\nexport default ArrowButton;\n"
+ "import React, { Component } from 'react';\nimport classnames from 'classnames';\nimport './index.less';\n\ntype type = 'arc' | 'notching' | 'arrow' | 'arrow2' | 'coupon' | 'notching';\ninterface IProps {\n type: type;\n}\n\nfunction ArrowButton(props: IProps) {\n const { type = 'arrow' } = props;\n\n return (\n \n );\n}\n\nexport default ArrowButton;\n"
+ },
+ 'components/Countdown/index.tsx': {
+ import: './components/Countdown',
+ content:
+ "import React, { Component } from 'react'\nimport classNames from 'classnames'\nimport PropTypes from 'prop-types'\nimport { AtCountDownProps, AtCountdownState } from '@/types/countdown'\nimport AtCountdownItem from './Com'\nimport './index.less'\n\nconst toSeconds = (\n day: number,\n hours: number,\n minutes: number,\n seconds: number): number => day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds\n\n\n\nclass AtCountdown extends Component {\n public static defaultProps: AtCountDownProps\n\n private seconds: number\n private timer: NodeJS.Timeout | number | undefined\n\n public constructor(props: AtCountDownProps) {\n super(props);\n const { day, hours, minutes, seconds } = this.props\n this.seconds = toSeconds(day!, hours!, minutes!, seconds!)\n\n console.log('2232323', this.seconds);\n\n const {\n day: _day,\n hours: _hours,\n minutes: _minutes,\n seconds: _seconds\n } = this.calculateTime();\n this.state = {\n _day,\n _hours,\n _minutes,\n _seconds\n }\n this.timer = undefined\n }\n\n private setTimer(): void {\n if (!this.timer) this.countdonwn()\n }\n\n private clearTimer(): void {\n if (this.timer) {\n clearTimeout(this.timer as number)\n this.timer = undefined\n }\n }\n\n private calculateTime() {\n let [day, hours, minutes, seconds] = [0, 0, 0, 0]\n\n // console.log('this.seconds', this.seconds);\n\n\n if (this.seconds > 0) {\n day = this.props.isShowDay ? Math.floor(this.seconds / (60 * 60 * 24)) : 0\n hours = Math.floor(this.seconds / (60 * 60)) - day * 24\n minutes = Math.floor(this.seconds / 60) - day * 24 * 60 - hours * 60\n seconds =\n Math.floor(this.seconds) -\n day * 24 * 60 * 60 -\n hours * 60 * 60 -\n minutes * 60\n }\n // console.log('hours', hours)\n return {\n day,\n hours,\n minutes,\n seconds\n }\n }\n\n // 倒计时\n private countdonwn(): void {\n // console.log('123')\n const { day, hours, minutes, seconds } = this.calculateTime()\n\n this.setState({\n _day: day,\n _hours: hours,\n _minutes: minutes,\n _seconds: seconds\n })\n this.seconds--\n\n if (this.seconds < 0) {\n this.clearTimer()\n this.props.onTimeUp && this.props.onTimeUp()\n return\n }\n\n this.timer = setTimeout(() => {\n this.countdonwn()\n }, 1000)\n }\n\n public componentWillReceiveProps(nextProps: AtCountDownProps): void {\n if (JSON.stringify(this.props) === JSON.stringify(nextProps)) return\n\n const { day, hours, minutes, seconds } = nextProps\n this.seconds = toSeconds(day!, hours!, minutes!, seconds!)\n this.clearTimer()\n this.setTimer()\n }\n\n public componentDidMount(): void {\n this.setTimer()\n }\n\n public componentWillUnmount(): void {\n this.clearTimer()\n }\n\n\n\n\n render(): JSX.Element {\n\n\n const {\n className,\n customStyle,\n format, // day: '天',hours: '时',minutes: '分',seconds: '秒'\n isShowDay, //\t是否显示天数\n isShowHour, //是否显示小时\n } = this.props\n\n const { _day, _hours, _minutes, _seconds } = this.state\n\n return (\n \n {isShowDay &&
}\n {isShowHour && (
)}\n
\n
\n
\n )\n }\n}\nAtCountdown.defaultProps = {\n customStyle: '',\n className: '',\n isShowDay: false,\n isShowHour: true,\n format: {\n day: '天',\n hours: '时',\n minutes: '分',\n seconds: '秒'\n },\n day: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n onTimeUp() {}\n}\n\n\nexport default AtCountdown\n"
+ },
+ 'Com/index.tsx': {
+ import: './Com',
+ content:
+ "import React, { Component } from 'react'\nimport PropTypes, { InferProps } from 'prop-types'\nimport { AtCountdownItemProps } from '@/types/countdown'\n\n\n\nclass AtCountdownItem extends Component {\n public static defaultProps: AtCountdownItemProps\n public static propTypes: InferProps\n\n private formatNum(num: number): string {\n return num <= 9 ? `0${num}` : `${num}`\n }\n\n public render(): JSX.Element {\n const { num, separator } = this.props\n\n return (\n \n
\n {this.formatNum(num)}\n
\n
{separator}\n
\n )\n }\n}\n\nexport default AtCountdownItem;\n\nAtCountdownItem.defaultProps = {\n num: 0,\n separator: ':'\n}\n\nAtCountdownItem.propTypes = {\n num: PropTypes.number.isRequired,\n separator: PropTypes.string\n}\n"
}
},
dependencies: {
react: { version: '17.0.1' },
- classnames: { version: '2.2.6' }
+ classnames: { version: '2.2.6' },
+ 'prop-types': { version: '15.7.2' }
},
- identifier: 'biuui-arrowbutton'
+ identifier: 'biuui-tag'
}
}
};
diff --git a/src/components/Countdown/Com/index.tsx b/src/components/Countdown/Com/index.tsx
new file mode 100644
index 0000000..632a871
--- /dev/null
+++ b/src/components/Countdown/Com/index.tsx
@@ -0,0 +1,37 @@
+import React, { Component } from 'react';
+import PropTypes, { InferProps } from 'prop-types';
+import { AtCountdownItemProps } from '@/types/countdown';
+
+class AtCountdownItem extends Component {
+ public static defaultProps: AtCountdownItemProps;
+ public static propTypes: InferProps;
+
+ private formatNum(num: number): string {
+ return num <= 9 ? `0${num}` : `${num}`;
+ }
+
+ public render(): JSX.Element {
+ const { num, separator } = this.props;
+
+ return (
+
+
+ {this.formatNum(num)}
+
+
{separator}
+
+ );
+ }
+}
+
+export default AtCountdownItem;
+
+AtCountdownItem.defaultProps = {
+ num: 0,
+ separator: ':'
+};
+
+AtCountdownItem.propTypes = {
+ num: PropTypes.number.isRequired,
+ separator: PropTypes.string
+};
diff --git a/src/components/Countdown/index.less b/src/components/Countdown/index.less
index e69de29..da68a77 100644
--- a/src/components/Countdown/index.less
+++ b/src/components/Countdown/index.less
@@ -0,0 +1,89 @@
+// @import "../../style/theme/default.scss";
+// @import "../../style/mixins/index.scss";
+
+// $font-size: $font-size-lg;
+
+// .at-count-down {
+// display: inline-block;
+// min-height: $font-size;
+
+// &__item {
+// display: inline-flex;
+// align-items: center;
+// }
+
+// &__time-box {
+// display: inline-block;
+// text-align: center;
+// min-width: $font-size;
+// font: {
+// size: $font-size;
+// family: countDownFont;
+// style: normal;
+// weight: 400;
+// variant: normal;
+// }
+
+// text-transform: none;
+// text-rendering: auto;
+// line-height: 1;
+// -webkit-font-smoothing: antialiased;
+// vertical-align: middle;
+// }
+
+// &__separator {
+// font-size: $font-size-base;
+// display: inline-flex;
+// align-items: center;
+// text-align: justify;
+// padding: 0 $spacing-v-xs;
+// }
+
+// &--card {
+// .at-count-down__time-box {
+// padding: $spacing-v-xs 0;
+// border: 1PX solid $color-border-grey;
+// border-radius: $border-radius-md;
+// color: #FF4949;
+// display: inline-block;
+// background-color: #fff;
+// position: relative;
+
+// .at-count-down__time {
+// position: relative;
+// z-index: $zindex-divider + 1;
+// }
+
+// &::after {
+// position: absolute;
+// content: '';
+// width: 100%;
+// height: 1PX;
+// top: 50%;
+// left: 0;
+// z-index: $zindex-divider;
+// background-color: $color-grey-3;
+// }
+// }
+// }
+// }
+.biu-countdown {
+ display: inline-block;
+ .biu-countdown__item {
+ display: inline-flex;
+ align-items: center;
+ .biu-countdown__time-box {
+ color: #333;
+ display: inline-block;
+ background-color: #fff;
+ position: relative;
+ .biu-countdown__time {
+ }
+ }
+ .biu-countdown__separator {
+ display: inline-flex;
+ text-align: justify;
+ align-items: center;
+ }
+ }
+}
diff --git a/src/components/Countdown/index.tsx b/src/components/Countdown/index.tsx
index e69de29..2d6b8bc 100644
--- a/src/components/Countdown/index.tsx
+++ b/src/components/Countdown/index.tsx
@@ -0,0 +1,170 @@
+import React, { Component } from 'react';
+import classNames from 'classnames';
+import PropTypes from 'prop-types';
+import { AtCountDownProps, AtCountdownState } from '@/types/countdown';
+import AtCountdownItem from './Com';
+import './index.less';
+
+const toSeconds = (
+ day: number,
+ hours: number,
+ minutes: number,
+ seconds: number
+): number => day * 60 * 60 * 24 + hours * 60 * 60 + minutes * 60 + seconds;
+
+class AtCountdown extends Component {
+ public static defaultProps: AtCountDownProps;
+
+ private seconds: number;
+ private timer: NodeJS.Timeout | number | undefined;
+
+ public constructor(props: AtCountDownProps) {
+ super(props);
+ const { day, hours, minutes, seconds } = this.props;
+ this.seconds = toSeconds(day!, hours!, minutes!, seconds!);
+
+ console.log('2232323', this.seconds);
+
+ const {
+ day: _day,
+ hours: _hours,
+ minutes: _minutes,
+ seconds: _seconds
+ } = this.calculateTime();
+ this.state = {
+ _day,
+ _hours,
+ _minutes,
+ _seconds
+ };
+ this.timer = undefined;
+ }
+
+ private setTimer(): void {
+ if (!this.timer) this.countdonwn();
+ }
+
+ private clearTimer(): void {
+ if (this.timer) {
+ clearTimeout(this.timer as number);
+ this.timer = undefined;
+ }
+ }
+
+ private calculateTime() {
+ let [day, hours, minutes, seconds] = [0, 0, 0, 0];
+
+ // console.log('this.seconds', this.seconds);
+
+ if (this.seconds > 0) {
+ day = this.props.isShowDay
+ ? Math.floor(this.seconds / (60 * 60 * 24))
+ : 0;
+ hours = Math.floor(this.seconds / (60 * 60)) - day * 24;
+ minutes = Math.floor(this.seconds / 60) - day * 24 * 60 - hours * 60;
+ seconds =
+ Math.floor(this.seconds) -
+ day * 24 * 60 * 60 -
+ hours * 60 * 60 -
+ minutes * 60;
+ }
+ // console.log('hours', hours)
+ return {
+ day,
+ hours,
+ minutes,
+ seconds
+ };
+ }
+
+ // 倒计时
+ private countdonwn(): void {
+ // console.log('123')
+ const { day, hours, minutes, seconds } = this.calculateTime();
+
+ this.setState({
+ _day: day,
+ _hours: hours,
+ _minutes: minutes,
+ _seconds: seconds
+ });
+ this.seconds--;
+
+ if (this.seconds < 0) {
+ this.clearTimer();
+ this.props.onTimeUp && this.props.onTimeUp();
+ return;
+ }
+
+ this.timer = setTimeout(() => {
+ this.countdonwn();
+ }, 1000);
+ }
+
+ public componentWillReceiveProps(nextProps: AtCountDownProps): void {
+ if (JSON.stringify(this.props) === JSON.stringify(nextProps)) return;
+
+ const { day, hours, minutes, seconds } = nextProps;
+ this.seconds = toSeconds(day!, hours!, minutes!, seconds!);
+ this.clearTimer();
+ this.setTimer();
+ }
+
+ public componentDidMount(): void {
+ this.setTimer();
+ }
+
+ public componentWillUnmount(): void {
+ this.clearTimer();
+ }
+
+ render(): JSX.Element {
+ const {
+ className,
+ customStyle,
+ format, // day: '天',hours: '时',minutes: '分',seconds: '秒'
+ isShowDay, // 是否显示天数
+ isShowHour //是否显示小时
+ } = this.props;
+
+ const { _day, _hours, _minutes, _seconds } = this.state;
+
+ return (
+
+ {isShowDay &&
}
+ {isShowHour && (
+
+ )}
+
+
+
+ );
+ }
+}
+AtCountdown.defaultProps = {
+ customStyle: '',
+ className: '',
+ isShowDay: false,
+ isShowHour: true,
+ format: {
+ day: '天',
+ hours: '时',
+ minutes: '分',
+ seconds: '秒'
+ },
+ day: 0,
+ hours: 0,
+ minutes: 0,
+ seconds: 0,
+ onTimeUp() {}
+};
+
+export default AtCountdown;
diff --git a/src/index.ts b/src/index.ts
index 35046fb..0fc1532 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,3 +2,4 @@ export { default as Button } from './components/Button';
export { default as Tag } from './components/Tag';
export { default as Curtain } from './components/Curtain';
export { default as ArrowButton } from './components/ArrowButton';
+export { default as Countdown } from './components/Countdown';
diff --git a/src/types/countdown.d.ts b/src/types/countdown.d.ts
new file mode 100644
index 0000000..72a7f4d
--- /dev/null
+++ b/src/types/countdown.d.ts
@@ -0,0 +1,82 @@
+import { ComponentClass } from 'react';
+
+export interface FormatObject {
+ /**
+ * 格式化分割符号:天
+ * @default '天'
+ */
+ day?: string;
+ /**
+ * 格式化分割符号:小时
+ * @default '时'
+ */
+ hours: string;
+ /**
+ * 格式化分割符号:分钟
+ * @default '分'
+ */
+ minutes: string;
+ /**
+ * 格式化分割符号:秒
+ * @default '秒'
+ */
+ seconds: string;
+}
+
+export interface AtCountDownProps {
+ /**
+ * 是否显示天数
+ * @default false
+ */
+ isShowDay?: boolean;
+ /**
+ * 是否显示小时
+ * @default true
+ */
+ isShowHour?: boolean;
+ /**
+ * 格式化分割符号
+ * @default { day: '天', hours: '时', minutes: '分', seconds: '秒' }
+ */
+ format?: FormatObject;
+ /**
+ * 天数
+ * @default 0
+ */
+ day?: number;
+ /**
+ * 小时
+ * @default 0
+ */
+ hours?: number;
+ /**
+ * 分钟
+ * @default 0
+ */
+ minutes?: number;
+ /**
+ * 秒
+ * @default 0
+ */
+ seconds?: number;
+ /**
+ * 倒计时时间到,执行的回调函数
+ */
+ onTimeUp?: Function;
+}
+
+export interface AtCountdownState {
+ _day: number;
+ _hours: number;
+ _minutes: number;
+ _seconds: number;
+}
+
+export interface AtCountdownItemProps {
+ num: number;
+ separator: string;
+}
+
+declare const AtCountDown: ComponentClass;
+
+export default AtCountDown;