From 8133e8cf3b37b2be764616493ade7c7a7678fce1 Mon Sep 17 00:00:00 2001 From: yiminghe Date: Fri, 27 Nov 2015 16:15:05 +0800 Subject: [PATCH] add gregorianCalendarLocale prop --- README.md | 10 +-- assets/index.less | 11 +-- assets/index/Combobox.less | 4 -- assets/index/Header.less | 7 +- assets/index/Panel.less | 38 +++++++---- assets/index/Picker.less | 42 +++++------- assets/index/Select.less | 12 ++-- examples/pick-time.js | 13 +++- package.json | 7 +- src/TimePicker.jsx | 134 ++++++++++++++++++++++++++----------- src/mixin/CommonMixin.js | 30 --------- src/module/Combobox.jsx | 24 ++++++- src/module/Header.jsx | 44 +++++++++--- src/module/Panel.jsx | 49 +++++--------- src/module/Select.jsx | 19 +++--- 15 files changed, 243 insertions(+), 201 deletions(-) delete mode 100644 assets/index/Combobox.less diff --git a/README.md b/README.md index 1c16244..d2dcc3c 100644 --- a/README.md +++ b/README.md @@ -31,16 +31,16 @@ API | disabled | Boolean | false | whether picker is disabled | | open | Boolean | false | current open state of picker. controlled prop | | defaultValue | GregorianCalendar | null | default initial value | -| value | GregorianCalendar | null | current value | +| value | GregorianCalendar | null | current value | +| gregorianCalendarLocale | GregorianCalendar locale object | null | if value and defaultValue not set, you should set this to your locale | | placeholder | String | '' | time input's placeholder | -| formatter | GregorianCalendarFormatter | HH:mm:ss or HH:mm or mm:ss | | +| showHour | Boolean | whether show hour | | +| showSecond | Boolean | whether show second | | +| formatter | String|GregorianCalendarFormatter | | | | hourOptions | Array | hour options | | | minuteOptions | Array | minute options | | | secondOptions | Array | second options | | | onChange | Function | null | called when select a different value | -| onOpen | Function | null | called when open picker | -| onClose | Function | null | called when close picker | -| inputClassName | String | '' | | | placement | String | bottomLeft | one of ['left','right','top','bottom', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight'] | | transitionName | String | '' | | diff --git a/assets/index.less b/assets/index.less index 36156cb..f4caf00 100644 --- a/assets/index.less +++ b/assets/index.less @@ -1,23 +1,14 @@ @prefixClass: rc-time-picker; .@{prefixClass} { - display: inline; + display: inline-block; box-sizing: border-box; * { box-sizing: border-box; } } -@font-face { - font-family: 'anticon'; - src: url('//at.alicdn.com/t/font_1434092639_4910953.eot'); - /* IE9*/ - src: url('//at.alicdn.com/t/font_1434092639_4910953.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('//at.alicdn.com/t/font_1434092639_4910953.woff') format('woff'), /* chrome、firefox */ url('//at.alicdn.com/t/font_1434092639_4910953.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ url('//at.alicdn.com/t/font_1434092639_4910953.svg#iconfont') format('svg'); - /* iOS 4.1- */ -} - @import "./index/Picker"; @import "./index/Panel"; @import "./index/Header"; -@import "./index/Combobox"; @import "./index/Select"; diff --git a/assets/index/Combobox.less b/assets/index/Combobox.less deleted file mode 100644 index a796d0a..0000000 --- a/assets/index/Combobox.less +++ /dev/null @@ -1,4 +0,0 @@ -.@{prefixClass} { - &-combobox { - } -} diff --git a/assets/index/Header.less b/assets/index/Header.less index ac3d662..7ad3d9f 100644 --- a/assets/index/Header.less +++ b/assets/index/Header.less @@ -1,8 +1,7 @@ -.@{prefixClass} { +.@{prefixClass}-panel { &-input { margin: 0; padding: 0; - border: 0; width: 100%; cursor: auto; line-height: 1.5; @@ -48,7 +47,3 @@ color: #666; } } - -.narrow .@{prefixClass}-input-wrap { - max-width: 111px; -} diff --git a/assets/index/Panel.less b/assets/index/Panel.less index a11c4aa..be7914f 100644 --- a/assets/index/Panel.less +++ b/assets/index/Panel.less @@ -1,15 +1,25 @@ -.@{prefixClass}-panel-inner { - display: inline-block; - position: relative; - outline: none; - border: 1px solid #ccc; - list-style: none; - font-size: 12px; - text-align: left; - background-color: #fff; - border-radius: 3px; - box-shadow: 0 1px 5px #ccc; - background-clip: padding-box; - border: 1px solid #ccc; - line-height: 1.5; +.@{prefixClass}-panel { + z-index: 1070; + width: 170px; + position: absolute; + box-sizing: border-box; + + * { + box-sizing: border-box; + } + + &-inner { + display: inline-block; + position: relative; + outline: none; + list-style: none; + font-size: 12px; + text-align: left; + background-color: #fff; + border-radius: 3px; + box-shadow: 0 1px 5px #ccc; + background-clip: padding-box; + border: 1px solid #ccc; + line-height: 1.5; + } } diff --git a/assets/index/Picker.less b/assets/index/Picker.less index dc1fbbd..76bf834 100644 --- a/assets/index/Picker.less +++ b/assets/index/Picker.less @@ -1,28 +1,18 @@ -.@{prefixClass}-panel { - z-index: 1070; - position: absolute; - - &.slide-up-enter.slide-up-enter-active&-placement-topLeft, - &.slide-up-enter.slide-up-enter-active&-placement-topRight, - &.slide-up-appear.slide-up-appear-active&-placement-topLeft, - &.slide-up-appear.slide-up-appear-active&-placement-topRight { - animation-name: antSlideDownIn; - } - - &.slide-up-enter.slide-up-enter-active&-placement-bottomLeft, - &.slide-up-enter.slide-up-enter-active&-placement-bottomRight, - &.slide-up-appear.slide-up-appear-active&-placement-bottomLeft, - &.slide-up-appear.slide-up-appear-active&-placement-bottomRight { - animation-name: antSlideUpIn; - } - - &.slide-up-leave.slide-up-leave-active&-placement-topLeft, - &.slide-up-leave.slide-up-leave-active&-placement-topRight { - animation-name: antSlideDownOut; - } - - &.slide-up-leave.slide-up-leave-active&-placement-bottomLeft, - &.slide-up-leave.slide-up-leave-active&-placement-bottomRight { - animation-name: antSlideUpOut; +.@{prefixClass} { + &-input { + width: 100%; + position: relative; + display: inline-block; + padding: 4px 7px; + height: 28px; + cursor: text; + font-size: 12px; + line-height: 1.5; + color: #666; + background-color: #fff; + background-image: none; + border: 1px solid #d9d9d9; + border-radius: 6px; + transition: border .2s cubic-bezier(0.645, 0.045, 0.355, 1), background .2s cubic-bezier(0.645, 0.045, 0.355, 1), box-shadow .2s cubic-bezier(0.645, 0.045, 0.355, 1); } } diff --git a/assets/index/Select.less b/assets/index/Select.less index 995d09e..e93e8f7 100644 --- a/assets/index/Select.less +++ b/assets/index/Select.less @@ -1,4 +1,4 @@ -.@{prefixClass}-select { +.@{prefixClass}-panel-select { float: left; overflow-y:auto; font-size: 12px; @@ -38,13 +38,13 @@ cursor: pointer; user-select: none; - &.selected { - background: #edfaff; - color: #2db7f5; - } - &:hover { background: #edfaff; } } + + &-option-selected { + background: #edfaff; + color: #2db7f5; + } } diff --git a/examples/pick-time.js b/examples/pick-time.js index 70de23d..178b622 100644 --- a/examples/pick-time.js +++ b/examples/pick-time.js @@ -10,7 +10,10 @@ import zhCn from 'gregorian-calendar/lib/locale/zh_CN'; import TimePicker from 'rc-time-picker'; import TimePickerLocale from 'rc-time-picker/src/locale/zh_CN'; -const formatter = new DateTimeFormat('HH:mm:ss'); +var showSecond = true; +var str = showSecond ? 'HH:mm:ss' : 'HH:mm'; + +const formatter = new DateTimeFormat(str); const now = new GregorianCalendar(zhCn); now.setTime(Date.now()); @@ -20,6 +23,12 @@ function onChange(value) { } ReactDom.render( - , + , document.getElementById('__react-content') ); + + +console.log(zhCn); \ No newline at end of file diff --git a/package.json b/package.json index 569661f..f9246c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-time-picker", - "version": "0.7.1", + "version": "1.0.0-alpha1", "description": "React TimePicker", "keywords": [ "react", @@ -57,10 +57,9 @@ "lint" ], "dependencies": { - "classnames": "~2.2.0", + "classnames": "2.x", "gregorian-calendar": "4.x", "gregorian-calendar-format": "4.x", - "rc-trigger": "1.x", - "rc-util": "2.x" + "rc-trigger": "1.x" } } diff --git a/src/TimePicker.jsx b/src/TimePicker.jsx index e82b46f..2694cb0 100644 --- a/src/TimePicker.jsx +++ b/src/TimePicker.jsx @@ -1,10 +1,10 @@ import React, {PropTypes} from 'react'; -import ReactDOM from 'react-dom'; import Trigger from 'rc-trigger'; -import {createChainedFunction} from 'rc-util'; import Panel from './module/Panel'; import placements from './util/placements'; import CommonMixin from './mixin/CommonMixin'; +import {getFormatter} from './util/index'; +import defaultGregorianCalendarLocale from 'gregorian-calendar/lib/locale/en_US'; function noop() { } @@ -16,18 +16,23 @@ function refFn(field, component) { const Picker = React.createClass({ propTypes: { prefixCls: PropTypes.string, - inputClassName: PropTypes.string, locale: PropTypes.object, value: PropTypes.object, - children: PropTypes.func, disabled: PropTypes.bool, + allowEmpty: PropTypes.bool, defaultValue: PropTypes.object, open: PropTypes.bool, + defaultOpen: PropTypes.bool, align: PropTypes.object, placement: PropTypes.any, transitionName: PropTypes.string, + getPopupContainer: PropTypes.func, + gregorianCalendarLocale: PropTypes.object, placeholder: PropTypes.string, - formatter: PropTypes.object, + formatter: PropTypes.any, + showHour: PropTypes.bool, + style: PropTypes.object, + showSecond: PropTypes.bool, hourOptions: PropTypes.array, minuteOptions: PropTypes.array, secondOptions: PropTypes.array, @@ -40,8 +45,13 @@ const Picker = React.createClass({ getDefaultProps() { return { - open: false, + defaultOpen: false, + style: {}, + gregorianCalendarLocale: defaultGregorianCalendarLocale, align: {}, + allowEmpty: true, + showHour: true, + showSecond: true, placement: 'bottomLeft', onChange: noop, onOpen: noop, @@ -51,10 +61,10 @@ const Picker = React.createClass({ getInitialState() { this.savePanelRef = refFn.bind(this, 'panelInstance'); - const { open, defaultValue, value } = this.props; + const { defaultOpen, defaultValue, open = defaultOpen, value = defaultValue } = this.props; return { - open: open, - value: value || defaultValue, + open, + value, }; }, @@ -80,12 +90,18 @@ const Picker = React.createClass({ }, onVisibleChange(open) { - this.setOpen(open, () => { - if (open) { - ReactDOM.findDOMNode(this.refs.picker).blur(); - ReactDOM.findDOMNode(this.panelInstance).focus(); - } - }); + this.setOpen(open); + }, + + onEsc() { + this.setOpen(false); + this.refs.picker.focus(); + }, + + onKeyDown(e) { + if (e.keyCode === 40) { + this.setOpen(true); + } }, setValue(value) { @@ -97,14 +113,60 @@ const Picker = React.createClass({ this.props.onChange(value); }, - getPanel() { - const { prefixCls, defaultValue, locale, formatter, placeholder, hourOptions, minuteOptions, secondOptions } = this.props; + getFormatter() { + const formatter = this.props.formatter; + const locale = this.props.locale; + if (formatter) { + if (formatter === this.lastFormatter) { + return this.normalFormatter; + } + this.normalFormatter = getFormatter(formatter, locale); + this.lastFormatter = formatter; + return this.normalFormatter; + } + if (!this.props.showSecond) { + if (!this.notShowSecondFormatter) { + this.notShowSecondFormatter = getFormatter('HH:mm', locale); + } + return this.notShowSecondFormatter; + } + if (!this.props.showHour) { + if (!this.notShowHourFormatter) { + this.notShowHourFormatter = getFormatter('mm:ss', locale); + } + return this.notShowHourFormatter; + } + if (!this.normalFormatter) { + this.normalFormatter = getFormatter('HH:mm:ss', locale); + } + return this.normalFormatter; + }, + + getPanelElement() { + const { prefixCls, defaultValue, locale, placeholder, hourOptions, minuteOptions, secondOptions, allowEmpty, showHour, showSecond, gregorianCalendarLocale, value } = this.props; + let calendarLocale; + if (value) { + calendarLocale = value.locale; + } else if (defaultValue) { + calendarLocale = defaultValue.locale; + } else { + calendarLocale = gregorianCalendarLocale; + } return ( - - + + diff --git a/src/mixin/CommonMixin.js b/src/mixin/CommonMixin.js index 0e8ed32..a6893b8 100644 --- a/src/mixin/CommonMixin.js +++ b/src/mixin/CommonMixin.js @@ -1,6 +1,5 @@ import {PropTypes} from 'react'; import enUs from '../locale/en_US'; -import {getFormatter} from '../util/index'; export default { propTypes: { @@ -14,33 +13,4 @@ export default { locale: enUs, }; }, - - getFormatter() { - const formatter = this.props.formatter; - const locale = this.props.locale; - if (formatter) { - if (formatter === this.lastFormatter) { - return this.normalFormatter; - } - this.normalFormatter = getFormatter(formatter, locale); - this.lastFormatter = formatter; - return this.normalFormatter; - } - if (!this.showSecond) { - if (!this.notShowSecondFormatter) { - this.notShowSecondFormatter = getFormatter('HH:mm', locale); - } - return this.notShowSecondFormatter; - } - if (!this.showHour) { - if (!this.notShowHourFormatter) { - this.notShowHourFormatter = getFormatter('mm:ss', locale); - } - return this.notShowHourFormatter; - } - if (!this.normalFormatter) { - this.normalFormatter = getFormatter('HH:mm:ss', locale); - } - return this.normalFormatter; - }, }; diff --git a/src/module/Combobox.jsx b/src/module/Combobox.jsx index afce675..3dfd321 100644 --- a/src/module/Combobox.jsx +++ b/src/module/Combobox.jsx @@ -1,5 +1,6 @@ import React, {PropTypes} from 'react'; import Select from './Select'; +import GregorianCalendar from 'gregorian-calendar'; const formatOption = (option) => { if (option < 10) { @@ -15,6 +16,7 @@ const Combobox = React.createClass({ value: PropTypes.object, onChange: PropTypes.func, showHour: PropTypes.bool, + gregorianCalendarLocale: PropTypes.object, showSecond: PropTypes.bool, hourOptions: PropTypes.array, minuteOptions: PropTypes.array, @@ -22,7 +24,13 @@ const Combobox = React.createClass({ }, onItemChange(type, itemValue) { - const { value, onChange } = this.props; + const { onChange } = this.props; + let value = this.props.value; + if (value) { + value = value.clone(); + } else { + value = this.getNow().clone(); + } if (type === 'hour') { value.setHourOfDay(itemValue); } else if (type === 'minute') { @@ -78,9 +86,19 @@ const Combobox = React.createClass({ ); }, - render() { - const { prefixCls, value } = this.props; + getNow() { + if (this.showNow) { + return this.showNow; + } + const value = new GregorianCalendar(this.props.gregorianCalendarLocale); + value.setTime(Date.now()); + this.showNow = value; + return value; + }, + render() { + const { prefixCls } = this.props; + const value = this.props.value || this.getNow(); return (
{this.getHourSelect(value.getHourOfDay())} diff --git a/src/module/Header.jsx b/src/module/Header.jsx index b65fd25..962328c 100644 --- a/src/module/Header.jsx +++ b/src/module/Header.jsx @@ -4,7 +4,7 @@ const Header = React.createClass({ propTypes: { formatter: PropTypes.object, prefixCls: PropTypes.string, - gregorianTimePickerLocale: PropTypes.object, + gregorianCalendarLocale: PropTypes.object, locale: PropTypes.object, disabledDate: PropTypes.func, placeholder: PropTypes.string, @@ -14,7 +14,8 @@ const Header = React.createClass({ secondOptions: PropTypes.array, onChange: PropTypes.func, onClear: PropTypes.func, - showClear: PropTypes.bool, + onEsc: PropTypes.func, + allowEmpty: PropTypes.bool, }, getInitialState() { @@ -25,6 +26,12 @@ const Header = React.createClass({ }; }, + componentDidMount() { + this.timer = setTimeout(() => { + this.refs.input.focus(); + }, 0); + }, + componentWillReceiveProps(nextProps) { const value = nextProps.value; this.setState({ @@ -33,19 +40,23 @@ const Header = React.createClass({ }); }, + componentWillUnmount() { + clearTimeout(this.timer); + }, + onInputChange(event) { const str = event.target.value; this.setState({ str, }); let value = null; - const {formatter, gregorianTimePickerLocale, hourOptions, minuteOptions, secondOptions, onChange} = this.props; + const {formatter, gregorianCalendarLocale, hourOptions, minuteOptions, secondOptions, onChange, allowEmpty} = this.props; if (str) { const originalValue = this.props.value; try { value = formatter.parse(str, { - locale: gregorianTimePickerLocale, + locale: gregorianCalendarLocale, obeyCount: true, }); } catch (ex) { @@ -84,8 +95,13 @@ const Header = React.createClass({ }); return; } - } else { + } else if (allowEmpty) { onChange(null); + } else { + this.setState({ + invalid: true, + }); + return; } this.setState({ @@ -93,24 +109,34 @@ const Header = React.createClass({ }); }, + onKeyDown(e) { + if (e.keyCode === 27) { + this.props.onEsc(); + } + }, + onClear() { this.setState({str: ''}); this.props.onClear(); }, getClearButton() { - const { locale, prefixCls, showClear } = this.props; - if (!showClear) { + const { locale, prefixCls, allowEmpty } = this.props; + if (!allowEmpty) { return null; } - return ; + return ; }, getInput() { const { prefixCls, placeholder } = this.props; const { invalid, str } = this.state; const invalidClass = invalid ? `${prefixCls}-input-invalid` : ''; - return ; + return (); }, render() { diff --git a/src/module/Panel.jsx b/src/module/Panel.jsx index e372774..b91c6fe 100644 --- a/src/module/Panel.jsx +++ b/src/module/Panel.jsx @@ -1,8 +1,4 @@ import React, {PropTypes} from 'react'; -import classnames from 'classnames'; -import GregorianCalendar from 'gregorian-calendar'; -import zhCn from 'gregorian-calendar/lib/locale/zh_CN'; - import CommonMixin from '../mixin/CommonMixin'; import Header from './Header'; import Combobox from './Combobox'; @@ -22,11 +18,16 @@ const Panel = React.createClass({ value: PropTypes.object, locale: PropTypes.object, placeholder: PropTypes.string, + gregorianCalendarLocale: PropTypes.object, formatter: PropTypes.object, hourOptions: PropTypes.array, minuteOptions: PropTypes.array, secondOptions: PropTypes.array, onChange: PropTypes.func, + onEsc: PropTypes.func, + allowEmpty: PropTypes.bool, + showHour: PropTypes.bool, + showSecond: PropTypes.bool, onClear: PropTypes.func, }, @@ -43,26 +44,11 @@ const Panel = React.createClass({ }, getInitialState() { - let value = this.props.value; - if (!value) { - value = new GregorianCalendar(zhCn); - value.setTime(Date.now()); - } return { - value, + value: this.props.value, }; }, - componentWillMount() { - const formatter = this.props.formatter; - const pattern = formatter.originalPattern; - if (pattern === 'HH:mm') { - this.showSecond = false; - } else if (pattern === 'mm:ss') { - this.showHour = false; - } - }, - componentWillReceiveProps(nextProps) { const value = nextProps.value; if (value) { @@ -81,37 +67,34 @@ const Panel = React.createClass({ this.props.onClear(); }, - showHour: true, - showSecond: true, - render() { - const { locale, prefixCls, placeholder, hourOptions, minuteOptions, secondOptions } = this.props; + const { locale, prefixCls, placeholder, hourOptions, minuteOptions, secondOptions, allowEmpty, showHour, showSecond, formatter, gregorianCalendarLocale } = this.props; const value = this.state.value; - const cls = classnames({ 'narrow': !this.showHour || !this.showSecond }); - return ( -
+
{ - const cls = classnames({ selected: selectedIndex === index}); - const ref = selectedIndex === index ? 'selected' : null; - return
  • {item}
  • ; + const selected = selectedIndex === index; + const cls = classnames({ + [`${prefixCls}-select-option-selected`]: selected, + }); + return
  • {item}
  • ; }); }, -- 2.41.0