@docsvision/material-ui-pickers 3.2.0-beta.24 → 3.2.0-beta.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/.size-snapshot.json +11 -11
  2. package/9db1cba1a61cb58db53f38425bbd1f95.7z +0 -0
  3. package/build/DatePicker/DatePicker.d.ts +2 -2
  4. package/build/DatePicker/DatePicker.js +1 -1
  5. package/build/DateTimePicker/DateTimePicker.js +1 -1
  6. package/build/Picker/Picker.js +1 -1
  7. package/build/TimePicker/TimePicker.js +1 -1
  8. package/build/_helpers/text-field-helper.d.ts +1 -1
  9. package/build/_shared/KeyboardDateInput.js +1 -1
  10. package/build/_shared/ModalDialog.d.ts +2 -2
  11. package/build/_shared/PureDateInput.js +1 -1
  12. package/build/_shared/ToolbarButton.d.ts +2 -2
  13. package/build/_shared/hooks/useKeyboardPickerState.js +2 -2
  14. package/build/constants/prop-types.js +2 -2
  15. package/build/dist/material-ui-pickers.esm.js +12 -12
  16. package/build/dist/material-ui-pickers.esm.js.map +1 -1
  17. package/build/dist/material-ui-pickers.js +62 -62
  18. package/build/dist/material-ui-pickers.js.map +1 -1
  19. package/build/dist/material-ui-pickers.umd.js +5790 -4511
  20. package/build/dist/material-ui-pickers.umd.min.js +1 -1
  21. package/build/package.json +1 -1
  22. package/build/views/Calendar/Calendar.js +2 -2
  23. package/build/views/Clock/Clock.d.ts +1 -1
  24. package/build/views/Clock/ClockPointer.d.ts +1 -1
  25. package/package.json +1 -1
  26. package/src/DatePicker/DatePicker.tsx +91 -0
  27. package/src/DatePicker/DatePickerToolbar.tsx +75 -0
  28. package/src/DatePicker/index.ts +7 -0
  29. package/src/DateTimePicker/DateTimePicker.tsx +72 -0
  30. package/src/DateTimePicker/DateTimePickerTabs.tsx +86 -0
  31. package/src/DateTimePicker/DateTimePickerToolbar.tsx +123 -0
  32. package/src/DateTimePicker/index.ts +7 -0
  33. package/src/MuiPickersUtilsProvider.tsx +39 -0
  34. package/src/Picker/Picker.tsx +275 -0
  35. package/src/Picker/WrappedKeyboardPicker.tsx +136 -0
  36. package/src/Picker/WrappedPurePicker.tsx +128 -0
  37. package/src/Rifm/Rifm.ts +213 -0
  38. package/src/TimePicker/TimePicker.tsx +67 -0
  39. package/src/TimePicker/TimePickerToolbar.tsx +180 -0
  40. package/src/TimePicker/index.tsx +7 -0
  41. package/src/__tests__/DatePicker/Calendar.test.tsx +51 -0
  42. package/src/__tests__/DatePicker/Month.test.tsx +36 -0
  43. package/src/__tests__/DatePicker/MonthSelection.test.tsx +37 -0
  44. package/src/__tests__/MuiPickersUtilsProvider.test.tsx +21 -0
  45. package/src/__tests__/TimePicker/Clock.test.tsx +68 -0
  46. package/src/__tests__/_helpers/date-utils.test.tsx +197 -0
  47. package/src/__tests__/_helpers/text-field-helper.test.tsx +34 -0
  48. package/src/__tests__/_shared/ModalDialog.test.tsx +109 -0
  49. package/src/__tests__/e2e/DatePicker.test.tsx +233 -0
  50. package/src/__tests__/e2e/DatePickerProps.test.tsx +18 -0
  51. package/src/__tests__/e2e/DatePickerRoot.test.tsx +154 -0
  52. package/src/__tests__/e2e/DateTimePicker.test.tsx +86 -0
  53. package/src/__tests__/e2e/DateTimePickerRoot.test.tsx +72 -0
  54. package/src/__tests__/e2e/KeyboardDatePicker.test.tsx +140 -0
  55. package/src/__tests__/e2e/KeyboardDateTimePicker.test.tsx +48 -0
  56. package/src/__tests__/e2e/Theme.test.tsx +30 -0
  57. package/src/__tests__/e2e/TimePicker.test.tsx +121 -0
  58. package/src/__tests__/e2e/commands.tsx +8 -0
  59. package/src/__tests__/setup.js +26 -0
  60. package/src/__tests__/test-utils.tsx +45 -0
  61. package/src/__tests__/tsconfig.json +5 -0
  62. package/src/_helpers/date-utils.ts +92 -0
  63. package/src/_helpers/text-field-helper.ts +239 -0
  64. package/src/_helpers/time-utils.ts +83 -0
  65. package/src/_helpers/utils.ts +8 -0
  66. package/src/_shared/KeyboardDateInput.tsx +161 -0
  67. package/src/_shared/ModalDialog.tsx +114 -0
  68. package/src/_shared/PickerToolbar.tsx +52 -0
  69. package/src/_shared/PureDateInput.tsx +45 -0
  70. package/src/_shared/ToolbarButton.tsx +63 -0
  71. package/src/_shared/ToolbarText.tsx +49 -0
  72. package/src/_shared/WithUtils.tsx +19 -0
  73. package/src/_shared/hooks/useIsLandscape.tsx +27 -0
  74. package/src/_shared/hooks/useKeyDown.ts +34 -0
  75. package/src/_shared/hooks/useKeyboardPickerState.ts +72 -0
  76. package/src/_shared/hooks/useOpenState.ts +22 -0
  77. package/src/_shared/hooks/usePickerState.ts +134 -0
  78. package/src/_shared/hooks/useUtils.ts +20 -0
  79. package/src/_shared/hooks/useViews.tsx +31 -0
  80. package/src/_shared/icons/ArrowLeftIcon.tsx +11 -0
  81. package/src/_shared/icons/ArrowRightIcon.tsx +11 -0
  82. package/src/_shared/icons/DateRangeIcon.tsx +11 -0
  83. package/src/_shared/icons/KeyboardIcon.tsx +11 -0
  84. package/src/_shared/icons/TimeIcon.tsx +12 -0
  85. package/src/constants/ClockType.ts +11 -0
  86. package/src/constants/dimensions.ts +5 -0
  87. package/src/constants/prop-types.ts +37 -0
  88. package/src/index.ts +48 -0
  89. package/src/typings/BasePicker.tsx +60 -0
  90. package/src/typings/date.ts +3 -0
  91. package/src/typings/extendMui.ts +10 -0
  92. package/src/typings/overrides.ts +44 -0
  93. package/src/views/Calendar/Calendar.tsx +361 -0
  94. package/src/views/Calendar/CalendarHeader.tsx +141 -0
  95. package/src/views/Calendar/Day.tsx +97 -0
  96. package/src/views/Calendar/DayWrapper.tsx +33 -0
  97. package/src/views/Calendar/SlideTransition.tsx +100 -0
  98. package/src/views/Clock/Clock.tsx +172 -0
  99. package/src/views/Clock/ClockNumber.tsx +91 -0
  100. package/src/views/Clock/ClockNumbers.tsx +76 -0
  101. package/src/views/Clock/ClockPointer.tsx +104 -0
  102. package/src/views/Clock/ClockView.tsx +105 -0
  103. package/src/views/Month/Month.tsx +76 -0
  104. package/src/views/Month/MonthView.tsx +94 -0
  105. package/src/views/Year/Year.tsx +77 -0
  106. package/src/views/Year/YearView.tsx +91 -0
  107. package/src/wrappers/InlineWrapper.tsx +80 -0
  108. package/src/wrappers/ModalWrapper.tsx +113 -0
  109. package/src/wrappers/StaticWrapper.tsx +22 -0
  110. package/src/wrappers/Wrapper.tsx +75 -0
  111. package/coverage/clover.xml +0 -601
  112. package/coverage/coverage-final.json +0 -22
  113. package/coverage/lcov-report/base.css +0 -224
  114. package/coverage/lcov-report/block-navigation.js +0 -79
  115. package/coverage/lcov-report/index.html +0 -201
  116. package/coverage/lcov-report/prettify.css +0 -1
  117. package/coverage/lcov-report/prettify.js +0 -2
  118. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  119. package/coverage/lcov-report/sorter.js +0 -170
  120. package/coverage/lcov-report/src/MuiPickersUtilsProvider.tsx.html +0 -186
  121. package/coverage/lcov-report/src/_helpers/date-utils.ts.html +0 -345
  122. package/coverage/lcov-report/src/_helpers/index.html +0 -123
  123. package/coverage/lcov-report/src/_helpers/time-utils.ts.html +0 -318
  124. package/coverage/lcov-report/src/_helpers/utils.ts.html +0 -93
  125. package/coverage/lcov-report/src/_shared/ModalDialog.tsx.html +0 -411
  126. package/coverage/lcov-report/src/_shared/WithUtils.tsx.html +0 -126
  127. package/coverage/lcov-report/src/_shared/hooks/index.html +0 -110
  128. package/coverage/lcov-report/src/_shared/hooks/useKeyDown.ts.html +0 -171
  129. package/coverage/lcov-report/src/_shared/hooks/useUtils.ts.html +0 -129
  130. package/coverage/lcov-report/src/_shared/icons/ArrowLeftIcon.tsx.html +0 -102
  131. package/coverage/lcov-report/src/_shared/icons/ArrowRightIcon.tsx.html +0 -102
  132. package/coverage/lcov-report/src/_shared/icons/index.html +0 -110
  133. package/coverage/lcov-report/src/_shared/index.html +0 -110
  134. package/coverage/lcov-report/src/constants/ClockType.ts.html +0 -102
  135. package/coverage/lcov-report/src/constants/dimensions.ts.html +0 -84
  136. package/coverage/lcov-report/src/constants/index.html +0 -110
  137. package/coverage/lcov-report/src/index.html +0 -97
  138. package/coverage/lcov-report/src/views/Calendar/Calendar.tsx.html +0 -1152
  139. package/coverage/lcov-report/src/views/Calendar/CalendarHeader.tsx.html +0 -492
  140. package/coverage/lcov-report/src/views/Calendar/Day.tsx.html +0 -360
  141. package/coverage/lcov-report/src/views/Calendar/DayWrapper.tsx.html +0 -168
  142. package/coverage/lcov-report/src/views/Calendar/SlideTransition.tsx.html +0 -369
  143. package/coverage/lcov-report/src/views/Calendar/index.html +0 -149
  144. package/coverage/lcov-report/src/views/Clock/Clock.tsx.html +0 -585
  145. package/coverage/lcov-report/src/views/Clock/ClockPointer.tsx.html +0 -381
  146. package/coverage/lcov-report/src/views/Clock/index.html +0 -110
  147. package/coverage/lcov-report/src/views/Month/Month.tsx.html +0 -297
  148. package/coverage/lcov-report/src/views/Month/MonthView.tsx.html +0 -351
  149. package/coverage/lcov-report/src/views/Month/index.html +0 -110
  150. package/coverage/lcov.info +0 -1094
@@ -0,0 +1,141 @@
1
+ import * as React from 'react';
2
+ import * as PropTypes from 'prop-types';
3
+ import Typography from '@material-ui/core/Typography';
4
+ import SlideTransition, { SlideDirection } from './SlideTransition';
5
+ import IconButton, { IconButtonProps } from '@material-ui/core/IconButton';
6
+ import { DateType } from '@date-io/type';
7
+ import { useUtils } from '../../_shared/hooks/useUtils';
8
+ import { MaterialUiPickersDate } from '../../typings/date';
9
+ import { makeStyles, useTheme } from '@material-ui/core/styles';
10
+ import { ArrowLeftIcon } from '../../_shared/icons/ArrowLeftIcon';
11
+ import { ArrowRightIcon } from '../../_shared/icons/ArrowRightIcon';
12
+
13
+ export interface CalendarHeaderProps {
14
+ currentMonth: DateType;
15
+ leftArrowIcon?: React.ReactNode;
16
+ rightArrowIcon?: React.ReactNode;
17
+ leftArrowButtonProps?: Partial<IconButtonProps>;
18
+ rightArrowButtonProps?: Partial<IconButtonProps>;
19
+ disablePrevMonth?: boolean;
20
+ disableNextMonth?: boolean;
21
+ slideDirection: SlideDirection;
22
+ onMonthChange: (date: MaterialUiPickersDate, direction: SlideDirection) => void | Promise<void>;
23
+ }
24
+
25
+ export const useStyles = makeStyles(
26
+ theme => ({
27
+ switchHeader: {
28
+ display: 'flex',
29
+ justifyContent: 'space-between',
30
+ alignItems: 'center',
31
+ marginTop: theme.spacing(0.5),
32
+ marginBottom: theme.spacing(1),
33
+ },
34
+ transitionContainer: {
35
+ width: '100%',
36
+ overflow: 'hidden',
37
+ height: 23,
38
+ },
39
+ iconButton: {
40
+ zIndex: 1,
41
+ backgroundColor: theme.palette.background.paper,
42
+ },
43
+ daysHeader: {
44
+ display: 'flex',
45
+ justifyContent: 'center',
46
+ alignItems: 'center',
47
+ maxHeight: 16,
48
+ },
49
+ dayLabel: {
50
+ width: 36,
51
+ margin: '0 2px',
52
+ textAlign: 'center',
53
+ color: theme.palette.text.hint,
54
+ },
55
+ }),
56
+ { name: 'MuiPickersCalendarHeader' }
57
+ );
58
+
59
+ export const CalendarHeader: React.SFC<CalendarHeaderProps> = ({
60
+ currentMonth,
61
+ onMonthChange,
62
+ leftArrowIcon,
63
+ rightArrowIcon,
64
+ leftArrowButtonProps,
65
+ rightArrowButtonProps,
66
+ disablePrevMonth,
67
+ disableNextMonth,
68
+ slideDirection,
69
+ }) => {
70
+ const utils = useUtils();
71
+ const classes = useStyles();
72
+ const theme = useTheme();
73
+ const rtl = theme.direction === 'rtl';
74
+
75
+ const selectNextMonth = () => onMonthChange(utils.getNextMonth(currentMonth), 'left');
76
+ const selectPreviousMonth = () => onMonthChange(utils.getPreviousMonth(currentMonth), 'right');
77
+
78
+ return (
79
+ <div>
80
+ <div className={classes.switchHeader}>
81
+ <IconButton
82
+ {...leftArrowButtonProps}
83
+ disabled={disablePrevMonth}
84
+ onClick={selectPreviousMonth}
85
+ className={classes.iconButton}
86
+ >
87
+ {rtl ? rightArrowIcon : leftArrowIcon}
88
+ </IconButton>
89
+
90
+ <SlideTransition
91
+ slideDirection={slideDirection}
92
+ transKey={currentMonth.toString()}
93
+ className={classes.transitionContainer}
94
+ >
95
+ <Typography align="center" variant="body1">
96
+ {utils.getCalendarHeaderText(currentMonth)}
97
+ </Typography>
98
+ </SlideTransition>
99
+
100
+ <IconButton
101
+ {...rightArrowButtonProps}
102
+ disabled={disableNextMonth}
103
+ onClick={selectNextMonth}
104
+ className={classes.iconButton}
105
+ >
106
+ {rtl ? leftArrowIcon : rightArrowIcon}
107
+ </IconButton>
108
+ </div>
109
+
110
+ <div className={classes.daysHeader}>
111
+ {utils.getWeekdays().map((day, index) => (
112
+ <Typography
113
+ key={index} // eslint-disable-line react/no-array-index-key
114
+ variant="caption"
115
+ className={classes.dayLabel}
116
+ >
117
+ {day}
118
+ </Typography>
119
+ ))}
120
+ </div>
121
+ </div>
122
+ );
123
+ };
124
+
125
+ CalendarHeader.displayName = 'CalendarHeader';
126
+
127
+ CalendarHeader.propTypes = {
128
+ leftArrowIcon: PropTypes.node,
129
+ rightArrowIcon: PropTypes.node,
130
+ disablePrevMonth: PropTypes.bool,
131
+ disableNextMonth: PropTypes.bool,
132
+ };
133
+
134
+ CalendarHeader.defaultProps = {
135
+ leftArrowIcon: <ArrowLeftIcon />,
136
+ rightArrowIcon: <ArrowRightIcon />,
137
+ disablePrevMonth: false,
138
+ disableNextMonth: false,
139
+ };
140
+
141
+ export default CalendarHeader;
@@ -0,0 +1,97 @@
1
+ import * as React from 'react';
2
+ import * as PropTypes from 'prop-types';
3
+ import clsx from 'clsx';
4
+ import IconButton from '@material-ui/core/IconButton';
5
+ import Typography from '@material-ui/core/Typography';
6
+ import { makeStyles } from '@material-ui/core/styles';
7
+
8
+ export const useStyles = makeStyles(
9
+ theme => ({
10
+ day: {
11
+ width: 36,
12
+ height: 36,
13
+ fontSize: theme.typography.caption.fontSize,
14
+ margin: '0 2px',
15
+ color: theme.palette.text.primary,
16
+ fontWeight: theme.typography.fontWeightMedium,
17
+ padding: 0,
18
+ },
19
+ hidden: {
20
+ opacity: 0,
21
+ pointerEvents: 'none',
22
+ },
23
+ current: {
24
+ color: theme.palette.primary.main,
25
+ fontWeight: 600,
26
+ },
27
+ daySelected: {
28
+ color: theme.palette.primary.contrastText,
29
+ backgroundColor: theme.palette.primary.main,
30
+ fontWeight: theme.typography.fontWeightMedium,
31
+ '&:hover': {
32
+ backgroundColor: theme.palette.primary.main,
33
+ },
34
+ },
35
+ dayDisabled: {
36
+ pointerEvents: 'none',
37
+ color: theme.palette.text.hint,
38
+ },
39
+ }),
40
+ { name: 'MuiPickersDay' }
41
+ );
42
+
43
+ export interface DayProps {
44
+ /** Day text */
45
+ children: React.ReactNode;
46
+ /** Is today */
47
+ current?: boolean;
48
+ /** Disabled? */
49
+ disabled?: boolean;
50
+ /** Hidden? */
51
+ hidden?: boolean;
52
+ /** Selected? */
53
+ selected?: boolean;
54
+ }
55
+
56
+ export const Day: React.FC<DayProps> = ({
57
+ children,
58
+ disabled,
59
+ hidden,
60
+ current,
61
+ selected,
62
+ ...other
63
+ }) => {
64
+ const classes = useStyles();
65
+ const className = clsx(classes.day, {
66
+ [classes.hidden]: hidden,
67
+ [classes.current]: current,
68
+ [classes.daySelected]: selected,
69
+ [classes.dayDisabled]: disabled,
70
+ });
71
+
72
+ return (
73
+ <IconButton className={className} tabIndex={hidden || disabled ? -1 : 0} {...other}>
74
+ <Typography variant="body2" color="inherit">
75
+ {children}
76
+ </Typography>
77
+ </IconButton>
78
+ );
79
+ };
80
+
81
+ Day.displayName = 'Day';
82
+
83
+ Day.propTypes = {
84
+ current: PropTypes.bool,
85
+ disabled: PropTypes.bool,
86
+ hidden: PropTypes.bool,
87
+ selected: PropTypes.bool,
88
+ };
89
+
90
+ Day.defaultProps = {
91
+ disabled: false,
92
+ hidden: false,
93
+ current: false,
94
+ selected: false,
95
+ };
96
+
97
+ export default Day;
@@ -0,0 +1,33 @@
1
+ import * as React from 'react';
2
+
3
+ export interface DayWrapperProps {
4
+ value: any;
5
+ children: React.ReactNode;
6
+ dayInCurrentMonth?: boolean;
7
+ disabled?: boolean;
8
+ onSelect: (value: any) => void;
9
+ }
10
+
11
+ const DayWrapper: React.FC<DayWrapperProps> = ({
12
+ children,
13
+ value,
14
+ disabled,
15
+ onSelect,
16
+ dayInCurrentMonth,
17
+ ...other
18
+ }) => {
19
+ const handleClick = React.useCallback(() => onSelect(value), [onSelect, value]);
20
+
21
+ return (
22
+ <div
23
+ role="presentation"
24
+ onClick={dayInCurrentMonth && !disabled ? handleClick : undefined}
25
+ onKeyPress={dayInCurrentMonth && !disabled ? handleClick : undefined}
26
+ {...other}
27
+ >
28
+ {children}
29
+ </div>
30
+ );
31
+ };
32
+
33
+ export default DayWrapper;
@@ -0,0 +1,100 @@
1
+ import * as React from 'react';
2
+ import clsx from 'clsx';
3
+ import { makeStyles } from '@material-ui/core/styles';
4
+ import { CSSTransition, TransitionGroup } from 'react-transition-group';
5
+
6
+ export type SlideDirection = 'right' | 'left';
7
+ interface SlideTransitionProps {
8
+ transKey: React.Key;
9
+ className?: string;
10
+ slideDirection: SlideDirection;
11
+ children: React.ReactChild;
12
+ }
13
+
14
+ const animationDuration = 350;
15
+ export const useStyles = makeStyles(
16
+ theme => {
17
+ const slideTransition = theme.transitions.create('transform', {
18
+ duration: animationDuration,
19
+ easing: 'cubic-bezier(0.35, 0.8, 0.4, 1)',
20
+ });
21
+
22
+ return {
23
+ transitionContainer: {
24
+ display: 'block',
25
+ position: 'relative',
26
+ '& > *': {
27
+ position: 'absolute',
28
+ top: 0,
29
+ right: 0,
30
+ left: 0,
31
+ },
32
+ },
33
+ 'slideEnter-left': {
34
+ willChange: 'transform',
35
+ transform: 'translate(100%)',
36
+ },
37
+ 'slideEnter-right': {
38
+ willChange: 'transform',
39
+ transform: 'translate(-100%)',
40
+ },
41
+ slideEnterActive: {
42
+ transform: 'translate(0%)',
43
+ transition: slideTransition,
44
+ },
45
+ slideExit: {
46
+ transform: 'translate(0%)',
47
+ },
48
+ 'slideExitActiveLeft-left': {
49
+ willChange: 'transform',
50
+ transform: 'translate(-200%)',
51
+ transition: slideTransition,
52
+ },
53
+ 'slideExitActiveLeft-right': {
54
+ willChange: 'transform',
55
+ transform: 'translate(200%)',
56
+ transition: slideTransition,
57
+ },
58
+ };
59
+ },
60
+ { name: 'MuiPickersSlideTransition' }
61
+ );
62
+
63
+ const SlideTransition: React.SFC<SlideTransitionProps> = ({
64
+ children,
65
+ transKey,
66
+ slideDirection,
67
+ className = null,
68
+ }) => {
69
+ const classes = useStyles();
70
+ const transitionClasses = {
71
+ exit: classes.slideExit,
72
+ enterActive: classes.slideEnterActive,
73
+ // @ts-ignore
74
+ enter: classes['slideEnter-' + slideDirection],
75
+ // @ts-ignore
76
+ exitActive: classes['slideExitActiveLeft-' + slideDirection],
77
+ };
78
+
79
+ return (
80
+ <TransitionGroup
81
+ className={clsx(classes.transitionContainer, className)}
82
+ childFactory={element =>
83
+ React.cloneElement(element, {
84
+ classNames: transitionClasses,
85
+ })
86
+ }
87
+ >
88
+ <CSSTransition
89
+ mountOnEnter
90
+ unmountOnExit
91
+ key={transKey + slideDirection}
92
+ timeout={animationDuration}
93
+ classNames={transitionClasses}
94
+ children={children}
95
+ />
96
+ </TransitionGroup>
97
+ );
98
+ };
99
+
100
+ export default SlideTransition;
@@ -0,0 +1,172 @@
1
+ import * as React from 'react';
2
+ import * as PropTypes from 'prop-types';
3
+ import ClockPointer from './ClockPointer';
4
+ import ClockType, { ClockViewType } from '../../constants/ClockType';
5
+ import { getHours, getMinutes } from '../../_helpers/time-utils';
6
+ import { withStyles, createStyles, WithStyles, Theme } from '@material-ui/core/styles';
7
+
8
+ export interface ClockProps extends WithStyles<typeof styles> {
9
+ type: ClockViewType;
10
+ value: number;
11
+ onChange: (value: number, isFinish?: boolean) => void;
12
+ ampm?: boolean;
13
+ minutesStep?: number;
14
+ children: React.ReactElement<any>[];
15
+ }
16
+
17
+ export class Clock extends React.Component<ClockProps> {
18
+ public static propTypes: any = {
19
+ type: PropTypes.oneOf(Object.keys(ClockType).map(key => ClockType[key as any])).isRequired,
20
+ value: PropTypes.number.isRequired,
21
+ onChange: PropTypes.func.isRequired,
22
+ children: PropTypes.arrayOf(PropTypes.node).isRequired,
23
+ ampm: PropTypes.bool,
24
+ minutesStep: PropTypes.number,
25
+ innerRef: PropTypes.any,
26
+ };
27
+
28
+ public static defaultProps = {
29
+ ampm: false,
30
+ minutesStep: 1,
31
+ };
32
+
33
+ public isMoving = false;
34
+
35
+ public setTime(e: any, isFinish = false) {
36
+ let { offsetX, offsetY } = e;
37
+
38
+ if (typeof offsetX === 'undefined') {
39
+ const rect = e.target.getBoundingClientRect();
40
+
41
+ offsetX = e.changedTouches[0].clientX - rect.left;
42
+ offsetY = e.changedTouches[0].clientY - rect.top;
43
+ }
44
+
45
+ const value =
46
+ this.props.type === ClockType.SECONDS || this.props.type === ClockType.MINUTES
47
+ ? getMinutes(offsetX, offsetY, this.props.minutesStep)
48
+ : getHours(offsetX, offsetY, Boolean(this.props.ampm));
49
+
50
+ this.props.onChange(value, isFinish);
51
+ }
52
+
53
+ public handleTouchMove = (e: React.TouchEvent) => {
54
+ this.isMoving = true;
55
+ this.setTime(e);
56
+ };
57
+
58
+ public handleTouchEnd = (e: React.TouchEvent) => {
59
+ if (this.isMoving) {
60
+ this.setTime(e, true);
61
+ this.isMoving = false;
62
+ }
63
+ };
64
+
65
+ public handleMove = (e: React.MouseEvent<HTMLDivElement>) => {
66
+ e.preventDefault();
67
+ e.stopPropagation();
68
+ // MouseEvent.which is deprecated, but MouseEvent.buttons is not supported in Safari
69
+ const isButtonPressed =
70
+ typeof e.buttons === 'undefined' ? e.nativeEvent.which === 1 : e.buttons === 1;
71
+
72
+ if (isButtonPressed) {
73
+ this.setTime(e.nativeEvent, false);
74
+ }
75
+ };
76
+
77
+ public handleMouseUp = (e: React.MouseEvent) => {
78
+ if (this.isMoving) {
79
+ this.isMoving = false;
80
+ }
81
+
82
+ this.setTime(e.nativeEvent, true);
83
+ };
84
+
85
+ public hasSelected = () => {
86
+ const { type, value } = this.props;
87
+
88
+ if (type === ClockType.HOURS) {
89
+ return true;
90
+ }
91
+
92
+ return value % 5 === 0;
93
+ };
94
+
95
+ public render() {
96
+ const { classes, value, children, type, ampm } = this.props;
97
+
98
+ const isPointerInner = !ampm && type === ClockType.HOURS && (value < 1 || value > 12);
99
+
100
+ return (
101
+ <div className={classes.container}>
102
+ <div className={classes.clock}>
103
+ <div
104
+ role="menu"
105
+ tabIndex={-1}
106
+ className={classes.squareMask}
107
+ onTouchMove={this.handleTouchMove}
108
+ onTouchEnd={this.handleTouchEnd}
109
+ onMouseUp={this.handleMouseUp}
110
+ onMouseMove={this.handleMove}
111
+ />
112
+
113
+ <div className={classes.pin} />
114
+
115
+ <ClockPointer
116
+ type={type}
117
+ value={value}
118
+ isInner={isPointerInner}
119
+ hasSelected={this.hasSelected()}
120
+ />
121
+
122
+ {children}
123
+ </div>
124
+ </div>
125
+ );
126
+ }
127
+ }
128
+
129
+ export const styles = (theme: Theme) =>
130
+ createStyles({
131
+ container: {
132
+ display: 'flex',
133
+ justifyContent: 'center',
134
+ alignItems: 'flex-end',
135
+ margin: `${theme.spacing(2)}px 0 ${theme.spacing(1)}px`,
136
+ },
137
+ clock: {
138
+ backgroundColor: 'rgba(0,0,0,.07)',
139
+ borderRadius: '50%',
140
+ height: 260,
141
+ width: 260,
142
+ position: 'relative',
143
+ pointerEvents: 'none',
144
+ zIndex: 1,
145
+ },
146
+ squareMask: {
147
+ width: '100%',
148
+ height: '100%',
149
+ position: 'absolute',
150
+ pointerEvents: 'auto',
151
+ outline: 'none',
152
+ touchActions: 'none',
153
+ userSelect: 'none',
154
+ '&:active': {
155
+ cursor: 'move',
156
+ },
157
+ },
158
+ pin: {
159
+ width: 6,
160
+ height: 6,
161
+ borderRadius: '50%',
162
+ backgroundColor: theme.palette.primary.main,
163
+ position: 'absolute',
164
+ top: '50%',
165
+ left: '50%',
166
+ transform: 'translate(-50%, -50%)',
167
+ },
168
+ });
169
+
170
+ export default withStyles(styles, {
171
+ name: 'MuiPickersClock',
172
+ })(Clock as React.ComponentType<ClockProps>);
@@ -0,0 +1,91 @@
1
+ import * as React from 'react';
2
+ import clsx from 'clsx';
3
+ import Typography from '@material-ui/core/Typography';
4
+ import { makeStyles } from '@material-ui/core/styles';
5
+
6
+ const positions: Record<number, [number, number]> = {
7
+ 0: [0, 40],
8
+ 1: [55, 19.6],
9
+ 2: [94.4, 59.5],
10
+ 3: [109, 114],
11
+ 4: [94.4, 168.5],
12
+ 5: [54.5, 208.4],
13
+ 6: [0, 223],
14
+ 7: [-54.5, 208.4],
15
+ 8: [-94.4, 168.5],
16
+ 9: [-109, 114],
17
+ 10: [-94.4, 59.5],
18
+ 11: [-54.5, 19.6],
19
+ 12: [0, 5],
20
+ 13: [36.9, 49.9],
21
+ 14: [64, 77],
22
+ 15: [74, 114],
23
+ 16: [64, 151],
24
+ 17: [37, 178],
25
+ 18: [0, 188],
26
+ 19: [-37, 178],
27
+ 20: [-64, 151],
28
+ 21: [-74, 114],
29
+ 22: [-64, 77],
30
+ 23: [-37, 50],
31
+ };
32
+
33
+ export interface ClockNumberProps {
34
+ index: number;
35
+ label: string;
36
+ selected: boolean;
37
+ isInner?: boolean;
38
+ }
39
+
40
+ export const useStyles = makeStyles(
41
+ theme => {
42
+ const size = theme.spacing(4);
43
+
44
+ return {
45
+ clockNumber: {
46
+ width: size,
47
+ height: 32,
48
+ userSelect: 'none',
49
+ position: 'absolute',
50
+ left: `calc(50% - ${size / 2}px)`,
51
+ display: 'inline-flex',
52
+ justifyContent: 'center',
53
+ alignItems: 'center',
54
+ borderRadius: '50%',
55
+ color:
56
+ theme.palette.type === 'light' ? theme.palette.text.primary : theme.palette.text.hint,
57
+ },
58
+ clockNumberSelected: {
59
+ color: theme.palette.primary.contrastText,
60
+ },
61
+ };
62
+ },
63
+ { name: 'MuiPickersClockNumber' }
64
+ );
65
+
66
+ export const ClockNumber: React.FC<ClockNumberProps> = ({ selected, label, index, isInner }) => {
67
+ const classes = useStyles();
68
+ const className = clsx(classes.clockNumber, {
69
+ [classes.clockNumberSelected]: selected,
70
+ });
71
+
72
+ const transformStyle = React.useMemo(() => {
73
+ const position = positions[index];
74
+
75
+ return {
76
+ transform: `translate(${position[0]}px, ${position[1]}px`,
77
+ };
78
+ }, [index]);
79
+
80
+ return (
81
+ <Typography
82
+ component="span"
83
+ className={className}
84
+ variant={isInner ? 'body2' : 'body1'}
85
+ style={transformStyle}
86
+ children={label}
87
+ />
88
+ );
89
+ };
90
+
91
+ export default ClockNumber;
@@ -0,0 +1,76 @@
1
+ import * as React from 'react';
2
+ import ClockNumber from './ClockNumber';
3
+ import { IUtils } from '@date-io/core/IUtils';
4
+ import { MaterialUiPickersDate } from '../../typings/date';
5
+
6
+ export const getHourNumbers = ({
7
+ ampm,
8
+ utils,
9
+ date,
10
+ }: {
11
+ ampm: boolean;
12
+ utils: IUtils<MaterialUiPickersDate>;
13
+ date: MaterialUiPickersDate;
14
+ }) => {
15
+ const currentHours = utils.getHours(date);
16
+
17
+ const hourNumbers: JSX.Element[] = [];
18
+ const startHour = ampm ? 1 : 0;
19
+ const endHour = ampm ? 12 : 23;
20
+
21
+ const isSelected = (hour: number) => {
22
+ if (ampm) {
23
+ if (hour === 12) {
24
+ return currentHours === 12 || currentHours === 0;
25
+ }
26
+
27
+ return currentHours === hour || currentHours - 12 === hour;
28
+ }
29
+
30
+ return currentHours === hour;
31
+ };
32
+
33
+ for (let hour = startHour; hour <= endHour; hour += 1) {
34
+ let label = hour.toString();
35
+
36
+ if (hour === 0) {
37
+ label = '00';
38
+ }
39
+
40
+ const props = {
41
+ index: hour,
42
+ label: utils.formatNumber(label),
43
+ selected: isSelected(hour),
44
+ isInner: !ampm && (hour === 0 || hour > 12),
45
+ };
46
+
47
+ hourNumbers.push(<ClockNumber key={hour} {...props} />);
48
+ }
49
+
50
+ return hourNumbers;
51
+ };
52
+
53
+ export const getMinutesNumbers = ({
54
+ value,
55
+ utils,
56
+ }: {
57
+ value: number;
58
+ utils: IUtils<MaterialUiPickersDate>;
59
+ }) => {
60
+ const f = utils.formatNumber;
61
+
62
+ return [
63
+ <ClockNumber label={f('00')} selected={value === 0} index={12} key={12} />,
64
+ <ClockNumber label={f('05')} selected={value === 5} index={1} key={1} />,
65
+ <ClockNumber label={f('10')} selected={value === 10} index={2} key={2} />,
66
+ <ClockNumber label={f('15')} selected={value === 15} index={3} key={3} />,
67
+ <ClockNumber label={f('20')} selected={value === 20} index={4} key={4} />,
68
+ <ClockNumber label={f('25')} selected={value === 25} index={5} key={5} />,
69
+ <ClockNumber label={f('30')} selected={value === 30} index={6} key={6} />,
70
+ <ClockNumber label={f('35')} selected={value === 35} index={7} key={7} />,
71
+ <ClockNumber label={f('40')} selected={value === 40} index={8} key={8} />,
72
+ <ClockNumber label={f('45')} selected={value === 45} index={9} key={9} />,
73
+ <ClockNumber label={f('50')} selected={value === 50} index={10} key={10} />,
74
+ <ClockNumber label={f('55')} selected={value === 55} index={11} key={11} />,
75
+ ];
76
+ };