├── .gitignore ├── LICENSE ├── README.md ├── demo └── index.html ├── dist ├── mdtimepicker-theme.css ├── mdtimepicker.css ├── mdtimepicker.js ├── mdtimepicker.min.css └── mdtimepicker.min.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── rollup.config.mjs ├── src ├── .babelrc.json ├── helpers.js ├── mdtimepicker.js ├── mdtimepicker.scss ├── themes │ ├── _format.scss │ ├── blue.scss │ ├── dark.scss │ ├── green.scss │ ├── indigo.scss │ ├── purple.scss │ ├── red.scss │ └── teal.scss └── vars.js ├── vue-timepicker.js └── vue3-timepicker.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | /logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | *.pid.lock 11 | 12 | # Bower dependency directory (https://bower.io/) 13 | bower_components 14 | 15 | # Dependency directories 16 | node_modules/ 17 | 18 | # Optional npm cache directory 19 | .npm 20 | 21 | # Optional eslint cache 22 | .eslintcache 23 | 24 | # Output of 'npm pack' 25 | *.tgz 26 | 27 | # parcel-bundler cache (https://parceljs.org/) 28 | .cache 29 | 30 | # IDE / Editor 31 | .idea 32 | 33 | # Service worker 34 | sw.* 35 | 36 | # macOS 37 | .DS_Store 38 | 39 | # Vim swap files 40 | *.swp 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Dionlee Uy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MDTimePicker 2 | ======== 3 | [![vanilla js](https://img.shields.io/npm/dt/@dmuy/timepicker?style=flat-square)](https://www.npmjs.com/package/@dmuy/timepicker) 4 | 5 | Buy Me a Coffee at ko-fi.com 6 | 7 | Material design inspired time picker plugin. 8 | 9 | ## Documentation 10 | * [Installation](https://github.com/dmuy/MDTimePicker/wiki/Installation) 11 | * [Options](https://github.com/dmuy/MDTimePicker/wiki/Options) 12 | * [Configurations](https://github.com/dmuy/MDTimePicker/wiki/Options#configurations) 13 | * [Callback Functions](https://github.com/dmuy/MDTimePicker/wiki/Options#callback-functions) 14 | * [Formatting](https://github.com/dmuy/MDTimePicker/wiki/Options#formatting) 15 | * [Usage](https://github.com/dmuy/MDTimePicker/wiki/Usage) 16 | * [Min and Max](https://github.com/dmuy/MDTimePicker/wiki/Usage#min-and-max) 17 | * [Built-in Methods](https://github.com/dmuy/MDTimePicker/wiki/Usage#usable-built-in-methods) 18 | * [Event Handling](https://github.com/dmuy/MDTimePicker/wiki/Usage#event) 19 | * [Themes](https://github.com/dmuy/MDTimePicker/wiki/Usage#themes) 20 | * [Usage (Vue)](https://github.com/dmuy/MDTimePicker/wiki/Usage-(Vue)) 21 | * [Nuxt](https://github.com/dmuy/MDTimePicker/wiki/Usage-(Vue)#nuxt) 22 | 23 | **[DEMO](https://dmuy.github.io/MDTimePicker/)** 24 | 25 | ## Screenshots 26 | ![alt text](https://i.imgur.com/M7Jb5H3.png "TimePicker: Hour") 27 | ![alt text](https://i.imgur.com/LmIkHoU.png "TimePicker: Minute") 28 | ![alt text](https://i.imgur.com/WyS2aHd.png "TimePicker: Dark") 29 | ![alt text](https://i.imgur.com/kNqqKMZ.png "TimePicker: 24-hour mode") 30 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Timepicker Plugin 5 | 6 | 7 | 8 | 9 | 10 | 31 | 32 | 33 |
34 |

MDTimePicker

35 |
36 | 37 | npm 38 | 39 | 40 | npm 41 | 42 | 43 | stars 44 | 45 |
46 |

Time picker

47 | 48 | 49 |
50 | Logger: 51 | 52 |
53 |
54 | 55 | 85 | 86 | -------------------------------------------------------------------------------- /dist/mdtimepicker-theme.css: -------------------------------------------------------------------------------- 1 | .mdtp__wrapper[data-theme='yellow'] .mdtp__time_holder { 2 | background-color: #F9A825; 3 | } 4 | 5 | .mdtp__wrapper[data-theme='yellow'] .mdtp__clock .mdtp__am.active, 6 | .mdtp__wrapper[data-theme='yellow'] .mdtp__clock .mdtp__pm.active, 7 | .mdtp__wrapper[data-theme='yellow'] .mdtp__clock .mdtp__clock_dot { 8 | background-color: #F9A825; 9 | } 10 | 11 | .mdtp__wrapper[data-theme='yellow'] .mdtp__clock .mdtp__digit.active span, 12 | .mdtp__wrapper[data-theme='yellow'] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover { 13 | background-color: #F9A825 !important; 14 | } 15 | 16 | .mdtp__wrapper[data-theme='yellow'] .mdtp__clock .mdtp__digit.active:before { 17 | background-color: #F9A825; 18 | } 19 | 20 | .mdtp__wrapper[data-theme='yellow'] .mdtp__button { 21 | color: #F9A825; 22 | } 23 | -------------------------------------------------------------------------------- /dist/mdtimepicker.css: -------------------------------------------------------------------------------- 1 | /*!Don't remove this! 2 | * MDTimePicker plugin styles 3 | * 4 | * Author: Dionlee Uy 5 | * Email: dionleeuy@gmail.com 6 | */ 7 | @import url("https://fonts.googleapis.com/css?family=Roboto:400,500&display=swap"); 8 | .mdtimepicker { 9 | position: fixed; 10 | top: 0; 11 | left: 0; 12 | right: 0; 13 | bottom: 0; 14 | font-family: Roboto, sans-serif; 15 | font-size: 14px; 16 | background-color: rgba(10, 10, 10, 0.65); 17 | transition: background-color .28s ease; 18 | z-index: 100001; 19 | } 20 | 21 | .mdtimepicker .mdtp__wrapper { 22 | position: absolute; 23 | display: flex; 24 | flex-direction: column; 25 | left: 50%; 26 | bottom: 24px; 27 | min-width: 280px; 28 | opacity: 1; 29 | outline: none; 30 | -webkit-user-select: none; 31 | -moz-user-select: none; 32 | user-select: none; 33 | border-radius: 4px; 34 | transform: translateX(-50%) scale(1); 35 | box-shadow: 0px 11px 15px -7px rgba(0, 0, 0, 0.2), 0px 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 9px 46px 8px rgba(0, 0, 0, 0.12); 36 | transition: transform .28s ease, opacity .28s ease; 37 | overflow: hidden; 38 | } 39 | 40 | .mdtimepicker .mdtp__wrapper.animate { 41 | transform: translateX(-50%) scale(1.05); 42 | opacity: 0; 43 | } 44 | 45 | .mdtimepicker .mdtp__time_holder { 46 | display: flex; 47 | flex-direction: row; 48 | align-items: center; 49 | justify-content: center; 50 | font-size: 46px; 51 | padding: 20px 24px; 52 | color: rgba(255, 255, 255, 0.5); 53 | text-align: center; 54 | background-color: #1565c0; 55 | } 56 | 57 | .mdtimepicker .mdtp__time_holder > span { 58 | display: inline-block; 59 | line-height: 48px; 60 | cursor: default; 61 | } 62 | 63 | .mdtimepicker .mdtp__time_holder > span:not(.mdtp__timedots):not(.mdtp__ampm) { 64 | cursor: pointer; 65 | margin: 0 4px; 66 | transition: color .2s linear; 67 | } 68 | 69 | .mdtimepicker .mdtp__time_holder .mdtp__time_h.active, 70 | .mdtimepicker .mdtp__time_holder .mdtp__time_m.active { 71 | color: #fafafa; 72 | } 73 | 74 | .mdtimepicker .mdtp__time_holder .mdtp__ampm { 75 | font-size: 18px; 76 | cursor: pointer; 77 | transition: color .2s linear; 78 | } 79 | 80 | .mdtimepicker .mdtp__time_holder .mdtp__ampm:hover { 81 | color: #fafafa; 82 | } 83 | 84 | .mdtimepicker .mdtp__clock_holder { 85 | position: relative; 86 | background-color: #fff; 87 | } 88 | 89 | .mdtimepicker .mdtp__clock_holder .mdtp__clock { 90 | position: relative; 91 | width: 250px; 92 | height: 250px; 93 | margin: 20px; 94 | border-radius: 50%; 95 | background-color: #eee; 96 | } 97 | 98 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__am, 99 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__pm { 100 | display: block; 101 | position: absolute; 102 | bottom: -8px; 103 | width: 36px; 104 | height: 36px; 105 | line-height: 36px; 106 | text-align: center; 107 | cursor: pointer; 108 | border-radius: 50%; 109 | border: 1px solid rgba(0, 0, 0, 0.1); 110 | background: rgba(0, 0, 0, 0.05); 111 | transition: background-color .2s ease, color .2s; 112 | z-index: 3; 113 | } 114 | 115 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__am:hover, 116 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__pm:hover { 117 | background-color: rgba(0, 0, 0, 0.1); 118 | } 119 | 120 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__am.active, 121 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__pm.active { 122 | color: #fafafa; 123 | background-color: #1565c0; 124 | } 125 | 126 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__am { 127 | left: -8px; 128 | } 129 | 130 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__pm { 131 | right: -8px; 132 | } 133 | 134 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__clock_dot { 135 | position: absolute; 136 | top: 50%; 137 | left: 50%; 138 | padding: 4px; 139 | border-radius: 50%; 140 | background-color: #1565c0; 141 | transform: translate(-50%, -50%); 142 | } 143 | 144 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__hour_holder, 145 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder { 146 | position: absolute; 147 | top: 0; 148 | width: 100%; 149 | height: 100%; 150 | opacity: 1; 151 | transform: scale(1); 152 | transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.35s ease; 153 | overflow: hidden; 154 | } 155 | 156 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__hour_holder.hidden, 157 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder.hidden { 158 | display: none; 159 | } 160 | 161 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__hour_holder.animate { 162 | transform: scale(1.2); 163 | opacity: 0; 164 | } 165 | 166 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder.animate { 167 | transform: scale(0.8); 168 | opacity: 0; 169 | } 170 | 171 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit { 172 | position: absolute; 173 | width: 50%; 174 | top: 50%; 175 | left: 0; 176 | margin-top: -16px; 177 | transform-origin: right center; 178 | z-index: 1; 179 | } 180 | 181 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit span { 182 | display: inline-block; 183 | width: 32px; 184 | height: 32px; 185 | line-height: 32px; 186 | margin-left: 8px; 187 | text-align: center; 188 | border-radius: 50%; 189 | cursor: pointer; 190 | transition: background-color .28s, color .14s; 191 | } 192 | 193 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit.inner--digit { 194 | width: 36%; 195 | left: 14%; 196 | z-index: 2; 197 | } 198 | 199 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit.active span, 200 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover { 201 | background-color: #1565c0 !important; 202 | color: #fff; 203 | z-index: 2; 204 | } 205 | 206 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit.digit--disabled span { 207 | color: #c8c8c8; 208 | cursor: not-allowed; 209 | background-color: transparent !important; 210 | } 211 | 212 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit.active:before { 213 | content: ''; 214 | display: block; 215 | position: absolute; 216 | top: calc(50% - 1px); 217 | right: 0; 218 | height: 2px; 219 | width: calc(100% - 40px); 220 | background-color: #1565c0; 221 | } 222 | 223 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit { 224 | font-size: 13px; 225 | } 226 | 227 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit:not(.marker) { 228 | margin-top: -6px; 229 | height: 12px; 230 | } 231 | 232 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit:not(.marker) span { 233 | width: 12px; 234 | height: 12px; 235 | line-height: 12px; 236 | margin-left: 14px; 237 | } 238 | 239 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit:not(.marker).active:before { 240 | width: calc(100% - 26px); 241 | } 242 | 243 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit.marker { 244 | margin-top: -12px; 245 | } 246 | 247 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit.marker span { 248 | width: 24px; 249 | height: 24px; 250 | line-height: 24px; 251 | margin-left: 10px; 252 | } 253 | 254 | .mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit.marker.active:before { 255 | width: calc(100% - 34px); 256 | } 257 | 258 | .mdtimepicker .mdtp__buttons { 259 | padding: 0 10px 10px; 260 | text-align: right; 261 | } 262 | 263 | .mdtimepicker .mdtp__buttons .mdtp__button { 264 | display: inline-block; 265 | padding: 0 16px; 266 | min-width: 40px; 267 | text-align: center; 268 | text-transform: uppercase; 269 | line-height: 32px; 270 | font-weight: 500; 271 | cursor: pointer; 272 | color: #1565c0; 273 | border-radius: 4px; 274 | transition: background-color .2s linear; 275 | } 276 | 277 | .mdtimepicker .mdtp__buttons .mdtp__button:hover { 278 | background-color: rgba(0, 0, 0, 0.1); 279 | } 280 | 281 | .mdtimepicker .mdtp__buttons .mdtp__button:active { 282 | background-color: rgba(0, 0, 0, 0.2); 283 | } 284 | 285 | .mdtimepicker .mdtp__buttons .mdtp__button.clear-btn { 286 | float: left; 287 | color: #ef5350 !important; 288 | } 289 | 290 | .mdtimepicker .mdtp__buttons:after { 291 | content: ''; 292 | display: block; 293 | clear: both; 294 | } 295 | 296 | .mdtimepicker.hidden { 297 | display: none; 298 | } 299 | 300 | .mdtimepicker.animate { 301 | background-color: transparent; 302 | } 303 | 304 | .mdtp__digit.rotate--15 { 305 | transform: rotate(-15deg); 306 | } 307 | 308 | .mdtp__digit.rotate--15 span { 309 | transform: rotate(15deg); 310 | } 311 | 312 | .mdtp__digit.rotate-6 { 313 | transform: rotate(6deg); 314 | } 315 | 316 | .mdtp__digit.rotate-6 span { 317 | transform: rotate(-6deg); 318 | } 319 | 320 | .mdtp__digit.rotate-12 { 321 | transform: rotate(12deg); 322 | } 323 | 324 | .mdtp__digit.rotate-12 span { 325 | transform: rotate(-12deg); 326 | } 327 | 328 | .mdtp__digit.rotate-15 { 329 | transform: rotate(15deg); 330 | } 331 | 332 | .mdtp__digit.rotate-15 span { 333 | transform: rotate(-15deg); 334 | } 335 | 336 | .mdtp__digit.rotate-18 { 337 | transform: rotate(18deg); 338 | } 339 | 340 | .mdtp__digit.rotate-18 span { 341 | transform: rotate(-18deg); 342 | } 343 | 344 | .mdtp__digit.rotate-24 { 345 | transform: rotate(24deg); 346 | } 347 | 348 | .mdtp__digit.rotate-24 span { 349 | transform: rotate(-24deg); 350 | } 351 | 352 | .mdtp__digit.rotate-30 { 353 | transform: rotate(30deg); 354 | } 355 | 356 | .mdtp__digit.rotate-30 span { 357 | transform: rotate(-30deg); 358 | } 359 | 360 | .mdtp__digit.rotate-36 { 361 | transform: rotate(36deg); 362 | } 363 | 364 | .mdtp__digit.rotate-36 span { 365 | transform: rotate(-36deg); 366 | } 367 | 368 | .mdtp__digit.rotate-42 { 369 | transform: rotate(42deg); 370 | } 371 | 372 | .mdtp__digit.rotate-42 span { 373 | transform: rotate(-42deg); 374 | } 375 | 376 | .mdtp__digit.rotate-45 { 377 | transform: rotate(45deg); 378 | } 379 | 380 | .mdtp__digit.rotate-45 span { 381 | transform: rotate(-45deg); 382 | } 383 | 384 | .mdtp__digit.rotate-48 { 385 | transform: rotate(48deg); 386 | } 387 | 388 | .mdtp__digit.rotate-48 span { 389 | transform: rotate(-48deg); 390 | } 391 | 392 | .mdtp__digit.rotate-54 { 393 | transform: rotate(54deg); 394 | } 395 | 396 | .mdtp__digit.rotate-54 span { 397 | transform: rotate(-54deg); 398 | } 399 | 400 | .mdtp__digit.rotate-60 { 401 | transform: rotate(60deg); 402 | } 403 | 404 | .mdtp__digit.rotate-60 span { 405 | transform: rotate(-60deg); 406 | } 407 | 408 | .mdtp__digit.rotate-66 { 409 | transform: rotate(66deg); 410 | } 411 | 412 | .mdtp__digit.rotate-66 span { 413 | transform: rotate(-66deg); 414 | } 415 | 416 | .mdtp__digit.rotate-72 { 417 | transform: rotate(72deg); 418 | } 419 | 420 | .mdtp__digit.rotate-72 span { 421 | transform: rotate(-72deg); 422 | } 423 | 424 | .mdtp__digit.rotate-75 { 425 | transform: rotate(75deg); 426 | } 427 | 428 | .mdtp__digit.rotate-75 span { 429 | transform: rotate(-75deg); 430 | } 431 | 432 | .mdtp__digit.rotate-78 { 433 | transform: rotate(78deg); 434 | } 435 | 436 | .mdtp__digit.rotate-78 span { 437 | transform: rotate(-78deg); 438 | } 439 | 440 | .mdtp__digit.rotate-84 { 441 | transform: rotate(84deg); 442 | } 443 | 444 | .mdtp__digit.rotate-84 span { 445 | transform: rotate(-84deg); 446 | } 447 | 448 | .mdtp__digit.rotate-90 { 449 | transform: rotate(90deg); 450 | } 451 | 452 | .mdtp__digit.rotate-90 span { 453 | transform: rotate(-90deg); 454 | } 455 | 456 | .mdtp__digit.rotate-96 { 457 | transform: rotate(96deg); 458 | } 459 | 460 | .mdtp__digit.rotate-96 span { 461 | transform: rotate(-96deg); 462 | } 463 | 464 | .mdtp__digit.rotate-102 { 465 | transform: rotate(102deg); 466 | } 467 | 468 | .mdtp__digit.rotate-102 span { 469 | transform: rotate(-102deg); 470 | } 471 | 472 | .mdtp__digit.rotate-105 { 473 | transform: rotate(105deg); 474 | } 475 | 476 | .mdtp__digit.rotate-105 span { 477 | transform: rotate(-105deg); 478 | } 479 | 480 | .mdtp__digit.rotate-108 { 481 | transform: rotate(108deg); 482 | } 483 | 484 | .mdtp__digit.rotate-108 span { 485 | transform: rotate(-108deg); 486 | } 487 | 488 | .mdtp__digit.rotate-114 { 489 | transform: rotate(114deg); 490 | } 491 | 492 | .mdtp__digit.rotate-114 span { 493 | transform: rotate(-114deg); 494 | } 495 | 496 | .mdtp__digit.rotate-120 { 497 | transform: rotate(120deg); 498 | } 499 | 500 | .mdtp__digit.rotate-120 span { 501 | transform: rotate(-120deg); 502 | } 503 | 504 | .mdtp__digit.rotate-126 { 505 | transform: rotate(126deg); 506 | } 507 | 508 | .mdtp__digit.rotate-126 span { 509 | transform: rotate(-126deg); 510 | } 511 | 512 | .mdtp__digit.rotate-132 { 513 | transform: rotate(132deg); 514 | } 515 | 516 | .mdtp__digit.rotate-132 span { 517 | transform: rotate(-132deg); 518 | } 519 | 520 | .mdtp__digit.rotate-135 { 521 | transform: rotate(135deg); 522 | } 523 | 524 | .mdtp__digit.rotate-135 span { 525 | transform: rotate(-135deg); 526 | } 527 | 528 | .mdtp__digit.rotate-138 { 529 | transform: rotate(138deg); 530 | } 531 | 532 | .mdtp__digit.rotate-138 span { 533 | transform: rotate(-138deg); 534 | } 535 | 536 | .mdtp__digit.rotate-144 { 537 | transform: rotate(144deg); 538 | } 539 | 540 | .mdtp__digit.rotate-144 span { 541 | transform: rotate(-144deg); 542 | } 543 | 544 | .mdtp__digit.rotate-150 { 545 | transform: rotate(150deg); 546 | } 547 | 548 | .mdtp__digit.rotate-150 span { 549 | transform: rotate(-150deg); 550 | } 551 | 552 | .mdtp__digit.rotate-156 { 553 | transform: rotate(156deg); 554 | } 555 | 556 | .mdtp__digit.rotate-156 span { 557 | transform: rotate(-156deg); 558 | } 559 | 560 | .mdtp__digit.rotate-162 { 561 | transform: rotate(162deg); 562 | } 563 | 564 | .mdtp__digit.rotate-162 span { 565 | transform: rotate(-162deg); 566 | } 567 | 568 | .mdtp__digit.rotate-165 { 569 | transform: rotate(165deg); 570 | } 571 | 572 | .mdtp__digit.rotate-165 span { 573 | transform: rotate(-165deg); 574 | } 575 | 576 | .mdtp__digit.rotate-168 { 577 | transform: rotate(168deg); 578 | } 579 | 580 | .mdtp__digit.rotate-168 span { 581 | transform: rotate(-168deg); 582 | } 583 | 584 | .mdtp__digit.rotate-174 { 585 | transform: rotate(174deg); 586 | } 587 | 588 | .mdtp__digit.rotate-174 span { 589 | transform: rotate(-174deg); 590 | } 591 | 592 | .mdtp__digit.rotate-180 { 593 | transform: rotate(180deg); 594 | } 595 | 596 | .mdtp__digit.rotate-180 span { 597 | transform: rotate(-180deg); 598 | } 599 | 600 | .mdtp__digit.rotate-186 { 601 | transform: rotate(186deg); 602 | } 603 | 604 | .mdtp__digit.rotate-186 span { 605 | transform: rotate(-186deg); 606 | } 607 | 608 | .mdtp__digit.rotate-192 { 609 | transform: rotate(192deg); 610 | } 611 | 612 | .mdtp__digit.rotate-192 span { 613 | transform: rotate(-192deg); 614 | } 615 | 616 | .mdtp__digit.rotate-195 { 617 | transform: rotate(195deg); 618 | } 619 | 620 | .mdtp__digit.rotate-195 span { 621 | transform: rotate(-195deg); 622 | } 623 | 624 | .mdtp__digit.rotate-198 { 625 | transform: rotate(198deg); 626 | } 627 | 628 | .mdtp__digit.rotate-198 span { 629 | transform: rotate(-198deg); 630 | } 631 | 632 | .mdtp__digit.rotate-204 { 633 | transform: rotate(204deg); 634 | } 635 | 636 | .mdtp__digit.rotate-204 span { 637 | transform: rotate(-204deg); 638 | } 639 | 640 | .mdtp__digit.rotate-210 { 641 | transform: rotate(210deg); 642 | } 643 | 644 | .mdtp__digit.rotate-210 span { 645 | transform: rotate(-210deg); 646 | } 647 | 648 | .mdtp__digit.rotate-216 { 649 | transform: rotate(216deg); 650 | } 651 | 652 | .mdtp__digit.rotate-216 span { 653 | transform: rotate(-216deg); 654 | } 655 | 656 | .mdtp__digit.rotate-222 { 657 | transform: rotate(222deg); 658 | } 659 | 660 | .mdtp__digit.rotate-222 span { 661 | transform: rotate(-222deg); 662 | } 663 | 664 | .mdtp__digit.rotate-225 { 665 | transform: rotate(225deg); 666 | } 667 | 668 | .mdtp__digit.rotate-225 span { 669 | transform: rotate(-225deg); 670 | } 671 | 672 | .mdtp__digit.rotate-228 { 673 | transform: rotate(228deg); 674 | } 675 | 676 | .mdtp__digit.rotate-228 span { 677 | transform: rotate(-228deg); 678 | } 679 | 680 | .mdtp__digit.rotate-234 { 681 | transform: rotate(234deg); 682 | } 683 | 684 | .mdtp__digit.rotate-234 span { 685 | transform: rotate(-234deg); 686 | } 687 | 688 | .mdtp__digit.rotate-240 { 689 | transform: rotate(240deg); 690 | } 691 | 692 | .mdtp__digit.rotate-240 span { 693 | transform: rotate(-240deg); 694 | } 695 | 696 | .mdtp__digit.rotate-246 { 697 | transform: rotate(246deg); 698 | } 699 | 700 | .mdtp__digit.rotate-246 span { 701 | transform: rotate(-246deg); 702 | } 703 | 704 | .mdtp__digit.rotate-252 { 705 | transform: rotate(252deg); 706 | } 707 | 708 | .mdtp__digit.rotate-252 span { 709 | transform: rotate(-252deg); 710 | } 711 | 712 | .mdtp__digit.rotate-255 { 713 | transform: rotate(255deg); 714 | } 715 | 716 | .mdtp__digit.rotate-255 span { 717 | transform: rotate(-255deg); 718 | } 719 | 720 | .mdtp__digit.rotate-258 { 721 | transform: rotate(258deg); 722 | } 723 | 724 | .mdtp__digit.rotate-258 span { 725 | transform: rotate(-258deg); 726 | } 727 | 728 | .mdtp__digit.rotate-264 { 729 | transform: rotate(264deg); 730 | } 731 | 732 | .mdtp__digit.rotate-264 span { 733 | transform: rotate(-264deg); 734 | } 735 | 736 | .mdtp__digit.rotate-270 { 737 | transform: rotate(270deg); 738 | } 739 | 740 | .mdtp__digit.rotate-270 span { 741 | transform: rotate(-270deg); 742 | } 743 | 744 | .mdtp__digit.rotate-276 { 745 | transform: rotate(276deg); 746 | } 747 | 748 | .mdtp__digit.rotate-276 span { 749 | transform: rotate(-276deg); 750 | } 751 | 752 | .mdtp__digit.rotate-282 { 753 | transform: rotate(282deg); 754 | } 755 | 756 | .mdtp__digit.rotate-282 span { 757 | transform: rotate(-282deg); 758 | } 759 | 760 | .mdtp__digit.rotate-285 { 761 | transform: rotate(285deg); 762 | } 763 | 764 | .mdtp__digit.rotate-285 span { 765 | transform: rotate(-285deg); 766 | } 767 | 768 | .mdtp__digit.rotate-288 { 769 | transform: rotate(288deg); 770 | } 771 | 772 | .mdtp__digit.rotate-288 span { 773 | transform: rotate(-288deg); 774 | } 775 | 776 | .mdtp__digit.rotate-294 { 777 | transform: rotate(294deg); 778 | } 779 | 780 | .mdtp__digit.rotate-294 span { 781 | transform: rotate(-294deg); 782 | } 783 | 784 | .mdtp__digit.rotate-300 { 785 | transform: rotate(300deg); 786 | } 787 | 788 | .mdtp__digit.rotate-300 span { 789 | transform: rotate(-300deg); 790 | } 791 | 792 | .mdtp__digit.rotate-306 { 793 | transform: rotate(306deg); 794 | } 795 | 796 | .mdtp__digit.rotate-306 span { 797 | transform: rotate(-306deg); 798 | } 799 | 800 | .mdtp__digit.rotate-312 { 801 | transform: rotate(312deg); 802 | } 803 | 804 | .mdtp__digit.rotate-312 span { 805 | transform: rotate(-312deg); 806 | } 807 | 808 | .mdtp__digit.rotate-315 { 809 | transform: rotate(315deg); 810 | } 811 | 812 | .mdtp__digit.rotate-315 span { 813 | transform: rotate(-315deg); 814 | } 815 | 816 | .mdtp__digit.rotate-318 { 817 | transform: rotate(318deg); 818 | } 819 | 820 | .mdtp__digit.rotate-318 span { 821 | transform: rotate(-318deg); 822 | } 823 | 824 | .mdtp__digit.rotate-324 { 825 | transform: rotate(324deg); 826 | } 827 | 828 | .mdtp__digit.rotate-324 span { 829 | transform: rotate(-324deg); 830 | } 831 | 832 | .mdtp__digit.rotate-330 { 833 | transform: rotate(330deg); 834 | } 835 | 836 | .mdtp__digit.rotate-330 span { 837 | transform: rotate(-330deg); 838 | } 839 | 840 | .mdtp__digit.rotate-336 { 841 | transform: rotate(336deg); 842 | } 843 | 844 | .mdtp__digit.rotate-336 span { 845 | transform: rotate(-336deg); 846 | } 847 | 848 | .mdtp__digit.rotate-342 { 849 | transform: rotate(342deg); 850 | } 851 | 852 | .mdtp__digit.rotate-342 span { 853 | transform: rotate(-342deg); 854 | } 855 | 856 | .mdtp__digit.rotate-348 { 857 | transform: rotate(348deg); 858 | } 859 | 860 | .mdtp__digit.rotate-348 span { 861 | transform: rotate(-348deg); 862 | } 863 | 864 | .mdtp__digit.rotate-354 { 865 | transform: rotate(354deg); 866 | } 867 | 868 | .mdtp__digit.rotate-354 span { 869 | transform: rotate(-354deg); 870 | } 871 | 872 | .mdtp__digit.rotate-360 { 873 | transform: rotate(360deg); 874 | } 875 | 876 | .mdtp__digit.rotate-360 span { 877 | transform: rotate(-360deg); 878 | } 879 | 880 | body[mdtimepicker-display='on'] { 881 | overflow: hidden; 882 | } 883 | 884 | @media (max-height: 360px) { 885 | .mdtimepicker .mdtp__wrapper { 886 | flex-direction: row; 887 | bottom: 8px; 888 | } 889 | .mdtimepicker .mdtp__time_holder { 890 | width: 160px; 891 | padding: 20px; 892 | } 893 | .mdtimepicker .mdtp__clock .mdtp__am, .mdtimepicker .mdtp__clock .mdtp__pm { 894 | bottom: -4px; 895 | } 896 | .mdtimepicker .mdtp__clock .mdtp__am { 897 | left: -4px; 898 | } 899 | .mdtimepicker .mdtp__clock .mdtp__pm { 900 | right: -4px; 901 | } 902 | } 903 | 904 | @media (max-height: 320px) { 905 | .mdtimepicker .mdtp__wrapper { 906 | bottom: 0; 907 | } 908 | } 909 | 910 | .mdtp__wrapper[data-theme='red'] .mdtp__time_holder { 911 | background-color: #c62828; 912 | } 913 | 914 | .mdtp__wrapper[data-theme='red'] .mdtp__clock .mdtp__am.active, 915 | .mdtp__wrapper[data-theme='red'] .mdtp__clock .mdtp__pm.active, 916 | .mdtp__wrapper[data-theme='red'] .mdtp__clock .mdtp__clock_dot { 917 | background-color: #c62828; 918 | } 919 | 920 | .mdtp__wrapper[data-theme='red'] .mdtp__clock .mdtp__digit.active span, 921 | .mdtp__wrapper[data-theme='red'] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover { 922 | background-color: #c62828 !important; 923 | } 924 | 925 | .mdtp__wrapper[data-theme='red'] .mdtp__clock .mdtp__digit.active:before { 926 | background-color: #c62828; 927 | } 928 | 929 | .mdtp__wrapper[data-theme='red'] .mdtp__button { 930 | color: #c62828; 931 | } 932 | 933 | .mdtp__wrapper[data-theme='green'] .mdtp__time_holder { 934 | background-color: #2e7d32; 935 | } 936 | 937 | .mdtp__wrapper[data-theme='green'] .mdtp__clock .mdtp__am.active, 938 | .mdtp__wrapper[data-theme='green'] .mdtp__clock .mdtp__pm.active, 939 | .mdtp__wrapper[data-theme='green'] .mdtp__clock .mdtp__clock_dot { 940 | background-color: #2e7d32; 941 | } 942 | 943 | .mdtp__wrapper[data-theme='green'] .mdtp__clock .mdtp__digit.active span, 944 | .mdtp__wrapper[data-theme='green'] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover { 945 | background-color: #2e7d32 !important; 946 | } 947 | 948 | .mdtp__wrapper[data-theme='green'] .mdtp__clock .mdtp__digit.active:before { 949 | background-color: #2e7d32; 950 | } 951 | 952 | .mdtp__wrapper[data-theme='green'] .mdtp__button { 953 | color: #2e7d32; 954 | } 955 | 956 | .mdtp__wrapper[data-theme='blue'] .mdtp__time_holder { 957 | background-color: #1565c0; 958 | } 959 | 960 | .mdtp__wrapper[data-theme='blue'] .mdtp__clock .mdtp__am.active, 961 | .mdtp__wrapper[data-theme='blue'] .mdtp__clock .mdtp__pm.active, 962 | .mdtp__wrapper[data-theme='blue'] .mdtp__clock .mdtp__clock_dot { 963 | background-color: #1565c0; 964 | } 965 | 966 | .mdtp__wrapper[data-theme='blue'] .mdtp__clock .mdtp__digit.active span, 967 | .mdtp__wrapper[data-theme='blue'] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover { 968 | background-color: #1565c0 !important; 969 | } 970 | 971 | .mdtp__wrapper[data-theme='blue'] .mdtp__clock .mdtp__digit.active:before { 972 | background-color: #1565c0; 973 | } 974 | 975 | .mdtp__wrapper[data-theme='blue'] .mdtp__button { 976 | color: #1565c0; 977 | } 978 | 979 | .mdtp__wrapper[data-theme='teal'] .mdtp__time_holder { 980 | background-color: #00695c; 981 | } 982 | 983 | .mdtp__wrapper[data-theme='teal'] .mdtp__clock .mdtp__am.active, 984 | .mdtp__wrapper[data-theme='teal'] .mdtp__clock .mdtp__pm.active, 985 | .mdtp__wrapper[data-theme='teal'] .mdtp__clock .mdtp__clock_dot { 986 | background-color: #00695c; 987 | } 988 | 989 | .mdtp__wrapper[data-theme='teal'] .mdtp__clock .mdtp__digit.active span, 990 | .mdtp__wrapper[data-theme='teal'] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover { 991 | background-color: #00695c !important; 992 | } 993 | 994 | .mdtp__wrapper[data-theme='teal'] .mdtp__clock .mdtp__digit.active:before { 995 | background-color: #00695c; 996 | } 997 | 998 | .mdtp__wrapper[data-theme='teal'] .mdtp__button { 999 | color: #00695c; 1000 | } 1001 | 1002 | .mdtp__wrapper[data-theme='purple'] .mdtp__time_holder { 1003 | background-color: #6a1b9a; 1004 | } 1005 | 1006 | .mdtp__wrapper[data-theme='purple'] .mdtp__clock .mdtp__am.active, 1007 | .mdtp__wrapper[data-theme='purple'] .mdtp__clock .mdtp__pm.active, 1008 | .mdtp__wrapper[data-theme='purple'] .mdtp__clock .mdtp__clock_dot { 1009 | background-color: #6a1b9a; 1010 | } 1011 | 1012 | .mdtp__wrapper[data-theme='purple'] .mdtp__clock .mdtp__digit.active span, 1013 | .mdtp__wrapper[data-theme='purple'] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover { 1014 | background-color: #6a1b9a !important; 1015 | } 1016 | 1017 | .mdtp__wrapper[data-theme='purple'] .mdtp__clock .mdtp__digit.active:before { 1018 | background-color: #6a1b9a; 1019 | } 1020 | 1021 | .mdtp__wrapper[data-theme='purple'] .mdtp__button { 1022 | color: #6a1b9a; 1023 | } 1024 | 1025 | .mdtp__wrapper[data-theme='indigo'] .mdtp__time_holder { 1026 | background-color: #283593; 1027 | } 1028 | 1029 | .mdtp__wrapper[data-theme='indigo'] .mdtp__clock .mdtp__am.active, 1030 | .mdtp__wrapper[data-theme='indigo'] .mdtp__clock .mdtp__pm.active, 1031 | .mdtp__wrapper[data-theme='indigo'] .mdtp__clock .mdtp__clock_dot { 1032 | background-color: #283593; 1033 | } 1034 | 1035 | .mdtp__wrapper[data-theme='indigo'] .mdtp__clock .mdtp__digit.active span, 1036 | .mdtp__wrapper[data-theme='indigo'] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover { 1037 | background-color: #283593 !important; 1038 | } 1039 | 1040 | .mdtp__wrapper[data-theme='indigo'] .mdtp__clock .mdtp__digit.active:before { 1041 | background-color: #283593; 1042 | } 1043 | 1044 | .mdtp__wrapper[data-theme='indigo'] .mdtp__button { 1045 | color: #283593; 1046 | } 1047 | 1048 | .mdtp__wrapper[data-theme='dark'] .mdtp__time_holder { 1049 | background-color: #121212; 1050 | } 1051 | 1052 | .mdtp__wrapper[data-theme='dark'] .mdtp__clock_holder { 1053 | background-color: #1d1d1d; 1054 | } 1055 | 1056 | .mdtp__wrapper[data-theme='dark'] .mdtp__clock_holder .mdtp__clock { 1057 | background-color: #181818; 1058 | } 1059 | 1060 | .mdtp__wrapper[data-theme='dark'] .mdtp__clock_holder .mdtp__clock .mdtp__digit:not(.digit--disabled) { 1061 | color: rgba(255, 255, 255, 0.87); 1062 | } 1063 | 1064 | .mdtp__wrapper[data-theme='dark'] .mdtp__clock_holder .mdtp__clock .mdtp__digit.digit--disabled span { 1065 | color: rgba(100, 100, 100, 0.87); 1066 | } 1067 | 1068 | .mdtp__wrapper[data-theme='dark'] .mdtp__clock_holder .mdtp__clock .mdtp__am:not(.active), 1069 | .mdtp__wrapper[data-theme='dark'] .mdtp__clock_holder .mdtp__clock .mdtp__pm:not(.active) { 1070 | color: rgba(255, 255, 255, 0.87); 1071 | background-color: rgba(200, 200, 200, 0.05); 1072 | } 1073 | 1074 | .mdtp__wrapper[data-theme='dark'] .mdtp__button { 1075 | color: #42a5f5; 1076 | } 1077 | 1078 | .mdtp__wrapper[data-theme='dark'] .mdtp__button:hover { 1079 | background-color: rgba(255, 255, 255, 0.04); 1080 | } 1081 | 1082 | .mdtp__wrapper[data-theme='dark'] .mdtp__button:active { 1083 | background-color: rgba(255, 255, 255, 0.1); 1084 | } 1085 | -------------------------------------------------------------------------------- /dist/mdtimepicker.min.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Roboto:400,500&display=swap");.mdtimepicker{background-color:hsla(0,0%,4%,.65);bottom:0;font-family:Roboto,sans-serif;font-size:14px;left:0;position:fixed;right:0;top:0;transition:background-color .28s ease;z-index:100001}.mdtimepicker .mdtp__wrapper{border-radius:4px;bottom:24px;box-shadow:0 11px 15px -7px rgba(0,0,0,.2),0 24px 38px 3px rgba(0,0,0,.14),0 9px 46px 8px rgba(0,0,0,.12);display:flex;flex-direction:column;left:50%;min-width:280px;opacity:1;outline:none;overflow:hidden;position:absolute;transform:translateX(-50%) scale(1);transition:transform .28s ease,opacity .28s ease;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mdtimepicker .mdtp__wrapper.animate{opacity:0;transform:translateX(-50%) scale(1.05)}.mdtimepicker .mdtp__time_holder{align-items:center;background-color:#1565c0;color:hsla(0,0%,100%,.5);display:flex;flex-direction:row;font-size:46px;justify-content:center;padding:20px 24px;text-align:center}.mdtimepicker .mdtp__time_holder>span{cursor:default;display:inline-block;line-height:48px}.mdtimepicker .mdtp__time_holder>span:not(.mdtp__timedots):not(.mdtp__ampm){cursor:pointer;margin:0 4px;transition:color .2s linear}.mdtimepicker .mdtp__time_holder .mdtp__time_h.active,.mdtimepicker .mdtp__time_holder .mdtp__time_m.active{color:#fafafa}.mdtimepicker .mdtp__time_holder .mdtp__ampm{cursor:pointer;font-size:18px;transition:color .2s linear}.mdtimepicker .mdtp__time_holder .mdtp__ampm:hover{color:#fafafa}.mdtimepicker .mdtp__clock_holder{background-color:#fff;position:relative}.mdtimepicker .mdtp__clock_holder .mdtp__clock{background-color:#eee;border-radius:50%;height:250px;margin:20px;position:relative;width:250px}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__am,.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__pm{background:rgba(0,0,0,.05);border:1px solid rgba(0,0,0,.1);border-radius:50%;bottom:-8px;cursor:pointer;display:block;height:36px;line-height:36px;position:absolute;text-align:center;transition:background-color .2s ease,color .2s;width:36px;z-index:3}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__am:hover,.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__pm:hover{background-color:rgba(0,0,0,.1)}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__am.active,.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__pm.active{background-color:#1565c0;color:#fafafa}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__am{left:-8px}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__pm{right:-8px}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__clock_dot{background-color:#1565c0;border-radius:50%;left:50%;padding:4px;position:absolute;top:50%;transform:translate(-50%,-50%)}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__hour_holder,.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder{height:100%;opacity:1;overflow:hidden;position:absolute;top:0;transform:scale(1);transition:transform .35s cubic-bezier(.4,0,.2,1),opacity .35s ease;width:100%}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__hour_holder.hidden,.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder.hidden{display:none}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__hour_holder.animate{opacity:0;transform:scale(1.2)}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder.animate{opacity:0;transform:scale(.8)}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit{left:0;margin-top:-16px;position:absolute;top:50%;transform-origin:right center;width:50%;z-index:1}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit span{border-radius:50%;cursor:pointer;display:inline-block;height:32px;line-height:32px;margin-left:8px;text-align:center;transition:background-color .28s,color .14s;width:32px}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit.inner--digit{left:14%;width:36%;z-index:2}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit.active span,.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover{background-color:#1565c0!important;color:#fff;z-index:2}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit.digit--disabled span{background-color:transparent!important;color:#c8c8c8;cursor:not-allowed}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__digit.active:before{background-color:#1565c0;content:"";display:block;height:2px;position:absolute;right:0;top:calc(50% - 1px);width:calc(100% - 40px)}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit{font-size:13px}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit:not(.marker){height:12px;margin-top:-6px}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit:not(.marker) span{height:12px;line-height:12px;margin-left:14px;width:12px}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit:not(.marker).active:before{width:calc(100% - 26px)}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit.marker{margin-top:-12px}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit.marker span{height:24px;line-height:24px;margin-left:10px;width:24px}.mdtimepicker .mdtp__clock_holder .mdtp__clock .mdtp__minute_holder .mdtp__digit.marker.active:before{width:calc(100% - 34px)}.mdtimepicker .mdtp__buttons{padding:0 10px 10px;text-align:right}.mdtimepicker .mdtp__buttons .mdtp__button{border-radius:4px;color:#1565c0;cursor:pointer;display:inline-block;font-weight:500;line-height:32px;min-width:40px;padding:0 16px;text-align:center;text-transform:uppercase;transition:background-color .2s linear}.mdtimepicker .mdtp__buttons .mdtp__button:hover{background-color:rgba(0,0,0,.1)}.mdtimepicker .mdtp__buttons .mdtp__button:active{background-color:rgba(0,0,0,.2)}.mdtimepicker .mdtp__buttons .mdtp__button.clear-btn{color:#ef5350!important;float:left}.mdtimepicker .mdtp__buttons:after{clear:both;content:"";display:block}.mdtimepicker.hidden{display:none}.mdtimepicker.animate{background-color:transparent}.mdtp__digit.rotate--15{transform:rotate(-15deg)}.mdtp__digit.rotate--15 span{transform:rotate(15deg)}.mdtp__digit.rotate-6{transform:rotate(6deg)}.mdtp__digit.rotate-6 span{transform:rotate(-6deg)}.mdtp__digit.rotate-12{transform:rotate(12deg)}.mdtp__digit.rotate-12 span{transform:rotate(-12deg)}.mdtp__digit.rotate-15{transform:rotate(15deg)}.mdtp__digit.rotate-15 span{transform:rotate(-15deg)}.mdtp__digit.rotate-18{transform:rotate(18deg)}.mdtp__digit.rotate-18 span{transform:rotate(-18deg)}.mdtp__digit.rotate-24{transform:rotate(24deg)}.mdtp__digit.rotate-24 span{transform:rotate(-24deg)}.mdtp__digit.rotate-30{transform:rotate(30deg)}.mdtp__digit.rotate-30 span{transform:rotate(-30deg)}.mdtp__digit.rotate-36{transform:rotate(36deg)}.mdtp__digit.rotate-36 span{transform:rotate(-36deg)}.mdtp__digit.rotate-42{transform:rotate(42deg)}.mdtp__digit.rotate-42 span{transform:rotate(-42deg)}.mdtp__digit.rotate-45{transform:rotate(45deg)}.mdtp__digit.rotate-45 span{transform:rotate(-45deg)}.mdtp__digit.rotate-48{transform:rotate(48deg)}.mdtp__digit.rotate-48 span{transform:rotate(-48deg)}.mdtp__digit.rotate-54{transform:rotate(54deg)}.mdtp__digit.rotate-54 span{transform:rotate(-54deg)}.mdtp__digit.rotate-60{transform:rotate(60deg)}.mdtp__digit.rotate-60 span{transform:rotate(-60deg)}.mdtp__digit.rotate-66{transform:rotate(66deg)}.mdtp__digit.rotate-66 span{transform:rotate(-66deg)}.mdtp__digit.rotate-72{transform:rotate(72deg)}.mdtp__digit.rotate-72 span{transform:rotate(-72deg)}.mdtp__digit.rotate-75{transform:rotate(75deg)}.mdtp__digit.rotate-75 span{transform:rotate(-75deg)}.mdtp__digit.rotate-78{transform:rotate(78deg)}.mdtp__digit.rotate-78 span{transform:rotate(-78deg)}.mdtp__digit.rotate-84{transform:rotate(84deg)}.mdtp__digit.rotate-84 span{transform:rotate(-84deg)}.mdtp__digit.rotate-90{transform:rotate(90deg)}.mdtp__digit.rotate-90 span{transform:rotate(-90deg)}.mdtp__digit.rotate-96{transform:rotate(96deg)}.mdtp__digit.rotate-96 span{transform:rotate(-96deg)}.mdtp__digit.rotate-102{transform:rotate(102deg)}.mdtp__digit.rotate-102 span{transform:rotate(-102deg)}.mdtp__digit.rotate-105{transform:rotate(105deg)}.mdtp__digit.rotate-105 span{transform:rotate(-105deg)}.mdtp__digit.rotate-108{transform:rotate(108deg)}.mdtp__digit.rotate-108 span{transform:rotate(-108deg)}.mdtp__digit.rotate-114{transform:rotate(114deg)}.mdtp__digit.rotate-114 span{transform:rotate(-114deg)}.mdtp__digit.rotate-120{transform:rotate(120deg)}.mdtp__digit.rotate-120 span{transform:rotate(-120deg)}.mdtp__digit.rotate-126{transform:rotate(126deg)}.mdtp__digit.rotate-126 span{transform:rotate(-126deg)}.mdtp__digit.rotate-132{transform:rotate(132deg)}.mdtp__digit.rotate-132 span{transform:rotate(-132deg)}.mdtp__digit.rotate-135{transform:rotate(135deg)}.mdtp__digit.rotate-135 span{transform:rotate(-135deg)}.mdtp__digit.rotate-138{transform:rotate(138deg)}.mdtp__digit.rotate-138 span{transform:rotate(-138deg)}.mdtp__digit.rotate-144{transform:rotate(144deg)}.mdtp__digit.rotate-144 span{transform:rotate(-144deg)}.mdtp__digit.rotate-150{transform:rotate(150deg)}.mdtp__digit.rotate-150 span{transform:rotate(-150deg)}.mdtp__digit.rotate-156{transform:rotate(156deg)}.mdtp__digit.rotate-156 span{transform:rotate(-156deg)}.mdtp__digit.rotate-162{transform:rotate(162deg)}.mdtp__digit.rotate-162 span{transform:rotate(-162deg)}.mdtp__digit.rotate-165{transform:rotate(165deg)}.mdtp__digit.rotate-165 span{transform:rotate(-165deg)}.mdtp__digit.rotate-168{transform:rotate(168deg)}.mdtp__digit.rotate-168 span{transform:rotate(-168deg)}.mdtp__digit.rotate-174{transform:rotate(174deg)}.mdtp__digit.rotate-174 span{transform:rotate(-174deg)}.mdtp__digit.rotate-180{transform:rotate(180deg)}.mdtp__digit.rotate-180 span{transform:rotate(-180deg)}.mdtp__digit.rotate-186{transform:rotate(186deg)}.mdtp__digit.rotate-186 span{transform:rotate(-186deg)}.mdtp__digit.rotate-192{transform:rotate(192deg)}.mdtp__digit.rotate-192 span{transform:rotate(-192deg)}.mdtp__digit.rotate-195{transform:rotate(195deg)}.mdtp__digit.rotate-195 span{transform:rotate(-195deg)}.mdtp__digit.rotate-198{transform:rotate(198deg)}.mdtp__digit.rotate-198 span{transform:rotate(-198deg)}.mdtp__digit.rotate-204{transform:rotate(204deg)}.mdtp__digit.rotate-204 span{transform:rotate(-204deg)}.mdtp__digit.rotate-210{transform:rotate(210deg)}.mdtp__digit.rotate-210 span{transform:rotate(-210deg)}.mdtp__digit.rotate-216{transform:rotate(216deg)}.mdtp__digit.rotate-216 span{transform:rotate(-216deg)}.mdtp__digit.rotate-222{transform:rotate(222deg)}.mdtp__digit.rotate-222 span{transform:rotate(-222deg)}.mdtp__digit.rotate-225{transform:rotate(225deg)}.mdtp__digit.rotate-225 span{transform:rotate(-225deg)}.mdtp__digit.rotate-228{transform:rotate(228deg)}.mdtp__digit.rotate-228 span{transform:rotate(-228deg)}.mdtp__digit.rotate-234{transform:rotate(234deg)}.mdtp__digit.rotate-234 span{transform:rotate(-234deg)}.mdtp__digit.rotate-240{transform:rotate(240deg)}.mdtp__digit.rotate-240 span{transform:rotate(-240deg)}.mdtp__digit.rotate-246{transform:rotate(246deg)}.mdtp__digit.rotate-246 span{transform:rotate(-246deg)}.mdtp__digit.rotate-252{transform:rotate(252deg)}.mdtp__digit.rotate-252 span{transform:rotate(-252deg)}.mdtp__digit.rotate-255{transform:rotate(255deg)}.mdtp__digit.rotate-255 span{transform:rotate(-255deg)}.mdtp__digit.rotate-258{transform:rotate(258deg)}.mdtp__digit.rotate-258 span{transform:rotate(-258deg)}.mdtp__digit.rotate-264{transform:rotate(264deg)}.mdtp__digit.rotate-264 span{transform:rotate(-264deg)}.mdtp__digit.rotate-270{transform:rotate(270deg)}.mdtp__digit.rotate-270 span{transform:rotate(-270deg)}.mdtp__digit.rotate-276{transform:rotate(276deg)}.mdtp__digit.rotate-276 span{transform:rotate(-276deg)}.mdtp__digit.rotate-282{transform:rotate(282deg)}.mdtp__digit.rotate-282 span{transform:rotate(-282deg)}.mdtp__digit.rotate-285{transform:rotate(285deg)}.mdtp__digit.rotate-285 span{transform:rotate(-285deg)}.mdtp__digit.rotate-288{transform:rotate(288deg)}.mdtp__digit.rotate-288 span{transform:rotate(-288deg)}.mdtp__digit.rotate-294{transform:rotate(294deg)}.mdtp__digit.rotate-294 span{transform:rotate(-294deg)}.mdtp__digit.rotate-300{transform:rotate(300deg)}.mdtp__digit.rotate-300 span{transform:rotate(-300deg)}.mdtp__digit.rotate-306{transform:rotate(306deg)}.mdtp__digit.rotate-306 span{transform:rotate(-306deg)}.mdtp__digit.rotate-312{transform:rotate(312deg)}.mdtp__digit.rotate-312 span{transform:rotate(-312deg)}.mdtp__digit.rotate-315{transform:rotate(315deg)}.mdtp__digit.rotate-315 span{transform:rotate(-315deg)}.mdtp__digit.rotate-318{transform:rotate(318deg)}.mdtp__digit.rotate-318 span{transform:rotate(-318deg)}.mdtp__digit.rotate-324{transform:rotate(324deg)}.mdtp__digit.rotate-324 span{transform:rotate(-324deg)}.mdtp__digit.rotate-330{transform:rotate(330deg)}.mdtp__digit.rotate-330 span{transform:rotate(-330deg)}.mdtp__digit.rotate-336{transform:rotate(336deg)}.mdtp__digit.rotate-336 span{transform:rotate(-336deg)}.mdtp__digit.rotate-342{transform:rotate(342deg)}.mdtp__digit.rotate-342 span{transform:rotate(-342deg)}.mdtp__digit.rotate-348{transform:rotate(348deg)}.mdtp__digit.rotate-348 span{transform:rotate(-348deg)}.mdtp__digit.rotate-354{transform:rotate(354deg)}.mdtp__digit.rotate-354 span{transform:rotate(-354deg)}.mdtp__digit.rotate-360{transform:rotate(1turn)}.mdtp__digit.rotate-360 span{transform:rotate(-1turn)}body[mdtimepicker-display=on]{overflow:hidden}@media (max-height:360px){.mdtimepicker .mdtp__wrapper{bottom:8px;flex-direction:row}.mdtimepicker .mdtp__time_holder{padding:20px;width:160px}.mdtimepicker .mdtp__clock .mdtp__am,.mdtimepicker .mdtp__clock .mdtp__pm{bottom:-4px}.mdtimepicker .mdtp__clock .mdtp__am{left:-4px}.mdtimepicker .mdtp__clock .mdtp__pm{right:-4px}}@media (max-height:320px){.mdtimepicker .mdtp__wrapper{bottom:0}}.mdtp__wrapper[data-theme=red] .mdtp__clock .mdtp__am.active,.mdtp__wrapper[data-theme=red] .mdtp__clock .mdtp__clock_dot,.mdtp__wrapper[data-theme=red] .mdtp__clock .mdtp__pm.active,.mdtp__wrapper[data-theme=red] .mdtp__time_holder{background-color:#c62828}.mdtp__wrapper[data-theme=red] .mdtp__clock .mdtp__digit.active span,.mdtp__wrapper[data-theme=red] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover{background-color:#c62828!important}.mdtp__wrapper[data-theme=red] .mdtp__clock .mdtp__digit.active:before{background-color:#c62828}.mdtp__wrapper[data-theme=red] .mdtp__button{color:#c62828}.mdtp__wrapper[data-theme=green] .mdtp__clock .mdtp__am.active,.mdtp__wrapper[data-theme=green] .mdtp__clock .mdtp__clock_dot,.mdtp__wrapper[data-theme=green] .mdtp__clock .mdtp__pm.active,.mdtp__wrapper[data-theme=green] .mdtp__time_holder{background-color:#2e7d32}.mdtp__wrapper[data-theme=green] .mdtp__clock .mdtp__digit.active span,.mdtp__wrapper[data-theme=green] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover{background-color:#2e7d32!important}.mdtp__wrapper[data-theme=green] .mdtp__clock .mdtp__digit.active:before{background-color:#2e7d32}.mdtp__wrapper[data-theme=green] .mdtp__button{color:#2e7d32}.mdtp__wrapper[data-theme=blue] .mdtp__clock .mdtp__am.active,.mdtp__wrapper[data-theme=blue] .mdtp__clock .mdtp__clock_dot,.mdtp__wrapper[data-theme=blue] .mdtp__clock .mdtp__pm.active,.mdtp__wrapper[data-theme=blue] .mdtp__time_holder{background-color:#1565c0}.mdtp__wrapper[data-theme=blue] .mdtp__clock .mdtp__digit.active span,.mdtp__wrapper[data-theme=blue] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover{background-color:#1565c0!important}.mdtp__wrapper[data-theme=blue] .mdtp__clock .mdtp__digit.active:before{background-color:#1565c0}.mdtp__wrapper[data-theme=blue] .mdtp__button{color:#1565c0}.mdtp__wrapper[data-theme=teal] .mdtp__clock .mdtp__am.active,.mdtp__wrapper[data-theme=teal] .mdtp__clock .mdtp__clock_dot,.mdtp__wrapper[data-theme=teal] .mdtp__clock .mdtp__pm.active,.mdtp__wrapper[data-theme=teal] .mdtp__time_holder{background-color:#00695c}.mdtp__wrapper[data-theme=teal] .mdtp__clock .mdtp__digit.active span,.mdtp__wrapper[data-theme=teal] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover{background-color:#00695c!important}.mdtp__wrapper[data-theme=teal] .mdtp__clock .mdtp__digit.active:before{background-color:#00695c}.mdtp__wrapper[data-theme=teal] .mdtp__button{color:#00695c}.mdtp__wrapper[data-theme=purple] .mdtp__clock .mdtp__am.active,.mdtp__wrapper[data-theme=purple] .mdtp__clock .mdtp__clock_dot,.mdtp__wrapper[data-theme=purple] .mdtp__clock .mdtp__pm.active,.mdtp__wrapper[data-theme=purple] .mdtp__time_holder{background-color:#6a1b9a}.mdtp__wrapper[data-theme=purple] .mdtp__clock .mdtp__digit.active span,.mdtp__wrapper[data-theme=purple] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover{background-color:#6a1b9a!important}.mdtp__wrapper[data-theme=purple] .mdtp__clock .mdtp__digit.active:before{background-color:#6a1b9a}.mdtp__wrapper[data-theme=purple] .mdtp__button{color:#6a1b9a}.mdtp__wrapper[data-theme=indigo] .mdtp__clock .mdtp__am.active,.mdtp__wrapper[data-theme=indigo] .mdtp__clock .mdtp__clock_dot,.mdtp__wrapper[data-theme=indigo] .mdtp__clock .mdtp__pm.active,.mdtp__wrapper[data-theme=indigo] .mdtp__time_holder{background-color:#283593}.mdtp__wrapper[data-theme=indigo] .mdtp__clock .mdtp__digit.active span,.mdtp__wrapper[data-theme=indigo] .mdtp__clock .mdtp__digit:not(.digit--disabled) span:hover{background-color:#283593!important}.mdtp__wrapper[data-theme=indigo] .mdtp__clock .mdtp__digit.active:before{background-color:#283593}.mdtp__wrapper[data-theme=indigo] .mdtp__button{color:#283593}.mdtp__wrapper[data-theme=dark] .mdtp__time_holder{background-color:#121212}.mdtp__wrapper[data-theme=dark] .mdtp__clock_holder{background-color:#1d1d1d}.mdtp__wrapper[data-theme=dark] .mdtp__clock_holder .mdtp__clock{background-color:#181818}.mdtp__wrapper[data-theme=dark] .mdtp__clock_holder .mdtp__clock .mdtp__digit:not(.digit--disabled){color:hsla(0,0%,100%,.87)}.mdtp__wrapper[data-theme=dark] .mdtp__clock_holder .mdtp__clock .mdtp__digit.digit--disabled span{color:hsla(0,0%,39%,.87)}.mdtp__wrapper[data-theme=dark] .mdtp__clock_holder .mdtp__clock .mdtp__am:not(.active),.mdtp__wrapper[data-theme=dark] .mdtp__clock_holder .mdtp__clock .mdtp__pm:not(.active){background-color:hsla(0,0%,78%,.05);color:hsla(0,0%,100%,.87)}.mdtp__wrapper[data-theme=dark] .mdtp__button{color:#42a5f5}.mdtp__wrapper[data-theme=dark] .mdtp__button:hover{background-color:hsla(0,0%,100%,.04)}.mdtp__wrapper[data-theme=dark] .mdtp__button:active{background-color:hsla(0,0%,100%,.1)} -------------------------------------------------------------------------------- /dist/mdtimepicker.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).mdtimepicker=e()}(this,function(){"use strict";function R(t){return(R="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function D(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function F(t,e){for(var n=0;ni;)!_n(r,n=e[i++])||~In(o,n)||Ln(o,n);return o}function sn(t,e){return(t=zn[qn(t)])==Wn||t!=Yn&&(Bn(e)?$n(e):!!e)}function P(t,e){var n,r,i,o=t.target,c=t.global,u=t.stat,a=c?Kn:u?Kn[o]||Zn(o,{}):(Kn[o]||{}).prototype;if(a)for(n in e){if(r=e[n],i=t.dontCallGetSet?(i=Xn(a,n))&&i.value:a[n],!er(c?n:o+(u?".":"#")+n,t.forced)&&void 0!==i){if(typeof r==typeof i)continue;tr(r,i)}(t.sham||i&&i.sham)&&Jn(r,"sham",!0),Qn(a,n,r,t)}}function ln(t){if("Symbol"===ur(t))throw TypeError("Cannot convert a Symbol value to a string");return ar(t)}var fn=g,dn=y,pn=p.exports,hn=W,_={},mn=Math.ceil,vn=Math.floor,gn=Math.trunc||function(t){t=+t;return(0"+t+""},Dr=function(){try{_r=new ActiveXObject("htmlfile")}catch(t){}Dr="undefined"==typeof document||document.domain&&_r?yr(_r):(t=jr("iframe"),e="java"+Mr+":",t.style.display="none",Lr.appendChild(t),t.src=String(e),(e=t.contentWindow.document).open(),e.write(Rr("document.F=Object")),e.close(),e.F);for(var t,e,n=Pr.length;n--;)delete Dr[Hr][Pr[n]];return Dr()},zt=(l[Cr]=!0,Object.create||function(t,e){var n;return null!==t?(gr[Hr]=Ar(t),n=new gr,gr[Hr]=null,n[Cr]=t):n=Dr(),void 0===e?n:Ir.f(n,e)}),x=t,Fr=a.RegExp,A=x(function(){var t=Fr(".","s");return!(t.dotAll&&t.exec("\n")&&"s"===t.flags)}),O=t,Vr=a.RegExp,_=O(function(){var t=Vr("(?b)","g");return"b"!==t.exec("b").groups.a||"bc"!=="b".replace(t,"$c")}),Nr=d,l=m,Gr=ln,x=s,O=T,$r=zt,Br=S.get,s=A,T=_,Ur=O("native-string-replace",String.prototype.replace),qr=RegExp.prototype.exec,zr=qr,Yr=l("".charAt),Wr=l("".indexOf),Kr=l("".replace),Xr=l("".slice),Jr=(A=/b*/g,Nr(qr,_=/a/,"a"),Nr(qr,A,"a"),0!==_.lastIndex||0!==A.lastIndex),Qr=x.BROKEN_CARET,Zr=void 0!==/()??/.exec("")[1],O=zr=Jr||Zr||Qr||s||T?function(t){var e,n,r,i,o,c,u=this,a=Br(u),t=Gr(t),s=a.raw;if(s)return s.lastIndex=u.lastIndex,f=Nr(zr,s,t),u.lastIndex=s.lastIndex,f;var l=a.groups,s=Qr&&u.sticky,f=Nr(br,u),a=u.source,d=0,p=t;if(s&&(f=Kr(f,"y",""),-1===Wr(f,"g")&&(f+="g"),p=Xr(t,u.lastIndex),0]*>)/g,Ni=/\$([$&'`]|\d{1,2})/g,Gi=s,$i=d,l=m,O=Er,x=t,Bi=o,Ui=g,qi=U,zi=nn,Yi=on,Wi=ln,Ki=q,Xi=xr,Ji=r,Qi=function(o,c,u,a,s,t){var l=u+o.length,f=a.length,e=Ni;return void 0!==s&&(s=Mi(s),e=Vi),Di(t,e,function(t,e){var n;switch(Ri(e,0)){case"$":return"$";case"&":return o;case"`":return Fi(c,0,u);case"'":return Fi(c,l);case"<":n=s[Fi(e,1,-1)];break;default:var r,i=+e;if(0==i)return t;if(f")})||!A||uo),p),ao=I,so=(p||en(Object.prototype,"toString",T?{}.toString:function(){return"[object "+ao(this)+"]"},{unsafe:!0}),TypeError),lo=n,fo=d,po=e,ho=r,mo=d,vo=n,go=o,yo=v,bo=function(t){if(9007199254740991=e.length?la(void 0,!0):(e=aa(e,n),t.index+=e.length,la(e,!1))}),t),ma=b,va=i("species"),p=m([].slice),h=P,ga=A,ya=f,ba=v,wa=rn,Ea=cn,ka=z,xa=iu,bt=i,Ta=p,a=function(e){return 51<=ma||!ha(function(){var t=[];return(t.constructor={})[va]=function(){return{foo:1}},1!==t[e](Boolean).foo})}("slice"),Sa=bt("species"),Oa=Array,_a=Math.max,Aa=(h({target:"Array",proto:!0,forced:!a},{slice:function(t,e){var n,r,i,o=ka(this),c=Ea(o),u=wa(t,c),a=wa(void 0===e?c:e,c);if(ga(o)&&(n=o.constructor,(n=ya(n)&&(n===Oa||ga(n.prototype))||ba(n)&&null===(n=n[Sa])?void 0:n)===Oa||void 0===n))return Ta(o,u,a);for(r=new(void 0===n?Oa:n)(_a(a-u,0)),i=0;u 0.5%, ie >= 11" 14 | } 15 | } 16 | ] 17 | ] 18 | } -------------------------------------------------------------------------------- /src/helpers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Helper functions 3 | */ 4 | export const hf = { 5 | /** 6 | * Appends element(s) to parent 7 | * @param {Element|Element[]} elem Element(s) to append to parent 8 | * @param {Element} to Parent element 9 | */ 10 | appendTo (elem, to, idx) { 11 | if (Array.isArray(elem)) { 12 | elem.forEach(el => { 13 | if (idx === 0) to.insertBefore(el, to.childNodes[idx] || null) 14 | else to.appendChild(el) 15 | }) 16 | } else { 17 | if (idx === 0) to.insertBefore(elem, to.childNodes[idx] || null) 18 | else to.appendChild(elem) 19 | } 20 | }, 21 | /** 22 | * Adds event listener to element(s) 23 | * @param {Element|Element[]} elem Element(s) to add event 24 | * @param {string} event Event name 25 | * @param {Function} handler Event handler 26 | */ 27 | addEvent (elem, event, handler) { 28 | function listenEvent(el, evt, fn) { 29 | el.addEventListener(evt, fn, false) 30 | } 31 | 32 | if (Array.isArray(elem)) { 33 | elem.forEach(e => listenEvent(e, event, handler)) 34 | } else listenEvent(elem, event, handler) 35 | }, 36 | /** 37 | * Removes event listener to element(s) 38 | * @param {Element|Element[]} elem Element(s) to remove event 39 | * @param {string} event Event name 40 | * @param {Function} handler Event handler 41 | */ 42 | removeEvent (elem, event, handler) { 43 | function delEvent(el, evt, fn) { 44 | el.removeEventListener(evt, fn, false) 45 | } 46 | 47 | if (Array.isArray(elem)) { 48 | elem.forEach(e => delEvent(e, event, handler)) 49 | } else delEvent(elem, event, handler) 50 | }, 51 | /** 52 | * Removes child nodes 53 | * @param {Element} elem Html element to empty 54 | */ 55 | empty (elem) { 56 | while (elem.firstChild) { elem.removeChild(elem.firstChild) } 57 | }, 58 | /** 59 | * Creates an HTML element; `document.createElement` helper function 60 | * @see {@link http://jsfiddle.net/andr3ww/pvuzgfg6/13/} 61 | * @param {string} tag HTML tag name (i.e. `div`, `span`, `a`) 62 | * @param {Object} attributes Attribute object 63 | * @param {string|Element} content Element content: text or HTML element(s) 64 | * @param {Boolean} isHtml Determines if `content` specified should added as an html element 65 | */ 66 | createElem (tag, attributes, content, isHtml) { 67 | var el = document.createElement(tag) 68 | 69 | if (typeof content !== 'undefined') 70 | el[isHtml || false ? 'innerHTML' : 'innerText'] = content 71 | 72 | if (typeof attributes !== 'undefined') 73 | hf.setAttributes(el, attributes) 74 | 75 | return el 76 | }, 77 | /** 78 | * Sets the attribute(s) of the element 79 | * @param {Element} el Html element 80 | * @param {Object} attrs Attribute object 81 | */ 82 | setAttributes (el, attrs) { 83 | for(var attr in attrs) { el.setAttribute(attr, attrs[attr]) } 84 | }, 85 | /** 86 | * Vanilla JavaScript version of jQuery.extend() 87 | * @see {@link https://gomakethings.com/vanilla-javascript-version-of-jquery-extend/} 88 | */ 89 | extend () { 90 | // Variables 91 | var extended = {} 92 | var deep = false 93 | var i = 0 94 | var length = arguments.length 95 | 96 | // Check if a deep merge 97 | if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') { 98 | deep = arguments[0] 99 | i++ 100 | } 101 | 102 | // Merge the object into the extended object 103 | var merge = function (obj) { 104 | for (var prop in obj) { 105 | if (Object.prototype.hasOwnProperty.call(obj, prop)) { 106 | // If deep merge and property is an object, merge properties 107 | if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') { 108 | extended[prop] = hf.extend(true, extended[prop], obj[prop]) 109 | } else { 110 | extended[prop] = obj[prop] 111 | } 112 | } 113 | } 114 | } 115 | 116 | // Loop through each object and conduct a merge 117 | for (; i < length; i++) { 118 | var obj = arguments[i] 119 | merge(obj) 120 | } 121 | 122 | return extended 123 | }, 124 | /** 125 | * Triggers the `change`, `onchange`, `datechanged` event on the specified input element 126 | * @param {HTMLInputElement} el HTML input element 127 | * @param {Object} data Event data 128 | */ 129 | triggerChange (el, data) { 130 | let change = document.createEvent('Event') 131 | let onChange = document.createEvent('Event') 132 | 133 | change.initEvent('change', false, false) 134 | onChange.initEvent('onchange', false, false) 135 | 136 | el.dispatchEvent(change) 137 | el.dispatchEvent(onChange) 138 | 139 | function CustomEvent(data) { 140 | let changeEvt = document.createEvent('CustomEvent') 141 | 142 | changeEvt.initCustomEvent('datechanged', false, false, null) 143 | changeEvt.data = data 144 | 145 | return changeEvt 146 | } 147 | 148 | el.dispatchEvent(new CustomEvent(data)) 149 | } 150 | } -------------------------------------------------------------------------------- /src/mdtimepicker.js: -------------------------------------------------------------------------------- 1 | import { MDTP_DATA, DEFAULT_CLASS, HOUR_START_DEG, HOUR_DEG_INCR, MIN_START_DEG, MIN_DEG_INCR, END_DEG, EX_KEYS, DEFAULTS } from './vars' 2 | import { hf } from './helpers' 3 | 4 | /** 5 | * Time class 6 | */ 7 | class Time { 8 | /** 9 | * Creates a time object 10 | * @param {number} hour Hour value (0 - 23) 11 | * @param {number} minute Minute value (0 - 59) 12 | */ 13 | constructor(hour, minute) { 14 | this.hour = hour 15 | this.minute = minute 16 | } 17 | setHour(value) { this.hour = value } 18 | getHour(is12Hour) { 19 | return is12Hour ? [0, 12].indexOf(this.hour) >= 0 ? 12 : (this.hour % 12) : this.hour 20 | } 21 | invert() { 22 | if (this.getPeriod() === 'AM') this.setHour(this.getHour() + 12) 23 | else this.setHour(this.getHour() - 12) 24 | } 25 | setMinutes(value) { this.minute = value } 26 | getMinutes() { return this.minute } 27 | getPeriod() { return this.hour < 12 ? 'AM' : 'PM' } 28 | format(format, hourPadding) { 29 | let that = this, is24Hour = (format.match(/h/g) || []).length > 1 30 | 31 | return format.replace(/(hh|h|mm|ss|tt|t)/g, function (e) { 32 | switch (e.toLowerCase()) { 33 | case 'h': 34 | let hour = that.getHour(true) 35 | return (hourPadding && hour < 10 ? '0' + hour : hour) 36 | case 'hh': return (that.hour < 10 ? '0' + that.hour : that.hour) 37 | case 'mm': return (that.minute < 10 ? '0' + that.minute : that.minute) 38 | case 'ss': return '00' 39 | case 't': return is24Hour ? '' : that.getPeriod().toLowerCase() 40 | case 'tt': return is24Hour ? '' : that.getPeriod() 41 | } 42 | }) 43 | } 44 | } 45 | 46 | /** 47 | * Time picker class 48 | */ 49 | class MDTimePicker { 50 | /** 51 | * Default configurations 52 | */ 53 | static default_configs = null; 54 | /** 55 | * Creates a time picker object 56 | * @param {HTMLInputElement} el Input element 57 | * @param {Object} config Time picker configurations 58 | */ 59 | constructor(el, config) { 60 | let _ = this 61 | 62 | this.visible = false 63 | this.activeView = 'hours' 64 | this.hTimeout = null 65 | this.mTimeout = null 66 | this.input = el 67 | this.input.readOnly = true 68 | this.config = config 69 | this.time = new Time(0, 0) 70 | this.selected = new Time(0, 0) 71 | this.timepicker = { 72 | overlay: hf.createElem('div', { class: 'mdtimepicker hidden' }), 73 | wrapper: hf.createElem('div', { class: 'mdtp__wrapper', tabindex: 0 }), 74 | timeHolder: { 75 | wrapper: hf.createElem('section', { class: 'mdtp__time_holder' }), 76 | hour: hf.createElem('span', { class: 'mdtp__time_h' }, '12'), 77 | dots: hf.createElem('span', { class: 'mdtp__timedots' }, ':'), 78 | minute: hf.createElem('span', { class: 'mdtp__time_m' }, '00'), 79 | am_pm: hf.createElem('span', { class: 'mdtp__ampm' }, 'AM') 80 | }, 81 | clockHolder: { 82 | wrapper: hf.createElem('section', { class: 'mdtp__clock_holder' }), 83 | am: hf.createElem('span', { class: 'mdtp__am' }, 'AM'), 84 | pm: hf.createElem('span', { class: 'mdtp__pm' }, 'PM'), 85 | clock: { 86 | wrapper: hf.createElem('div', { class: 'mdtp__clock' }), 87 | dot: hf.createElem('span', { class: 'mdtp__clock_dot' }), 88 | hours: hf.createElem('div', { class: 'mdtp__hour_holder' }), 89 | minutes: hf.createElem('div', { class: 'mdtp__minute_holder' }) 90 | }, 91 | buttonsHolder: { 92 | wrapper: hf.createElem('div', { class: 'mdtp__buttons' }), 93 | btnClear: hf.createElem('span', { class: 'mdtp__button clear-btn' }, 'Clear'), 94 | btnOk: hf.createElem('span', { class: 'mdtp__button ok' }, 'Ok'), 95 | btnCancel: hf.createElem('span', { class: 'mdtp__button cancel' }, 'Cancel') 96 | } 97 | } 98 | } 99 | 100 | this.setMinTime(this.input.dataset.mintime || this.config.minTime) 101 | this.setMaxTime(this.input.dataset.maxtime || this.config.maxTime) 102 | 103 | let picker = _.timepicker 104 | 105 | hf.appendTo(_._setup(), document.body) 106 | 107 | hf.addEvent(picker.overlay, 'click', () => { _.hide() }) 108 | 109 | hf.addEvent(picker.wrapper, 'click', e => e.stopPropagation()) 110 | hf.addEvent(picker.wrapper, 'keydown', e => { 111 | if (e.keyCode !== 27) return 112 | 113 | _.hide() 114 | }) 115 | 116 | if (!config.is24hour) { 117 | hf.addEvent(picker.timeHolder.am_pm, 'click', () => { 118 | _.setPeriod(_.selected.getPeriod() == 'AM' ? 'pm' : 'am') 119 | }) 120 | } 121 | 122 | hf.addEvent(picker.clockHolder.am, 'click', () => { 123 | if (_.selected.getPeriod() !== 'AM') _.setPeriod('am') 124 | }) 125 | 126 | hf.addEvent(picker.clockHolder.pm, 'click', () => { 127 | if (_.selected.getPeriod() !== 'PM') _.setPeriod('pm') 128 | }) 129 | 130 | hf.addEvent(picker.timeHolder.hour, 'click', () => { 131 | if (_.activeView !== 'hours') _._switchView('hours') 132 | }) 133 | 134 | hf.addEvent(picker.timeHolder.minute, 'click', () => { 135 | if (_.activeView !== 'minutes') _._switchView('minutes') 136 | }) 137 | 138 | hf.addEvent(picker.clockHolder.buttonsHolder.btnOk, 'click', () => { 139 | let selected = _.selected 140 | 141 | if (_.isDisabled(selected.getHour(), selected.getMinutes(), false)) return 142 | 143 | _.setValue(selected) 144 | 145 | let formatted = _.getFormattedTime() 146 | 147 | _._triggerChange({ time: formatted.time, value: formatted.value }) 148 | _.hide() 149 | }) 150 | 151 | hf.addEvent(picker.clockHolder.buttonsHolder.btnCancel, 'click', () => { _.hide() }) 152 | 153 | if (_.config.clearBtn) { 154 | hf.addEvent(picker.clockHolder.buttonsHolder.btnClear, 'click', () => { 155 | _.input.value = '' 156 | hf.setAttributes(_.input, { 157 | 'value': '', 'data-time': null 158 | }) 159 | 160 | _._triggerChange({ time: null, value: '' }) 161 | _.hide() 162 | }) 163 | } 164 | 165 | /* input event handlers */ 166 | function _inputClick() { _.show() } 167 | 168 | function _inputKeydown(e) { 169 | if (e.keyCode === 13) { 170 | _.show() 171 | } 172 | return !(EX_KEYS.indexOf(e.which) < 0) 173 | } 174 | 175 | /** 176 | * Unbinds input `click` and `keydown` event handlers 177 | */ 178 | this._unbindInput = function () { 179 | _.input.readOnly = false 180 | _.input.removeEventListener('click', _inputClick) 181 | _.input.removeEventListener('keydown', _inputKeydown) 182 | } 183 | 184 | hf.addEvent(_.input, 'keydown', _inputKeydown) 185 | hf.addEvent(_.input, 'click', _inputClick) 186 | 187 | if (_.input.value !== '') { 188 | let time = _.parseTime(_.input.value, _.config.format) 189 | 190 | _.setValue(time) 191 | } else { 192 | let time = _.getSystemTime() 193 | 194 | _.time = new Time(time.hour, time.minute) 195 | } 196 | 197 | _.resetSelected() 198 | _._switchView(_.activeView) 199 | 200 | if (_.config.events && _.config.events.ready) 201 | _.config.events.ready.call(_, _) 202 | } 203 | /** 204 | * Setup time picker html elements 205 | */ 206 | _setup() { 207 | let _ = this, picker = _.timepicker, overlay = picker.overlay, wrapper = picker.wrapper, 208 | time = picker.timeHolder, clock = picker.clockHolder 209 | 210 | hf.appendTo([time.hour, time.dots, time.minute], time.wrapper) 211 | hf.appendTo(time.wrapper, wrapper) 212 | 213 | if (!_.config.is24hour) hf.appendTo(time.am_pm, time.wrapper) 214 | 215 | // Setup hours 216 | let _hours = _.config.is24hour ? 24 : 12 217 | for (let i = 0; i < _hours; i++) { 218 | let value = i + 1, deg = ((HOUR_START_DEG + (i * HOUR_DEG_INCR)) % END_DEG) - (_.config.is24hour && value < 13 ? 15 : 0), 219 | is24 = value === 24, 220 | hour = hf.createElem('div', { class: `mdtp__digit rotate-${deg}`, 'data-hour': (is24 ? 0 : value) }), 221 | hourInner = hf.createElem('span', null, (is24 ? '00' : value)) 222 | 223 | hf.appendTo(hourInner, hour) 224 | 225 | if (_.config.is24hour && value < 13) hour.classList.add('inner--digit') 226 | 227 | hf.addEvent(hourInner, 'click', function() { 228 | let _hour = parseInt(this.parentNode.dataset.hour), 229 | _selectedT = _.selected.getPeriod(), 230 | _value = _.config.is24hour ? _hour : 231 | (_hour + ((_selectedT === 'PM' && _hour < 12) || (_selectedT === 'AM' && _hour === 12) ? 12 : 0)) % 24, 232 | disabled = _.isDisabled(_value, 0, true) 233 | 234 | if (disabled) return 235 | 236 | _.setHour(_value) 237 | _._switchView('minutes') 238 | }) 239 | 240 | hf.appendTo(hour, clock.clock.hours) 241 | } 242 | 243 | // Setup minutes 244 | for (let i = 0; i < 60; i++) { 245 | let min = i < 10 ? '0' + i : i, deg = (MIN_START_DEG + (i * MIN_DEG_INCR)) % END_DEG, 246 | minute = hf.createElem('div', { class: `mdtp__digit rotate-${deg}`, 'data-minute': i }), 247 | minuteInner = hf.createElem('span') 248 | 249 | hf.appendTo(minuteInner, minute) 250 | 251 | if (i % 5 === 0) { 252 | minute.classList.add('marker') 253 | minuteInner.innerText = min 254 | } 255 | 256 | hf.addEvent(minuteInner, 'click', function() { 257 | let _minute = parseInt(this.parentNode.dataset.minute), 258 | _hour = _.selected.getHour(), 259 | disabled = _.isDisabled(_hour, _minute, true) 260 | 261 | if (disabled) return 262 | 263 | _.setMinute(_minute) 264 | }) 265 | 266 | hf.appendTo(minute, clock.clock.minutes) 267 | } 268 | 269 | // Setup clock 270 | if (!_.config.is24hour) { 271 | hf.appendTo([clock.am, clock.pm], clock.clock.wrapper) 272 | } 273 | 274 | hf.appendTo([clock.clock.dot, clock.clock.hours, clock.clock.minutes], clock.clock.wrapper) 275 | hf.appendTo(clock.clock.wrapper, clock.wrapper) 276 | 277 | // Setup buttons 278 | if (_.config.clearBtn) { 279 | hf.appendTo(clock.buttonsHolder.btnClear, clock.buttonsHolder.wrapper) 280 | } 281 | 282 | hf.appendTo([clock.buttonsHolder.btnCancel, clock.buttonsHolder.btnOk], clock.buttonsHolder.wrapper) 283 | hf.appendTo(clock.buttonsHolder.wrapper, clock.wrapper) 284 | 285 | hf.appendTo(clock.wrapper, wrapper) 286 | 287 | // Setup theme 288 | wrapper.dataset.theme = _.input.dataset.theme || _.config.theme 289 | 290 | hf.appendTo(wrapper, overlay) 291 | 292 | return overlay 293 | } 294 | /** 295 | * Sets the hour value of the selected time 296 | * @param {number} hour Hour value 297 | */ 298 | setHour(hour) { 299 | if (typeof hour === 'undefined') 300 | throw new Error('Expecting a value.') 301 | 302 | let is12Hour = !this.config.is24hour 303 | 304 | this.selected.setHour(hour) 305 | 306 | let _selectedH = this.selected.getHour(is12Hour) 307 | 308 | this.timepicker.timeHolder.hour.innerText = is12Hour ? _selectedH : this.selected.format('hh') 309 | 310 | this.timepicker.clockHolder.clock.hours.querySelectorAll('div').forEach(div => { 311 | let val = parseInt(div.dataset.hour) 312 | 313 | div.classList[val === _selectedH ? 'add' : 'remove']('active') 314 | }) 315 | } 316 | /** 317 | * Sets the minute value of the selected time 318 | * @param {number} minute Minute value 319 | */ 320 | setMinute(minute) { 321 | if (typeof minute === 'undefined') 322 | throw new Error('Expecting a value.') 323 | 324 | this.selected.setMinutes(minute) 325 | 326 | this.timepicker.timeHolder.minute.innerText = minute < 10 ? '0' + minute : minute 327 | 328 | this.timepicker.clockHolder.clock.minutes.querySelectorAll('div').forEach(div => { 329 | let val = parseInt(div.dataset.minute) 330 | 331 | div.classList[val === minute ? 'add' : 'remove']('active') 332 | }) 333 | } 334 | /** 335 | * Sets the time period of the selected time 336 | * @param {string} period Period value (AM/PM) 337 | */ 338 | setPeriod(period) { 339 | if (typeof period === 'undefined') 340 | throw new Error('Expecting a value.') 341 | 342 | if (this.selected.getPeriod() !== period.toUpperCase()) 343 | this.selected.invert() 344 | 345 | let _period = this.selected.getPeriod() 346 | 347 | this._setDisabled(this.activeView) 348 | this.timepicker.timeHolder.am_pm.innerText = _period 349 | this.timepicker.clockHolder.am.classList[_period === 'AM' ? 'add' : 'remove']('active') 350 | this.timepicker.clockHolder.pm.classList[_period === 'PM' ? 'add' : 'remove']('active') 351 | } 352 | /** 353 | * Sets the value of the selected time 354 | * @param {string} value Time string values 355 | */ 356 | setValue(value) { 357 | if (typeof value === 'undefined') 358 | throw new Error('Expecting a value.') 359 | 360 | let time = typeof value === 'string' ? this.parseTime(value, this.config.format) : value 361 | 362 | this.time = new Time(time.hour, time.minute) 363 | 364 | let formatted = this.getFormattedTime() 365 | 366 | this.input.value = formatted.value 367 | hf.setAttributes(this.input, { 368 | 'value': formatted.value, 369 | 'data-time': formatted.time 370 | }) 371 | } 372 | /** 373 | * Sets the minimum time constraint 374 | * @param {string} time Minimum time value 375 | */ 376 | setMinTime(time) { this.minTime = time } 377 | /** 378 | * Sets the maximum time constraint 379 | * @param {string} time Maximum time value 380 | */ 381 | setMaxTime(time) { this.maxTime = time } 382 | /** 383 | * Sets the disabled digits of the clock 384 | * @param {string} view View name 385 | */ 386 | _setDisabled(view) { 387 | if (view !== 'hours' && view !== 'minutes') return 388 | 389 | let _ = this, clock = this.timepicker.clockHolder.clock 390 | 391 | if (view === 'hours') { 392 | clock.hours.querySelectorAll('.mdtp__digit').forEach(hour => { 393 | let value = parseInt(hour.dataset.hour), 394 | period = _.selected.getPeriod(), 395 | time = new Time(value, 0) 396 | 397 | if (!_.config.is24hour && period !== time.getPeriod()) 398 | time.invert() 399 | 400 | let disabled = _.isDisabled(time.getHour(), 0, true) 401 | 402 | hour.classList[disabled ? 'add' : 'remove']('digit--disabled') 403 | }) 404 | } 405 | 406 | if (view === 'minutes') { 407 | clock.minutes.querySelectorAll('.mdtp__digit').forEach(minute => { 408 | let value = parseInt(minute.dataset.minute), 409 | hour = _.selected.getHour(), 410 | disabled = _.isDisabled(hour, value, true) 411 | 412 | minute.classList[disabled ? 'add' : 'remove']('digit--disabled') 413 | }) 414 | } 415 | } 416 | /** 417 | * Determines if the given time is disabled 418 | * @param {number} hour Hour value 419 | * @param {number} minute Minute value 420 | * @param {boolean} renderMode `true` if called upon rendering; `false` otherwise 421 | */ 422 | isDisabled(hour, minute, renderMode) { 423 | let _ = this, minT = null, min = null, maxT = null, max = null, now = new Date(), 424 | time = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hour, minute, 0, 0), 425 | hourView = _.activeView === 'hours' 426 | 427 | if (_.minTime) 428 | minT = _.minTime === 'now' ? _.getSystemTime() : _.parseTime(_.minTime) 429 | if (_.maxTime) 430 | maxT = _.maxTime === 'now' ? _.getSystemTime() : _.parseTime(_.maxTime) 431 | 432 | if (minT) { 433 | min = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 434 | minT.getHour(), hourView && renderMode ? 0 : minT.getMinutes(), 0, 0) 435 | } 436 | 437 | if (maxT) { 438 | max = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 439 | maxT.getHour(), hourView && renderMode ? 0 : maxT.getMinutes(), 0, 0) 440 | } 441 | 442 | return (min && time < min) || (max && time > max) 443 | } 444 | /** 445 | * Resets the selected time to client (system) time 446 | */ 447 | resetSelected() { 448 | this.setHour(this.time.hour) 449 | this.setMinute(this.time.minute) 450 | this.setPeriod(this.time.getPeriod()) 451 | } 452 | /** 453 | * Returns the selected time string 454 | */ 455 | getFormattedTime() { 456 | let time = this.time.format(this.config.timeFormat, false), 457 | tValue = this.time.format(this.config.format, this.config.hourPadding) 458 | 459 | return { time: time, value: tValue } 460 | } 461 | /** 462 | * Returns the current client (system) time 463 | */ 464 | getSystemTime() { 465 | return (now => { 466 | return new Time(now.getHours(), now.getMinutes()) 467 | })(new Date()) 468 | } 469 | /** 470 | * Parses the given time string into a Time object 471 | * @param {string} time Time value 472 | * @param {string} tf Time format 473 | */ 474 | parseTime(time, tf) { 475 | let that = this, format = typeof tf === 'undefined' ? that.config.format : tf, 476 | hLength = (format.match(/h/g) || []).length, 477 | is24Hour = hLength > 1, 478 | // mLength = (format.match(/m/g) || []).length, 479 | tLength = (format.match(/t/g) || []).length, 480 | timeLength = time.length, 481 | fH = format.indexOf('h'), lH = format.lastIndexOf('h'), 482 | hour = '', min = '', t = '' 483 | 484 | // Parse hour 485 | if (that.config.hourPadding || is24Hour) { 486 | hour = time.substr(fH, 2) 487 | } else { 488 | let prev = format.substring(fH - 1, fH), next = format.substring(lH + 1, lH + 2) 489 | 490 | if (lH === format.length - 1) { 491 | hour = time.substring(time.indexOf(prev, fH - 1) + 1, timeLength) 492 | } else if (fH === 0) { 493 | hour = time.substring(0, time.indexOf(next, fH)) 494 | } else { 495 | hour = time.substring(time.indexOf(prev, fH - 1) + 1, time.indexOf(next, fH + 1)) 496 | } 497 | } 498 | 499 | format = format.replace(/(hh|h)/g, hour) 500 | 501 | let fM = format.indexOf('m'), lM = format.lastIndexOf('m'), 502 | fT = format.indexOf('t') 503 | 504 | // Parse minute 505 | let prevM = format.substring(fM - 1, fM), nextM = format.substring(lM + 1, lM + 2) 506 | 507 | if (lM === format.length - 1) { 508 | min = time.substring(time.indexOf(prevM, fM - 1) + 1, timeLength) 509 | } else if (fM === 0) { 510 | min = time.substring(0, 2) 511 | } else { 512 | min = time.substr(fM, 2) 513 | } 514 | 515 | // Parse t (am/pm) 516 | if (is24Hour) 517 | t = parseInt(hour) > 11 ? (tLength > 1 ? 'PM' : 'pm') : (tLength > 1 ? 'AM' : 'am') 518 | else 519 | t = time.substr(fT, 2) 520 | 521 | let isPm = t.toLowerCase() === 'pm', 522 | outTime = new Time(parseInt(hour), parseInt(min)) 523 | if ((isPm && parseInt(hour) < 12) || (!isPm && parseInt(hour) === 12)) { 524 | outTime.invert() 525 | } 526 | 527 | return outTime 528 | } 529 | /** 530 | * Switches the time picker view (screen) 531 | * @param {string} view View name 532 | */ 533 | _switchView(view) { 534 | let _ = this, picker = this.timepicker, anim_speed = 350 535 | 536 | if (view !== 'hours' && view !== 'minutes') return 537 | 538 | _.activeView = view 539 | _._setDisabled(view) 540 | 541 | picker.timeHolder.hour.classList[view === 'hours' ? 'add' : 'remove']('active') 542 | picker.timeHolder.minute.classList[view === 'hours' ? 'remove' : 'add']('active') 543 | 544 | picker.clockHolder.clock.hours.classList.add('animate') 545 | if (view === 'hours') 546 | picker.clockHolder.clock.hours.classList.remove('hidden') 547 | 548 | clearTimeout(_.hTimeout) 549 | 550 | _.hTimeout = setTimeout(() => { 551 | if (view !== 'hours') 552 | picker.clockHolder.clock.hours.classList.add('hidden') 553 | picker.clockHolder.clock.hours.classList.remove('animate') 554 | }, view === 'hours' ? 20 : anim_speed) 555 | 556 | picker.clockHolder.clock.minutes.classList.add('animate') 557 | if (view === 'minutes') 558 | picker.clockHolder.clock.minutes.classList.remove('hidden') 559 | 560 | clearTimeout(_.mTimeout) 561 | 562 | _.mTimeout = setTimeout(() => { 563 | if (view !== 'minutes') 564 | picker.clockHolder.clock.minutes.classList.add('hidden') 565 | picker.clockHolder.clock.minutes.classList.remove('animate') 566 | }, view === 'minutes' ? 20 : anim_speed) 567 | } 568 | /** 569 | * Shows the time picker 570 | */ 571 | show() { 572 | let _ = this 573 | 574 | if (_.input.value === '') { 575 | let time = _.getSystemTime() 576 | this.time = new Time(time.hour, time.minute) 577 | } 578 | 579 | _.resetSelected() 580 | 581 | document.body.setAttribute('mdtimepicker-display', 'on') 582 | 583 | _.timepicker.wrapper.classList.add('animate') 584 | _.timepicker.overlay.classList.remove('hidden') 585 | _.timepicker.overlay.classList.add('animate') 586 | setTimeout(function () { 587 | _.timepicker.overlay.classList.remove('animate') 588 | _.timepicker.wrapper.classList.remove('animate') 589 | _.timepicker.wrapper.focus() 590 | 591 | _.visible = true 592 | _.input.blur() 593 | 594 | if (_.config.events && _.config.events.shown) 595 | _.config.events.shown.call(_) 596 | }, 10) 597 | } 598 | /** 599 | * Hides the time picker 600 | */ 601 | hide() { 602 | let _ = this 603 | 604 | _.timepicker.overlay.classList.add('animate') 605 | _.timepicker.wrapper.classList.add('animate') 606 | setTimeout(function () { 607 | _._switchView('hours') 608 | _.timepicker.overlay.classList.add('hidden') 609 | _.timepicker.overlay.classList.remove('animate') 610 | _.timepicker.wrapper.classList.remove('animate') 611 | 612 | document.body.removeAttribute('mdtimepicker-display') 613 | 614 | _.visible = false 615 | _.input.focus() 616 | 617 | if (_.config.events && _.config.events.hidden) 618 | _.config.events.hidden.call(_) 619 | }, 300) 620 | } 621 | /** 622 | * Removes the time picker 623 | */ 624 | destroy() { 625 | this._unbindInput() 626 | this.timepicker.overlay.remove() 627 | delete this.input[MDTP_DATA] 628 | } 629 | /** 630 | * Triggers the change event on the input element 631 | * @param {Object} data Event data 632 | */ 633 | _triggerChange(data) { 634 | hf.triggerChange(this.input, data) 635 | 636 | if (this.config.events && this.config.events.timeChanged) 637 | this.config.events.timeChanged.call(this, data, this) 638 | } 639 | } 640 | 641 | /** 642 | * Time picker wrapper 643 | */ 644 | function mdtimepicker() { 645 | let args = arguments, 646 | arg0 = args[0], arg0IsList = arg0 instanceof NodeList || Array.isArray(arg0), arg0IsElem = arg0 instanceof Element, 647 | inputs = typeof arg0 === 'string' ? document.querySelectorAll(arg0) : 648 | (arg0IsList ? arg0 : (arg0IsElem ? [arg0] : document.querySelectorAll(DEFAULT_CLASS))), 649 | options = typeof arg0 === 'object' && !(arg0IsList) && !(arg0IsElem) ? arg0 : args[1] && typeof args[1] === 'object' ? args[1] : {}, 650 | _defaults = hf.extend({}, MDTimePicker.default_configs || DEFAULTS) 651 | 652 | if (options && options.is24hour) _defaults.format = 'hh:mm' 653 | 654 | Array.from(inputs).forEach(el => { 655 | let picker = el[MDTP_DATA] 656 | 657 | if (!picker) { 658 | el[MDTP_DATA] = (picker = new MDTimePicker(el, hf.extend(_defaults, options))) 659 | } 660 | 661 | if ((typeof arg0 === 'string' || arg0IsList || arg0IsElem) && (args[1] && typeof args[1] === 'string')) { 662 | picker[args[1]].apply(picker, Array.prototype.slice.call(args).slice(2)) 663 | } 664 | }) 665 | } 666 | 667 | mdtimepicker.defaults = function (configs) { 668 | MDTimePicker.default_configs = hf.extend(DEFAULTS, configs) 669 | } 670 | 671 | export default mdtimepicker -------------------------------------------------------------------------------- /src/mdtimepicker.scss: -------------------------------------------------------------------------------- 1 | /*!Don't remove this! 2 | * MDTimePicker plugin styles 3 | * 4 | * Author: Dionlee Uy 5 | * Email: dionleeuy@gmail.com 6 | */ 7 | 8 | @import url('https://fonts.googleapis.com/css?family=Roboto:400,500&display=swap'); 9 | 10 | $degrees: -15, 6, 12, 15, 18, 24, 30, 36, 42, 45, 48, 54, 60, 66, 72, 75, 78, 84, 90, 96, 102, 105, 108, 114, 120, 126, 132, 135, 138, 144, 150, 156, 162, 165, 168, 174, 11 | 180, 186, 192, 195, 198, 204, 210, 216, 222, 225, 228, 234, 240, 246, 252, 255, 258, 264, 270, 276, 282, 285, 288, 294, 300, 306, 312, 315, 318, 324, 330, 336, 342, 12 | 348, 354, 360; 13 | 14 | .mdtimepicker { 15 | position: fixed; 16 | top: 0; 17 | left: 0; 18 | right: 0; 19 | bottom: 0; 20 | font-family: Roboto, sans-serif; 21 | font-size: 14px; 22 | background-color: rgba(10,10,10,.65); 23 | transition: background-color .28s ease; 24 | z-index: 100001; 25 | 26 | .mdtp__wrapper { 27 | position: absolute; 28 | display: flex; 29 | flex-direction: column; 30 | left: 50%; 31 | bottom: 24px; 32 | min-width: 280px; 33 | opacity: 1; 34 | outline: none; 35 | user-select: none; 36 | border-radius: 4px; 37 | transform: translateX(-50%) scale(1); 38 | box-shadow: 0px 11px 15px -7px rgba(0, 0, 0, 0.2), 0px 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 9px 46px 8px rgba(0, 0, 0, 0.12); 39 | transition: transform .28s ease, opacity .28s ease; 40 | overflow: hidden; 41 | 42 | &.animate { 43 | transform: translateX(-50%) scale(1.05); 44 | opacity: 0; 45 | } 46 | } 47 | 48 | .mdtp__time_holder { 49 | display: flex; 50 | flex-direction: row; 51 | align-items: center; 52 | justify-content: center; 53 | font-size: 46px; 54 | padding: 20px 24px; 55 | color: rgba(255,255,255,.5); 56 | text-align: center; 57 | background-color: #1565c0; 58 | 59 | & > span { 60 | display: inline-block; 61 | line-height: 48px; 62 | cursor: default; 63 | 64 | &:not(.mdtp__timedots):not(.mdtp__ampm) { 65 | cursor: pointer; 66 | margin: 0 4px; 67 | transition: color .2s linear; 68 | } 69 | } 70 | 71 | .mdtp__time_h.active, 72 | .mdtp__time_m.active { color: #fafafa; } 73 | 74 | .mdtp__ampm { 75 | font-size: 18px; 76 | cursor: pointer; 77 | transition: color .2s linear; 78 | 79 | &:hover { 80 | color: #fafafa; 81 | } 82 | } 83 | } 84 | 85 | .mdtp__clock_holder { 86 | position: relative; 87 | background-color: #fff; 88 | 89 | .mdtp__clock { 90 | position: relative; 91 | width: 250px; 92 | height: 250px; 93 | margin: 20px; 94 | border-radius: 50%; 95 | background-color: #eee; 96 | 97 | .mdtp__am, 98 | .mdtp__pm { 99 | display: block; 100 | position: absolute; 101 | bottom: -8px; 102 | width: 36px; 103 | height: 36px; 104 | line-height: 36px; 105 | text-align: center; 106 | cursor: pointer; 107 | border-radius: 50%; 108 | border: 1px solid rgba(0,0,0,.1); 109 | background: rgba(0,0,0,.05); 110 | transition: background-color .2s ease, color .2s; 111 | z-index: 3; 112 | 113 | &:hover { background-color: rgba(0,0,0,.1); } 114 | 115 | &.active { 116 | color: #fafafa; 117 | background-color: #1565c0; 118 | } 119 | } 120 | 121 | .mdtp__am { left: -8px; } 122 | 123 | .mdtp__pm { right: -8px; } 124 | 125 | .mdtp__clock_dot { 126 | position: absolute; 127 | top: 50%; 128 | left: 50%; 129 | padding: 4px; 130 | border-radius: 50%; 131 | background-color: #1565c0; 132 | transform: translate(-50%,-50%); 133 | } 134 | 135 | .mdtp__hour_holder, 136 | .mdtp__minute_holder { 137 | position: absolute; 138 | top: 0; 139 | width: 100%; 140 | height: 100%; 141 | opacity: 1; 142 | transform: scale(1); 143 | transition: transform .35s cubic-bezier(0.4, 0.0, 0.2, 1), opacity .35s ease; 144 | overflow: hidden; 145 | 146 | &.hidden { display: none; } 147 | } 148 | 149 | .mdtp__hour_holder.animate { 150 | transform: scale(1.2); 151 | opacity: 0; 152 | } 153 | 154 | .mdtp__minute_holder.animate { 155 | transform: scale(.8); 156 | opacity: 0; 157 | } 158 | 159 | .mdtp__digit { 160 | position: absolute; 161 | width: 50%; 162 | top: 50%; 163 | left: 0; 164 | margin-top: -16px; 165 | transform-origin: right center; 166 | z-index: 1; 167 | 168 | span { 169 | display: inline-block; 170 | width: 32px; 171 | height: 32px; 172 | line-height: 32px; 173 | margin-left: 8px; 174 | text-align: center; 175 | border-radius: 50%; 176 | cursor: pointer; 177 | transition: background-color .28s, color .14s; 178 | } 179 | 180 | &.inner--digit { 181 | width: 36%; 182 | left: 14%; 183 | z-index: 2; 184 | } 185 | 186 | &.active span, 187 | &:not(.digit--disabled) span:hover { 188 | background-color: #1565c0 !important; 189 | color: #fff; 190 | z-index: 2; 191 | } 192 | 193 | &.digit--disabled span { 194 | color: rgb(200,200,200); 195 | cursor: not-allowed; 196 | background-color: transparent !important; 197 | } 198 | 199 | &.active:before { 200 | content: ''; 201 | display: block; 202 | position: absolute; 203 | top: calc(50% - 1px); 204 | right: 0; 205 | height: 2px; 206 | width: calc(100% - 40px); 207 | background-color: #1565c0; 208 | } 209 | } 210 | 211 | .mdtp__minute_holder { 212 | .mdtp__digit { 213 | font-size: 13px; 214 | 215 | &:not(.marker) { 216 | margin-top: -6px; 217 | height: 12px; 218 | 219 | span { 220 | width: 12px; 221 | height: 12px; 222 | line-height: 12px; 223 | margin-left: 14px; 224 | } 225 | } 226 | 227 | &:not(.marker).active:before { width: calc(100% - 26px); } 228 | 229 | &.marker { 230 | margin-top: -12px; 231 | 232 | span { 233 | width: 24px; 234 | height: 24px; 235 | line-height: 24px; 236 | margin-left: 10px; 237 | } 238 | } 239 | 240 | &.marker.active:before { width: calc(100% - 34px); } 241 | } 242 | } 243 | } 244 | } 245 | 246 | .mdtp__buttons { 247 | padding: 0 10px 10px; 248 | text-align: right; 249 | 250 | .mdtp__button { 251 | display: inline-block; 252 | padding: 0 16px; 253 | min-width: 40px; 254 | text-align: center; 255 | text-transform: uppercase; 256 | line-height: 32px; 257 | font-weight: 500; 258 | cursor: pointer; 259 | color: #1565c0; 260 | border-radius: 4px; 261 | transition: background-color .2s linear; 262 | 263 | &:hover { background-color: rgba(0,0,0,.1); } 264 | 265 | &:active { background-color: rgba(0,0,0,.2); } 266 | 267 | &.clear-btn { 268 | float: left; 269 | color: #ef5350 !important; 270 | } 271 | } 272 | 273 | &:after { 274 | content: ''; 275 | display: block; 276 | clear: both; 277 | } 278 | } 279 | 280 | &.hidden { display: none; } 281 | &.animate { background-color: transparent; } 282 | } 283 | 284 | @each $degree in $degrees { 285 | .mdtp__digit.rotate-#{$degree} { 286 | transform: rotate(#{$degree}deg); 287 | 288 | span { 289 | transform: rotate(#{0 - $degree}deg); 290 | } 291 | } 292 | } 293 | 294 | body[mdtimepicker-display='on'] { overflow: hidden; } 295 | 296 | @media (max-height: 360px) { 297 | .mdtimepicker { 298 | .mdtp__wrapper { 299 | flex-direction: row; 300 | bottom: 8px; 301 | } 302 | 303 | .mdtp__time_holder { 304 | width: 160px; 305 | padding: 20px; 306 | } 307 | 308 | .mdtp__clock { 309 | .mdtp__am, .mdtp__pm { bottom: -4px; } 310 | 311 | .mdtp__am { left: -4px; } 312 | .mdtp__pm { right: -4px; } 313 | } 314 | } 315 | } 316 | 317 | @media (max-height: 320px) { 318 | .mdtimepicker .mdtp__wrapper { bottom: 0; } 319 | } 320 | 321 | // themes 322 | @import './themes/red.scss'; 323 | @import './themes/green.scss'; 324 | @import './themes/blue.scss'; 325 | @import './themes/teal.scss'; 326 | @import './themes/purple.scss'; 327 | @import './themes/indigo.scss'; 328 | @import './themes/dark.scss'; -------------------------------------------------------------------------------- /src/themes/_format.scss: -------------------------------------------------------------------------------- 1 | $theme: 'yellow'; 2 | $color: #F9A825; 3 | 4 | .mdtp__wrapper[data-theme='#{$theme}'] { 5 | .mdtp__time_holder { background-color: $color; } 6 | 7 | .mdtp__clock { 8 | .mdtp__am.active, 9 | .mdtp__pm.active, 10 | .mdtp__clock_dot { background-color: $color; } 11 | 12 | .mdtp__digit { 13 | &.active span, 14 | &:not(.digit--disabled) span:hover { 15 | background-color: $color !important; 16 | } 17 | 18 | &.active:before { background-color: $color; } 19 | } 20 | } 21 | 22 | .mdtp__button { color: $color; } 23 | } -------------------------------------------------------------------------------- /src/themes/blue.scss: -------------------------------------------------------------------------------- 1 | $theme: 'blue'; 2 | $color: #1565c0; 3 | 4 | .mdtp__wrapper[data-theme='#{$theme}'] { 5 | .mdtp__time_holder { background-color: $color; } 6 | 7 | .mdtp__clock { 8 | .mdtp__am.active, 9 | .mdtp__pm.active, 10 | .mdtp__clock_dot { background-color: $color; } 11 | 12 | .mdtp__digit { 13 | &.active span, 14 | &:not(.digit--disabled) span:hover { 15 | background-color: $color !important; 16 | } 17 | 18 | &.active:before { background-color: $color; } 19 | } 20 | } 21 | 22 | .mdtp__button { color: $color; } 23 | } -------------------------------------------------------------------------------- /src/themes/dark.scss: -------------------------------------------------------------------------------- 1 | $theme: 'dark'; 2 | $headerBg: #121212; 3 | $contentBg: rgb(29,29,29); 4 | $clockBg: rgb(24,24,24); 5 | $color: rgba(255,255,255,.87); 6 | $periodBg: rgba(200,200,200,.05); 7 | $disabled: rgba(100,100,100,.87); 8 | $btnColor: #42a5f5; 9 | $btnHover: rgba(255,255,255,.04); 10 | $btnActive: rgba(255,255,255,.1); 11 | 12 | .mdtp__wrapper[data-theme='#{$theme}'] { 13 | .mdtp__time_holder { background-color: $headerBg; } 14 | .mdtp__clock_holder { 15 | background-color: $contentBg; 16 | 17 | .mdtp__clock { 18 | background-color: $clockBg; 19 | 20 | .mdtp__digit { 21 | &:not(.digit--disabled) { color: $color; } 22 | 23 | &.digit--disabled span { color: $disabled; } 24 | } 25 | 26 | .mdtp__am:not(.active), 27 | .mdtp__pm:not(.active) { 28 | color: $color; 29 | background-color: $periodBg; 30 | } 31 | } 32 | } 33 | 34 | .mdtp__button { 35 | color: $btnColor; 36 | 37 | &:hover { background-color: $btnHover; } 38 | 39 | &:active { background-color: $btnActive; } 40 | } 41 | } -------------------------------------------------------------------------------- /src/themes/green.scss: -------------------------------------------------------------------------------- 1 | $theme: 'green'; 2 | $color: #2e7d32; 3 | 4 | .mdtp__wrapper[data-theme='#{$theme}'] { 5 | .mdtp__time_holder { background-color: $color; } 6 | 7 | .mdtp__clock { 8 | .mdtp__am.active, 9 | .mdtp__pm.active, 10 | .mdtp__clock_dot { background-color: $color; } 11 | 12 | .mdtp__digit { 13 | &.active span, 14 | &:not(.digit--disabled) span:hover { 15 | background-color: $color !important; 16 | } 17 | 18 | &.active:before { background-color: $color; } 19 | } 20 | } 21 | 22 | .mdtp__button { color: $color; } 23 | } -------------------------------------------------------------------------------- /src/themes/indigo.scss: -------------------------------------------------------------------------------- 1 | $theme: 'indigo'; 2 | $color: #283593; 3 | 4 | .mdtp__wrapper[data-theme='#{$theme}'] { 5 | .mdtp__time_holder { background-color: $color; } 6 | 7 | .mdtp__clock { 8 | .mdtp__am.active, 9 | .mdtp__pm.active, 10 | .mdtp__clock_dot { background-color: $color; } 11 | 12 | .mdtp__digit { 13 | &.active span, 14 | &:not(.digit--disabled) span:hover { 15 | background-color: $color !important; 16 | } 17 | 18 | &.active:before { background-color: $color; } 19 | } 20 | } 21 | 22 | .mdtp__button { color: $color; } 23 | } -------------------------------------------------------------------------------- /src/themes/purple.scss: -------------------------------------------------------------------------------- 1 | $theme: 'purple'; 2 | $color: #6a1b9a; 3 | 4 | .mdtp__wrapper[data-theme='#{$theme}'] { 5 | .mdtp__time_holder { background-color: $color; } 6 | 7 | .mdtp__clock { 8 | .mdtp__am.active, 9 | .mdtp__pm.active, 10 | .mdtp__clock_dot { background-color: $color; } 11 | 12 | .mdtp__digit { 13 | &.active span, 14 | &:not(.digit--disabled) span:hover { 15 | background-color: $color !important; 16 | } 17 | 18 | &.active:before { background-color: $color; } 19 | } 20 | } 21 | 22 | .mdtp__button { color: $color; } 23 | } -------------------------------------------------------------------------------- /src/themes/red.scss: -------------------------------------------------------------------------------- 1 | $theme: 'red'; 2 | $color: #c62828; 3 | 4 | .mdtp__wrapper[data-theme='#{$theme}'] { 5 | .mdtp__time_holder { background-color: $color; } 6 | 7 | .mdtp__clock { 8 | .mdtp__am.active, 9 | .mdtp__pm.active, 10 | .mdtp__clock_dot { background-color: $color; } 11 | 12 | .mdtp__digit { 13 | &.active span, 14 | &:not(.digit--disabled) span:hover { 15 | background-color: $color !important; 16 | } 17 | 18 | &.active:before { background-color: $color; } 19 | } 20 | } 21 | 22 | .mdtp__button { color: $color; } 23 | } -------------------------------------------------------------------------------- /src/themes/teal.scss: -------------------------------------------------------------------------------- 1 | $theme: 'teal'; 2 | $color: #00695c; 3 | 4 | .mdtp__wrapper[data-theme='#{$theme}'] { 5 | .mdtp__time_holder { background-color: $color; } 6 | 7 | .mdtp__clock { 8 | .mdtp__am.active, 9 | .mdtp__pm.active, 10 | .mdtp__clock_dot { background-color: $color; } 11 | 12 | .mdtp__digit { 13 | &.active span, 14 | &:not(.digit--disabled) span:hover { 15 | background-color: $color !important; 16 | } 17 | 18 | &.active:before { background-color: $color; } 19 | } 20 | } 21 | 22 | .mdtp__button { color: $color; } 23 | } -------------------------------------------------------------------------------- /src/vars.js: -------------------------------------------------------------------------------- 1 | export const MDTP_DATA = '_mdtimepicker' 2 | 3 | /** 4 | * Default time picker input query selector class 5 | */ 6 | export const DEFAULT_CLASS = '.mdtimepicker-input' 7 | 8 | /** 9 | * Starting degree value for hour hand 10 | */ 11 | export const HOUR_START_DEG = 120 12 | 13 | /** 14 | * Hour hand degree increment 15 | */ 16 | export const HOUR_DEG_INCR = 30 17 | 18 | /** 19 | * Starting degree value for minute hand 20 | */ 21 | export const MIN_START_DEG = 90 22 | 23 | /** 24 | * Minute hand degree increment 25 | */ 26 | export const MIN_DEG_INCR = 6 27 | 28 | /** 29 | * Degree limit 30 | */ 31 | export const END_DEG = 360 32 | 33 | /** 34 | * Keydown excluded key codes 35 | */ 36 | export const EX_KEYS = [9, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123] 37 | 38 | /** 39 | * Default time picker configurations 40 | */ 41 | export const DEFAULTS = { 42 | // format of the time value (data-time attribute) 43 | timeFormat: 'hh:mm:ss.000', 44 | // format of the input value 45 | format: 'h:mm tt', 46 | // theme of the timepicker 47 | theme: 'blue', 48 | // determines if display value has zero padding for hour value less than 10 (i.e. 05:30 PM); 24-hour format has padding by default 49 | hourPadding: false, 50 | // determines if clear button is visible 51 | clearBtn: false, 52 | // determines if the clock will use 24-hour format in the UI; format config will be forced to `hh:mm` if not specified 53 | is24hour: false, 54 | // callback functions 55 | events: { 56 | ready: null, 57 | timeChanged: null, 58 | shown: null, 59 | hidden: null 60 | } 61 | } -------------------------------------------------------------------------------- /vue-timepicker.js: -------------------------------------------------------------------------------- 1 | import './dist/mdtimepicker.css' 2 | import mdtimepicker from './dist/mdtimepicker.js' 3 | 4 | export default { 5 | install(Vue, options) { 6 | 7 | if (! options) options = {} 8 | else mdtimepicker.defaults(options) 9 | 10 | // component 11 | Vue.component('mdtimepicker', { 12 | render(createElement) { 13 | return createElement('input', { 14 | domProps: { 15 | type: 'text' 16 | }, 17 | on: { 18 | timechanged: e => { 19 | this.$emit('timechanged', e) 20 | } 21 | } 22 | }) 23 | }, 24 | props: { 25 | options: { type: Object }, 26 | ready: { type: Function }, 27 | timeChanged: { type: Function }, 28 | shown: { type: Function }, 29 | hidden: { type: Function } 30 | }, 31 | methods: { 32 | setValue(value) { mdtimepicker(this.$el, 'setValue', value) }, 33 | setMinTime(value) { mdtimepicker(this.$el, 'setMinTime', value) }, 34 | setMaxTime(value) { mdtimepicker(this.$el, 'setMaxTime', value) }, 35 | show() { mdtimepicker(this.$el, 'show') }, 36 | hide() { mdtimepicker(this.$el, 'hide') }, 37 | destroy() { mdtimepicker(this.$el, 'destroy') } 38 | }, 39 | mounted() { 40 | let evtProps = { 41 | events: { ready: this.ready, timeChanged: this.timeChanged, shown: this.shown, hidden: this.hidden } 42 | } 43 | 44 | // remove undefined callbacks 45 | Object.keys(evtProps.events).forEach(key => evtProps.events[key] === undefined && delete evtProps.events[key]) 46 | 47 | // initialize 48 | mdtimepicker(this.$el, { ...this.options, ...evtProps }) 49 | }, 50 | destroyed() { 51 | this.destroy() 52 | } 53 | }) 54 | 55 | // v-mdtimepicker directive 56 | Vue.directive('mdtimepicker', { 57 | bind(el, binding) { 58 | mdtimepicker(el, binding.value) 59 | }, 60 | unbind(el) { 61 | mdtimepicker(el, 'destroy') 62 | } 63 | }) 64 | } 65 | } -------------------------------------------------------------------------------- /vue3-timepicker.js: -------------------------------------------------------------------------------- 1 | import './dist/mdtimepicker.css' 2 | import mdtimepicker from './dist/mdtimepicker.js' 3 | import { h } from 'vue' 4 | 5 | export default { 6 | install(app, options) { 7 | 8 | if (! options) options = {} 9 | else mdtimepicker.defaults(options) 10 | 11 | // component 12 | app.component('mdtimepicker', { 13 | render() { 14 | return h('input', { 15 | domProps: { 16 | type: 'text' 17 | }, 18 | on: { 19 | timechanged: e => { 20 | this.$emit('timechanged', e) 21 | } 22 | } 23 | }) 24 | }, 25 | props: { 26 | options: { type: Object }, 27 | ready: { type: Function }, 28 | timeChanged: { type: Function }, 29 | shown: { type: Function }, 30 | hidden: { type: Function } 31 | }, 32 | methods: { 33 | setValue(value) { mdtimepicker(this.$el, 'setValue', value) }, 34 | setMinTime(value) { mdtimepicker(this.$el, 'setMinTime', value) }, 35 | setMaxTime(value) { mdtimepicker(this.$el, 'setMaxTime', value) }, 36 | show() { mdtimepicker(this.$el, 'show') }, 37 | hide() { mdtimepicker(this.$el, 'hide') }, 38 | destroy() { mdtimepicker(this.$el, 'destroy') } 39 | }, 40 | mounted() { 41 | let evtProps = { 42 | events: { ready: this.ready, timeChanged: this.timeChanged, shown: this.shown, hidden: this.hidden } 43 | } 44 | 45 | // remove undefined callbacks 46 | Object.keys(evtProps.events).forEach(key => evtProps.events[key] === undefined && delete evtProps.events[key]) 47 | 48 | // initialize 49 | mdtimepicker(this.$el, { ...this.options, ...evtProps }) 50 | }, 51 | destroyed() { 52 | this.destroy() 53 | } 54 | }) 55 | 56 | // v-mdtimepicker directive 57 | app.directive('mdtimepicker', { 58 | bind(el, binding) { 59 | mdtimepicker(el, binding.value) 60 | }, 61 | unbind(el) { 62 | mdtimepicker(el, 'destroy') 63 | } 64 | }) 65 | } 66 | } --------------------------------------------------------------------------------