Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New props, functionalities and behaviour #18

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
15 changes: 12 additions & 3 deletions src/Clock.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ const styles = (theme) => ({
userSelect: 'none',
'&.selected': {
color: getContrastRatio(theme.palette.primary.main, theme.palette.common.black) < 7 ? theme.palette.common.white : theme.palette.common.black
}
},
'&.disabled': { opacity: '0.3' }
},
smallNumber: {
fontSize: '12px',
Expand Down Expand Up @@ -134,7 +135,7 @@ class Clock extends React.PureComponent {
}

render () {
const { classes, mode, value, ...other } = this.props
const { classes, mode, value, minutesStep, ...other } = this.props
const { touching } = this.state

return (
Expand Down Expand Up @@ -191,7 +192,9 @@ class Clock extends React.PureComponent {
{mode === 'minutes' && getNumbers(12, { size, start: 5, step: 5 }).map((digit, i) => (
<span
key={digit.display}
className={classNames(classes.number, { selected: value === digit.display || (digit.display === 60 && value === 0) })}
className={classNames(
classes.number,
{ selected: value === digit.display || (digit.display === 60 && value === 0), disabled: digit.display % (this.props.minutesStep) })}
style={{
transform: `translate(${digit.translateX}px, ${digit.translateY}px)`
}}
Expand All @@ -206,6 +209,8 @@ class Clock extends React.PureComponent {
}

Clock.propTypes = {
/** Steps between minutes. */
minutesStep: PropTypes.number,
/** Sets the mode of this clock. It can either select hours (supports 12- and 24-hour-clock) or minutes. */
mode: PropTypes.oneOf(['12h', '24h', 'minutes']).isRequired,
/** Callback that is called with the new hours/minutes (as a number) when the value is changed. */
Expand All @@ -214,6 +219,10 @@ Clock.propTypes = {
value: PropTypes.number.isRequired
}

Clock.defaultProps = {
minutesStep: 1
}

export default withStyles(styles)(Clock)

function getNumbers (count, { size, start = 1, step = 1 }) {
Expand Down
56 changes: 40 additions & 16 deletions src/TimeInput.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,38 @@ class TimeInput extends React.Component {
const defaultValue = new Date()
defaultValue.setSeconds(0)
defaultValue.setMilliseconds(0)
this.state = { open: false, value: props.value || props.defaultValue || defaultValue }
const initValue = props.value || props.defaultValue || defaultValue
this.state = { open: false, initValue, value: initValue }
}

componentWillReceiveProps (nextProps) {
if (nextProps.value !== this.props.value) {
this.setState({ value: nextProps.value })
this.setState({ initValue: nextProps.value, value: nextProps.value })
}
}

showDialog = () => this.setState({ open: true, newValue: this.state.value })
showDialog = () => this.setState({ open: true })

handleChange = (newValue) => {
this.setState({ newValue })
handleChange = (value) => {
if (this.props.updateImmediately && this.props.onChange != null) {
this.props.onChange(value)
}
this.setState({ value })
}

handleOk = () => {
if (this.props.onChange != null) {
this.props.onChange(this.state.newValue)
if (!this.props.updateImmediately && this.props.onChange != null) {
this.props.onChange(this.state.value)
}
this.setState({ open: false, value: this.state.newValue, newValue: null })
this.setState({ open: false, initValue: this.state.value })
}

handleCancel = () => this.setState({ open: false, newValue: null })
handleCancel = () => {
if (this.props.updateImmediately && this.props.onChange != null) {
this.props.onChange(this.state.initValue)
}
this.setState({ open: false, value: this.state.initValue })
}

render () {
const {
Expand All @@ -59,15 +68,19 @@ class TimeInput extends React.Component {
okLabel,
onChange, // eslint-disable-line
value: valueProp, // eslint-disable-line
minutesStep,
selectOnClose,
updateImmediately,
...other
} = this.props

const { value, newValue } = this.state
const { initValue, value } = this.state
const inputValue = updateImmediately ? value : initValue

const { hours, isPm } = formatHours(value.getHours(), mode)
const { hours, isPm } = formatHours(inputValue.getHours(), mode)
const formattedValue = mode === '12h'
? `${hours}:${twoDigits(value.getMinutes())} ${isPm ? 'pm' : 'am'}`
: `${twoDigits(value.getHours())}:${twoDigits(value.getMinutes())}`
? `${hours}:${twoDigits(inputValue.getMinutes())} ${isPm ? 'pm' : 'am'}`
: `${twoDigits(inputValue.getHours())}:${twoDigits(inputValue.getMinutes())}`

const { muiFormControl } = this.context
const disabled = disabledProp || (muiFormControl != null && muiFormControl.disabled)
Expand All @@ -80,16 +93,18 @@ class TimeInput extends React.Component {
value={formattedValue}
readOnly
key='TimeInput-input'
classes={{ input: classes.input }}
/>,
<Dialog
maxWidth='xs'
open={this.state.open}
key='TimeInput-dialog'
onClose={this.handleCancel}
onClose={selectOnClose ? this.handleOk : this.handleCancel}
>
<TimePicker
mode={mode}
value={newValue}
minutesStep={minutesStep}
value={value}
onChange={this.handleChange}
onMinutesSelected={autoOk ? this.handleOk : null}
classes={{ header: classes.header, body: classes.body }}
Expand All @@ -110,21 +125,30 @@ TimeInput.propTypes = {
cancelLabel: PropTypes.string,
/** The initial value of the time picker. */
defaultValue: PropTypes.instanceOf(Date),
/** Steps between minutes. */
minutesStep: PropTypes.number,
/** Sets the clock mode, 12-hour or 24-hour clocks are supported. */
mode: PropTypes.oneOf(['12h', '24h']),
/** Override the label of the ok button. */
okLabel: PropTypes.string,
/** Callback that is called with the new date (as Date instance) when the value is changed. */
onChange: PropTypes.func,
/** Sets the date when dialog is closed (clicking background). */
selectOnClose: PropTypes.bool,
/** Updates the input field when clock hands are moved */
updateImmediately: PropTypes.bool,
/** The value of the time picker, for use in controlled mode. */
value: PropTypes.instanceOf(Date)
}

TimeInput.defaultProps = {
autoOk: false,
cancelLabel: 'Cancel',
minutesStep: 1,
mode: '12h',
okLabel: 'Ok'
okLabel: 'Ok',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…these, too

selectOnClose: false,
updateImmediately: false
}

TimeInput.contextTypes = {
Expand Down
1 change: 0 additions & 1 deletion src/TimeInput.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ describe('<TimeInput />', () => {
tree.find(Button).at(0).simulate('click')

expect(getValue(tree)).toBe('13:37') // unchanged
expect(changeHandler).not.toHaveBeenCalled()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now is called in every date change and restored when canceled

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? There is no reason to call the change handler when the date isn't changed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did that change because I needed the time text field (and some other components) to be updated when the user changes the hour in real time, so every time the user moves the clock hands, changeHandler is called.

Copy link
Member

@leMaik leMaik Sep 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, that's a good point. 🤔 We should make that optional and turn it off by default. Maybe call that prop updateImmediately?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, I think that's the best option, thus maintaining the same behavior (avoiding some developers from going crazy when updating 🙃) and providing that functionality, which in my case is very useful

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my intention. 👍 Adding your use case while keeping this a minor update (i.e. no breaking changes).

})
})
})
Expand Down
12 changes: 7 additions & 5 deletions src/TimePicker.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,8 @@ class TimePicker extends React.Component {
} else {
this.setState({ hours: value }, this.propagateChange)
}
} else {
this.setState({ minutes: value }, () => {
this.propagateChange()
})
} else if (value % (this.props.minutesStep) === 0) {
this.setState({ minutes: value }, this.propagateChange)
}
}

Expand Down Expand Up @@ -186,6 +184,7 @@ class TimePicker extends React.Component {
value={clockMode === 'minutes' ? minutes : hours}
onMouseUp={this.handleClockChangeDone}
onTouchEnd={this.handleClockChangeDone}
minutesStep={this.props.minutesStep}
/>
</div>
</div>
Expand All @@ -196,6 +195,8 @@ class TimePicker extends React.Component {
TimePicker.propTypes = {
/** The initial value of the time picker. */
defaultValue: PropTypes.instanceOf(Date),
/** Steps between minutes. */
minutesStep: PropTypes.number,
/** Sets the clock mode, 12-hour or 24-hour clocks are supported. */
mode: PropTypes.oneOf(['12h', '24h']),
/** Callback that is called with the new date (as Date instance) when the value is changed. */
Expand All @@ -207,7 +208,8 @@ TimePicker.propTypes = {
}

TimePicker.defaultProps = {
mode: '12h'
mode: '12h',
minutesStep: 1
}

export default withStyles(styles)(TimePicker)
3 changes: 3 additions & 0 deletions src/__snapshots__/Clock.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ exports[`<Clock /> 12h matches the snapshot 1`] = `
"smallPointer": "Clock-smallPointer-7",
}
}
minutesStep={1}
mode="12h"
value={7}
>
Expand Down Expand Up @@ -209,6 +210,7 @@ exports[`<Clock /> 24h matches the snapshot 1`] = `
"smallPointer": "Clock-smallPointer-7",
}
}
minutesStep={1}
mode="24h"
value={7}
>
Expand Down Expand Up @@ -530,6 +532,7 @@ exports[`<Clock /> minutes matches the snapshot 1`] = `
"smallPointer": "Clock-smallPointer-7",
}
}
minutesStep={1}
mode="minutes"
value={42}
>
Expand Down
16 changes: 16 additions & 0 deletions src/__snapshots__/TimeInput.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,18 @@ exports[`<TimeInput /> 12h matches the snapshot 1`] = `
}
}
defaultValue={2017-10-15T13:37:00.000Z}
minutesStep={1}
mode="12h"
okLabel="Ok"
selectOnClose={false}
updateImmediately={false}
>
<WithStyles(Input)
classes={
Object {
"input": undefined,
}
}
disabled={false}
key="TimeInput-input"
onClick={[Function]}
Expand Down Expand Up @@ -177,10 +185,18 @@ exports[`<TimeInput /> 24h matches the snapshot 1`] = `
}
}
defaultValue={2017-10-15T13:37:00.000Z}
minutesStep={1}
mode="24h"
okLabel="Ok"
selectOnClose={false}
updateImmediately={false}
>
<WithStyles(Input)
classes={
Object {
"input": undefined,
}
}
disabled={false}
key="TimeInput-input"
onClick={[Function]}
Expand Down
6 changes: 6 additions & 0 deletions src/__snapshots__/TimePicker.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ exports[`<TimePicker /> 12h matches the snapshot 1`] = `
"time": "TimePicker-time-3",
}
}
minutesStep={1}
mode="12h"
value={2017-10-15T13:37:00.000Z}
>
Expand Down Expand Up @@ -65,6 +66,7 @@ exports[`<TimePicker /> 12h matches the snapshot 1`] = `
className="TimePicker-body-7"
>
<WithStyles(Clock)
minutesStep={1}
mode="12h"
onChange={[Function]}
onMouseUp={[Function]}
Expand All @@ -86,6 +88,7 @@ exports[`<TimePicker /> 12h matches the snapshot 1`] = `
"smallPointer": "Clock-smallPointer-14",
}
}
minutesStep={1}
mode="12h"
onChange={[Function]}
onMouseUp={[Function]}
Expand Down Expand Up @@ -282,6 +285,7 @@ exports[`<TimePicker /> 24h matches the snapshot 1`] = `
"time": "TimePicker-time-3",
}
}
minutesStep={1}
mode="24h"
value={2017-10-15T13:37:00.000Z}
>
Expand Down Expand Up @@ -317,6 +321,7 @@ exports[`<TimePicker /> 24h matches the snapshot 1`] = `
className="TimePicker-body-7"
>
<WithStyles(Clock)
minutesStep={1}
mode="24h"
onChange={[Function]}
onMouseUp={[Function]}
Expand All @@ -338,6 +343,7 @@ exports[`<TimePicker /> 24h matches the snapshot 1`] = `
"smallPointer": "Clock-smallPointer-14",
}
}
minutesStep={1}
mode="24h"
onChange={[Function]}
onMouseUp={[Function]}
Expand Down