[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    \"env\",\n    \"stage-0\",\n    \"react\"\n  ],\n  \"plugins\": [\n    \"system-import-transformer\"\n  ]\n}\n"
  },
  {
    "path": ".coveralls.yml",
    "content": "service_name: travis-ci\nrepo_token: MMi1goJ3ZCpZ5Iaz9i1tSus4G5psdpQTY\n"
  },
  {
    "path": ".eslintignore",
    "content": "node_modules/\nlib/\n.out.\n.storybook/\nwebpack.config.js\nindex.js\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"parser\": \"babel-eslint\",\n  \"extends\": \"standard\",\n  \"plugins\": [\n    \"react\",\n    \"import\",\n    \"babel\"\n  ],\n  \"parserOptions\": {\n    \"ecmaFeatures\": {\n      \"jsx\": true\n    }\n  },\n  \"env\": {\n    \"browser\": true,\n    \"node\": true,\n    \"es6\": true,\n    \"jquery\": true,\n    \"commonjs\": true,\n    \"phantomjs\": true,\n    \"mocha\": true\n  },\n  \"rules\": {\n    \"strict\": 0,\n    \"no-console\": 1,\n    \"no-debugger\": 1,\n    \"no-extra-semi\": 1,\n    \"no-constant-condition\": 2,\n    \"no-extra-boolean-cast\": 2,\n    \"no-return-assign\": 0,\n    \"use-isnan\": 2,\n    \"no-undef-init\": 2,\n    \"camelcase\": 2,\n    \"no-mixed-spaces-and-tabs\": 2,\n    \"no-const-assign\":2,\n    \"no-func-assign\": 2,\n    \"no-else-return\": 1,\n    \"no-obj-calls\": 2,\n    \"valid-typeof\": 2,\n    \"no-unused-vars\": 1,\n    \"quotes\": 0,\n    \"block-spacing\": 1,\n    \"semi\": 0,\n    \"keyword-spacing\": 1,\n    \"comma-dangle\": 0,\n    \"arrow-body-style\": 0,\n    \"array-bracket-spacing\": 1,\n    \"space-before-function-paren\": 0,\n    \"no-extra-bind\": 1,\n    \"no-var\": \"error\",\n    \"arrow-spacing\": [\"error\", { \"before\": true, \"after\": true }],\n    \"no-empty-function\": [\"error\", { \"allow\": [\"arrowFunctions\", \"constructors\"] }],\n    \"react/no-did-mount-set-state\": \"error\",\n    \"react/no-did-update-set-state\": \"error\",\n    \"react/react-in-jsx-scope\": \"error\",\n    \"react/jsx-uses-vars\": [2],\n    \"react/jsx-uses-react\": [2],\n    \"import/no-unresolved\": [2, {\"commonjs\": true, \"amd\": true}],\n    \"import/namespace\": 2,\n  \t\"import/default\": 2,\n  \t\"import/export\": 2,\n    \"babel/new-cap\": 1,\n    \"babel/object-curly-spacing\": 0,\n    \"babel/no-invalid-this\": 1,\n    \"babel/semi\": 1,\n    \"operator-linebreak\": 0\n  },\n  \"settings\": {\n    \"import/resolver\": {\n      \"node\": {\n        \"extensions\": [\".js\", \".jsx\"]\n      },\n      \"webpack\": {\n        \"config\": \"webpack.config.js\"\n      }\n    },\n    \"import/ignore\": [\"node_modules\"]\n  },\n  \"globals\": {\n    \"require\": true\n  }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "*.lock\n.DS_Store\n/lib\n/.out\n/node_modules\n/out*"
  },
  {
    "path": ".npmignore",
    "content": "/components/\n/examples\n/stories\n/webpack\n/.storybook\n/intro_src\n/test\n/src\n/.coveralls.yml\n/.travis.yml\n/webpack.config.js\n/doc\n"
  },
  {
    "path": ".storybook/addons.js",
    "content": "import '@storybook/addons';\nimport '@storybook/addon-knobs/register'\n"
  },
  {
    "path": ".storybook/config.js",
    "content": "import { addDecorator, configure, setAddon } from '@storybook/react';\n\nimport infoAddon from '@storybook/addon-info';\nimport moment from 'moment';\n\naddDecorator((story) => {\n  moment.locale('zh-cn');\n  return (story());\n});\n\nfunction loadStories() {\n  require('../stories/TimePicker');\n  require('../stories/TimePicker2');\n  require('../stories/DarkColor');\n  require('../stories/TwelveHoursMode');\n  require('../stories/ClassicThemePicker');\n  require('../stories/CustomTrigger');\n  require('../stories/DifferentLanguage');\n  require('../stories/WithTimeZones');\n}\n\nsetAddon(infoAddon);\n\nconfigure(loadStories, module);\n"
  },
  {
    "path": ".storybook/preview-head.html",
    "content": "<link href=\"https://fonts.googleapis.com/css?family=Open+Sans\" rel=\"stylesheet\">\n<link href=\"http://obpykithy.bkt.clouddn.com/hawkeye/styles/fonts.css\" rel=\"stylesheet\">\n<style>\n  * {\n    font-family: 'Open Sans', 'Lato', sans-serif;\n  }\n  .time_picker_wrapper {\n    height: 500px;\n    width: 300px;\n    margin: 50px auto;\n  }\n  .time_picker_wrapper2 {\n    display: flex;\n    flex-direction: row;\n    justify-content: center;\n    align-items: center;\n    margin-top: 100px;\n  }\n  .time_picker_trigger {\n    width: auto;\n    display: inline-block;\n    position: relative;\n    display: flex;\n    flex-direction: row;\n    justify-content: center;\n    align-items: center;\n  }\n  .gap {\n    float: left;\n    width: 20px;\n  }\n  .time_picker_container {\n    width: 300px;\n  }\n</style>\n"
  },
  {
    "path": ".storybook/webpack.config.js",
    "content": "const path = require('path');\nconst webpack = require('webpack');\n\nconst SOURCE_PATH = path.join(__dirname, '../src');\n\nmodule.exports = {\n  context: SOURCE_PATH,\n  module: {\n    rules: [\n      {\n        test: /\\.jsx?$/,\n        enforce: \"pre\",\n        loader: \"eslint-loader\",\n        exclude: /node_modules/,\n        include: SOURCE_PATH,\n      },\n      {\n        test:   /\\.css/,\n        loaders: ['style-loader', 'css-loader'],\n        include: path.resolve(__dirname, '../css/')\n      },\n      {\n        test:   /\\.css/,\n        loaders: ['style-loader', 'css-loader'],\n        include: path.resolve(__dirname, '../src/')\n      },\n      {\n        test: /\\.svg$/,\n        loader: 'babel!react-svg'\n      },\n      {\n        test: /\\.(js|jsx)$/,\n        include: SOURCE_PATH,\n        use: ['babel-loader'],\n        exclude: /node_modules/\n      },\n    ]\n  },\n  resolve: {\n    modules: ['node_modules'],\n    extensions: ['.js', '.jsx'],\n  },\n  plugins: [\n    new webpack.LoaderOptionsPlugin({\n      debug: true,\n      minimize: true,\n      options: {\n        context: SOURCE_PATH,\n      }\n    }),\n  ],\n  devtool: '#source-map',\n};\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - \"7\"\n  - \"6\"\nbefore_script:\n  - npm install -g mocha\n  - npm install -g eslint\n  - npm i\n  - npm i react\n  - npm i react-dom\nscript: npm test\nenv:\n  - REACT=16\nbundler_args: --retry 2\nmatrix:\n  fast_finish: true\ncache:\n  directories:\n    - node_modules\nafter_script:\n    - npm run coveralls\nnotifications:\n  webhooks: https://hook.bearychat.com/=bw9fs/travis/613010ff56ad38e540b93d5543cea6dd\n  slack: ecmadao:fKFA5rnMSWRUqZrA9bS3gaD2\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2016 ecmadao\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "![react-times](./doc/intro_src/react_times.png)\n\n[![npm version](https://badge.fury.io/js/react-times.svg)](https://badge.fury.io/js/react-times) [![Build Status](https://travis-ci.org/ecmadao/react-times.svg?branch=master)](https://travis-ci.org/ecmadao/react-times) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com) [![react-times](http://img.shields.io/npm/dm/react-times.svg)](https://www.npmjs.com/package/react-times) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/ecmadao/react-times/master/LICENSE)\n\n[![NPM](https://nodei.co/npm/react-times.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/react-times)\n\nREADME：[中文版](./doc/README_CN.md)\n\n> A time picker react-component, no jquery-rely, writing in es6 standard style.\n\n**Check [here](./doc/CHANGELOG.md) to see changed props in new version.**\n\n![react-times](./doc/intro_src/react-times.gif)\n\n# Online demo\n\nCheck [here](https://ecmadao.github.io/react-times) to play online demo.\n\n# Play in local\n\n```bash\n$ git clone https://github.com/ecmadao/react-times.git\n\n$ npm install\n\n$ npm run storybook\n```\n\n# Install\n\ndependencies:\n\n- [`moment`](https://github.com/moment/moment/)\n- [`react`](https://github.com/facebook/react)\n- [`react-dom`](https://github.com/facebook/react)\n\n> No jQuery rely 😤😤😤\n\nSo generally speaking, you should already have `react` & `react-dom` dependencies in your project. If not:\n\n```bash\n$ npm install react react-dom moment moment-timezone --save-dev\n# and\n$ npm install react-times --save-dev\n```\n\n# Config\n\nCause I'm using `moment-timezone`, you need to be able to parse json file.\n\nUse webpack (version < 2) config as example:\n\n- [How should I use moment-timezone with webpack?](https://stackoverflow.com/questions/29548386/how-should-i-use-moment-timezone-with-webpack)\n\n```bash\n$ npm i json-loader --save\n```\n\n```javascript\n// webpack.config.js\n// ATTENTION:\n// webpack >= v2.0.0 has native JSON support.\n// check here: https://github.com/webpack-contrib/json-loader/issues/65 for more information\n{\n  module: {\n    loaders: [\n        {include: /\\.json$/, loaders: [\"json-loader\"]}\n    ]\n  },\n  resolve: {\n    extensions: ['', '.json', '.jsx', '.js']\n  }\n}\n```\n\n# Usage\n\nThis component has two themes now: Material Theme by default, or Classic Theme.\n\n> Always remember import css file when you use react-times\n\n```javascript\n// basic usage\n// in some react component\nimport React from 'react';\nimport TimePicker from 'react-times';\n\n// use material theme\nimport 'react-times/css/material/default.css';\n// or you can use classic theme\nimport 'react-times/css/classic/default.css';\n\nexport default class SomeComponent extends React.Component {\n  onTimeChange(options) {\n    // do something\n  }\n\n  onFocusChange(focusStatue) {\n    // do something\n  }\n\n  render() {\n    <TimePicker\n      onFocusChange={this.onFocusChange.bind(this)}\n      onTimeChange={this.onTimeChange.bind(this)}\n    />\n  }\n}\n```\n\n> See more examples here:\n\n```javascript\n// some config example\nrender() {\n  <TimePicker\n    showTimezone // show the timezone, default false\n    focused // whether to show timepicker modal after rendered. default false\n    withoutIcon // whether to has time icon on button, default false\n    colorPalette=\"dark\" // main color, default \"light\"\n    time=\"13:05\" // initial time, default current time\n    theme=\"material\"\n    // or\n    // theme=\"classic\"\n    timeMode=\"12\" // use 24 or 12 hours mode, default 24\n    timezone=\"America/New_York\" // what timezone to use, detects the user's local timezone by default\n  />\n}\n```\n\n> For more detail usage, you can visit [example](https://github.com/ecmadao/react-times/tree/master/examples) or see the source code.\n\n# Show time\n\n- 24 hours mode with Material Theme, light color by default\n\n```javascript\n<TimePicker />\n```\n\n![24HoursMode](./doc/intro_src/24HoursMode.png)\n\n- 12 hours mode with Material Theme, light color by default\n\n```javascript\n<TimePicker timeMode=\"12\"/>\n```\n\n![12HoursMode](./doc/intro_src/12HoursMode.png)\n\n- 24 hours mode with Material Theme, dark color\n\n```javascript\n<TimePicker colorPalette=\"dark\"/>\n```\n\n![DarkColor](./doc/intro_src/DarkColor.png)\n\n- 24 hours mode, showing user current timezone. (Besides, your can use `timezone` props to custom timezone)\n\n```javascript\n<TimePicker showTimezone={true}/>\n```\n\n![showTimezone](./doc/intro_src/24HoursMode-showTimezone.png)\n\n- 24 hours mode with Classic Theme, light color by default\n\n```javascript\n<TimePicker theme=\"classic\"/>\n```\n\n![24HoursMode-ClassicTheme](./doc/intro_src/24HoursMode-ClassicTheme.png)\n\n- 24 hours mode with Classic Theme, dark color\n\n```javascript\n<TimePicker colorPalette=\"dark\" theme=\"classic\"/>\n```\n\n![24HoursMode-ClassicTheme-dark](./doc/intro_src/24HoursMode-ClassicTheme-dark.png)\n\n# APIs\n\n## Props\n\n- `time`\n\n> Initial time, must be a string, with `${hour}:${minute}` format, default now (by using `moment()`):\n\n```javascript\n// PropTypes.string\ntime='11:11'\ntime='11:01'\ntime='1:01'\ntime='1:1'\n```\n\n- `timeFormat`\n\n> To show the time using custom style\n\n```javascript\n// PropTypes.string\n// HH, MM means 24 hours mode\n// hh, mm means 12 hours mode\ntimeFormat='HH:MM'\ntimeFormat='hh:mm'\ntimeFormat='H:M'\ntimeFormat='h:m'\n\n// Warning:\n// If you are using 12 hours mode but with hh or mm format,\n// or using 24 hours mode with HH or MM format,\n// you will receive a warning on console, and force to use the timeMode props\n\n// So, if you wanna use hh:mm or h:m, you need to set timeMode props to 12\n// (cause timeMode default is 24)\n```\n\n- `timeFormatter`\n\n> To show the time using custom style\n\n```javascript\n// PropTypes.func\ntimeFormatter={({ hour, minute, meridiem }) => `${hour} - ${minute}`}\n\n// Note:\n// If you both set timeFormat and timeFormatter props (and they all validate), component will use timeFormatter function\n```\n\n- `focused`\n\n> Whether the timepicker pannel is focused or not when it did mount. Default `false`\n\n```javascript\n// PropTypes.bool\nfocused={false}\nfocused={true}\n```\n\n- `withoutIcon`\n\n> Whether the timepicker has a svg icon. Default `false`.\n\n```javascript\n// PropTypes.bool\nwithoutIcon={true}\n```\n\n- `colorPalette`\n\n> The main color palette of picker pannel. Default `light`.\n\n```javascript\n// PropTypes.string\ncolorPalette=\"dark\"\ncolorPalette=\"light\"\n```\n\n- `timeMode`\n\n> Support \"12\" or \"24\" hours mode.\n\n```javascript\n// PropTypes.string or PropTypes.number\ntimeMode=\"24\"\ntimeMode=24\ntimeMode=\"12\"\ntimeMode=12\n```\n\n- `meridiem`\n\n> `PropTypes.string`, support \"PM\" or \"AM\" for 12 hours mode, default `AM`\n\n- `showTimezone`\n\n> `PropTypes.bool`, whether show user timezone or not, default `false`\n\n- `timezone`\n\n> `PropTypes.string`, change user timezone, default user current local timezone.\n\n- `trigger`\n\n> `React.component`, means a DOM which can control TimePicker Modal \"open\" or \"close\" status.\n\n```javascript\n<TimePicker\n  focused={focused}\n  trigger={(\n    <div\n      onClick={this.handleFocusedChange.bind(this)} >\n      click to open modal\n    </div>\n  )}\n/>\n```\n\n- `closeOnOutsideClick`\n\n> If you don't wanna close panel when outside click, you can use closeOnOutsideClick={false}. Default true\n\n```\n<TimePicker\n  closeOnOutsideClick={false}\n/>\n```\n\n- `disabled`\n\n> Disable component. Default false\n\n```\n<TimePicker\n  disabled={true}\n/>\n```\n\n- `draggable`\n\nIf you don't want to drag the pointer, then you can set `draggable` props to `false`, then users can only use click to change time. Default `true`\n\n```\n<TimePicker\n  draggable={false}\n/>\n```\n\n- `language`\n\n> `React.string`, use different language. Default english.\n\n```javascript\n/*\n * support\n * en: english\n * zh-cn: 中文简体\n * zh-tw: 中文繁体\n * fr: Français\n * ja: 日本語\n */\n<TimePicker\n  language=\"zh-cn\" // 中文简体\n/>\n```\n\n- `phrases`\n\n> `React.object`, specify text values to use for specific messages.  By default, phrases will be set from defaults based on language.\n> Specify any of the available phrases you wish to override or all of them if your desired language is not yet supported.\n> See [language.js](./src/utils/language.js) for default phrases.\n\n```javascript\n<TimePicker\n  phrases={{\n    confirm: 'Are you sure?',\n    cancel: 'Do you want to cancel?',\n    close: 'DONE',\n    am: 'Ante Meridiem',\n    pm: 'Post Meridiem'\n  }}\n/>\n```\n\n- `minuteStep`\n\n> `React.number`, default `5`. It means the minium minute can change. You can set it to 1, 2, 3...\n\n```javascript\n<TimePicker\n  minuteStep={1}\n/>\n```\n\n- `timeConfig`\n\n> `React.object`, to config from, to, step limit for classic theme panel.\n\n```javascript\n<TimePicker\n  theme=\"classic\"\n  timeMode=\"12\"\n  timeConfig={{\n    from: '08:00 PM',\n    to: '08:00 AM',\n    step: 1,\n    unit: 'hour'\n  }}\n/>\n\n<TimePickerWrapper\n  theme=\"classic\"\n  timeMode=\"24\"\n  timeConfig={{\n    from: 9,\n    to: 19,\n    step: 30,\n    unit: 'minutes'\n  }}\n/>\n```\n\n- `limitDrag`\n\n> `React.bool`, default `false`. If `true`, it will limite the drag rotation by `minuteStep`\n\n```javascript\n<TimePicker\n  limitDrag\n/>\n```\n\n## Callback\n\n- `onFocusChange`\n\n`PropTypes.func`\n\n> The callback func when component `focused` state is changed.\n\n- `onTimeChange`\n\n`PropTypes.func`\n\n> The callback func when component `hour` or `minute` or `AM/PM` state is changed.\n\n```javascript\nonTimeChange(options) {\n  // you can get hour, minute and meridiem here\n  const {\n    hour,\n    minute,\n    meridiem\n  } = options;\n}\n```\n\n- `onTimezoneChange`\n\n`PropTypes.func`\n\n> The callback func when timezone changed.  Receives timezone object as argument with the following properties:\n* city\n* zoneAbbr\n* zoneName\n\n# Article\n\n- [一言不合造轮子--撸一个ReactTimePicker](https://github.com/ecmadao/Coding-Guide/blob/master/Notes/React/ReactJS/Write%20a%20React%20Timepicker%20Component%20hand%20by%20hand.md)\n\n# Todos\n\n- Test\n\n  - [x] TimePicker Component\n  - [x] PickerDragHandler Component\n  - [x] PickerPointGenerator Component\n  - [x] MaterialTheme Component\n  - [x] TwelveHoursTheme Component\n  - [x] PickerPoint Component\n  - [x] OutsideClickHandler Component\n\n  - [x] utils test\n\n- Color Palette (Now It has light and dark color)\n\n  - [x] light\n  - [x] dark\n  - [ ] colorful\n\n- Themes\n\n  - [x] Material Theme\n  - [x] Classical Theme\n\n- Mode\n\n  - [x] 12h mode\n  - [x] 24h mode\n\n- Animations\n\n# Thx\n\nThanks to the Airbnb's open source project: [react-dates](https://github.com/airbnb/react-dates), I have learn a lot from that. Thanks.\n\n# Core Contributors 🎉\n\n- **[carlodicelico](https://github.com/carlodicelico)**\n- **[erin-doyle](https://github.com/erin-doyle)**\n- **[MatthieuLemoine](https://github.com/MatthieuLemoine)**\n- **[naseeihity](https://github.com/naseeihity)**\n- **[shianqi](https://github.com/shianqi)**\n- **[thg303](https://github.com/thg303)**\n\n# License\n\n[MIT License](./LICENSE)\n"
  },
  {
    "path": "css/base.css",
    "content": ".time_picker_container {\n  position: relative;\n}\n\n.time_picker_preview {\n  height: 50px;\n}\n\n.time_picker_preview:not(.disabled):active, .time_picker_preview:not(.disabled).active {\n  box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.12), 0 0 8px 0 rgba(0, 0, 0, 0.08);\n  -moz-box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.12), 0 0 8px 0 rgba(0, 0, 0, 0.08);\n  -webkit-box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.12), 0 0 8px 0 rgba(0, 0, 0, 0.08);\n}\n\n.time_picker_preview.disabled {\n  cursor: not-allowed;\n}\n\n.preview_container {\n  position: absolute;\n  left: 50%;\n  height: 50px;\n  line-height: 50px;\n  padding-left: 30px;\n  transform: translateX(-50%);\n  -o-transform: translateX(-50%);\n  -ms-transform: translateX(-50%);\n  -webkit-transform: translateX(-50%);\n  -moz-transform: translateX(-50%);\n}\n\n.preview_container.without_icon {\n  padding-right: 30px;\n}\n\n.preview_container svg {\n  width: 25px;\n  height: 25px;\n  position: absolute;\n  top: 12px;\n  left: 0;\n}\n\n.react_times_button {\n  user-select: none;\n  position: relative;\n  cursor: pointer;\n  color: #343434;\n  border-radius: 2px;\n  background-color: #fff;\n  transition: all 200ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -ms-transition: all 200ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -moz-transition: all 200ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -o-transition: all 200ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -webkit-transition: all 200ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  box-shadow: 2px 2px 15px 0 rgba(0, 0, 0, .15);\n  -moz-box-shadow: 2px 2px 15px 0 rgba(0, 0, 0, .15);\n  -webkit-box-shadow: 2px 2px 15px 0 rgba(0, 0, 0, .15);\n}\n\n.react_times_button.pressDown {\n  box-shadow: 1px 1px 4px 0 rgba(0, 0, 0, 0.1);\n  -moz-box-shadow: 1px 1px 4px 0 rgba(0, 0, 0, 0.1);\n  -webkit-box-shadow: 1px 1px 4px 0 rgba(0, 0, 0, 0.1);\n}\n\n.react_times_button.pressDown .wrapper {\n  transform: translateY(1px);\n}\n\n.react_times_button .wrapper {\n  transform: translateY(0);\n  height: 100%;\n}\n\n.modal_container {\n  user-select: none;\n  cursor: default;\n  position: absolute;\n  width: 100%;\n  transition: all 200ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -ms-transition: all 200ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -moz-transition: all 200ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -o-transition: all 200ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -webkit-transition: all 200ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  background-color: #fff;\n  border-radius: 2px;\n  top: 100%;\n  left: 0;\n  box-shadow: 4px 4px 30px 0 rgba(0, 0, 0, 0.2);\n  -moz-box-shadow: 4px 4px 30px 0 rgba(0, 0, 0, 0.2);\n  -webkit-box-shadow: 4px 4px 30px 0 rgba(0, 0, 0, 0.2);\n\n  opacity: 0;\n  z-index: -1;\n  visibility: hidden;\n  backface-visibility: hidden;\n  transform: scale(0.7) translateY(20px);\n  -ms-transform: scale(0.7) translateY(20px);\n  -moz-transform: scale(0.7) translateY(20px);\n  -o-transform: scale(0.7) translateY(20px);\n  -webkit-transform: scale(0.7) translateY(20px);\n}\n\n.outside_container.active .modal_container {\n  opacity: 1;\n  z-index: 2;\n  visibility: visible;\n  transform: scale(1) translateY(20px);\n  -ms-transform: scale(1) translateY(20px);\n  -moz-transform: scale(1) translateY(20px);\n  -o-transform: scale(1) translateY(20px);\n  -webkit-transform: scale(1) translateY(20px);\n}"
  },
  {
    "path": "css/classic/default.css",
    "content": "@import \"../base.css\";\n\n.classic_theme_container {\n  height: 250px;\n  overflow-y: scroll;\n}\n\n.classic_theme_container .classic_time {\n  cursor: pointer;\n  width: 100%;\n  height: 40px;\n  line-height: 40px;\n  text-align: center;\n  border-bottom: 1px solid #f3f3f3;\n  background-color: #fff;\n  transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -ms-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -moz-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -o-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -webkit-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1);\n}\n\n.classic_theme_container .classic_time .meridiem {\n  font-size: 0.8em;\n  opacity: 0.7;\n  padding-left: 5px;\n}\n\n.classic_theme_container .classic_time.dark.active,\n.classic_theme_container .classic_time.dark:hover {\n  background-color: #4a4a4a;\n  color: #fff;\n}\n\n.classic_theme_container .classic_time.light.active,\n.classic_theme_container .classic_time.light:hover {\n  background-color: #3498db;\n  color: #fff;\n}\n\n/* dark theme */\n.dark .classic_theme_container {\n  background-color: #4a4a4a;\n}\n\n.dark .classic_theme_container .classic_time {\n  border-bottom: 1px solid #5d5d5d;\n  background-color: #4a4a4a;\n  color: #fff;\n}\n\n.dark .classic_theme_container .classic_time.active,\n.dark .classic_theme_container .classic_time:hover {\n  background-color: #343434;\n}\n"
  },
  {
    "path": "css/material/base.css",
    "content": "@import \"../base.css\";\n\n.time_picker_modal_container {\n}\n\n.time_picker_modal_header,\n.time_picker_modal_footer,\n.timezone_picker_modal_header {\n  height: 75px;\n  line-height: 75px;\n  text-align: center;\n  margin-bottom: 30px;\n  background-color: #3498db;\n  color: #FFFFFF;\n  font-size: 2.5em;\n  border-radius: 2px 2px 0 0;\n}\n\n.timezone_picker_modal_header {\n  line-height: initial;\n}\n\n.time_picker_header_delivery {\n  opacity: 0.5;\n}\n.time_picker_modal_header .time_picker_header {\n  cursor: pointer;\n  opacity: 0.5;\n  transition: opacity 0.3s;\n}\n.time_picker_modal_header .time_picker_header.active {\n  cursor: default;\n  opacity: 1;\n}\n.time_picker_modal_header .time_picker_header:hover {\n  opacity: 1;\n}\n.time_picker_modal_header .time_picker_header.meridiem {\n  font-size: 0.8em;\n}\n\n.time_picker_modal_footer {\n  font-size: 1em;\n  margin-bottom: 0;\n}\n\n.time_picker_modal_footer.clickable {\n  cursor: pointer;\n}\n\n.picker_container {\n  width: 260px;\n  height: 260px;\n  margin: 0 20px 20px;\n  border-radius: 50%;\n  background-color: #f0f0f0;\n  position: relative;\n}\n\n.picker_pointer_container {\n  opacity: 1;\n  transition: all 300ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -ms-transition: all 300ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -moz-transition: all 300ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -o-transition: all 300ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -webkit-transition: all 300ms cubic-bezier(0.165, 0.84, 0.44, 1);\n}\n\n.picker_pointer_container.animation {\n  opacity: 0;\n  transform: scale3d(0.85, 0.85, 1);\n  -o-transform: scale3d(0.85, 0.85, 1);\n  -ms-transform: scale3d(0.85, 0.85, 1);\n  -moz-transform: scale3d(0.85, 0.85, 1);\n  -webkit-transform: scale3d(0.85, 0.85, 1);\n}\n\n.picker_center {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 10px;\n  height: 10px;\n  border-radius: 50%;\n  background-color: #3498db;\n  transform: translate(-50%, -50%);\n  -ms-transform: translate(-50%, -50%);\n  -moz-transform: translate(-50%, -50%);\n  -o-transform: translate(-50%, -50%);\n  -webkit-transform: translate(-50%, -50%);\n}\n\n.picker_point {\n  left: 50%;\n  cursor: pointer;\n  position: absolute;\n  width: 30px;\n  height: 30px;\n  text-align: center;\n  line-height: 30px;\n  border-radius: 50%;\n}\n.picker_point.point_outter {\n  top: 5px;\n  color: #5d5d5d;\n  transform-origin: center 125px;\n  -o-transform-origin: center 125px;\n  -ms-transform-origin: center 125px;\n  -moz-transform-origin: center 125px;\n  -webkit-transform-origin: center 125px;\n}\n\n.picker_point.point_inner {\n  top: 40px;\n  color: #a7a7a7;\n  transform-origin: center 90px;\n  -o-transform-origin: center 90px;\n  -ms-transform-origin: center 90px;\n  -moz-transform-origin: center 90px;\n  -webkit-transform-origin: center 90px;\n}\n\n.picker_minute_point {\n  left: 50%;\n  cursor: pointer;\n  position: absolute;\n  top: 15px;\n  color: #5d5d5d;\n  transform-origin: center 115px;\n  -o-transform-origin: center 115px;\n  -ms-transform-origin: center 115px;\n  -moz-transform-origin: center 115px;\n  -webkit-transform-origin: center 115px;\n  width: 2px;\n  height: 2px;\n  border-radius: 50%;\n  background-color: #3498db;\n}\n\n.picker_pointer {\n  position: absolute;\n  width: 4px;\n  height: 110px;\n  left: 50%;\n  top: 20px;\n  background-color: #3498db;\n  transform-origin: center bottom;\n}\n\n.picker_pointer.animation {\n  transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -ms-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -moz-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -o-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1);\n  -webkit-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1);\n}\n\n.picker_pointer .pointer_drag {\n  position: absolute;\n  width: 35px;\n  height: 35px;\n  border-radius: 50%;\n  top: -17.5px;\n  left: -15.5px;\n  background-color: #3498db;\n  color: #fff;\n  text-align: center;\n  line-height: 35px;\n}\n\n.picker_pointer .pointer_drag.draggable {\n  cursor: move;\n}\n\n.buttons_wrapper {\n  float: right;\n  margin-top: 5px;\n}\n"
  },
  {
    "path": "css/material/button.css",
    "content": ".time_picker_button {\n  padding: 5px 10px;\n  background-color: transparent;\n  display: inline-block;\n  color: #949494;\n  opacity: 0.6;\n  transition: opacity 0.2s;\n  box-shadow: none;\n}\n\n.time_picker_button:hover {\n  opacity: 1;\n}\n"
  },
  {
    "path": "css/material/default.css",
    "content": "@import \"./base.css\";\n@import \"./button.css\";\n@import \"./timezone.css\";\n\n.dark .time_picker_preview {\n}\n\n.dark .time_picker_preview .preview_container svg {\n}\n\n.dark .time_picker_preview.active {\n}\n\n.dark .time_picker_modal_container {\n  background-color: #4a4a4a;\n}\n\n.dark .time_picker_modal_header,\n.dark .time_picker_modal_footer {\n  background-color: #343434;\n}\n\n.dark .time_picker_modal_header .time_picker_header.active,\n.dark .time_picker_modal_header .time_picker_header:hover {\n}\n\n.dark .picker_container {\n  background-color: #4a4a4a;\n}\n\n.dark .picker_container .picker_center,\n.dark .picker_container .picker_pointer,\n.dark .picker_container .picker_pointer .pointer_drag{\n  background-color: #F4511E;\n}\n\n.dark .picker_minute_point,\n.dark .picker_point.point_outter {\n  color: #fff;\n}\n\n.dark .picker_point.point_inner {\n  color: #D0D0D0;\n}\n"
  },
  {
    "path": "css/material/timezone.css",
    "content": ".timezone_picker_modal_container {\n  user-select: none;\n  cursor: default;\n  position: absolute;\n  z-index: 3;\n  background-color: #fff;\n  border-radius: 2px;\n  top: 0;\n  width: 100%;\n  box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.12), 0 0 4px 0 rgba(0, 0, 0, 0.08);\n  -moz-box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.12), 0 0 4px 0 rgba(0, 0, 0, 0.08);\n  -webkit-box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.12), 0 0 4px 0 rgba(0, 0, 0, 0.08);\n}\n\n.timezone_picker_modal_container-enter {\n  right: -100%;\n  opacity: 0.5;\n}\n\n.timezone_picker_modal_container-enter.timezone_picker_modal_container-enter-active {\n  right: 0;\n  opacity: 1;\n  transition: right 100ms ease-out, opacity 100ms ease-out;\n  -ms-transition: right 100ms ease-out, opacity 100ms ease-out;\n  -moz-transition: right 100ms ease-out, opacity 100ms ease-out;\n  -o-transition: right 100ms ease-out, opacity 100ms ease-out;\n  -webkit-transition: right 100ms ease-out, opacity 100ms ease-out;\n}\n\n.timezone_picker_modal_container-exit {\n  right: 0;\n  opacity: 1;\n}\n\n.timezone_picker_modal_container-exit.timezone_picker_modal_container-exit-active {\n  right: -100%;\n  opacity: 0.5;\n  transition: right 100ms ease-in, opacity 100ms ease-in;\n  -ms-transition: right 100ms ease-in, opacity 100ms ease-in;\n  -moz-transition: right 100ms ease-in, opacity 100ms ease-in;\n  -o-transition: right 100ms ease-in, opacity 100ms ease-in;\n  -webkit-transition: right 100ms ease-in, opacity 100ms ease-in;\n}\n\n.timezone_picker_modal_header {\n  font-size: 1em;\n  position: relative;\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  align-items: center;\n}\n\n.timezone_picker_header_title {\n  flex: 1;\n  text-align: left;\n}\n\n.timezone_picker_modal_header span.icon {\n  height: 25px;\n  width: 50px;\n}\n\n.timezone_picker_modal_header svg {\n  width: 25px;\n  height: 25px;\n  fill: #fff;\n  cursor: pointer;\n}\n\n.timezone_picker_container {\n  min-width: 260px;\n  min-height: 300px;\n  display: flex;\n  margin: 0 20px 20px;\n  position: relative;\n}\n\n.timezone_picker_search {\n  padding: 0 10px;\n  position: relative;\n  width: 100%;\n}\n\n.timezone_picker_search input {\n  box-sizing: border-box;\n  margin-bottom: 1%;\n  padding: 10px 10px;\n  width: 100%;\n  height: 100%;\n\n  font-size: 0.9rem;\n  line-height: 2;\n  border: none;\n  border-bottom: 1px solid #adb5bd;\n  outline: none;\n  border-radius: 2px;\n  transition: border .2s;\n}\n\n.timezone_picker_search input::-webkit-input-placeholder,\n.timezone_picker_search input::-moz-input-placeholder,\n.timezone_picker_search input:-ms-input-placeholder,\n.timezone_picker_search input:-moz-input-placeholder {\n  color: #c6cace;\n}\n\n.timezone_picker_search .bootstrap-typeahead-input-main {\n  color: #757575;\n}\n\n.timezone_picker_search input:focus {\n  color: #4b4b4b;\n  border-bottom: 1px solid #3498db;\n}\n\n/**\n* The react-bootstrap-typeahead library sort of assumes bootstrap is already in use for styling\n* so it refers to some bootstrap classes.  We don't need to use bootstrap just for a few classes so\n* the relevant styles have been copied here\n*/\n.clearfix:before,\n.clearfix:after {\n  display: table;\n  content: \" \";\n}\n.clearfix:after {\n  clear: both;\n}\n\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  font-size: 14px;\n  text-align: left;\n  list-style: none;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n  background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n  box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n}\n\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.42857143;\n  color: #333;\n  white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  color: #262626;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #fff;\n  text-decoration: none;\n  background-color: #337ab7;\n  outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n"
  },
  {
    "path": "doc/CHANGELOG.md",
    "content": "# CHANGELOG\n\n### v3.1.3\n\n#### new props\n\n- Add `timeConfig` props: to config from, to, step for classic theme panel.\n\n### v3.1.0\n\n#### remove props\n\n- Remove `onHourChange`\n- Remove `onMinuteChange`\n- Remove `onMeridiemChange`\n\n#### change props\n\n- `onTimeChange` will get a dict now, including `hour`, `minute`, `meridiem`\n\n#### new props\n\n- Add `closeOnOutsideClick`\n\n### v2.2.3\n\n#### new props\n\n- Add `timeFormat` props\n- Add `timeFormatter` props\n\n### v2.2.0\n\n#### new props\n\n- Add `minuteStep` props\n- Add `limitDrag` props\n\n### v2.1.3\n\n- Bugfixed for drag position offset\n- Add `onTimezoneChange` callback\n\n### v2.1.0\n\n#### new props\n\n- `phrases`: `PropTypes.object`\n- `timezone`: `PropTypes.string`\n- `onTimezoneChange`: `PropTypes.func`\n\n### v2.0.0\n\n#### changed props\n\n- `onTimeQuantumChange` --> `onMeridiemChange`\n- `timeQuantum` --> `meridiem`\n- `dragable` --> `draggable`\n\n#### new props\n\n- `showTimezone`: `PropTypes.bool`, default `false`\n- `timezone`:  `PropTypes.string`, default user current local timezone\n"
  },
  {
    "path": "doc/README_CN.md",
    "content": "![react-times](./doc/intro_src/react_times.png)\n\n[![npm version](https://badge.fury.io/js/react-times.svg)](https://badge.fury.io/js/react-times) [![Build Status](https://travis-ci.org/ecmadao/react-times.svg?branch=master)](https://travis-ci.org/ecmadao/react-times) [![Coverage Status](https://coveralls.io/repos/github/ecmadao/react-times/badge.svg?branch=master)](https://coveralls.io/github/ecmadao/react-times?branch=master) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com) [![react-times](http://img.shields.io/npm/dm/react-times.svg)](https://www.npmjs.com/package/react-times) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/ecmadao/react-times/master/LICENSE)\n\n[![NPM](https://nodei.co/npm/react-times.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/react-times)\n\nREADME：[English Version](./README.md)\n\n> 一个 React 时间选择器组件，使用 ES6 标准语法编写，没有 jQuery 依赖\n\n**戳 [这里](./doc/CHANGELOG.md) 查看新版中更改/新增的 props。**\n\n![react-times](./doc/intro_src/react-times.gif)\n\n# 线上 demo\n\n戳[这里](https://ecmadao.github.io/react-times)玩线上 demo\n\n# 本地玩起来\n\n```bash\n$ git clone https://github.com/ecmadao/react-times.git\n\n$ npm install\n\n$ npm run storybook\n```\n\n# 安装说明\n\n单独使用插件时所需的依赖：\n\n- [`moment`](https://github.com/moment/moment/)\n- [`react`](https://github.com/facebook/react)\n- [`react-dom`](https://github.com/facebook/react)\n\n> No jQuery 😤😤😤\n\n使用的时候，需要你的项目里已经安装了`react`和`react-dom`。如果没有的话：\n\n```bash\n$ npm install react react-dom --save-dev\n# and\n$ npm install react-times --save-dev\n```\n\n注意：因为组件使用了`moment-timezone`，所以你本地需要能够编辑 json 文件。webpack 2 以下的用户可以通过 json-loader 解决该问题。webpack >= 2 后自带 json 解析功能。\n\n# 使用方式\n\n目前组件总共有两种主题：Material 主题和经典主题\n\n> 在使用组件的时候，记得要引入对应主题的 CSS 文件\n\n```javascript\n// 基本使用方式\n// 假设要在某个组件里使用该插件 (SomeComponent)\nimport React from 'react';\nimport TimePicker from 'react-times';\n\n// 使用 Material 主题的话引入：\nimport 'react-times/css/material/default.css';\n// 否则经典主题的话则引入：\nimport 'react-times/css/classic/default.css';\n\nexport default class SomeComponent extends React.Component {\n  onTimeChange(options) {\n    // do something\n  }\n\n  onFocusChange(focusStatue) {\n    // do something\n  }\n\n  render() {\n    <TimePicker\n      onFocusChange={this.onFocusChange.bind(this)}\n      onTimeChange={this.onTimeChange.bind(this)}\n      // 确定主题，不填该 props 则默认为 material\n      theme=\"material\"\n      // or\n      // theme=\"classic\"\n    />\n  }\n}\n```\n\n关于配置的栗子：\n\n```javascript\nrender() {\n  <TimePicker\n      colorPalette=\"dark\" // main color, default \"light\"\n      focused={true} // whether to show timepicker modal after rendered. default false\n      withoutIcon={true} // whether to has time icon on button, default false\n      time=\"13:05\" // initial time, default current time\n      theme=\"material\"\n      // or\n      // theme=\"classic\"\n      timeMode=\"12\" // use 24 or 12 hours mode, default 24\n  />\n}\n```\n\n> 你可以戳 [这里](https://github.com/ecmadao/react-times/tree/master/examples) 查看更多栗子\n\n# 秀一下\n\n- 24 小时制，亮色调的 Material 主题（默认）\n\n```javascript\n<TimePicker />\n```\n\n![24HoursMode](./doc/intro_src/24HoursMode.png)\n\n- 12 小时制，亮色调的 Material 主题\n\n```javascript\n<TimePicker timeMode=\"12\"/>\n```\n\n![12HoursMode](./doc/intro_src/12HoursMode.png)\n\n- 24 小时制，暗色调的 Material 主题\n\n```javascript\n<TimePicker colorPalette=\"dark\"/>\n```\n\n![DarkColor](./doc/intro_src/DarkColor.png)\n\n- 24 小时制，展示用户当前时区。（除此以外，可以通过 `timezone` props 来手动改变时区）\n\n```javascript\n<TimePicker showTimezone={true}/>\n```\n\n![showTimezone](./doc/intro_src/24HoursMode-showTimezone.png)\n\n- 24 小时制，亮色调的经典主题\n\n```javascript\n<TimePicker theme=\"classic\"/>\n```\n\n![24HoursMode-ClassicTheme](./doc/intro_src/24HoursMode-ClassicTheme.png)\n\n- 24 小时制，暗色调的经典主题\n\n```javascript\n<TimePicker colorPalette=\"dark\" theme=\"classic\"/>\n```\n\n![24HoursMode-ClassicTheme-dark](./doc/intro_src/24HoursMode-ClassicTheme-dark.png)\n\n# APIs\n\n## Props\n\n- `time`\n\n> 初始化时的时间，格式是 `${hour}:${minute}`，不传则默认使用当前时间（通过`moment()`）\n\n```javascript\n// PropTypes.string\ntime=\"11:11\"\ntime=\"11:01\"\ntime=\"1:01\"\ntime=\"1:1\"\n```\n\n- `timeFormat`\n\n> 自定义时间的格式\n\n```javascript\n// PropTypes.string\n// HH, MM 代表 24 小时制\n// hh, mm 代表 12 小时制\ntimeFormat='HH:MM'\ntimeFormat='hh:mm'\n\n// Warning:\n// 如果设定 timeMode 为 12 小时制，且 timeFormat 中含有 hh 或者 mm；\n// 或者设定 timeMode 为 24 小时制，且 timeFormat 中含有 HH 或者 MM，\n// 则会在浏览器控制台中输出一条警告，且时间格式会被转换为 timeMode 所设定的格式\n\n// 因此，如果想把 timeFormat 设定为 hh:mm 或者 h:m，则还需要把 timeMode 设置为 12\n// (因为 timeMode 默认为 24)\n```\n\n- `timeFormatter`\n\n> 自定义时间的格式\n\n```javascript\n// PropTypes.func\ntimeFormatter={({ hour, minute, meridiem }) => `${hour} - ${minute}`}\n\n// 注:\n// 当同时设定了 timeFormat 和 timeFormatter 时（都合法），会使用 timeFormatter\n```\n\n- `focused`\n\n> 初始化时时间选择器的 modal 是否打开，默认为`false`\n\n```javascript\n// PropTypes.bool\nfocused={false}\nfocused={true}\n```\n\n- `withoutIcon`\n\n> 时间选择器的按钮上是否不需要 svg icon，默认为`false`\n\n```javascript\n// PropTypes.bool\nwithoutIcon={true}\n```\n\n- `colorPalette`\n\n> 配色方案，默认为`light`\n\n```javascript\n// PropTypes.string\ncolorPalette=\"dark\"\ncolorPalette=\"light\"\n```\n\n- `timeMode`\n\n> 12 或 24 小时制，默认为 24\n\n```javascript\n// PropTypes.string or PropTypes.number\ntimeMode=\"24\"\ntimeMode=24\ntimeMode=\"12\"\ntimeMode=12\n```\n\n- `meridiem`\n\n> 上下午，在 12 小时制里为 \"AM\" 或 \"PM\"。默认为 `AM`\n\n- `showTimezone`\n\n> `PropTypes.bool`，代表是否展示用户的时区。默认为 `false`\n\n- `timezone`\n\n> `PropTypes.string`，可以通过该 props 改变用户所处的时区。默认为用户当前本地时区。\n\n- `trigger`\n\n> 开启、关闭时间选择器 Modal 的触发器，是一个 React Component\n\n```javascript\n<TimePicker\n  focused={focused}\n  trigger={(\n    <div\n      onClick={this.handleFocusedChange.bind(this)} >\n      click to open modal\n    </div>\n  )}\n/>\n```\n\n- `closeOnOutsideClick`\n\n> 点击 Modal 外部后是否关闭。默认为 true\n\n```\n<TimePicker\n  closeOnOutsideClick={false}\n/>\n```\n\n- `disabled`\n\n> 禁用组件。默认为 false\n\n```\n<TimePicker\n  disabled={true}\n/>\n```\n\n- `draggable`\n\n如果想禁用拖拽，则可以设置 `draggable` 为 `false`，那样的话用户只能通过点击来改变时间。默认为 `true`\n\n```\n<TimePicker\n  draggable={true}\n/>\n```\n\n- `language`\n\n> 语言。默认为英语\n\n```javascript\n/*\n * support\n * en: english\n * zh-cn: 中文简体\n * zh-tw: 中文繁体\n * fr: Français\n * ja: 日本語\n */\n<TimePicker\n  language=\"zh-cn\" // 中文简体\n/>\n```\n\n- `phrases`\n\n> `React.object`，用于自定义一些短语。可以在 [language.js](./src/utils/language.js) 查看所有的默认短语\n\n```javascript\n<TimePicker\n  phrases={{\n    confirm: '确认更改？',\n    cancel: '确认取消？',\n    close: 'DONE',\n    am: '上午',\n    pm: '下午'\n  }}\n/>\n```\n\n- `minuteStep`\n\n> `React.number`, 默认为 `5`。该属性代表当分针改变时的最小步长(minute)。可以设置为 1，2，3....\n\n```javascript\n<TimePicker\n  minuteStep={1}\n/>\n```\n\n- `timeConfig`\n\n> `React.object`, 用于配置 classic theme 时可选的时间范围以及步长\n\n```javascript\n<TimePicker\n  theme=\"classic\"\n  timeMode=\"12\"\n  timeConfig={{\n    from: '08:00 PM',\n    to: '08:00 AM',\n    step: 1,\n    unit: 'hour'\n  }}\n/>\n\n<TimePickerWrapper\n  theme=\"classic\"\n  timeMode=\"24\"\n  timeConfig={{\n    from: 9,\n    to: 19,\n    step: 30,\n    unit: 'minutes'\n  }}\n/>\n```\n\n- `limitDrag`\n\n> `React.bool`, 默认为 `false`. 当设置为 `true` 时，将会限制用户的拖拽（从连续性的拖拽变为间断性拖拽，间隔由 `minuteStep` 确定）\n\n```javascript\n<TimePicker\n  limitDrag\n/>\n```\n\n## 回调\n\n- `onFocusChange`\n\n`PropTypes.func`\n\n> 当组件`focused`属性改变，也就是选择器 modal 被打开或关闭时调用\n\n- `onTimeChange`\n\n`PropTypes.func`\n\n> 小时`hour`，分钟`minute`或者上下午`meridiem`被改变时的回调\n\n```javascript\nonTimeChange(options) {\n  const {\n    hour,\n    minute,\n    meridiem\n  } = options;\n  // ...\n}\n```\n\n- `onTimezoneChange`\n\n`PropTypes.func`\n\n> 当时区改变时的回调\n\n# 相关文章\n\n- [一言不合造轮子--撸一个ReactTimePicker](https://github.com/ecmadao/Coding-Guide/blob/master/Notes/React/ReactJS/Write%20a%20React%20Timepicker%20Component%20hand%20by%20hand.md)\n\n# Todos\n\n- 测试\n\n  - [x] TimePicker Component\n  - [x] PickerDragHandler Component\n  - [x] PickerPointGenerator Component\n  - [x] MaterialTheme Component\n  - [x] TwelveHoursTheme Component\n  - [x] PickerPoint Component\n  - [x] OutsideClickHandler Component\n\n  - [x] utils test\n\n- 配色\n\n  - [x] light\n  - [x] dark\n  - [ ] colorful\n\n- 主题\n\n  - [x] Material Theme\n  - [x] Classical Theme\n\n- 小时制\n\n  - [x] 12h mode\n  - [x] 24h mode\n\n- 动画\n\n# 致谢\n\n感谢 Airbnb 的 [react-dates](https://github.com/airbnb/react-dates) 组件，没有它我也不会想着写一个小时选择组件\n\n# 核心贡献者 🎉\n\n- **[carlodicelico](https://github.com/carlodicelico)**\n- **[erin-doyle](https://github.com/erin-doyle)**\n- **[MatthieuLemoine](https://github.com/MatthieuLemoine)**\n- **[naseeihity](https://github.com/naseeihity)**\n- **[shianqi](https://github.com/shianqi)**\n- **[thg303](https://github.com/thg303)**\n\n# 版权\n\n[MIT License](./LICENSE)\n"
  },
  {
    "path": "examples/TimePickerWrapper.js",
    "content": "\nimport React from 'react';\nimport TimePicker from '../src/components/TimePicker';\nimport timeHelper from '../src/utils/time';\nimport ICONS from '../src/utils/icons';\n\nclass TimePickerWrapper extends React.Component {\n  constructor(props) {\n    super(props);\n    const { defaultTime, meridiem, focused, showTimezone, timezone } = props;\n    let hour = '';\n    let minute = '';\n    if (!defaultTime) {\n      [hour, minute] = timeHelper.current().split(/:/);\n    } else {\n      [hour, minute] = defaultTime.split(/:/);\n    }\n\n    this.state = {\n      hour,\n      minute,\n      meridiem,\n      focused,\n      timezone,\n      showTimezone,\n    };\n\n    this.onFocusChange = this.onFocusChange.bind(this);\n    this.onTimeChange = this.onTimeChange.bind(this);\n    this.handleFocusedChange = this.handleFocusedChange.bind(this);\n  }\n\n  onTimeChange(options) {\n    const {\n      hour,\n      minute,\n      meridiem\n    } = options;\n\n    this.setState({ hour, minute, meridiem });\n  }\n\n  onFocusChange(focused) {\n    console.log(`onFocusChange: ${focused}`);\n    this.setState({ focused });\n  }\n\n  handleFocusedChange() {\n    const { focused } = this.state;\n    this.setState({ focused: !focused });\n  }\n\n  get basicTrigger() {\n    const { hour, minute } = this.state;\n    return (\n      <div\n        onClick={this.handleFocusedChange}\n        className=\"time_picker_trigger\"\n      >\n        <div>\n          Click to open panel<br />\n          {hour}:{minute}\n        </div>\n      </div>\n    );\n  }\n\n  get customTrigger() {\n    return (\n      <div\n        onClick={this.handleFocusedChange}\n        className=\"time_picker_trigger\"\n      >\n        {ICONS.time}\n      </div>\n    );\n  }\n\n  get trigger() {\n    const { customTriggerId } = this.props;\n    const triggers = {\n      0: (<div />),\n      1: this.basicTrigger,\n      2: this.customTrigger\n    };\n    return triggers[customTriggerId] || null;\n  }\n\n  render() {\n    const {\n      hour,\n      minute,\n      focused,\n      meridiem,\n      timezone,\n      showTimezone,\n    } = this.state;\n\n    return (\n      <div className=\"time_picker_wrapper\">\n        <TimePicker\n          trigger={this.trigger}\n          {...this.props}\n          focused={focused}\n          meridiem={meridiem}\n          timezone={timezone}\n          onFocusChange={this.onFocusChange}\n          onTimeChange={this.onTimeChange}\n          showTimezone={showTimezone}\n          time={hour && minute ? `${hour}:${minute}` : null}\n        />\n      </div>\n    );\n  }\n}\n\nTimePickerWrapper.defaultProps = {\n  customTriggerId: null,\n  defaultTime: null,\n  focused: false,\n  meridiem: null,\n  showTimezone: false\n};\n\nexport default TimePickerWrapper;\n"
  },
  {
    "path": "examples/TimePickerWrapper2.js",
    "content": "\nimport React from 'react';\nimport TimePicker from '../src/components/TimePicker';\nimport timeHelper from '../src/utils/time';\nimport ICONS from '../src/utils/icons';\n\nclass TimePickerWrapper extends React.Component {\n  constructor(props) {\n    super(props);\n    const { defaultTime, meridiem, focused, showTimezone, timezone } = props;\n    let hour = '';\n    let minute = '';\n    if (!defaultTime) {\n      [hour, minute] = timeHelper.current().split(/:/);\n    } else {\n      [hour, minute] = defaultTime.split(/:/);\n    }\n\n    this.state = {\n      1: {\n        hour,\n        minute,\n        meridiem,\n        focused,\n        timezone,\n        showTimezone,\n      },\n      2: {\n        hour,\n        minute,\n        meridiem,\n        focused,\n        timezone,\n        showTimezone,\n      }\n    };\n\n    this.onFocusChange = this.onFocusChange.bind(this);\n    this.onTimeChange = this.onTimeChange.bind(this);\n    this.handleFocusedChange = this.handleFocusedChange.bind(this);\n  }\n\n  onTimeChange(section) {\n\n    return (options) => {\n      const {\n        hour,\n        minute,\n        meridiem\n      } = options;\n\n      this.setState({\n        [section]: Object.assign({}, this.state[section], {\n          hour, minute, meridiem\n        })\n      });\n    };\n  }\n\n  onFocusChange(section) {\n    return focused => this.setState({\n      [section]: Object.assign({}, this.state[section], {\n        focused\n      })\n    });\n  }\n\n  handleFocusedChange(section) {\n    return () => this.setState({\n      [section]: Object.assign({}, this.state[section], {\n        focused: !this.state[section].focused\n      })\n    });\n  }\n\n  getBasicTrigger() {\n    const { hour, minute } = this.state;\n    return (\n      <div\n        onClick={this.handleFocusedChange}\n        className=\"time_picker_trigger\"\n      >\n        <div>\n          Click to open panel<br />\n          {hour}:{minute}\n        </div>\n      </div>\n    );\n  }\n\n  getCustomTrigger() {\n    return (\n      <div\n        onClick={this.handleFocusedChange}\n        className=\"time_picker_trigger\"\n      >\n        {ICONS.time}\n      </div>\n    );\n  }\n\n  getTrigger(section) {\n    const { customTriggerId } = this.props;\n    const triggers = {\n      0: (<div />),\n      1: this.getBasicTrigger(section),\n      2: this.getCustomTrigger()\n    };\n    return triggers[customTriggerId] || null;\n  }\n\n  renderTrigger(section) {\n    const {\n      hour,\n      minute,\n      focused,\n      meridiem,\n      timezone,\n      showTimezone,\n    } = this.state[section];\n\n    return (\n      <TimePicker\n        id={section}\n        trigger={this.getTrigger(section)}\n        {...this.props}\n        focused={focused}\n        meridiem={meridiem}\n        timezone={timezone}\n        onFocusChange={this.onFocusChange(section)}\n        onTimeChange={this.onTimeChange(section)}\n        showTimezone={showTimezone}\n        time={hour && minute ? `${hour}:${minute}` : null}\n      />\n    );\n  }\n\n  render() {\n    return (\n      <div className=\"time_picker_wrapper2\">\n        {this.renderTrigger(1)}\n        <div className=\"gap\" />\n        {this.renderTrigger(2)}\n      </div>\n    );\n  }\n}\n\nTimePickerWrapper.defaultProps = {\n  customTriggerId: null,\n  defaultTime: null,\n  focused: false,\n  meridiem: null,\n  showTimezone: false\n};\n\nexport default TimePickerWrapper;\n"
  },
  {
    "path": "examples/TimeZonesPickerWrapper.js",
    "content": "\nimport React from 'react';\nimport Timezone from '../src/components/Timezone';\nimport timeHelper from '../src/utils/time';\nimport languageHelper from '../src/utils/language';\n\nconst TIME = timeHelper.time();\nTIME.current = timeHelper.current();\nTIME.tz = timeHelper.guessUserTz();\n\nconst style = {\n  width: '300px',\n  position: 'absolute',\n  left: '50%',\n  top: '100px',\n  transform: 'translateX(-50%)'\n};\n\nclass TimeZonesPickerWrapper extends React.Component {\n  constructor(props) {\n    super(props);\n    const {timezone} = this.props;\n\n    this.state = {\n      timezone\n    };\n  }\n\n  languageData() {\n    const {language = 'en', phrases = {}} = this.props;\n    return Object.assign({}, languageHelper.get(language), phrases);\n  }\n\n  render() {\n    const {timezone} = this.state;\n    const {onTimezoneChange} = this.props;\n\n    return (\n      <div style={style}>\n        <div className=\"outside_container active\">\n          <div className='time_picker_modal_container'>\n            <Timezone\n              phrases={this.languageData()}\n              timezone={timezone}\n              timezoneIsEditable={true}\n              onTimezoneChange={onTimezoneChange}\n            />\n          </div>\n        </div>\n      </div>\n    )\n  }\n}\n\nTimeZonesPickerWrapper.defaultProps = {\n  timezone: TIME.tz\n};\n\nexport default TimeZonesPickerWrapper;\n"
  },
  {
    "path": "index.js",
    "content": "require('./lib/utils/time').default;\nvar TimePicker = require('./lib/components/TimePicker').default;\n\nmodule.exports = TimePicker;\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-times\",\n  \"description\": \"A react time-picker component, no jquery-rely\",\n  \"version\": \"3.1.12\",\n  \"author\": \"ecmadao\",\n  \"bugs\": {\n    \"url\": \"https://github.com/ecmadao/react-times/issues\"\n  },\n  \"dependencies\": {\n    \"classnames\": \"^2.2.6\",\n    \"prop-types\": \"^15.6.0\",\n    \"react-bootstrap-typeahead\": \"^2.4.0\",\n    \"react-transition-group\": \"^2.2.1\"\n  },\n  \"peerDependencies\": {\n    \"moment\": \"^2.19.1\",\n    \"moment-timezone\": \"^0.5.14\",\n    \"react\": \"^16.2.0\",\n    \"react-dom\": \"^16.2.0\"\n  },\n  \"devDependencies\": {\n    \"@storybook/addon-info\": \"^3.3.14\",\n    \"@storybook/addon-knobs\": \"^3.3.14\",\n    \"@storybook/addons\": \"^3.3.14\",\n    \"@storybook/react\": \"^3.3.12\",\n    \"@storybook/storybook-deployer\": \"^2.2.0\",\n    \"babel-cli\": \"^6.14.0\",\n    \"babel-core\": \"^6.14.0\",\n    \"babel-eslint\": \"^6.1.2\",\n    \"babel-loader\": \"^7.1.2\",\n    \"babel-plugin-system-import-transformer\": \"^3.1.0\",\n    \"babel-polyfill\": \"^6.16.0\",\n    \"babel-preset-env\": \"^1.6.1\",\n    \"babel-preset-react\": \"^6.11.1\",\n    \"babel-preset-stage-0\": \"^6.16.0\",\n    \"babel-register\": \"^6.14.0\",\n    \"chai\": \"^3.5.0\",\n    \"coveralls\": \"^2.13.1\",\n    \"enzyme\": \"^3.3.0\",\n    \"enzyme-adapter-react-16\": \"^1.1.1\",\n    \"eslint\": \"^3.17.1\",\n    \"eslint-config-standard\": \"^7.0.1\",\n    \"eslint-loader\": \"^1.6.3\",\n    \"eslint-plugin-babel\": \"^4.1.1\",\n    \"eslint-plugin-import\": \"^2.2.0\",\n    \"eslint-plugin-promise\": \"^3.5.0\",\n    \"eslint-plugin-react\": \"^6.10.0\",\n    \"eslint-plugin-standard\": \"^2.1.1\",\n    \"husky\": \"^0.14.3\",\n    \"in-publish\": \"^2.0.0\",\n    \"jsdom\": \"^11.6.2\",\n    \"mocha\": \"^3.3.0\",\n    \"mocha-lcov-reporter\": \"^1.3.0\",\n    \"moment\": \"^2.22.0\",\n    \"moment-timezone\": \"^0.5.14\",\n    \"react\": \"^16.3.1\",\n    \"react-dom\": \"^16.3.1\",\n    \"react-svg-loader\": \"^2.1.0\",\n    \"rimraf\": \"^2.6.1\",\n    \"safe-publish-latest\": \"^1.1.1\",\n    \"sinon\": \"^2.2.0\",\n    \"sinon-sandbox\": \"^1.0.2\",\n    \"style-loader\": \"^0.20.1\",\n    \"webpack\": \"3.10.0\"\n  },\n  \"homepage\": \"https://github.com/ecmadao/react-times#readme\",\n  \"keywords\": [\n    \"react\",\n    \"reactjs\",\n    \"time picker\",\n    \"time-picker\",\n    \"timepicker\"\n  ],\n  \"license\": \"MIT\",\n  \"main\": \"index.js\",\n  \"maintainers\": [\n    {\n      \"email\": \"wlec@outlook.com\",\n      \"name\": \"ecmadao\"\n    },\n    {\n      \"email\": \"carlodicelico@gmail.com\",\n      \"name\": \"carlodicelico\"\n    }\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/ecmadao/react-times.git\"\n  },\n  \"scripts\": {\n    \"babel\": \"babel ./src --out-dir ./lib\",\n    \"build\": \"npm run clean && npm run babel\",\n    \"build:js\": \"babel src/ -d lib/ --ignore src/components\",\n    \"clean\": \"rimraf lib\",\n    \"coveralls\": \"cat ./coverage/lcov/lcov.info | ./node_modules/.bin/coveralls\",\n    \"deploy-storybook\": \"storybook-to-ghpages\",\n    \"eslint\": \"./node_modules/eslint/bin/eslint.js src\",\n    \"mocha\": \"./node_modules/mocha/bin/mocha --recursive ./test/_helpers --compilers js:babel-register,jsx:babel-register\",\n    \"postversion\": \"git commit package.json -m \\\"Version $npm_package_version\\\" && npm run tag && git push && git push --tags && npm publish --registry=https://registry.npmjs.org/\",\n    \"prepublish\": \"in-publish && safe-publish-latest && npm run build || not-in-publish\",\n    \"pretest\": \"npm run --silent eslint\",\n    \"scratch\": \"test/components/TwelveHoursTheme_spec.jsx\",\n    \"storybook\": \"start-storybook -p 9001 -c .storybook\",\n    \"storybook-deploy\": \"npm i && npm run storybook-pro && npm run deploy-storybook\",\n    \"storybook-pro\": \"build-storybook -c .storybook -o .out\",\n    \"tag\": \"git tag v$npm_package_version\",\n    \"test\": \"npm run mocha --silent test\",\n    \"test:watch\": \"npm run mocha test -- --watch\",\n    \"lint\": \"./node_modules/.bin/eslint ./src && ./node_modules/.bin/eslint ./test && ./node_modules/.bin/eslint ./stories\",\n    \"prepush\": \"npm run lint && npm test\"\n  }\n}\n"
  },
  {
    "path": "src/components/ClassicTheme/index.jsx",
    "content": "\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport timeHelper from '../../utils/time';\n\nconst propTypes = {\n  hour: PropTypes.string,\n  minute: PropTypes.string,\n  timeMode: PropTypes.number,\n  meridiem: PropTypes.string,\n  clearFocus: PropTypes.func,\n  colorPalette: PropTypes.string,\n  handleTimeChange: PropTypes.func,\n  handleMeridiemChange: PropTypes.func,\n  focusDropdownOnTime: PropTypes.bool,\n};\n\nconst defaultProps = {\n  hour: '00',\n  minute: '00',\n  timeMode: 24,\n  meridiem: 'AM',\n  colorPalette: 'light',\n  clearFocus: Function.prototype,\n  handleTimeChange: Function.prototype,\n  handleMeridiemChange: Function.prototype,\n  focusDropdownOnTime: false,\n};\n\nclass ClassicTheme extends React.PureComponent {\n  constructor(props) {\n    super(props);\n    this.handleTimeChange = this.handleTimeChange.bind(this);\n    this.handleFocusDropdownOnTime = this.handleFocusDropdownOnTime.bind(this);\n    this.dropDown = React.createRef();\n    this.dropDownActiveTime = React.createRef();\n  }\n\n  componentDidMount() {\n    this.handleFocusDropdownOnTime();\n  }\n  componentDidUpdate() {\n    this.handleFocusDropdownOnTime();\n  }\n\n  handleFocusDropdownOnTime() {\n    if (this.props.focusDropdownOnTime) {\n      this.dropDown.current.scrollTop = this.dropDownActiveTime && this.dropDownActiveTime.current && this.dropDownActiveTime.current.offsetTop || 0;\n    }\n  }\n\n  handleTimeChange(timeData) {\n    const [time, meridiem] = timeData.split(' ');\n    const [hour, minute] = time.split(':');\n    const { handleTimeChange, clearFocus } = this.props;\n    handleTimeChange && handleTimeChange({\n      hour,\n      minute,\n      meridiem: meridiem || null\n    });\n    clearFocus && clearFocus();\n  }\n\n  checkTimeIsActive(time) {\n    const { hour, minute, meridiem } = this.props;\n    const [times, rawMeridiem] = time.split(' ');\n    const [rawHour, rawMinute] = times.split(':');\n    const currentHour = timeHelper.validate(rawHour);\n    const currentMinute = timeHelper.validate(rawMinute);\n\n    if (parseInt(hour, 10) !== parseInt(currentHour, 10)) {\n      return false;\n    }\n    if (meridiem && meridiem !== rawMeridiem) {\n      return false;\n    }\n    if (Math.abs(parseInt(minute, 10) - parseInt(currentMinute, 10)) < 15) {\n      return true;\n    }\n    return false;\n  }\n\n  renderTimes(timeDatas) {\n    const { colorPalette, focusDropdownOnTime } = this.props;\n\n    return timeDatas.map((timeData, index) => {\n      const timeClass = this.checkTimeIsActive(timeData)\n        ? 'classic_time active'\n        : 'classic_time';\n      const [time, meridiem] = timeData.split(' ');\n      return (\n        <div\n          key={index}\n          onClick={() => {\n            this.handleTimeChange(timeData);\n          }}\n          className={`${timeClass} ${colorPalette}`}\n          ref={this.checkTimeIsActive(timeData) ? this.dropDownActiveTime : null}\n        >\n          {time}\n          {meridiem ? <span className=\"meridiem\">{meridiem}</span> : null}\n        </div>\n      );\n    });\n  }\n\n  render() {\n    const { timeMode, timeConfig = {} } = this.props;\n    const timeDatas = timeMode === 12\n      ? timeHelper.get12ModeTimes(timeConfig)\n      : timeHelper.get24ModeTimes(timeConfig);\n\n    return (\n      <div\n        className=\"modal_container classic_theme_container\"\n        ref={this.dropDown}\n      >\n        {this.renderTimes(timeDatas)}\n      </div>\n    );\n  }\n}\n\nClassicTheme.propTypes = propTypes;\nClassicTheme.defaultProps = defaultProps;\n\nexport default ClassicTheme;\n"
  },
  {
    "path": "src/components/Common/AsyncComponent.jsx",
    "content": "\nimport React from 'react';\n\nconst asyncComponent = getComponent =>\n  class AsyncComponent extends React.Component {\n    static Component = null;\n    state = { Component: AsyncComponent.Component };\n\n    componentWillMount() {\n      if (!this.state.Component) {\n        getComponent().then(Component => {\n          AsyncComponent.Component = Component;\n          this.setState({ Component });\n        });\n      }\n    }\n    render() {\n      const { Component } = this.state;\n      if (Component) {\n        return <Component {...this.props} />;\n      }\n      return null;\n    }\n  }\n\nexport default asyncComponent;\n"
  },
  {
    "path": "src/components/Common/Button.jsx",
    "content": "\nimport React from 'react';\nimport cx from 'classnames';\nimport PropTypes from 'prop-types';\n\nclass Button extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      pressed: false\n    };\n\n    this.onMouseUp = this.onMouseUp.bind(this);\n    this.onMouseDown = this.onMouseDown.bind(this);\n    this.onMouseEnter = this.onMouseEnter.bind(this);\n    this.onMouseLeave = this.onMouseLeave.bind(this);\n  }\n\n  onMouseDown() {\n    this.setState({ pressed: true });\n  }\n\n  onMouseUp() {\n    this.setState({ pressed: false });\n  }\n\n  onMouseEnter() {\n    const { onMouseEnter } = this.props;\n    onMouseEnter && onMouseEnter();\n  }\n\n  onMouseLeave() {\n    this.onMouseUp();\n    const { onMouseLeave } = this.props;\n    onMouseLeave && onMouseLeave();\n  }\n\n  render() {\n    const {\n      onClick,\n      children,\n      className,\n    } = this.props;\n    const { pressed } = this.state;\n\n    const buttonClass = cx(\n      'react_times_button',\n      pressed && 'pressDown',\n      className\n    );\n\n    return (\n      <div\n        onClick={onClick}\n        className={buttonClass}\n        onMouseUp={this.onMouseUp}\n        onMouseOut={this.onMouseUp}\n        onMouseDown={this.onMouseDown}\n        onMouseLeave={this.onMouseLeave}\n        onMouseEnter={this.onMouseEnter}\n      >\n        <div className=\"wrapper\">\n          {children}\n        </div>\n      </div>\n    );\n  }\n}\n\nButton.propTypes = {\n  text: PropTypes.string,\n  onClick: PropTypes.func,\n  children: PropTypes.oneOfType([\n    PropTypes.element,\n    PropTypes.node,\n    PropTypes.array,\n    PropTypes.string\n  ]),\n  className: PropTypes.string,\n};\n\nButton.defaultProps = {\n  text: 'button',\n  onClick: Function.prototype,\n  children: null,\n  className: '',\n};\n\nexport default Button;\n"
  },
  {
    "path": "src/components/MaterialTheme/TwelveHoursMode.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport {\n  MINUTES,\n  TWELVE_HOURS,\n  PICKER_RADIUS,\n  POINTER_RADIUS,\n  MAX_ABSOLUTE_POSITION,\n  MIN_ABSOLUTE_POSITION,\n} from '../../utils/constant.js';\nimport timeHelper from '../../utils/time';\nimport Button from '../Common/Button';\nimport PickerDragHandler from '../Picker/PickerDragHandler';\nimport pickerPointGenerator from '../Picker/PickerPointGenerator';\n\nconst TIME = timeHelper.time();\n\nconst propTypes = {\n  hour: PropTypes.string,\n  language: PropTypes.string,\n  minute: PropTypes.string,\n  draggable: PropTypes.bool,\n  meridiem: PropTypes.string,\n  phrases: PropTypes.object,\n  handleHourChange: PropTypes.func,\n  handleMinuteChange: PropTypes.func,\n};\n\nconst defaultProps = {\n  hour: TIME.hour12,\n  language: 'en',\n  minute: TIME.minute,\n  draggable: false,\n  meridiem: TIME.meridiem,\n  handleHourChange: Function.prototype,\n  handleMinuteChange: Function.prototype,\n};\n\nclass TwelveHoursMode extends React.PureComponent {\n  constructor(props) {\n    super(props);\n    const hourPointerRotate = this.resetHourDegree();\n    const minutePointerRotate = this.resetMinuteDegree();\n    this.state = {\n      hourPointerRotate,\n      minutePointerRotate\n    };\n\n    this.handleHourChange = this.handleHourChange.bind(this);\n    this.handleMinuteChange = this.handleMinuteChange.bind(this);\n    this.handleDegreeChange = this.handleDegreeChange.bind(this);\n    this.handleMeridiemChange = this.handleMeridiemChange.bind(this);\n    this.handleHourPointerClick = this.handleHourPointerClick.bind(this);\n    this.handleMinutePointerClick = this.handleMinutePointerClick.bind(this);\n  }\n\n  resetHourDegree() {\n    const hour = parseInt(this.props.hour, 10);\n    let pointerRotate = 0;\n    TWELVE_HOURS.forEach((h, index) => {\n      if (hour === index + 1) {\n        pointerRotate = (360 * (index + 1)) / 12;\n      }\n    });\n    return pointerRotate;\n  }\n\n  resetMinuteDegree() {\n    const minute = parseInt(this.props.minute, 10);\n    let pointerRotate = 0;\n    MINUTES.forEach((m, index) => {\n      if (minute === index) {\n        pointerRotate = (360 * index) / 60;\n      }\n    });\n    return pointerRotate;\n  }\n\n  getHourTopAndHeight() {\n    const height = MIN_ABSOLUTE_POSITION - POINTER_RADIUS;\n    const top = (PICKER_RADIUS - MIN_ABSOLUTE_POSITION) + POINTER_RADIUS;\n    return [top, height];\n  }\n\n  getMinuteTopAndHeight() {\n    const height = MAX_ABSOLUTE_POSITION - POINTER_RADIUS;\n    const top = (PICKER_RADIUS - MAX_ABSOLUTE_POSITION) + POINTER_RADIUS;\n    return [top, height];\n  }\n\n  handleMeridiemChange() {\n    const { meridiem, phrases } = this.props;\n    const newMeridiem = (meridiem === 'AM' || meridiem === phrases.am)\n      ? phrases.pm\n      : phrases.am;\n    if (newMeridiem !== meridiem) {\n      const { handleMeridiemChange } = this.props;\n      handleMeridiemChange && handleMeridiemChange(newMeridiem);\n    }\n  }\n\n  handleHourPointerClick(options) {\n    const {\n      time,\n      pointerRotate = null,\n    } = options;\n    this.handleHourChange(time);\n    pointerRotate !== null && this.handleDegreeChange({ hourPointerRotate: pointerRotate });\n  }\n\n  handleMinutePointerClick(options) {\n    const {\n      time,\n      pointerRotate = null,\n    } = options;\n    this.handleMinuteChange(time);\n    pointerRotate !== null && this.handleDegreeChange({ minutePointerRotate: pointerRotate });\n  }\n\n  handleDegreeChange(pointerRotate) {\n    this.setState(pointerRotate);\n  }\n\n  handleHourChange(time) {\n    const hour = parseInt(time, 10);\n    const { handleHourChange } = this.props;\n    handleHourChange && handleHourChange(hour);\n  }\n\n  handleMinuteChange(time) {\n    const minute = parseInt(time, 10);\n    const { handleMinuteChange } = this.props;\n    handleMinuteChange && handleMinuteChange(minute);\n  }\n\n  render() {\n    const {\n      hour,\n      minute,\n      phrases,\n      timeMode,\n      meridiem,\n      draggable,\n      clearFocus,\n      limitDrag,\n      minuteStep,\n      showTimezone,\n    } = this.props;\n\n    const { hourPointerRotate, minutePointerRotate } = this.state;\n\n    const [top, height] = this.getHourTopAndHeight();\n    const hourRotateState = {\n      top,\n      height,\n      pointerRotate: hourPointerRotate\n    };\n    const [minuteTop, minuteHeight] = this.getMinuteTopAndHeight();\n    const minuteRotateState = {\n      top: minuteTop,\n      height: minuteHeight,\n      pointerRotate: minutePointerRotate\n    };\n\n    const HourPickerPointGenerator = pickerPointGenerator('hour', 12);\n    const MinutePickerPointGenerator = pickerPointGenerator('minute', 12);\n\n    return (\n      <React.Fragment>\n        <div className=\"time_picker_modal_header\">\n          <span className=\"time_picker_header active\">\n            {hour}:{minute}\n          </span>&nbsp;\n          <span\n            onClick={this.handleMeridiemChange}\n            className=\"time_picker_header meridiem\"\n          >\n            {meridiem}\n          </span>\n        </div>\n        <div className=\"picker_container\">\n          <HourPickerPointGenerator\n            handleTimePointerClick={this.handleHourPointerClick}\n            pointerRotate={hourPointerRotate}\n          />\n          <MinutePickerPointGenerator\n            handleTimePointerClick={this.handleMinutePointerClick}\n            pointerRotate={minutePointerRotate}\n          />\n          <PickerDragHandler\n            step={1}\n            timeMode={timeMode}\n            limitDrag={limitDrag}\n            minuteStep={minuteStep}\n            rotateState={minuteRotateState}\n            time={parseInt(minute, 10)}\n            minLength={MAX_ABSOLUTE_POSITION}\n            draggable={draggable}\n            handleTimePointerClick={this.handleMinutePointerClick}\n          />\n          <PickerDragHandler\n            step={0}\n            timeMode={timeMode}\n            limitDrag={limitDrag}\n            minuteStep={minuteStep}\n            rotateState={hourRotateState}\n            time={parseInt(hour, 10)}\n            maxLength={MIN_ABSOLUTE_POSITION}\n            draggable={draggable}\n            handleTimePointerClick={this.handleHourPointerClick}\n          />\n        </div>\n        {!showTimezone ? (\n          <div className=\"buttons_wrapper\">\n            <Button\n              onClick={clearFocus}\n              className=\"time_picker_button\"\n            >\n              {phrases.close}\n            </Button>\n          </div>\n        ) : null}\n      </React.Fragment>\n    );\n  }\n}\n\nTwelveHoursMode.propTypes = propTypes;\nTwelveHoursMode.defaultProps = defaultProps;\n\nexport default TwelveHoursMode;\n"
  },
  {
    "path": "src/components/MaterialTheme/TwentyFourHoursMode.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport {\n  HOURS,\n  MINUTES,\n  PICKER_RADIUS,\n  POINTER_RADIUS,\n  MAX_ABSOLUTE_POSITION,\n  MIN_ABSOLUTE_POSITION,\n} from '../../utils/constant.js';\nimport PickerDragHandler from '../Picker/PickerDragHandler';\nimport pickerPointGenerator from '../Picker/PickerPointGenerator';\n\nconst propTypes = {\n  step: PropTypes.number,\n  hour: PropTypes.string,\n  autoMode: PropTypes.bool,\n  minute: PropTypes.string,\n  handleHourChange: PropTypes.func,\n  handleMinuteChange: PropTypes.func,\n  clearFocus: PropTypes.func\n};\n\nconst defaultProps = {\n  step: 0,\n  hour: '00',\n  minute: '00',\n  autoMode: true,\n  clearFocus: Function.prototype,\n  handleHourChange: Function.prototype,\n  handleMinuteChange: Function.prototype,\n};\n\nclass TwentyFourHoursMode extends React.PureComponent {\n  constructor(props) {\n    super(props);\n    const pointerRotate = this.resetHourDegree();\n    const { step } = props;\n    this.state = {\n      step,\n      pointerRotate\n    };\n    this.handleStepChange = this.handleStepChange.bind(this);\n    this.handleTimeChange = this.handleTimeChange.bind(this);\n    this.handleTimePointerClick = this.handleTimePointerClick.bind(this);\n  }\n\n  handleStepChange(step) {\n    const stateStep = this.state.step;\n    if (stateStep !== step) {\n      this.pickerPointerContainer && this.pickerPointerContainer.addAnimation();\n      setTimeout(() => {\n        this.pickerPointerContainer && this.pickerPointerContainer.removeAnimation();\n        this.setStep(step);\n      }, 300);\n    }\n  }\n\n  setStep(step) {\n    const pointerRotate = step === 0\n      ? this.resetHourDegree()\n      : this.resetMinuteDegree();\n    this.setState({\n      step,\n      pointerRotate\n    });\n  }\n\n  clearFocus() {\n    const { autoClose, clearFocus } = this.props;\n    autoClose && clearFocus && clearFocus();\n  }\n\n  handleTimePointerClick(options) {\n    const {\n      time,\n      autoMode = null,\n      pointerRotate = null,\n    } = options;\n\n    const isInteger = function(num) {\n      return (num ^ 0) === +num;\n    }\n    if (Number.isInteger) {\n      Number.isInteger(pointerRotate) && this.setState({ pointerRotate: pointerRotate });\n    } else {\n      isInteger(pointerRotate) && this.setState({ pointerRotate: pointerRotate });\n    }\n    this.handleTimeChange(time, autoMode);\n  }\n\n  handleTimeChange(time, autoMode = null) {\n    const validateTime = parseInt(time, 10);\n    const { step } = this.state;\n    const auto = autoMode === null ? this.props.autoMode : autoMode;\n\n    const {\n      handleHourChange,\n      handleMinuteChange,\n    } = this.props;\n\n    if (step === 0) {\n      handleHourChange && handleHourChange(validateTime);\n    } else {\n      handleMinuteChange && handleMinuteChange(validateTime);\n    }\n    if (!auto) return;\n\n    if (step === 0) {\n      this.handleStepChange(1);\n    } else {\n      this.clearFocus();\n      this.setStep(0);\n    }\n  }\n\n  resetHourDegree() {\n    const hour = parseInt(this.props.hour, 10);\n    let pointerRotate = 0;\n    HOURS.forEach((h, index) => {\n      if (hour === index + 1) {\n        pointerRotate = index < 12\n          ? (360 * (index + 1)) / 12\n          : (360 * ((index + 1) - 12)) / 12;\n      }\n    });\n    return pointerRotate;\n  }\n\n  resetMinuteDegree() {\n    const minute = parseInt(this.props.minute, 10);\n    let pointerRotate = 0;\n    MINUTES.forEach((m, index) => {\n      if (minute === index) {\n        pointerRotate = (360 * index) / 60;\n      }\n    });\n    return pointerRotate;\n  }\n\n  getTopAndHeight() {\n    const { step } = this.state;\n    const { hour, minute } = this.props;\n    const time = step === 0 ? hour : minute;\n    const splitNum = step === 0 ? 12 : 60;\n    const minLength = step === 0\n      ? MIN_ABSOLUTE_POSITION\n      : MAX_ABSOLUTE_POSITION;\n    const height = time < splitNum\n      ? minLength - POINTER_RADIUS\n      : MAX_ABSOLUTE_POSITION - POINTER_RADIUS;\n    const top = time < splitNum\n      ? (PICKER_RADIUS - minLength) + POINTER_RADIUS\n      : (PICKER_RADIUS - MAX_ABSOLUTE_POSITION) + POINTER_RADIUS;\n    return [top, height];\n  }\n\n  render() {\n    const {\n      hour,\n      minute,\n      timeMode,\n      draggable,\n      limitDrag,\n      minuteStep,\n    } = this.props;\n\n    const { step, pointerRotate } = this.state;\n\n    const activeHourClass = step === 0\n      ? 'time_picker_header active'\n      : 'time_picker_header';\n    const activeMinuteClass = step === 1\n      ? 'time_picker_header active'\n      : 'time_picker_header';\n    const [top, height] = this.getTopAndHeight();\n    const rotateState = {\n      top,\n      height,\n      pointerRotate\n    };\n    const type = step === 0 ? 'hour' : 'minute';\n    const PickerPointGenerator = pickerPointGenerator(type);\n\n    return (\n      <React.Fragment>\n        <div className=\"time_picker_modal_header\">\n          <span\n            className={activeHourClass}\n            onClick={() => this.handleStepChange(0)}\n          >\n            {hour}\n          </span>\n          <span className=\"time_picker_header_delivery\">:</span>\n          <span\n            className={activeMinuteClass}\n            onClick={() => this.handleStepChange(1)}\n          >\n            {minute}\n          </span>\n        </div>\n        <div className=\"picker_container\">\n          <PickerPointGenerator\n            ref={ref => (this.pickerPointerContainer = ref)}\n            handleTimePointerClick={this.handleTimePointerClick}\n            pointerRotate={pointerRotate}\n          />\n          <PickerDragHandler\n            step={step}\n            timeMode={timeMode}\n            limitDrag={limitDrag}\n            minuteStep={minuteStep}\n            draggable={draggable}\n            rotateState={rotateState}\n            time={step === 0 ? parseInt(hour, 10) : parseInt(minute, 10)}\n            minLength={step === 0\n              ? MIN_ABSOLUTE_POSITION\n              : MAX_ABSOLUTE_POSITION}\n            handleTimePointerClick={this.handleTimePointerClick}\n          />\n        </div>\n      </React.Fragment>\n    );\n  }\n}\n\nTwentyFourHoursMode.propTypes = propTypes;\nTwentyFourHoursMode.defaultProps = defaultProps;\n\nexport default TwentyFourHoursMode;\n"
  },
  {
    "path": "src/components/MaterialTheme/index.jsx",
    "content": "\nimport React from 'react';\nimport asyncComponent from '../Common/AsyncComponent';\nimport Timezone from '../Timezone';\n\nconst DialPlates = {\n  12: asyncComponent(\n    () => System.import('./TwelveHoursMode')\n      .then(component => component.default)\n  ),\n  24: asyncComponent(\n    () => System.import('./TwentyFourHoursMode')\n      .then(component => component.default)\n  ),\n};\n\nconst MaterialTheme = (props) => {\n  const {\n    phrases,\n    timeMode,\n    timezone,\n    showTimezone,\n    onTimezoneChange,\n    timezoneIsEditable,\n  } = props;\n\n  const DialPlate = DialPlates[timeMode];\n  return (\n    <div className=\"modal_container time_picker_modal_container\" id=\"MaterialTheme\">\n      <DialPlate\n        {...props}\n      />\n      {showTimezone\n        ? <Timezone\n          phrases={phrases}\n          timezone={timezone}\n          timezoneIsEditable={timezoneIsEditable}\n          onTimezoneChange={onTimezoneChange}\n        />\n        : null\n      }\n    </div>\n  );\n};\n\nexport default MaterialTheme;\n"
  },
  {
    "path": "src/components/OutsideClickHandler.jsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport PropTypes from 'prop-types';\n\nconst propTypes = {\n  children: PropTypes.node,\n  onOutsideClick: PropTypes.func,\n};\n\nconst defaultProps = {\n  children: <span />,\n  onOutsideClick: Function.prototype,\n};\n\nclass OutsideClickHandler extends React.PureComponent {\n  constructor(props) {\n    super(props);\n    this.hasAction = false;\n    this.onOutsideClick = this.onOutsideClick.bind(this);\n  }\n\n  componentDidMount() {\n    this.bindActions();\n  }\n\n  componentDidUpdate() {\n    this.bindActions();\n  }\n\n  componentWillUnmount() {\n    this.unbindActions();\n  }\n\n  bindActions() {\n    const { closeOnOutsideClick } = this.props;\n    if (closeOnOutsideClick) {\n      if (this.hasAction) return;\n      if (document.addEventListener) {\n        document.addEventListener('mousedown', this.onOutsideClick, true);\n      } else {\n        document.attachEvent('onmousedown', this.onOutsideClick);\n      }\n      this.hasAction = true;\n    }\n  }\n\n  unbindActions() {\n    if (!this.hasAction) return;\n    const { closeOnOutsideClick } = this.props;\n    if (closeOnOutsideClick) {\n      if (document.removeEventListener) {\n        document.removeEventListener('mousedown', this.onOutsideClick, true);\n      } else {\n        document.detachEvent('onmousedown', this.onOutsideClick);\n      }\n      this.hasAction = false;\n    }\n  }\n\n  onOutsideClick(e) {\n    const event = e || window.event;\n    const mouseTarget = (typeof event.which !== 'undefined') ? event.which : event.button;\n    const isDescendantOfRoot = ReactDOM.findDOMNode(this.childNode).contains(event.target);\n\n    if (!isDescendantOfRoot && mouseTarget === 1) {\n      const { onOutsideClick } = this.props;\n      onOutsideClick && onOutsideClick(event);\n    }\n  }\n\n  render() {\n    const { focused } = this.props;\n    const outsideClass = focused\n      ? 'outside_container active'\n      : 'outside_container';\n    return (\n      <div ref={c => (this.childNode = c)} className={outsideClass}>\n        {this.props.children}\n      </div>\n    );\n  }\n}\n\nOutsideClickHandler.propTypes = propTypes;\nOutsideClickHandler.defaultProps = defaultProps;\n\nexport default OutsideClickHandler;\n"
  },
  {
    "path": "src/components/Picker/PickerDragHandler.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport {\n  PICKER_RADIUS,\n  POINTER_RADIUS,\n  MAX_ABSOLUTE_POSITION,\n  MIN_ABSOLUTE_POSITION,\n} from '../../utils/constant.js';\nimport darg from '../../utils/drag';\n\nconst propTypes = {\n  time: PropTypes.number,\n  step: PropTypes.number,\n  draggable: PropTypes.bool,\n  pointerRotate: PropTypes.number,\n  minLength: PropTypes.number,\n  maxLength: PropTypes.number,\n  minuteStep: PropTypes.number,\n  limitDrag: PropTypes.bool,\n  rotateState: PropTypes.shape({\n    top: PropTypes.number,\n    height: PropTypes.number,\n    pointerRotate: PropTypes.number\n  }),\n  handleTimePointerClick: PropTypes.func\n};\n\nconst defaultProps = {\n  time: 0,\n  step: 0,\n  pointerRotate: 0,\n  rotateState: {\n    top: 0,\n    height: 0,\n    pointerRotate: 0\n  },\n  minLength: MIN_ABSOLUTE_POSITION,\n  maxLength: MAX_ABSOLUTE_POSITION,\n  minuteStep: 5,\n  limitDrag: false,\n  handleTimePointerClick: Function.prototype\n};\n\nclass PickerDragHandler extends React.PureComponent {\n  constructor(props) {\n    super(props);\n    this.startX = 0;\n    this.startY = 0;\n    this.originX = null;\n    this.originY = null;\n    this.dragCenterX = null;\n    this.dragCenterY = null;\n    this.offsetDragCenterX = 0;\n    this.offsetDragCenterY = 0;\n    this.state = this.initialRotationAndLength();\n\n    this.handleMouseDown = this.handleMouseDown.bind(this);\n    this.handleMouseMove = this.handleMouseMove.bind(this);\n    this.handleMouseUp = this.handleMouseUp.bind(this);\n    this.resetOrigin = this.resetOrigin.bind(this);\n  }\n\n  componentDidMount() {\n    this.resetOrigin();\n    if (window.addEventListener) {\n      window.addEventListener('resize', this.resetOrigin, true);\n    } else {\n      window.addEventListener('onresize', this.resetOrigin);\n    }\n    if (document.addEventListener) {\n      document.addEventListener('scroll', this.resetOrigin, true);\n      document.addEventListener('mousemove', this.handleMouseMove, true);\n      document.addEventListener('mouseup', this.handleMouseUp, true);\n      document.addEventListener('touchmove', this.handleMouseMove, true);\n      document.addEventListener('touchend', this.handleMouseUp, true);\n    } else {\n      document.addEventListener('onscroll', this.resetOrigin);\n      document.attachEvent('onmousemove', this.handleMouseMove);\n      document.attachEvent('onmouseup', this.handleMouseUp);\n      document.attachEvent('ontouchmove', this.handleMouseMove);\n      document.attachEvent('ontouchend', this.handleMouseUp);\n    }\n  }\n\n  componentWillUnmount() {\n    if (window.addEventListener) {\n      window.removeEventListener('resize', this.resetOrigin, true);\n    } else {\n      window.detachEvent('onresize', this.resetOrigin);\n    }\n    if (document.removeEventListener) {\n      document.removeEventListener('scroll', this.resetOrigin, true);\n      document.removeEventListener('mousemove', this.handleMouseMove, true);\n      document.removeEventListener('mouseup', this.handleMouseUp, true);\n      document.removeEventListener('touchmove', this.handleMouseMove, true);\n      document.removeEventListener('touchend', this.handleMouseUp, true);\n    } else {\n      document.detachEvent('onscroll', this.resetOrigin);\n      document.detachEvent('onmousemove', this.handleMouseMove);\n      document.detachEvent('onmouseup', this.handleMouseUp);\n      document.detachEvent('ontouchmove', this.handleMouseMove);\n      document.detachEvent('ontouchend', this.handleMouseUp);\n    }\n  }\n\n  componentDidUpdate(prevProps) {\n    const { step, time, rotateState } = this.props;\n    const { draging } = this.state;\n    const prevStep = prevProps.step;\n    const prevTime = prevProps.time;\n    const PrevRotateState = prevProps.rotateState;\n    if ((step !== prevStep\n      || time !== prevTime\n      || rotateState.pointerRotate !== PrevRotateState.pointerRotate)\n      && !draging) {\n      this.resetState();\n    }\n  }\n\n  initialRotationAndLength() {\n    const { rotateState } = this.props;\n    const {\n      top,\n      height,\n      pointerRotate\n    } = rotateState;\n    this.initialHeight = height;\n    return {\n      top,\n      height,\n      pointerRotate,\n      draging: false\n    };\n  }\n\n  resetState() {\n    this.setState(this.initialRotationAndLength());\n  }\n\n  resetOrigin() {\n    const centerPoint = this.pickerCenter;\n    const centerPointPos = centerPoint.getBoundingClientRect();\n    this.originX =\n      centerPointPos.left +\n      (centerPoint.clientWidth / 2) +\n      Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) + POINTER_RADIUS;\n    this.originY =\n      centerPointPos.top +\n      (centerPoint.clientHeight / 2) +\n      Math.max(document.documentElement.scrollTop, document.body.scrollTop) + POINTER_RADIUS;\n\n    this.resetDragCenter();\n  }\n\n  resetDragCenter() {\n    this.offsetDragCenterX = 0;\n    this.offsetDragCenterY = 0;\n\n    const dragCenterPoint = this.dragCenter;\n    const dragCenterPointPos = dragCenterPoint.getBoundingClientRect();\n    this.dragCenterX =\n      dragCenterPointPos.left +\n      (dragCenterPoint.clientWidth / 2) +\n      Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);\n    this.dragCenterY =\n      dragCenterPointPos.top +\n      (dragCenterPoint.clientHeight / 2) +\n      Math.max(document.documentElement.scrollTop, document.body.scrollTop);\n  }\n\n  getRadian(x, y) {\n    let sRad = Math.atan2(y - this.originY, x - this.originX);\n    sRad -= Math.atan2(\n      this.startY - this.originY,\n      this.startX - this.originX\n    );\n    if (sRad > Math.PI) {\n      sRad -= Math.PI * 2;\n    } else if (sRad < -Math.PI) {\n      sRad += Math.PI * 2;\n    }\n    sRad += darg.degree2Radian(this.props.rotateState.pointerRotate);\n    return sRad;\n  }\n\n  getAbsolutePosition(x, y) {\n    return Math.sqrt(\n      Math.pow((x - this.originX), 2) + Math.pow((y - this.originY), 2)\n    );\n  }\n\n  getPointerRotate(options = {}) {\n    const {\n      dragX,\n      dragY,\n    } = options;\n    const {\n      step,\n      limitDrag,\n      minuteStep,\n    } = this.props;\n    const sRad = this.getRadian(dragX, dragY);\n    let pointerRotate = sRad * (360 / (2 * Math.PI));\n\n    if (limitDrag) {\n      const degree = sRad * (360 / (2 * Math.PI));\n      const isHour = step === 0;\n      const sectionCount = isHour ? 12 : (60 / minuteStep);\n      const roundSeg = Math.round(degree / (360 / sectionCount));\n      pointerRotate = roundSeg * (360 / sectionCount);\n    }\n    return pointerRotate;\n  }\n\n  handleTimePointerChange(options = {}) {\n    const {\n      dragX,\n      dragY,\n      autoMode = null,\n      pointerRotate = null,\n    } = options;\n    const {\n      step,\n      timeMode,\n      minLength,\n      maxLength,\n      minuteStep,\n      handleTimePointerClick,\n    } = this.props;\n\n    const sRad = this.getRadian(dragX, dragY);\n\n    const degree = sRad * (360 / (2 * Math.PI));\n    const isHour = step === 0;\n    const sectionCount = isHour ? 12 : (60 / minuteStep);\n    let roundSeg = Math.round(degree / (360 / sectionCount));\n\n    let absolutePosition = this.getAbsolutePosition(dragX, dragY);\n    absolutePosition = darg.validatePosition(\n      absolutePosition,\n      minLength,\n      maxLength\n    );\n    if (minLength < absolutePosition && absolutePosition < maxLength) {\n      if ((absolutePosition - minLength) > (maxLength - minLength) / 2) {\n        absolutePosition = maxLength;\n      } else {\n        absolutePosition = minLength;\n      }\n    }\n    while (roundSeg > sectionCount) {\n      roundSeg -= sectionCount;\n    }\n    let time = absolutePosition === minLength\n      ? roundSeg\n      : roundSeg + sectionCount;\n\n    if (isHour) {\n      if (absolutePosition === minLength && time < 0) {\n        time += 12;\n      } else if (absolutePosition !== minLength && time < 12) {\n        time = 24 + (time - 12);\n      }\n      time = time === 24 ? 12 : time;\n      if (time === 12 && Number(timeMode) === 12) time = 0;\n    } else {\n      time = (time * minuteStep === 60 ? 0 : time * minuteStep);\n      time = time < 0 ? 60 + time : time;\n    }\n\n    handleTimePointerClick && handleTimePointerClick({\n      time,\n      autoMode,\n      pointerRotate\n    });\n  }\n\n  handleMouseDown(e) {\n    if (!this.state.draging) {\n      const event = e || window.event;\n      event.preventDefault();\n      event.stopPropagation();\n      const pos = darg.mousePosition(event);\n      this.startX = pos.x;\n      this.startY = pos.y;\n\n      this.resetDragCenter();\n      this.offsetDragCenterX = this.dragCenterX - this.startX;\n      this.offsetDragCenterY = this.dragCenterY - this.startY;\n\n      this.setState({\n        draging: true\n      });\n    }\n  }\n\n  handleMouseMove(e) {\n    if (this.state.draging) {\n      const {\n        minLength,\n        maxLength,\n      } = this.props;\n      const pos = darg.mousePosition(e);\n      const dragX = pos.x + this.offsetDragCenterX;\n      const dragY = pos.y + this.offsetDragCenterY;\n      if (this.originX !== dragX && this.originY !== dragY) {\n        const pointerRotate = this.getPointerRotate({ dragX, dragY });\n\n        const absolutePosition = this.getAbsolutePosition(dragX, dragY);\n        const height = darg.validatePosition(\n          absolutePosition,\n          minLength - POINTER_RADIUS,\n          maxLength - POINTER_RADIUS\n        );\n        const top = PICKER_RADIUS - height;\n        this.setState({\n          top,\n          height,\n          pointerRotate\n        });\n\n        this.handleTimePointerChange({\n          dragX,\n          dragY,\n          autoMode: false\n        });\n      }\n    }\n  }\n\n  handleMouseUp(e) {\n    if (this.state.draging) {\n      this.setState({\n        draging: false\n      });\n\n      const pos = darg.mousePosition(e);\n      const endX = pos.x + this.offsetDragCenterX;\n      const endY = pos.y + this.offsetDragCenterY;\n\n      let pointerRotate = this.getPointerRotate({\n        dragX: endX,\n        dragY: endY\n      });\n      const remainder = pointerRotate % 30;\n      const base = Math.floor(pointerRotate / 30);\n      pointerRotate = (base + (remainder >= 15 ? 1 : 0)) * 30;\n\n      this.setState({ pointerRotate });\n      this.handleTimePointerChange({\n        dragX: endX,\n        dragY: endY,\n        pointerRotate,\n      });\n    }\n  }\n\n  render() {\n    const { time, draggable } = this.props;\n    const { draging, height, top, pointerRotate } = this.state;\n    const pickerPointerClass = draging\n      ? 'picker_pointer'\n      : 'picker_pointer animation';\n\n    return (\n      <div className=\"picker_handler\">\n        <div\n          className={pickerPointerClass}\n          style={darg.initialPointerStyle(height, top, pointerRotate)}\n        >\n          <div\n            ref={r => (this.dragCenter = r)}\n            className={`pointer_drag ${draggable ? 'draggable' : ''}`}\n            style={darg.rotateStyle(-pointerRotate)}\n            onMouseDown={draggable ? this.handleMouseDown : Function.prototype}\n            onTouchStart={draggable ? this.handleMouseDown : Function.prototype}\n          >\n            {time}\n          </div>\n        </div>\n        <div\n          className=\"picker_center\"\n          ref={p => (this.pickerCenter = p)}\n        />\n      </div>\n    );\n  }\n}\n\nPickerDragHandler.propTypes = propTypes;\nPickerDragHandler.defaultProps = defaultProps;\n\nexport default PickerDragHandler;\n"
  },
  {
    "path": "src/components/Picker/PickerPoint.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport darg from '../../utils/drag';\n\nconst propTypes = {\n  index: PropTypes.number,\n  angle: PropTypes.number,\n  onClick: PropTypes.func,\n  pointClass: PropTypes.string,\n};\n\nconst defaultProps = {\n  index: 0,\n  angle: 0,\n  onClick: Function.prototype,\n  pointClass: 'picker_point point_outter',\n};\n\nconst PickerPoint = (props) => {\n  const {\n    index,\n    angle,\n    onClick,\n    pointClass,\n    pointerRotate,\n  } = props;\n  const inlineStyle = darg.inlineRotateStyle(angle);\n  const wrapperStyle = darg.rotateStyle(-angle);\n\n  return (\n    <div\n      style={inlineStyle}\n      className={pointClass}\n      onClick={() => {\n        let relativeRotate = angle - (pointerRotate % 360);\n        if (relativeRotate >= 180) {\n          relativeRotate -= 360;\n        } else if (relativeRotate < -180) {\n          relativeRotate += 360;\n        }\n        onClick && onClick({\n          time: index,\n          pointerRotate: relativeRotate + pointerRotate\n        });\n      }}\n      onMouseDown={darg.disableMouseDown}\n    >\n      <div className=\"point_wrapper\" style={wrapperStyle}>\n        {index}\n      </div>\n    </div>\n  );\n};\n\nPickerPoint.propTypes = propTypes;\nPickerPoint.defaultProps = defaultProps;\n\nexport default PickerPoint;\n"
  },
  {
    "path": "src/components/Picker/PickerPointGenerator.jsx",
    "content": "import React from 'react';\nimport {\n  HOURS,\n  MINUTES,\n  TWELVE_HOURS\n} from '../../utils/constant.js';\nimport PickerPoint from './PickerPoint';\n\nconst pickerPointGenerator = (type = 'hour', mode = 24) =>\n  class PickerPointGenerator extends React.PureComponent {\n    addAnimation() {\n      this.pickerPointerContainer.className = 'animation';\n    }\n\n    removeAnimation() {\n      this.pickerPointerContainer.className = '';\n    }\n\n    renderMinutePointes() {\n      return MINUTES.map((_, index) => {\n        const angle = (360 * index) / 60;\n        if (index % 5 === 0) {\n          return (\n            <PickerPoint\n              key={index}\n              angle={angle}\n              index={index}\n              pointerRotate={this.props.pointerRotate}\n              onClick={this.props.handleTimePointerClick}\n            />\n          );\n        }\n        return null;\n      });\n    }\n\n    renderHourPointes() {\n      const hours = parseInt(mode, 10) === 24 ? HOURS : TWELVE_HOURS;\n      return hours.map((_, index) => {\n        const pointClass = index < 12\n          ? 'picker_point point_inner'\n          : 'picker_point point_outter';\n        const angle = index < 12\n          ? (360 * index) / 12\n          : (360 * (index - 12)) / 12;\n        return (\n          <PickerPoint\n            key={index}\n            angle={angle}\n            index={index}\n            pointClass={pointClass}\n            pointerRotate={this.props.pointerRotate}\n            onClick={this.props.handleTimePointerClick}\n          />\n        );\n      });\n    }\n\n    render() {\n      return (\n        <div\n          ref={ref => (this.pickerPointerContainer = ref)}\n          className=\"picker_pointer_container\"\n        >\n          {type === 'hour'\n            ? this.renderHourPointes()\n            : this.renderMinutePointes()}\n        </div>\n      );\n    }\n  };\n\nexport default pickerPointGenerator;\n"
  },
  {
    "path": "src/components/TimePicker.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport cx from 'classnames';\nimport OutsideClickHandler from './OutsideClickHandler';\nimport Button from './Common/Button';\nimport timeHelper from '../utils/time.js';\nimport languageHelper from '../utils/language';\nimport ICONS from '../utils/icons';\nimport { is } from '../utils/func';\nimport asyncComponent from './Common/AsyncComponent';\n\nconst DialPlates = {\n  material: asyncComponent(\n    () => System.import('./MaterialTheme')\n      .then(component => component.default)\n  ),\n  classic: asyncComponent(\n    () => System.import('./ClassicTheme')\n      .then(component => component.default)\n  ),\n};\n\n// aliases for defaultProps readability\nconst TIME = timeHelper.time({ useTz: false });\nTIME.current = timeHelper.current();\n\nconst propTypes = {\n  autoMode: PropTypes.bool,\n  autoClose: PropTypes.bool,\n  colorPalette: PropTypes.string,\n  draggable: PropTypes.bool,\n  focused: PropTypes.bool,\n  language: PropTypes.string,\n  meridiem: PropTypes.string,\n  onFocusChange: PropTypes.func,\n  onTimeChange: PropTypes.func,\n  onTimezoneChange: PropTypes.func,\n  phrases: PropTypes.object,\n  placeholder: PropTypes.string,\n  showTimezone: PropTypes.bool,\n  theme: PropTypes.string,\n  time: PropTypes.string,\n  timeMode: PropTypes.oneOfType([\n    PropTypes.string,\n    PropTypes.number\n  ]),\n  timezone: PropTypes.string,\n  timezoneIsEditable: PropTypes.bool,\n  trigger: PropTypes.oneOfType([\n    PropTypes.func,\n    PropTypes.object,\n    PropTypes.element,\n    PropTypes.array,\n    PropTypes.node,\n    PropTypes.instanceOf(React.Component),\n    PropTypes.instanceOf(React.PureComponent)\n  ]),\n  withoutIcon: PropTypes.bool,\n  minuteStep: PropTypes.number,\n  limitDrag: PropTypes.bool,\n  timeFormat: PropTypes.string,\n  timeFormatter: PropTypes.func,\n  useTz: PropTypes.bool,\n  closeOnOutsideClick: PropTypes.bool,\n  timeConfig: PropTypes.object,\n  disabled: PropTypes.bool,\n  focusDropdownOnTime: PropTypes.bool,\n};\n\nconst defaultProps = {\n  autoMode: true,\n  autoClose: true,\n  colorPalette: 'light',\n  draggable: true,\n  focused: false,\n  language: 'en',\n  meridiem: TIME.meridiem,\n  onFocusChange: Function.prototype,\n  onTimeChange: Function.prototype,\n  onTimezoneChange: Function.prototype,\n  placeholder: '',\n  showTimezone: false,\n  theme: 'material',\n  time: '',\n  timeMode: TIME.mode,\n  trigger: null,\n  withoutIcon: false,\n  minuteStep: 5,\n  limitDrag: false,\n  timeFormat: '',\n  timeFormatter: null,\n  useTz: true,\n  closeOnOutsideClick: true,\n  timeConfig: {\n    step: 30,\n    unit: 'minutes'\n  },\n  disabled: false,\n  focusDropdownOnTime: true,\n};\n\nclass TimePicker extends React.PureComponent {\n  constructor(props) {\n    super(props);\n    const { focused, timezone, onTimezoneChange } = props;\n    const timeData = this.timeData(false);\n    const timezoneData = timeHelper.tzForName(timeData.timezone);\n\n    this.state = {\n      focused,\n      timezoneData,\n      timeChanged: false\n    };\n\n    this.onBlur = this.onBlur.bind(this);\n    this.onFocus = this.onFocus.bind(this);\n    this.timeData = this.timeData.bind(this);\n    this.handleTimeChange = this.handleTimeChange.bind(this);\n    this.handleHourChange = this.handleHourChange.bind(this);\n    this.handleMinuteChange = this.handleMinuteChange.bind(this);\n    this.handleMeridiemChange = this.handleMeridiemChange.bind(this);\n    this.handleHourAndMinuteChange = this.handleHourAndMinuteChange.bind(this);\n\n    // if a timezone value was not passed in,\n    // call the callback with the default value used for timezone\n    if (!timezone) {\n      onTimezoneChange(timezoneData);\n    }\n  }\n\n  componentWillReceiveProps(nextProps) {\n    const { focused } = nextProps;\n    if (focused !== this.props.focused) {\n      this.setState({ focused });\n    }\n  }\n\n  onFocus() {\n    const { focused } = this.state;\n    if (!focused) {\n      this.onFocusChange(!focused);\n    }\n  }\n\n  onBlur() {\n    const { focused } = this.state;\n    if (focused) {\n      this.onFocusChange(!focused);\n    }\n  }\n\n  onFocusChange(focused) {\n    const { disabled } = this.props;\n    if (disabled) return;\n\n    this.setState({ focused });\n    const { onFocusChange } = this.props;\n    onFocusChange && onFocusChange(focused);\n  }\n\n  timeData(timeChanged) {\n    const {\n      time,\n      useTz,\n      timeMode,\n      timezone,\n      meridiem,\n    } = this.props;\n    const timeData = timeHelper.time({\n      time,\n      meridiem,\n      timeMode,\n      tz: timezone,\n      useTz: !time && !timeChanged && useTz\n    });\n    return timeData;\n  }\n\n  get languageData() {\n    const { language, phrases = {} } = this.props;\n    return Object.assign({}, languageHelper.get(language), phrases);\n  }\n\n  get hourAndMinute() {\n    const { timeMode } = this.props;\n    const timeData = this.timeData(this.state.timeChanged);\n    // Since someone might pass a time in 24h format, etc., we need to get it from\n    // timeData to 'translate' it into the local format, including its accurate meridiem\n    const hour = (parseInt(timeMode, 10) === 12)\n      ? (parseInt(timeData.hour12, 10) === 12 ? '00' : timeData.hour12)\n      : (parseInt(timeData.hour24, 10) === 24 ? '00' : timeData.hour24);\n    const minute = timeData.minute;\n    return [hour, minute];\n  }\n\n  get formattedTime() {\n    const {\n      timeMode,\n      timeFormat,\n      timeFormatter,\n    } = this.props;\n\n    const [hour, minute] = this.hourAndMinute;\n    const validTimeMode = timeHelper.validateTimeMode(timeMode);\n\n    let times = '';\n    if (timeFormatter && is.func(timeFormatter)) {\n      times = timeFormatter({\n        hour,\n        minute,\n        meridiem: this.meridiem\n      });\n    } else if (timeFormat && is.string(timeFormat)) {\n      times = timeFormat;\n      if (/HH?/.test(times) || /MM?/.test(times)) {\n        if (validTimeMode === 12) {\n          console.warn('It seems you are using 12 hours mode with 24 hours time format. Please check your timeMode and timeFormat props');\n        }\n      } else if (/hh?/.test(times) || /mm?/.test(times)) {\n        if (validTimeMode === 24) {\n          console.warn('It seems you are using 24 hours mode with 12 hours time format. Please check your timeMode and timeFormat props');\n        }\n      }\n      times = times.replace(/(HH|hh)/g, hour);\n      times = times.replace(/(MM|mm)/g, minute);\n      times = times.replace(/(H|h)/g, Number(hour));\n      times = times.replace(/(M|m)/g, Number(minute));\n    } else {\n      times = (validTimeMode === 12)\n        ? `${hour} : ${minute} ${this.meridiem}`\n        : `${hour} : ${minute}`;\n    }\n    return times;\n  }\n\n  get meridiem() {\n    const { meridiem } = this.props;\n    const timeData = this.timeData(this.state.timeChanged);\n    const localMessages = this.languageData;\n    // eslint-disable-next-line no-unneeded-ternary\n    const m = (meridiem) ? meridiem : timeData.meridiem;\n    // eslint-disable-next-line no-extra-boolean-cast\n    return m && !!(m.match(/^am|pm/i)) ? localMessages[m.toLowerCase()] : m;\n  }\n\n  onTimeChanged(timeChanged) {\n    this.setState({ timeChanged });\n  }\n\n  handleHourChange(hour) {\n    const validateHour = timeHelper.validate(hour);\n    const minute = this.hourAndMinute[1];\n    this.handleTimeChange({\n      hour: validateHour,\n      minute,\n      meridiem: this.meridiem\n    });\n  }\n\n  handleMinuteChange(minute) {\n    const validateMinute = timeHelper.validate(minute);\n    const hour = this.hourAndMinute[0];\n\n    this.handleTimeChange({\n      hour,\n      minute: validateMinute,\n      meridiem: this.meridiem\n    });\n  }\n\n  handleMeridiemChange(meridiem) {\n    const [hour, minute] = this.hourAndMinute;\n    this.handleTimeChange({\n      hour,\n      minute,\n      meridiem\n    });\n  }\n\n  handleTimeChange(options) {\n    const { onTimeChange } = this.props;\n    onTimeChange && onTimeChange(options);\n    this.onTimeChanged(true);\n  }\n\n  handleHourAndMinuteChange(time) {\n    this.onTimeChanged(true);\n    const { onTimeChange, autoClose } = this.props;\n    if (autoClose) this.onBlur();\n    return onTimeChange && onTimeChange(time);\n  }\n\n  renderDialPlate() {\n    const {\n      theme,\n      disabled,\n      timeMode,\n      autoMode,\n      autoClose,\n      draggable,\n      language,\n      limitDrag,\n      minuteStep,\n      timeConfig,\n      colorPalette,\n      showTimezone,\n      onTimezoneChange,\n      timezoneIsEditable,\n      focusDropdownOnTime,\n    } = this.props;\n\n    if (disabled) return null;\n\n    const dialTheme = theme === 'material' ? theme : 'classic';\n    const DialPlate = DialPlates[dialTheme];\n\n    const { timezoneData } = this.state;\n    const [hour, minute] = this.hourAndMinute;\n\n    return (\n      <DialPlate\n        hour={hour}\n        minute={minute}\n        autoMode={autoMode}\n        autoClose={autoClose}\n        language={language}\n        draggable={draggable}\n        limitDrag={limitDrag}\n        timezone={timezoneData}\n        meridiem={this.meridiem}\n        timeConfig={timeConfig}\n        showTimezone={showTimezone}\n        phrases={this.languageData}\n        colorPalette={colorPalette}\n        clearFocus={this.onBlur}\n        timeMode={parseInt(timeMode, 10)}\n        onTimezoneChange={onTimezoneChange}\n        minuteStep={parseInt(minuteStep, 10)}\n        timezoneIsEditable={timezoneIsEditable}\n        handleHourChange={this.handleHourChange}\n        handleTimeChange={this.handleTimeChange}\n        handleMinuteChange={this.handleMinuteChange}\n        handleMeridiemChange={this.handleMeridiemChange}\n        focusDropdownOnTime={focusDropdownOnTime}\n      />\n    );\n  }\n\n  render() {\n    const {\n      trigger,\n      disabled,\n      placeholder,\n      withoutIcon,\n      colorPalette,\n      closeOnOutsideClick\n    } = this.props;\n\n    const { focused } = this.state;\n    const times = this.formattedTime;\n\n    const pickerPreviewClass = cx(\n      'time_picker_preview',\n      focused && 'active',\n      disabled && 'disabled'\n    );\n    const containerClass = cx(\n      'time_picker_container',\n      colorPalette === 'dark' && 'dark'\n    );\n    const previewContainerClass = cx(\n      'preview_container',\n      withoutIcon && 'without_icon'\n    );\n\n    return (\n      <div className={containerClass}>\n        {trigger || (\n          <Button\n            onClick={this.onFocus}\n            className={pickerPreviewClass}\n          >\n            <div className={previewContainerClass}>\n              {withoutIcon ? '' : (ICONS.time)}\n              {placeholder || times}\n            </div>\n          </Button>\n        )}\n        <OutsideClickHandler\n          focused={focused}\n          onOutsideClick={this.onBlur}\n          closeOnOutsideClick={disabled ? false : closeOnOutsideClick}\n        >\n          {this.renderDialPlate()}\n        </OutsideClickHandler>\n      </div>\n    );\n  }\n}\n\nTimePicker.propTypes = propTypes;\nTimePicker.defaultProps = defaultProps;\n\nexport default TimePicker;\n"
  },
  {
    "path": "src/components/Timezone/TimezonePicker.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Typeahead } from 'react-bootstrap-typeahead';\n\nimport timeHelper from '../../utils/time';\nimport ICONS from '../../utils/icons';\nimport Button from '../Common/Button';\n\nclass TimezonePicker extends React.PureComponent {\n  constructor(props) {\n    super(props);\n\n    this.handleTimezoneChange = this.handleTimezoneChange.bind(this);\n  }\n\n  handleTimezoneChange(selection) {\n    const { handleTimezoneChange, onClearFocus } = this.props;\n    const zoneObject = selection[0];\n    if (zoneObject) {\n      handleTimezoneChange && handleTimezoneChange(zoneObject);\n      onClearFocus();\n    }\n  }\n\n  render() {\n    const { phrases, onClearFocus } = this.props;\n    return (\n      <div className=\"timezone_picker_modal_container\">\n        <div className=\"timezone_picker_modal_header\">\n          <span onClick={onClearFocus} className=\"icon\">\n            {ICONS.chevronLeft}\n          </span>\n          <span className=\"timezone_picker_header_title\">\n            {phrases.timezonePickerTitle}\n          </span>\n        </div>\n        <div className=\"timezone_picker_container\">\n          <div className=\"timezone_picker_search\">\n            <Typeahead\n              onChange={this.handleTimezoneChange}\n              labelKey={option => `${option.city} - ${option.zoneAbbr}`}\n              options={timeHelper.tzMaps}\n              maxResults={5}\n              minLength={3}\n              placeholder={phrases.timezonePickerLabel}\n            />\n          </div>\n        </div>\n        <div className=\"buttons_wrapper\">\n          <Button\n            onClick={onClearFocus}\n            className=\"time_picker_button\"\n          >\n            {phrases.close}\n          </Button>\n        </div>\n      </div>\n    );\n  }\n}\n\nTimezonePicker.propTypes = {\n  phrases: PropTypes.object,\n  onClearFocus: PropTypes.func,\n  handleTimezoneChange: PropTypes.func\n};\nTimezonePicker.defaultProps = {\n  onClearFocus: Function.prototype,\n  handleTimezoneChange: Function.prototype\n};\n\nexport default TimezonePicker;\n"
  },
  {
    "path": "src/components/Timezone/index.jsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { CSSTransition, TransitionGroup } from 'react-transition-group';\n\nimport timeHelper from '../../utils/time';\nimport TimezonePicker from './TimezonePicker';\n\nconst TIME = timeHelper.time();\nTIME.tz = timeHelper.guessUserTz();\n\nclass Timezone extends React.PureComponent {\n  constructor(props) {\n    super(props);\n    const { timezone } = this.props;\n\n    this.state = {\n      focused: false,\n      timezone,\n    };\n\n    this.onClearFocus = this.onClearFocus.bind(this);\n    this.handleFocusedChange = this.handleFocusedChange.bind(this);\n    this.handleTimezoneChange = this.handleTimezoneChange.bind(this);\n  }\n\n  onClearFocus() {\n    this.setState({ focused: false });\n  }\n\n  handleFocusedChange() {\n    if (!this.props.timezoneIsEditable) return;\n\n    const { focused } = this.state;\n    this.setState({ focused: !focused });\n  }\n\n  handleTimezoneChange(timezone) {\n    this.setState({ timezone });\n    const { onTimezoneChange } = this.props;\n    onTimezoneChange && onTimezoneChange(timezone);\n  }\n\n  render() {\n    const { focused, timezone } = this.state;\n    const { phrases, timezoneIsEditable } = this.props;\n    const footerClass = timezoneIsEditable\n      ? 'time_picker_modal_footer clickable'\n      : 'time_picker_modal_footer';\n\n    const timeZonePicker = () => {\n      if (!timezoneIsEditable || !focused) return '';\n\n      return (\n        <CSSTransition\n          classNames=\"timezone_picker_modal_container\"\n          timeout={{ enter: 200, exit: 200 }}>\n          <TimezonePicker\n            key=\"timezonePicker\"\n            phrases={phrases}\n            onClearFocus={this.onClearFocus}\n            handleTimezoneChange={this.handleTimezoneChange}\n          />\n        </CSSTransition>\n      );\n    };\n\n    return (\n      <div>\n        <div className={footerClass} onClick={this.handleFocusedChange}>\n          <span className=\"time_picker_modal_footer_timezone\">\n            {timezone.zoneName} {timezone.zoneAbbr}\n          </span>\n        </div>\n        <TransitionGroup>{timeZonePicker()}</TransitionGroup>\n      </div>\n    );\n  }\n}\n\nTimezone.propTypes = {\n  phrases: PropTypes.object,\n  timezone: PropTypes.shape({\n    city: PropTypes.string,\n    zoneAbbr: PropTypes.string,\n    zoneName: PropTypes.string,\n  }),\n  timezoneIsEditable: PropTypes.bool,\n  onTimezoneChange: PropTypes.func,\n};\nTimezone.defaultProps = {\n  timezone: TIME.tz,\n  timezoneIsEditable: false,\n  onTimezoneChange: Function.prototype,\n};\n\nexport default Timezone;\n"
  },
  {
    "path": "src/utils/constant.js",
    "content": "\nconst getArray = length => new Array(length).join('0').split('');\n\nexport const HOURS = getArray(24 + 1);\nexport const TWELVE_HOURS = getArray(12 + 1);\nexport const MINUTES = getArray(60 + 1);\n\nconst PICKER_WIDTH = 260;\nconst POINTER_WIDTH = 35;\n\nexport const PICKER_RADIUS = PICKER_WIDTH / 2;\nexport const MAX_ABSOLUTE_POSITION = 125;\nexport const MIN_ABSOLUTE_POSITION = 90;\nexport const POINTER_RADIUS = POINTER_WIDTH / 2;\n\nexport const BROWSER_COMPATIBLE = [\n  '',\n  'O',\n  'Moz',\n  'Ms',\n  'ms',\n  'Webkit'\n];\n\nexport const MERIDIEMS = ['AM', 'PM'];\n"
  },
  {
    "path": "src/utils/drag.js",
    "content": "\nimport { BROWSER_COMPATIBLE } from './constant';\n\nconst getScrollPosition = () => {\n  const position = {\n    x: document.documentElement.scrollLeft\n    || document.body.scrollLeft\n    || 0,\n    y: document.documentElement.scrollTop\n    || document.body.scrollTop\n    || 0,\n  };\n  return position;\n};\n\nconst mousePosition = (e) => {\n  const event = e || window.event;\n  let xPos;\n  const scrollPosition = getScrollPosition();\n\n  if (event.pageX) {\n    xPos = event.pageX;\n  } else if ((event.clientX + scrollPosition.x) - document.body.clientLeft) {\n    xPos = (event.clientX + scrollPosition.x) - document.body.clientLeft;\n  } else if (event.touches[0]) {\n    xPos = event.touches[0].clientX;\n  } else {\n    xPos = event.changedTouches[0].clientX;\n  }\n  let yPos;\n  if (event.pageY) {\n    yPos = event.pageY;\n  } else if ((event.clientY + scrollPosition.y) - document.body.clientTop) {\n    yPos = (event.clientY + scrollPosition.y) - document.body.clientTop;\n  } else if (event.touches[0]) {\n    yPos = event.touches[0].clientY;\n  } else {\n    yPos = event.changedTouches[0].clientY;\n  }\n  return {\n    x: xPos,\n    y: yPos,\n  };\n};\n\nconst disableMouseDown = (e) => {\n  const event = e || window.event;\n  event.preventDefault();\n  event.stopPropagation();\n};\n\nconst browserStyles = (type, style) => BROWSER_COMPATIBLE.reduce((dict, browser) => {\n  const key = browser\n    ? `${browser}${type[0].toUpperCase()}${type.slice(1)}`\n    : type;\n  dict[key] = style;\n  return dict;\n}, {});\n\nconst getRotateStyle = degree =>\n  browserStyles('transform', `rotate(${degree}deg)`);\n\nconst getInlineRotateStyle = degree =>\n  browserStyles('transform', `translateX(-50%) rotate(${degree}deg)`);\n\nconst getInitialPointerStyle = (height, top, degree) =>\n  Object.assign({\n    height: `${height}px`,\n    top: `${top}px`,\n  }, browserStyles('transform', `translateX(-50%) rotate(${degree}deg)`));\n\nconst getStandardAbsolutePosition = (position, minPosition, maxPosition) => {\n  let p = position;\n  if (p < minPosition) {\n    p = minPosition;\n  }\n  if (p > maxPosition) {\n    p = maxPosition;\n  }\n  return p;\n};\n\nconst degree2Radian = degree => (degree * (2 * Math.PI)) / 360;\n\nexport default {\n  degree2Radian,\n  mousePosition,\n  disableMouseDown,\n  rotateStyle: getRotateStyle,\n  inlineRotateStyle: getInlineRotateStyle,\n  initialPointerStyle: getInitialPointerStyle,\n  validatePosition: getStandardAbsolutePosition\n};\n"
  },
  {
    "path": "src/utils/func.js",
    "content": "// simple utils for working with sequences like Array or string\n\nconst checkType = (val, result) =>\n  Object.prototype.toString.call(val) === result;\n\nexport const is = {\n  object: val => checkType(val, '[object Object]'),\n  array: val => Array.isArray(val),\n  func: val => checkType(val, '[object Function]'),\n  string: val => checkType(val, '[object String]'),\n  undefined: val => typeof val === 'undefined',\n};\n\nexport const isSeq = seq => (is.string(seq) || is.array(seq));\nexport const head = seq => isSeq(seq) ? seq[0] : null;\nexport const first = head;\nexport const tail = seq => isSeq(seq) ? seq.slice(1) : null;\nexport const rest = tail;\nexport const last = seq => isSeq(seq) ? seq[seq.length - 1] : null;\n"
  },
  {
    "path": "src/utils/icons.js",
    "content": "import React from 'react';\n\nconst time = (\n  <svg width=\"48\" height=\"48\" viewBox=\"0 0 48 48\">\n    <path d=\"M23.99 4C12.94 4 4 12.95 4 24s8.94 20 19.99 20C35.04 44 44 35.05 44 24S35.04 4 23.99 4zM24 40c-8.84 0-16-7.16-16-16S15.16 8 24 8s16 7.16 16 16-7.16 16-16 16zM25 14h-3v12l10.49 6.3L34 29.84l-9-5.34z\" />\n  </svg>\n);\nconst chevronLeft = (\n  <svg width=\"1792\" height=\"1792\" viewBox=\"0 0 1792 1792\">\n    <path d=\"M1427 301l-531 531 531 531q19 19 19 45t-19 45l-166 166q-19 19-45 19t-45-19l-742-742q-19-19-19-45t19-45l742-742q19-19 45-19t45 19l166 166q19 19 19 45t-19 45z\" />\n  </svg>\n);\n\nexport default {\n  time,\n  chevronLeft\n};\n"
  },
  {
    "path": "src/utils/language.js",
    "content": "const LANGUAGES = {\n  en: {\n    confirm: 'confirm',\n    cancel: 'cancel',\n    close: 'close',\n    timezonePickerTitle: 'Pick a timezone',\n    timezonePickerLabel: 'Closest city or timezone',\n    am: 'AM',\n    pm: 'PM'\n  },\n  'zh-cn': {\n    confirm: '确认',\n    cancel: '取消',\n    close: '关闭',\n    timezonePickerTitle: '选择时区',\n    timezonePickerLabel: '最近的城市或时区',\n    am: '上午',\n    pm: '下午'\n  },\n  'zh-tw': {\n    confirm: '確認',\n    cancel: '取消',\n    close: '關閉',\n    timezonePickerTitle: '選擇時區',\n    timezonePickerLabel: '最近的城市或時區',\n    am: '上午',\n    pm: '下午'\n  },\n  fr: {\n    confirm: 'Confirmer',\n    cancel: 'Annulé',\n    close: 'Arrêter',\n    timezonePickerTitle: 'Choisissez un timezone',\n    timezonePickerLabel: 'Ville la plus proche ou timezone',\n    am: 'AM',\n    pm: 'PM'\n  },\n  ja: {\n    confirm: '確認します',\n    cancel: 'キャンセル',\n    close: 'クローズ',\n    timezonePickerTitle: 'タイムゾーンを選択する',\n    timezonePickerLabel: '最も近い都市またはTimezone',\n    am: 'AM',\n    pm: 'PM'\n  }\n};\n\nconst language = (type = 'en') => LANGUAGES[type];\n\nexport default {\n  get: language\n};\n"
  },
  {
    "path": "src/utils/time.js",
    "content": "\nimport moment from 'moment-timezone';\nimport { head, last, is } from './func';\n\n// loads moment-timezone's timezone data, which comes from the\n// IANA Time Zone Database at https://www.iana.org/time-zones\nmoment.tz.load({\n  zones: [],\n  links: [],\n  version: 'latest',\n});\n\nconst guessUserTz = () => {\n  // User-Agent sniffing is not always reliable, but is the recommended technique\n  // for determining whether or not we're on a mobile device according to MDN\n  // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#Mobile_Tablet_or_Desktop\n  const isMobile = global.navigator !== undefined\n    ? global.navigator.userAgent.match(/Mobi/)\n    : false;\n\n  const supportsIntl = global.Intl !== undefined;\n\n  let userTz;\n\n  if (isMobile && supportsIntl) {\n    // moment-timezone gives preference to the Intl API regardless of device type,\n    // so unset global.Intl to trick moment-timezone into using its fallback\n    // see https://github.com/moment/moment-timezone/issues/441\n    // TODO: Clean this up when that issue is resolved\n    const globalIntl = global.Intl;\n    global.Intl = undefined;\n    userTz = moment.tz.guess();\n    global.Intl = globalIntl;\n  } else {\n    userTz = moment.tz.guess();\n  }\n\n  // return GMT if we're unable to guess or the system is using UTC\n  if (!userTz || userTz === 'UTC') return getTzForName('Etc/Greenwich');\n\n  try {\n    return getTzForName(userTz);\n  } catch (e) {\n    console.error(e);\n    return getTzForName('Etc/Greenwich');\n  }\n};\n\n/**\n * Create a time data object using moment.\n * If a time is provided, just format it; if not, use the current time.\n *\n * @function getValidTimeData\n * @param  {string} time          a time; defaults to now\n * @param  {string} meridiem      AM or PM; defaults to AM via moment\n * @param  {Number} timeMode      12 or 24-hour mode\n * @param  {string} tz            a timezone name; defaults to guessing a user's tz or GMT\n * @return {Object}               a key-value representation of time data\n */\nconst getValidTimeData = (options = {}) => {\n  const {\n    tz,\n    time,\n    timeMode,\n    useTz = true,\n    meridiem = null,\n  } = options;\n  const validMeridiem = getValidMeridiem(meridiem);\n\n  // when we only have a valid meridiem, that implies a 12h mode\n  const mode = (validMeridiem && !timeMode) ? 12 : timeMode || 24;\n  const timezone = tz || guessUserTz().zoneName;\n\n  const validMode = getValidateTimeMode(mode);\n  const validTime = getValidTimeString(time, validMeridiem);\n  const format12 = 'hh:mmA';\n  const format24 = 'HH:mmA';\n\n  // What format is the hour we provide to moment below in?\n  const hourFormat = (validMode === 12) ? format12 : format24;\n\n  let time24;\n  let time12;\n  const formatTime = moment(`1970-01-01 ${validTime}`, `YYYY-MM-DD ${hourFormat}`, 'en');\n  if (time || !useTz) {\n    time24 = ((validTime)\n      ? formatTime.format(format24)\n      : moment().format(format24)).split(/:/);\n    time12 = ((validTime)\n      ? formatTime.format(format12)\n      : moment().format(format12)).split(/:/);\n  } else {\n    time24 = ((validTime)\n      ? formatTime.tz(timezone).format(format24)\n      : moment().tz(timezone).format(format24)).split(/:/);\n\n    time12 = ((validTime)\n      ? formatTime.tz(timezone).format(format12)\n      : moment().tz(timezone).format(format12)).split(/:/);\n  }\n\n  const timeData = {\n    timezone,\n    mode: validMode,\n    hour24: head(time24),\n    minute: last(time24).slice(0, 2),\n    hour12: head(time12).replace(/^0/, ''),\n    meridiem: validMode === 12 ? last(time12).slice(2) : null,\n  };\n\n  return timeData;\n};\n\n/**\n * Format the current time as a string\n * @function getCurrentTime\n * @return {string}\n */\nconst getCurrentTime = () => {\n  const time = getValidTimeData();\n  return `${time.hour24}:${time.minute}`;\n};\n\n/**\n * Get an integer representation of a time.\n * @function getValidateIntTime\n * @param  {string} time\n * @return {Number}\n */\nconst getValidateIntTime = (time) => {\n  if (isNaN(parseInt(time, 10))) { return 0; }\n  return parseInt(time, 10);\n};\n\n/**\n * Validate, set a default for, and stringify time data.\n * @function getValidateTime\n * @param {string}\n * @return {string}\n */\nconst getValidateTime = (time) => {\n  let result = time;\n  if (is.undefined(result)) { result = '00'; }\n  if (isNaN(parseInt(result, 10))) { result = '00'; }\n  if (parseInt(result, 10) < 10) { result = `0${parseInt(result, 10)}`; }\n  return `${result}`;\n};\n\n/**\n * Given a time and meridiem, produce a time string to pass to moment\n * @function getValidTimeString\n * @param  {string} time\n * @param  {string} meridiem\n * @return {string}\n */\nconst getValidTimeString = (time, meridiem) => {\n  if (is.string(time)) {\n    let validTime = (time && time.indexOf(':').length >= 0)\n      ? time.split(/:/).map(t => getValidateTime(t)).join(':')\n      : time;\n    const hourAsInt = parseInt(head(validTime.split(/:/)), 10);\n    const is12hTime = (hourAsInt > 0 && hourAsInt <= 12);\n\n    validTime = (validTime && meridiem && is12hTime)\n      ? `${validTime} ${meridiem}`\n      : validTime;\n\n    return validTime;\n  }\n\n  return time;\n};\n\n/**\n * Given a meridiem, try to ensure that it's formatted for use with moment\n * @function getValidMeridiem\n * @param  {string} meridiem\n * @return {string}\n */\nconst getValidMeridiem = (meridiem) => {\n  if (is.string(meridiem)) {\n    return (meridiem && meridiem.match(/am|pm/i)) ? meridiem.toLowerCase() : null;\n  }\n\n  return meridiem;\n};\n\n/**\n * Ensure that a meridiem passed as a prop has a valid value\n * @function getValidateMeridiem\n * @param  {string} time\n * @param  {string|Number} timeMode\n * @return {string|null}\n */\nconst getValidateMeridiem = (time, timeMode) => {\n  const validateTime = time || getCurrentTime();\n  const mode = parseInt(timeMode, 10);\n  // eslint-disable-next-line no-unused-vars\n  let hour = validateTime.split(/:/)[0];\n  hour = getValidateIntTime(hour);\n\n  if (mode === 12) return (hour > 12) ? 'PM' : 'AM';\n\n  return null;\n};\n\n/**\n * Validate and set a sensible default for time modes.\n *\n * @function getValidateTimeMode\n * @param  {string|Number} timeMode\n * @return {Number}\n */\nconst getValidateTimeMode = (timeMode) => {\n  const mode = parseInt(timeMode, 10);\n\n  if (isNaN(mode)) { return 24; }\n  if (mode !== 24 && mode !== 12) { return 24; }\n\n  return mode;\n};\n\nconst tzNames = (() => {\n  //  We want to subset the existing timezone data as much as possible, both for efficiency\n  //  and to avoid confusing the user. Here, we focus on removing reduntant timezone names\n  //  and timezone names for timezones we don't necessarily care about, like Antarctica, and\n  //  special timezone names that exist for convenience.\n  const scrubbedPrefixes = ['Antarctica', 'Arctic', 'Chile'];\n  const scrubbedSuffixes = ['ACT', 'East', 'Knox_IN', 'LHI', 'North', 'NSW', 'South', 'West'];\n\n  const tznames = moment.tz.names()\n      .filter(name => name.indexOf('/') >= 0)\n      .filter(name => !scrubbedPrefixes.indexOf(name.split('/')[0]) >= 0)\n      .filter(name => !scrubbedSuffixes.indexOf(name.split('/').slice(-1)[0]) >= 0);\n\n  return tznames;\n})();\n\n// We need a human-friendly city name for each timezone identifier\n// counting Canada/*, Mexico/*, and US/* allows users to search for\n// things like 'Eastern' or 'Mountain' and get matches back\nconst tzCities = tzNames\n    .map(name => (['Canada', 'Mexico', 'US'].indexOf(name.split('/')[0]) >= 0)\n      ? name : name.split('/').slice(-1)[0])\n    .map(name => name.replace(/_/g, ' '));\n\n// Provide a mapping between a human-friendly city name and its corresponding\n// timezone identifier and timezone abbreviation as a named export.\n// We can fuzzy match on any of these.\nconst tzMaps = tzCities.map((city) => {\n  const tzMap = {};\n  const tzName = tzNames[tzCities.indexOf(city)];\n\n  tzMap.city = city;\n  tzMap.zoneName = tzName;\n  tzMap.zoneAbbr = moment().tz(tzName).zoneAbbr();\n\n  return tzMap;\n});\n\nconst getTzForCity = (city) => {\n  const val = city.toLowerCase();\n  const maps = tzMaps.filter(tzMap => tzMap.city.toLowerCase() === val);\n  return head(maps);\n};\n\nconst getTzCountryAndCity = (name) => {\n  const sections = name.split('/');\n  return {\n    country: sections[0].toLowerCase(),\n    city: sections.slice(-1)[0].toLowerCase()\n  };\n};\n\nconst _matchTzByName = (target, name) => {\n  const v1 = getTzCountryAndCity(target);\n  const v2 = getTzCountryAndCity(name);\n\n  return v1.country === v2.country && v1.city === v2.city;\n};\n\nconst getTzForName = (name) => {\n  let maps = tzMaps.filter(tzMap => tzMap.zoneName === name);\n  if (!maps.length && /\\//.test(name)) {\n    maps = tzMaps.filter(tzMap => tzMap.zoneAbbr === name);\n  }\n  if (!maps.length) {\n    maps = tzMaps.filter(tzMap => _matchTzByName(tzMap.zoneName, name));\n  }\n  if (!maps.length) {\n    throw new Error(`Can not find target timezone for ${name}`);\n  }\n  return head(maps);\n};\n\nconst hourFormatter = (hour, defaultTime = '00:00') => {\n  if (!hour) return defaultTime;\n\n  let [h, m, meridiem] = `${hour}`.split(/[:|\\s]/);\n\n  if (meridiem && meridiem.toLowerCase() === 'pm') meridiem = 'PM';\n  if (meridiem && meridiem.toLowerCase() === 'am') meridiem = 'AM';\n  if (meridiem && meridiem !== 'AM' && meridiem !== 'PM') meridiem = 'AM';\n\n  if (!h || isNaN(h)) h = '0';\n  if (!meridiem && Number(h > 24)) h = Number(h) - 24;\n  if (meridiem && Number(h > 12)) h = Number(h) - 12;\n  if (!m || isNaN(m) || Number(m) >= 60) m = '0';\n\n  if (Number(h) < 10) h = `0${Number(h)}`;\n  if (Number(m) < 10) m = `0${Number(m)}`;\n\n  return meridiem ? `${h}:${m} ${meridiem}` : `${h}:${m}`;\n};\n\nconst withoutMeridiem = hour => hour.replace(/\\s[P|A]M$/, '');\n\nconst getStartAndEnd = (from, to) => {\n  const current = moment();\n  const date = current.format('YYYY-MM-DD');\n  const nextDate = current.add(1, 'day').format('YYYY-MM-DD');\n\n  const f = hourFormatter(from, '00:00');\n  const t = hourFormatter(to, '23:30');\n\n  let start = `${date} ${withoutMeridiem(f)}`;\n  const endTmp = withoutMeridiem(t);\n  let end = moment(`${date} ${endTmp}`) <= moment(start)\n    ? `${nextDate} ${endTmp}`\n    : `${date} ${endTmp}`;\n\n  if (/PM$/.test(f)) start = moment(start).add(12, 'hours').format('YYYY-MM-DD HH:mm');\n  if (/PM$/.test(t)) end = moment(end).add(12, 'hours').format('YYYY-MM-DD HH:mm');\n\n  return {\n    start,\n    end\n  };\n};\n\nconst get12ModeTimes = ({ from, to, step = 30, unit = 'minutes' }) => {\n  const {\n    start,\n    end\n  } = getStartAndEnd(from, to);\n\n  const times = [];\n  let time = moment(start);\n  while (time <= moment(end)) {\n    const hour = Number(time.format('HH'));\n    times.push(`${time.format('hh:mm')} ${hour >= 12 ? 'PM' : 'AM'}`);\n    time = time.add(step, unit);\n  }\n  return times;\n};\n\nconst get24ModeTimes = ({ from, to, step = 30, unit = 'minutes' }) => {\n  const {\n    start,\n    end\n  } = getStartAndEnd(from, to);\n\n  const times = [];\n  let time = moment(start);\n  while (time <= moment(end)) {\n    times.push(time.format('HH:mm'));\n    time = time.add(step, unit);\n  }\n  return times;\n};\n\nexport default {\n  tzMaps,\n  guessUserTz,\n  hourFormatter,\n  getStartAndEnd,\n  get12ModeTimes,\n  get24ModeTimes,\n  withoutMeridiem,\n  time: getValidTimeData,\n  current: getCurrentTime,\n  tzForCity: getTzForCity,\n  tzForName: getTzForName,\n  validate: getValidateTime,\n  validateInt: getValidateIntTime,\n  validateMeridiem: getValidateMeridiem,\n  validateTimeMode: getValidateTimeMode,\n};\n"
  },
  {
    "path": "stories/ClassicThemePicker.js",
    "content": "import '../css/classic/default.css';\n\nimport React from 'react';\nimport TimePickerWrapper from '../examples/TimePickerWrapper';\nimport { storiesOf } from '@storybook/react';\n\nstoriesOf('Classic Theme', module)\n  .addWithInfo('basic', () => (\n    <TimePickerWrapper theme=\"classic\" />\n  ))\n  .addWithInfo('with default time', () => (\n    <TimePickerWrapper theme=\"classic\" defaultTime=\"17:00\" />\n  ))\n  .addWithInfo('dropdown focus on time/default time', () => (\n    <React.Fragment>\n      <TimePickerWrapper\n        theme=\"classic\"\n        defaultTime=\"17:00\"\n        focusDropdownOnTime\n      />\n    </React.Fragment>\n  ))\n  .addWithInfo('dark color', () => (\n    <TimePickerWrapper theme=\"classic\" colorPalette=\"dark\" />\n  ))\n  .addWithInfo('12 hours mode', () => (\n    <TimePickerWrapper\n      theme=\"classic\"\n      timeMode=\"12\"\n      defaultTime=\"10:30\"\n    />\n  ))\n  .addWithInfo('limit start, end, step for 12 hours mode', () => (\n    <TimePickerWrapper\n      theme=\"classic\"\n      timeMode=\"12\"\n      timeConfig={{\n        from: '08:00 PM',\n        to: '08:00 AM',\n        step: 1,\n        unit: 'hour'\n      }}\n    />\n  ))\n  .addWithInfo('limit start, end, step for 24 hours mode', () => (\n    <TimePickerWrapper\n      theme=\"classic\"\n      timeMode=\"24\"\n      timeConfig={{\n        from: 9,\n        to: 19,\n        step: 30,\n        unit: 'minutes'\n      }}\n    />\n  ))\n  .addWithInfo('focused at setup', () => (\n    <TimePickerWrapper\n      focused\n      theme=\"classic\"\n    />\n  ))\n  .addWithInfo('Set default time', () => (\n    <TimePickerWrapper\n      theme=\"classic\"\n      defaultTime=\"12:00\"\n    />\n  ))\n  .addWithInfo('Focus dropdown on time', () => (\n    <TimePickerWrapper\n      focusDropdownOnTime\n      theme=\"classic\"\n      defaultTime=\"12:00\"\n    />\n  ));\n"
  },
  {
    "path": "stories/CustomTrigger.js",
    "content": "import React from 'react';\nimport { storiesOf } from '@storybook/react';\nimport { withKnobs } from '@storybook/addon-knobs';\nimport TimePickerWrapper from '../examples/TimePickerWrapper';\nimport '../css/material/default.css';\n\nstoriesOf('Custom TimePicker Trigger', module)\n  .addDecorator(withKnobs)\n  .addWithInfo('basic example', () => (\n    <TimePickerWrapper\n      customTriggerId={1}\n    />\n  ))\n  .addWithInfo('any custom DOM', () => (\n    <TimePickerWrapper\n      customTriggerId={2}\n    />\n  ))\n  .addWithInfo('only render picker modal', () => (\n    <TimePickerWrapper\n      focused\n      autoClose={false}\n      trigger={<div />}\n      closeOnOutsideClick={false}\n    />\n  ));\n"
  },
  {
    "path": "stories/DarkColor.js",
    "content": "import '../css/material/default.css';\n\nimport React from 'react';\nimport TimePickerWrapper from '../examples/TimePickerWrapper';\nimport { storiesOf } from '@storybook/react';\n\nstoriesOf('DarkColor', module)\n  .addWithInfo('basic', () => (\n    <TimePickerWrapper colorPalette=\"dark\" />\n  ))\n  .addWithInfo('with default time', () => (\n    <TimePickerWrapper\n      colorPalette=\"dark\"\n      defaultTime=\"11:50\"\n    />\n  ))\n  .addWithInfo('focused at setup', () => (\n    <TimePickerWrapper\n      colorPalette=\"dark\"\n      focused\n    />\n  ))\n  .addWithInfo('without icon', () => (\n    <TimePickerWrapper\n      focused\n      withoutIcon\n      colorPalette=\"dark\"\n    />\n  ));\n"
  },
  {
    "path": "stories/DifferentLanguage.js",
    "content": "import React from 'react';\nimport { storiesOf } from '@storybook/react';\nimport { withKnobs, text } from '@storybook/addon-knobs';\nimport TimePickerWrapper from '../examples/TimePickerWrapper';\nimport '../css/material/default.css';\n\nstoriesOf('Different Languages', module)\n  .addDecorator(withKnobs)\n  .addWithInfo('English (basic)', () => (\n    <TimePickerWrapper timeMode=\"12\" />\n  ))\n  .addWithInfo('汉语 - 简体', () => (\n    <TimePickerWrapper\n      timeMode=\"12\"\n      language=\"zh-cn\"\n    />\n  ))\n  .addWithInfo('汉语 - 繁体', () => (\n    <TimePickerWrapper\n      timeMode=\"12\"\n      language=\"zh-tw\"\n    />\n  ))\n  .addWithInfo('Français', () => (\n    <TimePickerWrapper\n      timeMode=\"12\"\n      language=\"fr\"\n    />\n  ))\n  .addWithInfo('日本語', () => (\n    <TimePickerWrapper\n      timeMode=\"12\"\n      language=\"ja\"\n    />\n  ))\n  .addWithInfo('custom phrases', () => {\n    const confirm = text('confirm', 'okey dokey');\n    const cancel = text('cancel', 'hold it there!');\n    const close = text('close', 'DONE');\n    const am = text('am', 'Ante');\n    const pm = text('pm', 'Post');\n\n    return (\n      <TimePickerWrapper\n        timeMode=\"12\"\n        language=\"en\"\n        phrases={{\n          confirm,\n          cancel,\n          close,\n          am,\n          pm\n        }}\n      />\n    );\n  });\n"
  },
  {
    "path": "stories/TimePicker.js",
    "content": "import React from 'react';\nimport { storiesOf } from '@storybook/react';\nimport '../css/material/default.css';\nimport { text, withKnobs } from '@storybook/addon-knobs';\nimport TimePickerWrapper from '../examples/TimePickerWrapper';\n\nstoriesOf('Default TimePicker', module)\n  .addDecorator(withKnobs)\n  .addWithInfo('basic', () => (\n    <TimePickerWrapper />\n  ))\n  .addWithInfo('disabled', () => (\n    <TimePickerWrapper disabled />\n  ))\n  .addWithInfo('with default time', () => {\n    const aDefaultTime = text('set default time', '13:20');\n    return (\n      <TimePickerWrapper\n        defaultTime={aDefaultTime}\n      />\n    );\n  })\n  .addWithInfo('focused at setup', () => (\n    <TimePickerWrapper\n      focused\n    />\n  ))\n  .addWithInfo('not auto change time panel', () => (\n    <TimePickerWrapper\n      autoMode={false}\n    />\n  ))\n  .addWithInfo('undraggable', () => (\n    <TimePickerWrapper\n      draggable={false}\n    />\n  ))\n  .addWithInfo('disable outside click close', () => (\n    <TimePickerWrapper\n      closeOnOutsideClick={false}\n    />\n  ))\n  .addWithInfo('custom minute step', () => (\n    <TimePickerWrapper\n      autoMode={false}\n      minuteStep={5}\n      defaultTime={'22:10'}\n    />\n  ))\n  .addWithInfo('limit drag', () => (\n    <TimePickerWrapper\n      limitDrag\n      autoMode={false}\n      minuteStep={1}\n    />\n  ))\n  .addWithInfo('custom HH-MM format', () => (\n    <TimePickerWrapper\n      timeFormat={'HH-MM'}\n    />\n  ))\n  .addWithInfo('custom H-M format', () => (\n    <TimePickerWrapper\n      timeFormat={'H-M'}\n    />\n  ))\n  .addWithInfo('custom time formatter', () => (\n    <TimePickerWrapper\n      timeFormatter={({ hour, minute }) => `${hour} & ${minute}`}\n    />\n  ));\n"
  },
  {
    "path": "stories/TimePicker2.js",
    "content": "import React from 'react';\nimport { storiesOf } from '@storybook/react';\nimport '../css/material/default.css';\nimport { text, withKnobs } from '@storybook/addon-knobs';\nimport TimePickerWrapper2 from '../examples/TimePickerWrapper2';\n\nstoriesOf('Multi TimePicker', module)\n  .addDecorator(withKnobs)\n  .addWithInfo('basic', () => (\n    <TimePickerWrapper2 />\n  ));\n"
  },
  {
    "path": "stories/TwelveHoursMode.js",
    "content": "\nimport React from 'react';\nimport TimePickerWrapper from '../examples/TimePickerWrapper';\nimport { storiesOf } from '@storybook/react';\nimport '../css/material/default.css';\n\nstoriesOf('TwelveHoursMode', module)\n  .addWithInfo('basic', () => (\n    <TimePickerWrapper\n      timeMode=\"12\"\n    />\n  ))\n  .addWithInfo('with default time', () => (\n    <TimePickerWrapper\n      timeMode=\"12\"\n      defaultTime=\"13:15\"\n    />\n  ))\n  .addWithInfo('focused at setup, no icon', () => (\n    <TimePickerWrapper\n      withoutIcon\n      timeMode=\"12\"\n      focused\n    />\n  ))\n  .addWithInfo('custom minute step', () => (\n    <TimePickerWrapper\n      autoMode={false}\n      minuteStep={1}\n      timeMode=\"12\"\n    />\n  ))\n  .addWithInfo('limit drag', () => (\n    <TimePickerWrapper\n      limitDrag\n      autoMode={false}\n      minuteStep={1}\n      timeMode=\"12\"\n    />\n  ))\n  .addWithInfo('disable outside click close', () => (\n    <TimePickerWrapper\n      timeMode=\"12\"\n      closeOnOutsideClick={false}\n    />\n  ));\n"
  },
  {
    "path": "stories/WithTimeZones.js",
    "content": "import '../css/material/default.css';\n\nimport { withKnobs } from '@storybook/addon-knobs';\nimport React from 'react';\nimport TimePickerWrapper from '../examples/TimePickerWrapper';\nimport TimeZonesPickerWrapper from '../examples/TimeZonesPickerWrapper';\nimport { storiesOf } from '@storybook/react';\nimport timeHelper from '../src/utils/time.js';\n\nconst tzForCity = timeHelper.tzForCity('Kuala Lumpur');\n\nstoriesOf('TimeZones', module)\n  .addDecorator(withKnobs)\n  .addWithInfo('with default (detected) timezone', () => (\n    <TimePickerWrapper showTimezone />\n  ))\n  .addWithInfo('with default (custom) timezone', () => (\n    <TimePickerWrapper timezone={tzForCity.zoneName} showTimezone />\n  ))\n  .addWithInfo('with timezone search', () => (\n    <TimePickerWrapper showTimezone timezoneIsEditable />\n  ))\n  .addWithInfo('with 12 hour (custom) time', () => (\n    <TimePickerWrapper\n      timeMode=\"12\"\n      defaultTime=\"13:15\"\n      showTimezone\n      timezoneIsEditable\n    />\n  ))\n  .addWithInfo('with dark theme', () => (\n    <TimePickerWrapper colorPalette=\"dark\" showTimezone timezoneIsEditable />\n  ))\n  .addWithInfo('timezone picker', () => <TimeZonesPickerWrapper />);\n"
  },
  {
    "path": "test/_helpers/adapter.js",
    "content": "import Enzyme from 'enzyme';\nimport Adapter from 'enzyme-adapter-react-16';\n\nEnzyme.configure({ adapter: new Adapter() });\n"
  },
  {
    "path": "test/_helpers/ignoreSVGStrings.jsx",
    "content": "require.extensions['.svg'] = (obj) => {\n  obj.exports = () => (\n    <svg>SVG_TEST_STUB</svg>\n  );\n};\n"
  },
  {
    "path": "test/components/ClassicTheme_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { shallow } from 'enzyme';\nimport '../_helpers/adapter';\n\n\nimport ClassicTheme from '../../src/components/ClassicTheme';\n\ndescribe('ClassicTheme', () => {\n  describe('ClassicTheme render', () => {\n    it('should render correctly', () => {\n      const wrapper = shallow(<ClassicTheme />);\n      expect(wrapper.is('.classic_theme_container')).to.equal(true);\n    });\n  });\n});\n"
  },
  {
    "path": "test/components/MaterialTheme_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { shallow } from 'enzyme';\nimport MaterialTheme from '../../src/components/MaterialTheme';\nimport languageHelper from '../../src/utils/language';\nimport '../_helpers/adapter';\n\nconst phrases = languageHelper.get('en');\n\ndescribe('MaterialTheme', () => {\n  describe('MaterialTheme Timezone render', () => {\n    it('should render the Timezone footer', () => {\n      const mockTimezone = {\n        zoneName: 'Some Zone',\n        zoneAbbr: 'SZ'\n      };\n      const wrapper = shallow(\n        <MaterialTheme\n          showTimezone\n          phrases={phrases}\n          timezone={mockTimezone}\n        />\n      );\n      expect(wrapper.find('Timezone')).to.have.lengthOf(1);\n    });\n\n    it('should not render the Timezone footer', () => {\n      const wrapper = shallow(<MaterialTheme />);\n      expect(wrapper.find('Timezone')).to.have.lengthOf(0);\n    });\n  });\n\n  describe('MaterialTheme render correctly', () => {\n    it('should render with className', () => {\n      const wrapper = shallow(<MaterialTheme />);\n      expect(wrapper.is('.modal_container')).to.equal(true);\n      expect(wrapper.is('.time_picker_modal_container')).to.equal(true);\n    });\n  });\n});\n"
  },
  {
    "path": "test/components/PickerDargHandler_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { mount } from 'enzyme';\nimport PickerDragHandler from '../../src/components/Picker/PickerDragHandler';\nimport { JSDOM } from 'jsdom';\nimport '../_helpers/adapter';\n\nconst jsdom = new JSDOM('<!doctype html><html><body></body></html>');\nconst { window } = jsdom;\n\nfunction copyProps(src, target) {\n  const props = Object.getOwnPropertyNames(src)\n    .filter(prop => typeof target[prop] === 'undefined')\n    .reduce((result, prop) => ({\n      ...result,\n      [prop]: Object.getOwnPropertyDescriptor(src, prop),\n    }), {});\n  Object.defineProperties(target, props);\n}\n\nglobal.window = window;\nglobal.document = window.document;\nglobal.navigator = {\n  userAgent: 'node.js',\n};\ncopyProps(window, global);\n\ndescribe('PickerDragHandler', () => {\n  describe('PickerDragHandler Init', () => {\n    const wrapper = mount(<PickerDragHandler />);\n    it('should render component correctly', () => {\n      expect(wrapper.find('.picker_handler').length).to.equal(1);\n    });\n\n    it('should render correct draging state', () => {\n      expect(wrapper.state().draging).to.equal(false);\n    });\n  });\n});\n"
  },
  {
    "path": "test/components/PickerPointGenerator_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { shallow } from 'enzyme';\nimport PickerPoint from '../../src/components/Picker/PickerPoint';\nimport pickerPointGenerator from '../../src/components/Picker/PickerPointGenerator';\nimport '../_helpers/adapter';\n\ndescribe('PickerPointGenerator', () => {\n  describe('Render 24 hours', () => {\n    const PickerPointGenerator = pickerPointGenerator('hour');\n    const wrapper = shallow(<PickerPointGenerator handleTimePointerClick={Function.prototype}/>);\n    it('should render with currect wrapper', () => {\n      expect(wrapper.is('.picker_pointer_container')).to.equal(true);\n    });\n\n    it('should render with 24 PickerPoint', () => {\n      expect(wrapper.find(PickerPoint)).to.have.lengthOf(24);\n    });\n  });\n\n  describe('Render 12 hours', () => {\n    const PickerPointGenerator = pickerPointGenerator('hour', 12);\n    const wrapper = shallow(<PickerPointGenerator handleTimePointerClick={Function.prototype}/>);\n    it('should render with currect wrapper', () => {\n      expect(wrapper.is('.picker_pointer_container')).to.equal(true);\n    });\n\n    it('should render with 12 PickerPoint', () => {\n      expect(wrapper.find(PickerPoint)).to.have.lengthOf(12);\n    });\n  });\n\n  describe('Render minutes', () => {\n    const PickerPointGenerator = pickerPointGenerator('minute');\n    const wrapper = shallow(<PickerPointGenerator handleTimePointerClick={Function.prototype}/>);\n    it('should render with 12 PickerPoint', () => {\n      expect(wrapper.find(PickerPoint)).to.have.lengthOf(12);\n    });\n  });\n});\n"
  },
  {
    "path": "test/components/PickerPoint_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { shallow } from 'enzyme';\nimport PickerPoint from '../../src/components/Picker/PickerPoint';\nimport '../_helpers/adapter';\n\ndescribe('PickerPoint', () => {\n  const wrapper = shallow(\n    <PickerPoint\n      index={12}\n      angle={360}\n    />\n  );\n\n  it('should render with currect wrapper', () => {\n    expect(wrapper.is('.picker_point.point_outter')).to.equal(true);\n  });\n});\n"
  },
  {
    "path": "test/components/TimePicker_func_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { shallow } from 'enzyme';\nimport sinon from 'sinon-sandbox';\nimport languageHelper from '../../src/utils/language';\nimport TimePicker from '../../src/components/TimePicker';\nimport '../_helpers/adapter';\n\ndescribe('TimePicker func', () => {\n  describe('handle focus change func', () => {\n    it('should focus', () => {\n      const wrapper = shallow(<TimePicker />);\n      wrapper.instance().onFocus();\n      expect(wrapper.state().focused).to.equal(true);\n    });\n\n    it('should clear focus', () => {\n      const wrapper = shallow(<TimePicker />);\n      wrapper.instance().onBlur();\n      expect(wrapper.state().focused).to.equal(false);\n    });\n\n    it('should callback when focus', () => {\n      const onFocusChangeStub = sinon.stub();\n      const wrapper = shallow(<TimePicker onFocusChange={onFocusChangeStub} />);\n      wrapper.instance().onFocus();\n      expect(onFocusChangeStub.callCount).to.equal(1);\n    });\n  });\n\n  describe('handle hour change func', () => {\n    // it('should change hour', () => {\n    //   const wrapper = shallow(<TimePicker />);\n    //   wrapper.instance().handleHourChange(11);\n    //   expect(wrapper.props().time.split(':')[0]).to.equal('11');\n    // });\n    //\n    // it('should change to validate hour', () => {\n    //   const wrapper = shallow(<TimePicker />);\n    //   wrapper.instance().handleHourChange(1);\n    //   expect(wrapper.props().time.split(':')[1]).to.equal('01');\n    // });\n\n    it('should change callback when hour change', () => {\n      const onTimeChangeStub = sinon.stub();\n      const wrapper = shallow(<TimePicker onTimeChange={onTimeChangeStub} />);\n      wrapper.instance().handleHourChange(1);\n      expect(onTimeChangeStub.callCount).to.equal(1);\n    });\n  });\n\n  describe('handle minute change func', () => {\n    // it('should change minute', () => {\n    //   const wrapper = shallow(<TimePicker />);\n    //   wrapper.instance().handleMinuteChange(59);\n    //   expect(wrapper.state().minute).to.equal('59');\n    // });\n    //\n    // it('should change to validate minute', () => {\n    //   const wrapper = shallow(<TimePicker />);\n    //   wrapper.instance().handleMinuteChange(9);\n    //   expect(wrapper.state().minute).to.equal('09');\n    // });\n\n    it('should change callback when minute change', () => {\n      const onTimeChangeStub = sinon.stub();\n      const wrapper = shallow(<TimePicker onTimeChange={onTimeChangeStub} />);\n      wrapper.instance().handleMinuteChange(1);\n      expect(onTimeChangeStub.callCount).to.equal(1);\n    });\n  });\n\n  describe('languageData func', () => {\n    it('should return the default language messages when no phrases provided', () => {\n      const wrapper = shallow(<TimePicker />);\n      const messages = wrapper.instance().languageData;\n      expect(messages).to.deep.equal(languageHelper.get('en'));\n    });\n\n    it('should return the phrases when all phrases provided', () => {\n      const phrases = {\n        confirm: 'foo',\n        cancel: 'bar',\n        close: 'baz',\n        timezonePickerLabel: 'This is a Label',\n        timezonePickerTitle: 'This is a Title',\n        am: 'fizz',\n        pm: 'buzz'\n      };\n      const wrapper = shallow(<TimePicker phrases={phrases} />);\n      const messages = wrapper.instance().languageData;\n      expect(messages).to.deep.equal(phrases);\n    });\n\n    it('should return the default language messages for any phrases not provided', () => {\n      const phrases = {\n        cancel: 'bar',\n        close: 'baz'\n      };\n      const expectedMessages = Object.assign({}, languageHelper.get('en'), phrases);\n      const wrapper = shallow(<TimePicker phrases={phrases} />);\n      const messages = wrapper.instance().languageData;\n      expect(messages).to.deep.equal(expectedMessages);\n    });\n  });\n});\n"
  },
  {
    "path": "test/components/TimePicker_init_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { shallow } from 'enzyme';\n// import ClassicTheme from '../../src/components/ClassicTheme';\n// import MaterialTheme from '../../src/components/MaterialTheme';\nimport OutsideClickHandler from '../../src/components/OutsideClickHandler';\nimport PickerDragHandler from '../../src/components/Picker/PickerDragHandler';\nimport TimePicker from '../../src/components/TimePicker';\nimport timeHelper from '../../src/utils/time';\nimport '../_helpers/adapter';\n\ndescribe('TimePicker initial', () => {\n  describe('render basic picker', () => {\n    it('should be wrappered by div.time_picker_container', () => {\n      const wrapper = shallow(<TimePicker />);\n      expect(wrapper.is('.time_picker_container')).to.equal(true);\n    });\n\n    it('renders an OutsideClickHandler', () => {\n      const wrapper = shallow(<TimePicker />);\n      expect(wrapper.find(OutsideClickHandler)).to.have.lengthOf(1);\n    });\n\n    // it('renders an MaterialTheme', () => {\n    //   const wrapper = shallow(<TimePicker />);\n    //   expect(wrapper.contains(MaterialTheme)).to.have.lengthOf(1);\n    // });\n\n    // it('renders an ClassicTheme', () => {\n    //   const wrapper = shallow(<TimePicker theme=\"classic\" />);\n    //   expect(wrapper.contains(ClassicTheme)).to.have.lengthOf(1);\n    // });\n\n    it('renders an PickerDragHandler', () => {\n      const wrapper = shallow(<TimePicker />);\n      expect(wrapper.find(PickerDragHandler)).to.have.lengthOf(0);\n    });\n  });\n\n  describe('render with props', () => {\n    it('should be wrapped by div.time_picker_container.dark', () => {\n      const wrapper = shallow(<TimePicker colorPalette=\"dark\" />);\n      expect(wrapper.is('.time_picker_container.dark')).to.equal(true);\n    });\n\n    it('should render with focused', () => {\n      const wrapper = shallow(<TimePicker focused />);\n      expect(wrapper.find('.time_picker_preview.active')).to.have.lengthOf(1);\n      expect(wrapper.find(OutsideClickHandler).props().closeOnOutsideClick).to.equal(true);\n    });\n\n    it('should render disabled component', () => {\n      const wrapper = shallow(<TimePicker disabled />);\n      expect(wrapper.find('.time_picker_preview.disabled')).to.have.lengthOf(1);\n      expect(wrapper.find(OutsideClickHandler).props().closeOnOutsideClick).to.equal(false);\n    });\n\n    it('should render with focused on child', () => {\n      const wrapper = shallow(<TimePicker focused />);\n      expect(wrapper.find(OutsideClickHandler).props().focused).to.equal(true);\n    });\n\n    it('should render with no onOutsideClick handler', () => {\n      const wrapper = shallow(<TimePicker focused closeOnOutsideClick={false} />);\n      expect(wrapper.find(OutsideClickHandler).props().focused).to.equal(true);\n      wrapper.find(OutsideClickHandler).simulate('click');\n      expect(wrapper.find(OutsideClickHandler).props().focused).to.equal(true);\n    });\n\n    it('should render without icon', () => {\n      const wrapper = shallow(<TimePicker withoutIcon />);\n      expect(wrapper.find('.preview_container.without_icon')).to.have.lengthOf(1);\n    });\n\n    // it('should render with default time in child props', () => {\n    //   const wrapper = mount(<TimePicker time=\"22:23\" />);\n    //   const time = timeHelper.time({ time: '22:23' });\n    //   console.log(wrapper.find(MaterialTheme));\n    //   expect(wrapper.find(MaterialTheme).props().hour).to.equal(time.hour24);\n    //   expect(wrapper.find(MaterialTheme).props().minute).to.equal(time.minute);\n    // });\n\n    it('should render with default time in DOM', () => {\n      const wrapper = shallow(<TimePicker time=\"22:23\" withoutIcon />);\n      const time = timeHelper.time({ time: '22:23' });\n      expect(wrapper.find('.preview_container').text()).to.equal(`${time.hour24} : ${time.minute}`);\n    });\n\n    // it('should render with current time in child props', () => {\n    //   const wrapper = shallow(<TimePicker />);\n    //   const time = timeHelper.time({\n    //     time: timeHelper.current()\n    //   });\n    //   expect(wrapper.find('#MaterialTheme').props().hour).to.equal(time.hour24);\n    //   expect(wrapper.find('#MaterialTheme').props().minute).to.equal(time.minute);\n    // });\n\n    it('should render with current time in DOM', () => {\n      const wrapper = shallow(<TimePicker withoutIcon />);\n      const time = timeHelper.time({\n        time: timeHelper.current()\n      });\n      expect(wrapper.find('.preview_container').text()).to.equal(`${time.hour24} : ${time.minute}`);\n    });\n\n    it('should render with current time format HH&MM', () => {\n      const wrapper = shallow(<TimePicker time=\"22:23\" timeFormat=\"HH&MM\" />);\n      const time = timeHelper.time({ time: '22:23' });\n      expect(wrapper.find('.preview_container').text()).to.equal(`${time.hour24}&23`);\n    });\n\n    it('should render with current time format hh&mm', () => {\n      const wrapper = shallow(<TimePicker time=\"12:23\" timeFormat=\"hh&mm\" timeMode={12} />);\n      const time = timeHelper.time({ time: '12:23' });\n      expect(wrapper.find('.preview_container').text()).to.equal('00&23');\n    });\n  });\n});\n"
  },
  {
    "path": "test/components/Time_zone_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { shallow } from 'enzyme';\nimport Timezone from '../../src/components/Timezone';\nimport languageHelper from '../../src/utils/language';\nimport '../_helpers/adapter';\n\nconst phrases = languageHelper.get('en');\nconst mockTimezone = {\n  zoneName: 'Some Zone',\n  zoneAbbr: 'SZ'\n};\n\ndescribe('Timezone', () => {\n  describe('Timezone render', () => {\n    const wrapper = shallow(\n      <Timezone\n        phrases={phrases}\n        timezone={mockTimezone}\n      />\n    );\n\n    it('should render the Timezone footer', () => {\n      expect(wrapper.find('.time_picker_modal_footer_timezone')).to.have.lengthOf(1);\n    });\n\n    it('should render the Timezone Name and Abbreviation', () => {\n      expect(wrapper.find('.time_picker_modal_footer_timezone').text())\n        .to.equal(`${mockTimezone.zoneName} ${mockTimezone.zoneAbbr}`);\n    });\n  });\n\n  describe('props', () => {\n    describe('when timezoneIsEditable is true', () => {\n      it('should render the Time Picker modal footer clickable', () => {\n        const wrapper = shallow(\n          <Timezone\n            phrases={phrases}\n            timezoneIsEditable\n          />\n        );\n\n        expect(wrapper.find('.time_picker_modal_footer').hasClass('clickable')).to.equal(true);\n      });\n\n      describe('when focused is true', () => {\n        it('should render the TimezonePicker', () => {\n          const wrapper = shallow(\n            <Timezone\n              phrases={phrases}\n              timezoneIsEditable\n            />\n          );\n          wrapper.setState({ focused: true });\n\n          expect(wrapper.find('TimezonePicker')).to.have.lengthOf(1);\n        });\n      });\n\n      describe('when focused is false', () => {\n        it('should not render the TimezonePicker', () => {\n          const wrapper = shallow(\n            <Timezone\n              phrases={phrases}\n              timezoneIsEditable\n            />\n          );\n          wrapper.setState({ focused: false });\n\n          expect(wrapper.find('TimezonePicker')).to.have.lengthOf(0);\n        });\n      });\n    });\n\n    describe('when timezoneIsEditable is false', () => {\n      it('should not render the Time Picker modal footer clickable', () => {\n        const wrapper = shallow(\n          <Timezone\n            phrases={phrases}\n            timezoneIsEditable={false}\n          />\n        );\n\n        expect(wrapper.find('.time_picker_modal_footer').hasClass('clickable')).to.equal(false);\n      });\n\n      describe('when focused is true', () => {\n        it('should not render the TimezonePicker', () => {\n          const wrapper = shallow(\n            <Timezone\n              phrases={phrases}\n              timezoneIsEditable={false}\n            />\n          );\n          wrapper.setState({ focused: true });\n\n          expect(wrapper.find('TimezonePicker')).to.have.lengthOf(0);\n        });\n      });\n\n      describe('when focused is false', () => {\n        it('should not render the TimezonePicker', () => {\n          const wrapper = shallow(\n            <Timezone\n              phrases={phrases}\n              timezoneIsEditable={false}\n            />\n          );\n          wrapper.setState({ focused: false });\n\n          expect(wrapper.find('TimezonePicker')).to.have.lengthOf(0);\n        });\n      });\n    });\n  });\n\n  describe('onClearFocus Func', () => {\n    it('should clear focused', () => {\n      const wrapper = shallow(\n        <Timezone\n          phrases={phrases}\n        />\n      );\n      wrapper.setState({ focused: true });\n\n      wrapper.instance().onClearFocus();\n      expect(wrapper.state().focused).to.equal(false);\n    });\n  });\n\n  describe('handleFocusedChange Func', () => {\n    const wrapper = shallow(\n      <Timezone\n        phrases={phrases}\n        timezoneIsEditable\n      />\n    );\n\n    it('should toggle focused', () => {\n      wrapper.setState({ focused: true });\n\n      wrapper.instance().handleFocusedChange();\n      expect(wrapper.state().focused).to.equal(false);\n\n      wrapper.instance().handleFocusedChange();\n      expect(wrapper.state().focused).to.equal(true);\n    });\n\n    it('should toggle focused onClick of modal footer', () => {\n      wrapper.setState({ focused: false });\n      wrapper.find('.time_picker_modal_footer').simulate('click');\n      expect(wrapper.state().focused).to.equal(true);\n    });\n  });\n\n  describe('handleTimezoneChange Func', () => {\n    it('should set the timezone', () => {\n      const wrapper = shallow(\n        <Timezone\n          phrases={phrases}\n          timezone={{}}\n        />\n      );\n\n      wrapper.instance().handleTimezoneChange(mockTimezone);\n      expect(wrapper.state().timezone).to.equal(mockTimezone);\n    });\n  });\n});\n"
  },
  {
    "path": "test/components/Timezone_Picker_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { shallow } from 'enzyme';\nimport sinon from 'sinon-sandbox';\nimport TimezonePicker from '../../src/components/Timezone/TimezonePicker';\nimport languageHelper from '../../src/utils/language';\nimport '../_helpers/adapter';\n\nconst phrases = languageHelper.get('en');\nconst mockTimezone = {\n  zoneName: 'Some Zone',\n  zoneAbbr: 'SZ'\n};\n\ndescribe('TimezonePicker', () => {\n  describe('TimezonePicker render', () => {\n    const wrapper = shallow(\n      <TimezonePicker\n        phrases={phrases}\n      />\n    );\n\n    it('should render a header with a title', () => {\n      expect(wrapper.find('.timezone_picker_header_title').text()).to.equal(phrases.timezonePickerTitle);\n    });\n\n    it('should render a Typeahead', () => {\n      expect(wrapper.find('OnClickOutside(Typeahead)')).to.have.lengthOf(1);\n    });\n\n    it('should render a close button', () => {\n      expect(wrapper.find('Button').prop('children')).to.equal(phrases.close);\n    });\n  });\n\n  describe('onClearFocus func', () => {\n    it('should callback when onClick header \"back\" icon', () => {\n      const onFocusChangeStub = sinon.stub();\n      const wrapper = shallow(\n        <TimezonePicker\n          phrases={phrases}\n          onClearFocus={onFocusChangeStub}\n        />\n      );\n      wrapper.find('.timezone_picker_modal_header').find('svg').parent().simulate('click');\n      expect(onFocusChangeStub.callCount).to.equal(1);\n    });\n\n    it('should callback when onClick Button', () => {\n      const onFocusChangeStub = sinon.stub();\n      const wrapper = shallow(\n        <TimezonePicker\n          phrases={phrases}\n          onClearFocus={onFocusChangeStub}\n        />\n      );\n      wrapper.find('Button').simulate('click');\n      expect(onFocusChangeStub.callCount).to.equal(1);\n    });\n\n    it('should callback when timezone change', () => {\n      const onFocusChangeStub = sinon.stub();\n      const wrapper = shallow(\n        <TimezonePicker\n          phrases={phrases}\n          onClearFocus={onFocusChangeStub}\n        />\n      );\n      wrapper.instance().handleTimezoneChange([mockTimezone]);\n      expect(onFocusChangeStub.callCount).to.equal(1);\n    });\n  });\n\n  describe('handle timezone change func', () => {\n    it('should callback when timezone change', () => {\n      const onTimezoneChangeStub = sinon.stub();\n      const wrapper = shallow(\n        <TimezonePicker\n          phrases={phrases}\n          handleTimezoneChange={onTimezoneChangeStub}\n        />\n      );\n      wrapper.instance().handleTimezoneChange([mockTimezone]);\n      expect(onTimezoneChangeStub.callCount).to.equal(1);\n      expect(onTimezoneChangeStub.calledWith(mockTimezone));\n    });\n  });\n});\n"
  },
  {
    "path": "test/components/TwelveHoursTheme_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { shallow } from 'enzyme';\nimport sinon from 'sinon-sandbox';\nimport TwelveHoursMode from '../../src/components/MaterialTheme/TwelveHoursMode';\nimport PickerDragHandler from '../../src/components/Picker/PickerDragHandler';\nimport languageHelper from '../../src/utils/language';\nimport '../_helpers/adapter';\n\nconst phrases = languageHelper.get('en');\n\ndescribe('TwelveHoursMode', () => {\n  describe('TwelveHoursMode init with defaultTime', () => {\n    const wrapper = shallow(\n      <TwelveHoursMode\n        focused\n        hour={'01'}\n        minute={'45'}\n        phrases={phrases}\n      />\n    );\n    it('should render component correctly', () => {\n      expect(wrapper.find('.meridiem')).to.have.lengthOf(1);\n    });\n\n    it('should render PickerDragHandler component', () => {\n      expect(wrapper.find(PickerDragHandler)).to.have.lengthOf(2);\n    });\n\n    it('should init correct state', () => {\n      expect(wrapper.state()).to.deep.equal({\n        hourPointerRotate: 30,\n        minutePointerRotate: 270\n      });\n    });\n  });\n\n  describe('TwelveHoursMode Func', () => {\n    const handleHourChange = sinon.stub();\n    const handleMinuteChange = sinon.stub();\n    const handleMeridiemChange = sinon.stub();\n    const wrapper = shallow(\n      <TwelveHoursMode\n        focused\n        hour={'01'}\n        minute={'45'}\n        meridiem={'AM'}\n        phrases={phrases}\n        handleHourChange={handleHourChange}\n        handleMinuteChange={handleMinuteChange}\n        handleMeridiemChange={handleMeridiemChange}\n      />\n    );\n    it('should handleHourPointerClick', () => {\n      wrapper.instance().handleHourPointerClick({\n        time: 3,\n        pointerRotate: 90\n      });\n      expect(wrapper.state().hourPointerRotate).to.equal(90);\n      expect(handleHourChange.callCount).to.equal(1);\n    });\n\n    it('should handleHourPointerClick', () => {\n      wrapper.instance().handleMinutePointerClick({\n        time: 30,\n        pointerRotate: 180\n      });\n      expect(wrapper.state().minutePointerRotate).to.equal(180);\n      expect(handleMinuteChange.callCount).to.equal(1);\n    });\n\n    it('should handleMeridiemChange', () => {\n      wrapper.instance().handleMeridiemChange();\n      expect(handleMeridiemChange.callCount).to.equal(1);\n      wrapper.instance().handleMeridiemChange();\n      expect(handleMeridiemChange.callCount).to.equal(2);\n    });\n  });\n});\n"
  },
  {
    "path": "test/components/TwentyFourHoursMode_spec.jsx",
    "content": "import React from 'react';\nimport { expect } from 'chai';\nimport { shallow } from 'enzyme';\nimport sinon from 'sinon-sandbox';\nimport TwentyFourHoursMode from '../../src/components/MaterialTheme/TwentyFourHoursMode';\nimport PickerDragHandler from '../../src/components/Picker/PickerDragHandler';\nimport languageHelper from '../../src/utils/language';\nimport '../_helpers/adapter';\n\nconst phrases = languageHelper.get('en');\n\ndescribe('TwentyFourHoursMode', () => {\n  describe('TwentyFourHoursMode Init', () => {\n    const wrapper = shallow(\n      <TwentyFourHoursMode hour={'03'} />\n    );\n\n    it('should render PickerDragHandler component', () => {\n      expect(wrapper.find(PickerDragHandler)).to.have.lengthOf(1);\n    });\n\n    it('should init currect state', () => {\n      expect(wrapper.state()).to.deep.equal({\n        step: 0,\n        pointerRotate: 90\n      });\n    });\n  });\n\n  describe('TwentyFourHoursMode Func', () => {\n    const handleHourChange = sinon.stub();\n    const handleMinuteChange = sinon.stub();\n    const wrapper = shallow(\n      <TwentyFourHoursMode\n        hour={'01'}\n        minute={'45'}\n        handleHourChange={handleHourChange}\n        handleMinuteChange={handleMinuteChange}\n      />\n    );\n\n    it('should handleHourChange', () => {\n      wrapper.instance().handleTimePointerClick({\n        time: 6,\n        pointerRotate: 180\n      });\n      expect(wrapper.state().pointerRotate).to.equal(180);\n      expect(handleHourChange.callCount).to.equal(1);\n    });\n\n    it('should handleStepChange', () => {\n      wrapper.instance().handleStepChange(1);\n      expect(wrapper.state()).to.deep.equal({\n        step: 0,\n        pointerRotate: 180\n      });\n      setTimeout(() => {\n        expect(wrapper.state()).to.deep.equal({\n          step: 1,\n          pointerRotate: 270\n        });\n      }, 300);\n    });\n\n    it('should handleMinuteChange', () => {\n      const newWrapper = shallow(\n        <TwentyFourHoursMode\n          hour={'01'}\n          minute={'45'}\n          step={1}\n          handleHourChange={handleHourChange}\n          handleMinuteChange={handleMinuteChange}\n        />\n      );\n      newWrapper.instance().handleTimePointerClick({\n        time: 30,\n        pointerRotate: 180\n      });\n      // after click minute, we close the panel & reset step state.\n      expect(newWrapper.state().pointerRotate).to.equal(30);\n      expect(newWrapper.state().step).to.equal(0);\n      expect(handleMinuteChange.callCount).to.equal(1);\n    });\n  });\n});\n"
  },
  {
    "path": "test/utils_spec.js",
    "content": "import moment from 'moment-timezone';\nimport { expect } from 'chai';\nimport timeHelper from '../src/utils/time';\nimport drag from '../src/utils/drag';\nimport {\n  MAX_ABSOLUTE_POSITION,\n  MIN_ABSOLUTE_POSITION\n} from '../src/utils/constant';\nimport { isSeq, head, tail, last } from '../src/utils/func';\n\ndescribe('Functional utils', () => {\n  describe('isSeq', () => {\n    it('should correctly detect a sequence', () => {\n      const isSequence = [isSeq('foo'), isSeq('foo'.split())].every(e => e === true);\n      const isNotSequence = [isSeq({ message: 'foo' }), isSeq(8), isSeq(true)].every(e => e === false);\n      expect(isSequence).to.equal(true);\n      expect(isNotSequence).to.equal(true);\n    });\n  });\n\n  describe('head', () => {\n    it('should return the first element of a sequence', () => {\n      expect(head('foo')).to.equal('f');\n      expect(head('foo'.split(''))).to.equal('f');\n    });\n  });\n\n  describe('tail', () => {\n    it('should return the last elements of a sequence', () => {\n      expect(tail('foo')).to.equal('oo');\n      expect(tail('foo'.split(''))).to.deep.equal(['o', 'o']);\n    });\n  });\n\n  describe('last', () => {\n    it('should return the last element of a sequence', () => {\n      expect(last('foo')).to.equal('o');\n      expect(last('foo'.split(''))).to.equal('o');\n    });\n  });\n});\n\n// because mocha doesn't play nice with arrow functions 😞\nconst tz = timeHelper.guessUserTz();\nconst time24 = moment().tz(tz.zoneName).format('HH:mmA').split(/:/);\nconst time12 = moment().tz(tz.zoneName).format('hh:mmA').split(/:/);\n\nconst modes = [24, 12];\nconst meridies = ['AM', 'PM']; // yes, this is the correct plural 😜\n\ndescribe('Time utils', () => {\n  describe('getCurrentTime()', () => {\n    it('should return the current time as a string in 24h format', () => {\n      const timeString = timeHelper.current();\n      expect(timeString).to.equal(time24.join(':').slice(0, 5));\n    });\n  });\n\n  describe('given a call to getValidTimeData()', () => {\n    describe('when passed no arguments', () => {\n      it('then it should default to the current local time in 24h mode', () => {\n        const testTimeData = timeHelper.time();\n\n        const timeData = {\n          hour12: head(time12).replace(/^0/, ''),\n          hour24: head(time24),\n          minute: last(time24).slice(0, 2),\n          meridiem: null,\n          mode: 24,\n          timezone: tz.zoneName\n        };\n\n        expect(testTimeData).to.deep.equal(timeData);\n      });\n    });\n\n    describe('when passed only a mode', () => {\n      it('then it should default to the current local time, with user-specified mode', () => {\n        modes.forEach((mode) => {\n          const testTimeData = timeHelper.time({\n            timeMode: mode\n          });\n          const timeData = {\n            mode,\n            hour12: head(time12).replace(/^0/, ''),\n            hour24: head(time24),\n            minute: last(time24).slice(0, 2),\n            meridiem: mode === 12 ? last(time12).slice(2) : null,\n            timezone: tz.zoneName\n          };\n\n          expect(testTimeData).to.deep.equal(timeData);\n        });\n      });\n    });\n\n    describe('when we passed only a meridiem', () => {\n      it('then it should default to the current local time, in 12h mode, ignoring meridiem', () => {\n        meridies.forEach((meridiem) => {\n          const testTimeData = timeHelper.time({ meridiem });\n          const timeData = {\n            hour12: head(time12).replace(/^0/, ''),\n            hour24: head(time24),\n            minute: last(time24).slice(0, 2),\n            meridiem: last(time12).slice(2),\n            mode: 12,\n            timezone: tz.zoneName\n          };\n\n          expect(testTimeData).to.deep.equal(timeData);\n        });\n      });\n    });\n  });\n\n  describe('Test getValidateTime func', () => {\n    it('should return 00 when get undefined', () => {\n      expect(timeHelper.validate()).to.equal('00');\n    });\n\n    it('should return 00 when get NaN', () => {\n      expect(timeHelper.validate('abc')).to.equal('00');\n    });\n\n    it('should return itself when validate', () => {\n      expect(timeHelper.validate('12')).to.equal('12');\n    });\n\n    it('should return a string with 0', () => {\n      expect(timeHelper.validate('2')).to.equal('02');\n    });\n  });\n\n  describe('Test getValidateIntTime func', () => {\n    it('should return 0', () => {\n      expect(timeHelper.validateInt('a')).to.equal(0);\n    });\n\n    it('should return int', () => {\n      expect(timeHelper.validateInt('11')).to.equal(11);\n    });\n\n    it('should return 0', () => {\n      expect(timeHelper.validateInt(null)).to.equal(0);\n    });\n  });\n\n  describe('Test getStandardAbsolutePosition func', () => {\n    it('should return the MinPosition', () => {\n      expect(\n        drag.validatePosition(\n          MIN_ABSOLUTE_POSITION - 1, MIN_ABSOLUTE_POSITION, MAX_ABSOLUTE_POSITION\n        )\n      ).to.equal(MIN_ABSOLUTE_POSITION);\n    });\n\n    it('should return the MaxPosition', () => {\n      expect(\n        drag.validatePosition(\n          MAX_ABSOLUTE_POSITION + 1, MAX_ABSOLUTE_POSITION, MAX_ABSOLUTE_POSITION\n        )\n      ).to.equal(MAX_ABSOLUTE_POSITION);\n    });\n  });\n\n  describe('Test timezone utils function', () => {\n    it('should get timezone by name', () => {\n      expect(\n        timeHelper.tzForName('America/Indianapolis').zoneName\n      ).to.equal('America/Indiana/Indianapolis');\n    });\n\n    it('should get timezone by city', () => {\n      expect(\n        timeHelper.tzForCity('shanghai').zoneName\n      ).to.equal('Asia/Shanghai');\n    });\n  });\n\n  describe('Test time format function', () => {\n    it('should format hour', () => {\n      expect(timeHelper.hourFormatter('8')).to.equal('08:00');\n      expect(timeHelper.hourFormatter('13:1')).to.equal('13:01');\n      expect(timeHelper.hourFormatter('2:60')).to.equal('02:00');\n    });\n\n    it('should format hour with default time', () => {\n      expect(timeHelper.hourFormatter('', '11:11')).to.equal('11:11');\n      expect(timeHelper.hourFormatter()).to.equal('00:00');\n    });\n\n    it('should format hour with meridiem', () => {\n      expect(timeHelper.hourFormatter('2:6 pm')).to.equal('02:06 PM');\n      expect(timeHelper.hourFormatter('2:6 12')).to.equal('02:06 AM');\n      expect(timeHelper.hourFormatter('13:00 pm')).to.equal('01:00 PM');\n    });\n\n    it('should remove meridiem in time', () => {\n      expect(timeHelper.withoutMeridiem('08:00 PM')).to.equal('08:00');\n      expect(timeHelper.withoutMeridiem('08:00 AM')).to.equal('08:00');\n      expect(timeHelper.withoutMeridiem('08:00')).to.equal('08:00');\n    })\n  });\n\n  describe('Test times render function', () => {\n    it('should render full 24 hour times with 30 minutes step', () => {\n      const times = timeHelper.get24ModeTimes({});\n      expect(times.length).to.equal(48);\n      expect(times[0]).to.equal('00:00');\n      expect(times[47]).to.equal('23:30');\n    });\n\n    it('should render full 24 hour times with 1 hour step', () => {\n      const times = timeHelper.get24ModeTimes({ step: 1, unit: 'hour' });\n      expect(times.length).to.equal(24);\n      expect(times[0]).to.equal('00:00');\n      expect(times[23]).to.equal('23:00');\n    });\n\n    it('should render 24 hour times cross one day with 1 hour step', () => {\n      const times = timeHelper.get24ModeTimes({\n        from: '20',\n        to: '8',\n        step: 1,\n        unit: 'hour'\n      });\n      expect(times.length).to.equal(13);\n      expect(times[0]).to.equal('20:00');\n      expect(times[12]).to.equal('08:00');\n    });\n\n    it('should render full 12 hour times with 30 minutes step', () => {\n      const times = timeHelper.get12ModeTimes({});\n      expect(times.length).to.equal(48);\n      expect(times[0]).to.equal('12:00 AM');\n      expect(times[47]).to.equal('11:30 PM');\n    });\n\n    it('should render full 12 hour times with 1 hour step', () => {\n      const times = timeHelper.get12ModeTimes({ step: 1, unit: 'hour' });\n      expect(times.length).to.equal(24);\n      expect(times[0]).to.equal('12:00 AM');\n      expect(times[23]).to.equal('11:00 PM');\n    });\n\n    it('should render 12 hour times cross one day with 1 hour step', () => {\n      const times = timeHelper.get12ModeTimes({\n        from: '08:00 PM',\n        to: '08:00 AM',\n        step: 1,\n        unit: 'hour'\n      });\n      expect(times.length).to.equal(13);\n      expect(times[0]).to.equal('08:00 PM');\n      expect(times[12]).to.equal('08:00 AM');\n    });\n  });\n});\n"
  }
]