├── .circleci
└── config.yml
├── .eslintrc.js
├── .fatherrc.js
├── .gitignore
├── .travis.yml
├── HISTORY.md
├── LICENSE.md
├── README.md
├── assets
├── index.less
└── index
│ ├── Header.less
│ ├── Panel.less
│ ├── Picker.less
│ └── Select.less
├── examples
├── disabled.js
├── format.js
├── hidden.js
├── open.js
├── pick-time.js
├── step.js
├── twelve-hours.js
└── value-and-defaultValue.js
├── index.d.ts
├── index.js
├── jest.config.js
├── now.json
├── package.json
├── src
├── Combobox.jsx
├── Header.jsx
├── Panel.jsx
├── Select.jsx
├── TimePicker.jsx
├── index.js
└── placements.js
└── tests
├── Header.spec.jsx
├── Select.spec.jsx
├── TimePicker.spec.jsx
├── __snapshots__
└── TimePicker.spec.jsx.snap
├── index.js
└── util.js
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | lint:
4 | docker:
5 | - image: circleci/node:latest
6 | steps:
7 | - checkout
8 | - restore_cache:
9 | keys:
10 | - v1-dependencies-{{ checksum "package.json" }}
11 | - run: npm install
12 | - save_cache:
13 | paths:
14 | - node_modules
15 | key: v1-dependencies-{{ checksum "package.json" }}
16 | - run: npm run lint
17 | test:
18 | docker:
19 | - image: circleci/node:latest
20 | working_directory: ~/repo
21 | steps:
22 | - checkout
23 | - restore_cache:
24 | keys:
25 | - v1-dependencies-{{ checksum "package.json" }}
26 | - run: npm install
27 | - save_cache:
28 | paths:
29 | - node_modules
30 | key: v1-dependencies-{{ checksum "package.json" }}
31 | - run: npm test -- --coverage
32 | workflows:
33 | version: 2
34 | build_and_test:
35 | jobs:
36 | - lint
37 | - test
38 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports= require('@umijs/fabric/dist/eslint');
2 |
--------------------------------------------------------------------------------
/.fatherrc.js:
--------------------------------------------------------------------------------
1 | export default {
2 | cjs: 'babel',
3 | esm: { type: 'babel', importLibToEs: true },
4 | preCommit: {
5 | eslint: true,
6 | prettier: true,
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.log
3 | .idea/
4 | .ipr
5 | .iws
6 | *~
7 | ~*
8 | *.diff
9 | *.patch
10 | *.bak
11 | .DS_Store
12 | Thumbs.db
13 | .project
14 | .*proj
15 | .svn/
16 | *.swp
17 | *.swo
18 | *.pyc
19 | *.pyo
20 | .build
21 | node_modules
22 | .cache
23 | dist
24 | assets/**/*.css
25 | build
26 | lib
27 | coverage
28 | .vscode
29 | yarn.lock
30 | es/
31 | package-lock.json
32 | src/*.map
33 | .prettierrc
34 | tslint.json
35 | tsconfig.test.json
36 | .prettierignore
37 | .storybook
38 | storybook/index.js
39 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - 10
5 |
6 | script:
7 | - |
8 | if [ "$TEST_TYPE" = coverage ]; then
9 | npm run coverage && \
10 | bash <(curl -s https://codecov.io/bash)
11 | else
12 | npm run $TEST_TYPE
13 | fi
14 | env:
15 | matrix:
16 | - TEST_TYPE=lint
17 | - TEST_TYPE=test
18 | - TEST_TYPE=coverage
19 |
--------------------------------------------------------------------------------
/HISTORY.md:
--------------------------------------------------------------------------------
1 | # History
2 |
3 | 3.7.2 / 2019-08-28
4 | ---------------------------
5 |
6 | - Fix React lifecycle wanring. #163
7 |
8 | 3.7.0 / 2019-06-13
9 | ---------------------------
10 |
11 | - Improve accessibility. #153
12 |
13 | 3.6.0
14 | ---------------------------
15 |
16 | - Refacotr dom structure.
17 |
18 | 3.5.0 / 2018-12-23
19 | ---------------------------
20 |
21 | - Add `popupStyle`
22 | - Add `onAmPmChange`
23 | - Add Typescript definition
24 |
25 | 3.4.0 / 2018-08-13
26 | ---------------------------
27 |
28 | - Add `inputIcon`
29 |
30 | 3.3.0 / 2018-02-08
31 | ---------------------------
32 |
33 | - Add `inputReadOnly`
34 |
35 | 3.2.0 / 2017-11-15
36 | ---------------------------
37 |
38 | - Add `blur()` and `autoFocus`.
39 |
40 |
41 | 3.1.0 / 2017-11-02
42 | ---------------------------
43 |
44 | - Upgrade to `rc-trigger@2.x`.
45 |
46 |
47 | 3.0.0 / 2017-10-22
48 | ---------------------------
49 |
50 | - Support React 16.
51 | - Add `onKeydown`.
52 | - Add `focusOnOpen`.
53 | - Add `hourStep` `minuteStep` `secondStep`.
54 | - Fix disabled style.
55 | - Use `this.xxx` to replace `this.refs.xxx`.
56 |
57 | 2.4.0 / 2017-05-02
58 | ---------------------------
59 |
60 | Add `popupClassName` prop.
61 |
62 | 2.3.0 / 2017-03-08
63 | ---------------------------
64 |
65 | Add `use12Hours` prop.
66 |
67 | 2.2.0 / 2016-11-11
68 | ---------------------------
69 |
70 | Add `showMinute` prop.
71 |
72 | 2.1.0 / 2016-10-25
73 | ---------------------------
74 |
75 | Add `addon` prop.
76 |
77 | 2.0.0 / 2016-08-04
78 | ---------------------------
79 |
80 | goodbye gregorian-calendar, hello moment
81 |
82 | 1.1.0 / 2016-01-14
83 | ---------------------------
84 |
85 | remove gregorianCalendarLocale prop, move to locale.calendar
86 |
87 | 1.0.0 / 2015-12-21
88 | -------------------------
89 |
90 | release!
91 |
92 | 1.0.0-alpha9 / 2015-12-16
93 | ------------------
94 |
95 | `fixed` update bugs when value empty.
96 |
97 | 1.0.0-alpha7 / 2015-12-12
98 | ------------------
99 |
100 | `new` add options `disabledHours`, `disabledMinutes`, `disabledSeconds` and `hideDisabledOptions`.
101 | `remove` remove options `hourOptions`, `minuteOptions` and `secondOptions`.
102 |
103 | 1.0.0-alpha2 / 2015-12-03
104 | ------------------
105 |
106 | `fixed` IE8 compatible.
107 | `new` add test users.
108 |
109 | 0.7.1 / 2015-11-20
110 | ------------------
111 |
112 | `fixed` change value to null when clear input content to remove the react warning.
113 |
114 | 0.7.0 / 2015-11-20
115 | ------------------
116 |
117 | `update` change the className of panel and its container.
118 |
119 | 0.5.6 / 2015-11-19
120 | ------------------
121 |
122 | `fixed` use another method to change time and fix the bug about value.getTime().
123 |
124 | 0.5.4 / 2015-11-19
125 | ------------------
126 |
127 | `update` change value prop to defaultValue.
128 |
129 | 0.5.2 / 2015-11-19
130 | ------------------
131 |
132 | `update` renew placements config.
133 |
134 | 0.5.1 / 2015-11-19
135 | ------------------
136 |
137 | `update` change the className of select panel container.
138 |
139 | 0.5.0 / 2015-11-19
140 | ------------------
141 |
142 | `update` clear input content and close select panel when click [x] on select panel.
143 |
144 | `new` can custom input className now.
145 |
146 |
147 | 0.4.0 / 2015-11-18
148 | ------------------
149 |
150 | `update` clear input content when click [x] on select panel.
151 |
152 | 0.3.3 / 2015-11-17
153 | ------------------
154 |
155 | `fixed` fix some bugs.
156 |
157 | 0.3.0 / 2015-11-17
158 | ------------------
159 |
160 | `update` remove TimePanel and merge it to TimePicker.
161 |
162 | 0.2.0 / 2015-11-16
163 | ------------------
164 |
165 | `update` rename the component, update document.
166 |
167 | 0.1.0 / 2015-11-12
168 | ------------------
169 |
170 | `new` [#305](https://github.com/ant-design/ant-design/issues/305#issuecomment-147027817) release 0.1.0 ([@wuzhao](https://github.com/wuzhao)\)
171 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-present yiminghe
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TimePicker
2 |
3 | React Time Picker Control.
4 |
5 | [![NPM version][npm-image]][npm-url]
6 | [![build status][circleci-image]][circleci-url]
7 | [![Test coverage][coveralls-image]][coveralls-url]
8 | [](https://david-dm.org/react-component/time-picker)
9 | [](https://david-dm.org/react-component/time-picker?type=dev)
10 | [![npm download][download-image]][download-url]
11 | [](https://github.com/react-component/time-picker)
12 |
13 | [Storybook]: https://github.com/storybooks/press/blob/master/badges/storybook.svg
14 | [npm-image]: http://img.shields.io/npm/v/rc-time-picker.svg?style=flat-square
15 | [npm-url]: http://npmjs.org/package/rc-time-picker
16 | [circleci-image]: https://img.shields.io/circleci/react-component/time-picker.svg?style=flat-square
17 | [circleci-url]: https://circleci.com/gh/react-component/time-picker
18 | [coveralls-image]: https://img.shields.io/coveralls/react-component/time-picker.svg?style=flat-square
19 | [coveralls-url]: https://coveralls.io/r/react-component/time-picker?branch=maste
20 | [node-image]: https://img.shields.io/badge/node.js-%3E=_0.10-green.svg?style=flat-square
21 | [node-url]: http://nodejs.org/download/
22 | [download-image]: https://img.shields.io/npm/dm/rc-time-picker.svg?style=flat-square
23 | [download-url]: https://npmjs.org/package/rc-time-picker
24 |
25 | example
26 | --------
27 |
28 | http://react-component.github.io/time-picker/
29 |
30 | install
31 | -------
32 |
33 | ```
34 | npm install rc-time-picker
35 | ```
36 |
37 | Usage
38 | -----
39 |
40 | ```
41 | import TimePicker from 'rc-time-picker';
42 | import ReactDOM from 'react-dom';
43 | import 'rc-time-picker/assets/index.css';
44 | ReactDOM.render(, container);
45 | ```
46 |
47 | API
48 | ---
49 |
50 | ### TimePicker
51 |
52 | | Name | Type | Default | Description |
53 | |-------------------------|-----------------------------------|---------|-------------|
54 | | prefixCls | String | 'rc-time-picker' | prefixCls of this component |
55 | | clearText | String | 'clear' | clear tooltip of icon |
56 | | disabled | Boolean | false | whether picker is disabled |
57 | | allowEmpty | Boolean | true | allow clearing text |
58 | | open | Boolean | false | current open state of picker. controlled prop |
59 | | defaultValue | moment | null | default initial value |
60 | | defaultOpenValue | moment | moment() | default open panel value, used to set utcOffset,locale if value/defaultValue absent |
61 | | value | moment | null | current value |
62 | | placeholder | String | '' | time input's placeholder |
63 | | className | String | '' | time picker className |
64 | | inputClassName | String | '' | time picker input element className |
65 | | id | String | '' | time picker id |
66 | | popupClassName | String | '' | time panel className |
67 | | popupStyle | object | {} | customize popup style
68 | | showHour | Boolean | true | whether show hour | |
69 | | showMinute | Boolean | true | whether show minute |
70 | | showSecond | Boolean | true | whether show second |
71 | | format | String | - | moment format |
72 | | disabledHours | Function | - | disabled hour options |
73 | | disabledMinutes | Function | - | disabled minute options |
74 | | disabledSeconds | Function | - | disabled second options |
75 | | use12Hours | Boolean | false | 12 hours display mode |
76 | | hideDisabledOptions | Boolean | false | whether hide disabled options |
77 | | onChange | Function | null | called when time-picker a different value |
78 | | onAmPmChange | Function | null | called when time-picker an am/pm value |
79 | | addon | Function | - | called from timepicker panel to render some addon to its bottom, like an OK button. Receives panel instance as parameter, to be able to close it like `panel.close()`.|
80 | | placement | String | bottomLeft | one of ['topLeft', 'topRight', 'bottomLeft', 'bottomRight'] |
81 | | transitionName | String | '' | |
82 | | name | String | - | sets the name of the generated input |
83 | | onOpen | Function({ open }) | | when TimePicker panel is opened |
84 | | onClose | Function({ open }) | | when TimePicker panel is closed |
85 | | hourStep | Number | 1 | interval between hours in picker |
86 | | minuteStep | Number | 1 | interval between minutes in picker |
87 | | secondStep | Number | 1 | interval between seconds in picker |
88 | | focusOnOpen | Boolean | false | automatically focus the input when the picker opens |
89 | | inputReadOnly | Boolean | false | set input to read only |
90 | | inputIcon | ReactNode | | specific the time-picker icon. |
91 | | clearIcon | ReactNode | | specific the clear icon. |
92 |
93 | ## Test Case
94 |
95 | ```
96 | npm test
97 | ```
98 |
99 | ## Coverage
100 |
101 | ```
102 | npm run coverage
103 | ```
104 |
105 | open coverage/ dir
106 |
107 | License
108 | -------
109 |
110 | rc-time-picker is released under the MIT license.
111 |
--------------------------------------------------------------------------------
/assets/index.less:
--------------------------------------------------------------------------------
1 | @prefixClass: rc-time-picker;
2 |
3 | .@{prefixClass} {
4 | display: inline-block;
5 | position: relative;
6 | box-sizing: border-box;
7 | * {
8 | box-sizing: border-box;
9 | }
10 |
11 | &-clear {
12 | position: absolute;
13 | right: 6px;
14 | cursor: pointer;
15 | overflow: hidden;
16 | width: 20px;
17 | height: 20px;
18 | text-align: center;
19 | line-height: 20px;
20 | top: 3px;
21 | margin: 0;
22 |
23 | &-icon:after {
24 | content: "x";
25 | font-size: 12px;
26 | font-style: normal;
27 | color: #aaa;
28 | display: inline-block;
29 | line-height: 1;
30 | height: 20px;
31 | width: 20px;
32 | transition: color 0.3s ease;
33 | }
34 |
35 | &-icon:hover:after {
36 | color: #666;
37 | }
38 | }
39 | }
40 |
41 | @import "./index/Picker";
42 | @import "./index/Panel";
43 | @import "./index/Header";
44 | @import "./index/Select";
45 |
--------------------------------------------------------------------------------
/assets/index/Header.less:
--------------------------------------------------------------------------------
1 | .@{prefixClass}-panel {
2 | &-input {
3 | margin: 0;
4 | padding: 0;
5 | width: 100%;
6 | cursor: auto;
7 | line-height: 1.5;
8 | outline: 0;
9 | border: 1px solid transparent;
10 |
11 | &-wrap {
12 | box-sizing: border-box;
13 | position: relative;
14 | padding: 6px;
15 | border-bottom: 1px solid #e9e9e9;
16 | }
17 |
18 | &-invalid {
19 | border-color: red;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/assets/index/Panel.less:
--------------------------------------------------------------------------------
1 | .@{prefixClass}-panel {
2 | z-index: 1070;
3 | width: 170px;
4 | position: absolute;
5 | box-sizing: border-box;
6 |
7 | * {
8 | box-sizing: border-box;
9 | }
10 |
11 | &-inner {
12 | display: inline-block;
13 | position: relative;
14 | outline: none;
15 | list-style: none;
16 | font-size: 12px;
17 | text-align: left;
18 | background-color: #fff;
19 | border-radius: 4px;
20 | box-shadow: 0 1px 5px #ccc;
21 | background-clip: padding-box;
22 | border: 1px solid #ccc;
23 | line-height: 1.5;
24 | }
25 |
26 | &-narrow {
27 | max-width: 113px;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/assets/index/Picker.less:
--------------------------------------------------------------------------------
1 | .@{prefixClass} {
2 | &-input {
3 | width: 100%;
4 | position: relative;
5 | display: inline-block;
6 | padding: 4px 7px;
7 | height: 28px;
8 | cursor: text;
9 | font-size: 12px;
10 | line-height: 1.5;
11 | color: #666;
12 | background-color: #fff;
13 | background-image: none;
14 | border: 1px solid #d9d9d9;
15 | border-radius: 4px;
16 | 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);
17 | &[disabled] {
18 | color: #ccc;
19 | background: #f7f7f7;
20 | cursor: not-allowed;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/assets/index/Select.less:
--------------------------------------------------------------------------------
1 | .@{prefixClass}-panel-select {
2 | float: left;
3 | font-size: 12px;
4 | border: 1px solid #e9e9e9;
5 | border-width: 0 1px;
6 | margin-left: -1px;
7 | box-sizing: border-box;
8 | width: 56px;
9 | max-height: 144px;
10 | overflow-y: auto;
11 | position: relative; // Fix chrome weird render bug
12 |
13 | &-active {
14 | overflow-y: auto;
15 | }
16 |
17 | &:first-child {
18 | border-left: 0;
19 | margin-left: 0;
20 | }
21 |
22 | &:last-child {
23 | border-right: 0;
24 | }
25 |
26 | ul {
27 | list-style: none;
28 | box-sizing: border-box;
29 | margin: 0;
30 | padding: 0;
31 | width: 100%;
32 | }
33 |
34 | li {
35 | list-style: none;
36 | margin: 0;
37 | padding: 0 0 0 16px;
38 | width: 100%;
39 | height: 24px;
40 | line-height: 24px;
41 | text-align: left;
42 | cursor: pointer;
43 | user-select: none;
44 |
45 | &:hover {
46 | background: #edfaff;
47 | }
48 | }
49 |
50 | li&-option-selected {
51 | background: #f7f7f7;
52 | font-weight: bold;
53 | }
54 |
55 | li&-option-disabled {
56 | color: #ccc;
57 | &:hover {
58 | background: transparent;
59 | cursor: not-allowed;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/examples/disabled.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 |
3 | import '../assets/index.less';
4 | import React from 'react';
5 | import moment from 'moment';
6 | import TimePicker from '..';
7 |
8 | const showSecond = true;
9 | const str = showSecond ? 'HH:mm:ss' : 'HH:mm';
10 |
11 | const now = moment()
12 | .hour(14)
13 | .minute(30);
14 |
15 | function generateOptions(length, excludedOptions) {
16 | const arr = [];
17 | for (let value = 0; value < length; value += 1) {
18 | if (excludedOptions.indexOf(value) < 0) {
19 | arr.push(value);
20 | }
21 | }
22 | return arr;
23 | }
24 |
25 | function onChange(value) {
26 | console.log(value && value.format(str));
27 | }
28 |
29 | function disabledHours() {
30 | return [0, 1, 2, 3, 4, 5, 6, 7, 8, 22, 23];
31 | }
32 |
33 | function disabledMinutes(h) {
34 | switch (h) {
35 | case 9:
36 | return generateOptions(60, [30]);
37 | case 21:
38 | return generateOptions(60, [0]);
39 | default:
40 | return generateOptions(60, [0, 30]);
41 | }
42 | }
43 |
44 | function disabledSeconds(h, m) {
45 | return [h + (m % 60)];
46 | }
47 |
48 | const App = () => (
49 | <>
50 |
Disabled picker
51 |
52 | Disabled options
53 |
62 | >
63 | );
64 |
65 | export default App;
66 |
--------------------------------------------------------------------------------
/examples/format.js:
--------------------------------------------------------------------------------
1 | import '../assets/index.less';
2 | import React from 'react';
3 | import moment from 'moment';
4 | import TimePicker from '..';
5 |
6 | const App = () => (
7 | <>
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | >
16 | );
17 |
18 | export default App;
19 |
--------------------------------------------------------------------------------
/examples/hidden.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | import '../assets/index.less';
3 | import React from 'react';
4 | import moment from 'moment';
5 | import TimePicker from '..';
6 |
7 | const showSecond = true;
8 | const str = showSecond ? 'HH:mm:ss' : 'HH:mm';
9 |
10 | function onChange(value) {
11 | console.log(value && value.format(str));
12 | }
13 |
14 | const App = () => (
15 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 22, 23]}
23 | disabledMinutes={() => [0, 2, 4, 6, 8]}
24 | hideDisabledOptions
25 | />
26 | );
27 |
28 | export default App;
29 |
--------------------------------------------------------------------------------
/examples/open.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | import '../assets/index.less';
3 | import React from 'react';
4 | import moment from 'moment';
5 | import TimePicker from '..';
6 |
7 | const iconStyle = {
8 | position: 'absolute',
9 | width: '24px',
10 | right: 0,
11 | top: 0,
12 | bottom: 0,
13 | display: 'flex',
14 | alignItems: 'center',
15 | justifyContent: 'center',
16 | };
17 |
18 | const starPath =
19 | 'M908.1 353.1l-253.9-36.9L540.7 86.1c-3' +
20 | '.1-6.3-8.2-11.4-14.5-14.5-15.8-7.8-35-1.3-42.9 14.5L3' +
21 | '69.8 316.2l-253.9 36.9c-7 1-13.4 4.3-18.3 9.3-12.3 12' +
22 | '.7-12.1 32.9 0.6 45.3l183.7 179.1-43.4 252.9c-1.2 6.9' +
23 | '-0.1 14.1 3.2 20.3 8.2 15.6 27.6 21.7 43.2 13.4L512 7' +
24 | '54l227.1 119.4c6.2 3.3 13.4 4.4 20.3 3.2 17.4-3 29.1-' +
25 | '19.5 26.1-36.9l-43.4-252.9 183.7-179.1c5-4.9 8.3-11.3' +
26 | ' 9.3-18.3 2.7-17.5-9.5-33.7-27-36.3zM664.8 561.6l36.1' +
27 | ' 210.3L512 672.7 323.1 772l36.1-210.3-152.8-149L417.6' +
28 | ' 382 512 190.7 606.4 382l211.2 30.7-152.8 148.9z';
29 |
30 | const redoPath =
31 | 'M758.2 839.1C851.8 765.9 912 651.9 912' +
32 | ' 523.9 912 303 733.5 124.3 512.6 124 291.4 123.7 112 ' +
33 | '302.8 112 523.9c0 125.2 57.5 236.9 147.6 310.2 3.5 2.' +
34 | '8 8.6 2.2 11.4-1.3l39.4-50.5c2.7-3.4 2.1-8.3-1.2-11.1' +
35 | '-8.1-6.6-15.9-13.7-23.4-21.2-29.4-29.4-52.5-63.6-68.6' +
36 | '-101.7C200.4 609 192 567.1 192 523.9s8.4-85.1 25.1-12' +
37 | '4.5c16.1-38.1 39.2-72.3 68.6-101.7 29.4-29.4 63.6-52.' +
38 | '5 101.7-68.6C426.9 212.4 468.8 204 512 204s85.1 8.4 1' +
39 | '24.5 25.1c38.1 16.1 72.3 39.2 101.7 68.6 29.4 29.4 52' +
40 | '.5 63.6 68.6 101.7 16.7 39.4 25.1 81.3 25.1 124.5s-8.' +
41 | '4 85.1-25.1 124.5c-16.1 38.1-39.2 72.3-68.6 101.7-9.3' +
42 | ' 9.3-19.1 18-29.3 26L668.2 724c-4.1-5.3-12.5-3.5-14.1' +
43 | ' 3l-39.6 162.2c-1.2 5 2.6 9.9 7.7 9.9l167 0.8c6.7 0 1' +
44 | '0.5-7.7 6.3-12.9l-37.3-47.9z';
45 |
46 | class App extends React.Component {
47 | state = {
48 | open: false,
49 | useIcon: false,
50 | };
51 |
52 | getIcon = (path, style = {}) => (
53 |
65 |
74 |
75 | );
76 |
77 | setOpen = ({ open }) => {
78 | this.setState({ open });
79 | };
80 |
81 | toggleOpen = () => {
82 | const { open } = this.state;
83 | this.setState({
84 | open: !open,
85 | });
86 | };
87 |
88 | toggleIcon = () => {
89 | const { useIcon } = this.state;
90 | this.setState({
91 | useIcon: !useIcon,
92 | });
93 | };
94 |
95 | render() {
96 | const inputIcon = this.getIcon(starPath, iconStyle);
97 | const { useIcon, open } = this.state;
98 | const clearIcon = this.getIcon(redoPath, { ...iconStyle, right: 20 });
99 | return (
100 |
101 |
104 |
107 |
119 |
120 | );
121 | }
122 | }
123 |
124 | export default App;
125 |
--------------------------------------------------------------------------------
/examples/pick-time.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | import '../assets/index.less';
3 | import React from 'react';
4 | import moment from 'moment';
5 | import TimePicker from '..';
6 |
7 | const showSecond = true;
8 | const str = showSecond ? 'HH:mm:ss' : 'HH:mm';
9 |
10 | function onChange(value) {
11 | console.log(value && value.format(str));
12 | }
13 |
14 | const App = () => (
15 |
22 | );
23 |
24 | export default App;
25 |
--------------------------------------------------------------------------------
/examples/step.js:
--------------------------------------------------------------------------------
1 | import '../assets/index.less';
2 | import React from 'react';
3 | import moment from 'moment';
4 | import TimePicker from '..';
5 |
6 | const App = () => ;
7 |
8 | export default App;
9 |
--------------------------------------------------------------------------------
/examples/twelve-hours.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | import '../assets/index.less';
3 | import React from 'react';
4 | import moment from 'moment';
5 | import TimePicker from '..';
6 |
7 | const format = 'h:mm a';
8 |
9 | const now = moment()
10 | .hour(0)
11 | .minute(0);
12 |
13 | function onChange(value) {
14 | console.log(value && value.format(format));
15 | }
16 |
17 | const App = () => (
18 |
27 | );
28 |
29 | export default App;
30 |
--------------------------------------------------------------------------------
/examples/value-and-defaultValue.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | import '../assets/index.less';
3 | import React from 'react';
4 | import moment from 'moment';
5 | import TimePicker from '..';
6 |
7 | class App extends React.Component {
8 | state = {
9 | value: moment(),
10 | };
11 |
12 | handleValueChange = value => {
13 | console.log(value && value.format('HH:mm:ss'));
14 | this.setState({ value });
15 | };
16 |
17 | clear = () => {
18 | this.setState({
19 | value: undefined,
20 | });
21 | };
22 |
23 | render() {
24 | const { value } = this.state;
25 | return (
26 |
27 |
28 |
29 |
32 |
33 | );
34 | }
35 | }
36 |
37 | export default App;
38 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module "rc-time-picker" {
2 | import { Moment } from "moment";
3 | import * as React from "react";
4 |
5 | type TimePickerProps = {
6 | prefixCls?: string;
7 | clearText?: string;
8 | disabled?: boolean;
9 | allowEmpty?: boolean;
10 | open?: boolean;
11 | defaultValue?: Moment;
12 | defaultOpenValue?: Moment;
13 | value?: Moment;
14 | placeholder?: string;
15 | className?: string;
16 | inputClassName?: string;
17 | id?: string;
18 | popupClassName?: string;
19 | popupStyle?: any;
20 | showHour?: boolean;
21 | showMinute?: boolean;
22 | showSecond?: boolean;
23 | format?: string;
24 | disabledHours?: () => number[];
25 | disabledMinutes?: (hour: number) => number[];
26 | disabledSeconds?: (hour: number, minute: number) => number[];
27 | use12Hours?: boolean;
28 | hideDisabledOptions?: boolean;
29 | onChange?: (newValue: Moment | null) => void;
30 | onAmPmChange?: (ampm: 'PM' | 'AM') => void;
31 | addon?: (instance: typeof Panel) => React.ReactNode;
32 | placement?: string;
33 | transitionName?: string;
34 | name?: string;
35 | autoComplete?: string;
36 | onFocus?: (event: React.FocusEvent) => void;
37 | onBlur?: (event: React.FocusEvent) => void;
38 | onKeyDown?: (event: React.KeyboardEvent) => void;
39 | autoFocus?: boolean;
40 | onOpen?: (newState: { open: true }) => void;
41 | onClose?: (newState: { open: false }) => void;
42 | hourStep?: number;
43 | minuteStep?: number;
44 | secondStep?: number;
45 | focusOnOpen?: boolean;
46 | inputReadOnly?: boolean;
47 | inputIcon?: React.ReactNode;
48 | clearIcon?: React.ReactNode;
49 | getPopupContainer?: React.ReactNode;
50 | };
51 | export default class TimePicker extends React.Component {
52 | focus(): void;
53 | blur(): void;
54 | }
55 | class Panel extends React.Component {
56 | close(): void;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './src/';
2 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | snapshotSerializers: [require.resolve('enzyme-to-json/serializer')],
3 | };
4 |
--------------------------------------------------------------------------------
/now.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "name": "rc-time-picker",
4 | "builds": [
5 | {
6 | "src": "package.json",
7 | "use": "@now/static-build",
8 | "config": { "distDir": ".doc" }
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rc-time-picker",
3 | "version": "4.0.0-alpha.3",
4 | "description": "React TimePicker",
5 | "keywords": [
6 | "react",
7 | "react-time-picker",
8 | "react-component",
9 | "timepicker",
10 | "time-picker",
11 | "ui component",
12 | "ui",
13 | "component"
14 | ],
15 | "files": [
16 | "lib",
17 | "es",
18 | "assets/*.css",
19 | "assets/*.less",
20 | "index.d.ts"
21 | ],
22 | "main": "lib/index",
23 | "module": "es/index",
24 | "homepage": "http://github.com/react-component/time-picker",
25 | "author": "wuzhao.mail@gmail.com",
26 | "repository": {
27 | "type": "git",
28 | "url": "git@github.com:react-component/time-picker.git"
29 | },
30 | "bugs": {
31 | "url": "http://github.com/react-component/time-picker/issues"
32 | },
33 | "license": "MIT",
34 | "dependencies": {
35 | "classnames": "2.x",
36 | "moment": "2.x",
37 | "raf": "^3.4.1",
38 | "rc-trigger": "^4.0.0-alpha.8"
39 | },
40 | "devDependencies": {
41 | "cross-env": "^7.0.0",
42 | "enzyme": "^3.8.0",
43 | "enzyme-to-json": "^3.4.0",
44 | "father": "^2.24.1",
45 | "np": "^6.0.0",
46 | "rc-util": "^5.1.0"
47 | },
48 | "peerDependencies": {
49 | "react": "^16.0.0",
50 | "react-dom": "^16.0.0"
51 | },
52 | "scripts": {
53 | "start": "cross-env NODE_ENV=development father doc dev --storybook",
54 | "build": "father doc build --storybook",
55 | "compile": "father build && lessc assets/index.less assets/index.css",
56 | "gh-pages": "npm run build && father doc deploy",
57 | "prepublishOnly": "npm run compile && np --yolo --no-publish",
58 | "lint": "eslint src/ examples/ --ext .tsx,.ts,.jsx,.js",
59 | "test": "father test",
60 | "coverage": "father test --coverage",
61 | "now-build": "npm run build"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Combobox.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Select from './Select';
3 |
4 | const formatOption = (option, disabledOptions) => {
5 | let value = `${option}`;
6 | if (option < 10) {
7 | value = `0${option}`;
8 | }
9 |
10 | let disabled = false;
11 | if (disabledOptions && disabledOptions.indexOf(option) >= 0) {
12 | disabled = true;
13 | }
14 |
15 | return {
16 | value,
17 | disabled,
18 | };
19 | };
20 |
21 | class Combobox extends Component {
22 | onItemChange = (type, itemValue) => {
23 | const {
24 | onChange,
25 | defaultOpenValue,
26 | use12Hours,
27 | value: propValue,
28 | isAM,
29 | onAmPmChange,
30 | } = this.props;
31 | const value = (propValue || defaultOpenValue).clone();
32 |
33 | if (type === 'hour') {
34 | if (use12Hours) {
35 | if (isAM) {
36 | value.hour(+itemValue % 12);
37 | } else {
38 | value.hour((+itemValue % 12) + 12);
39 | }
40 | } else {
41 | value.hour(+itemValue);
42 | }
43 | } else if (type === 'minute') {
44 | value.minute(+itemValue);
45 | } else if (type === 'ampm') {
46 | const ampm = itemValue.toUpperCase();
47 | if (use12Hours) {
48 | if (ampm === 'PM' && value.hour() < 12) {
49 | value.hour((value.hour() % 12) + 12);
50 | }
51 |
52 | if (ampm === 'AM') {
53 | if (value.hour() >= 12) {
54 | value.hour(value.hour() - 12);
55 | }
56 | }
57 | }
58 | onAmPmChange(ampm);
59 | } else {
60 | value.second(+itemValue);
61 | }
62 | onChange(value);
63 | };
64 |
65 | onEnterSelectPanel = range => {
66 | const { onCurrentSelectPanelChange } = this.props;
67 | onCurrentSelectPanelChange(range);
68 | };
69 |
70 | getHourSelect(hour) {
71 | const { prefixCls, hourOptions, disabledHours, showHour, use12Hours, onEsc } = this.props;
72 | if (!showHour) {
73 | return null;
74 | }
75 | const disabledOptions = disabledHours();
76 | let hourOptionsAdj;
77 | let hourAdj;
78 | if (use12Hours) {
79 | hourOptionsAdj = [12].concat(hourOptions.filter(h => h < 12 && h > 0));
80 | hourAdj = hour % 12 || 12;
81 | } else {
82 | hourOptionsAdj = hourOptions;
83 | hourAdj = hour;
84 | }
85 |
86 | return (
87 |