Skip to content

MinutePicker: Add minutesStep and minutesPerRow parameters to TimeInput #214

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ You can also set locale for *Input component locally using ``localization`` prop
| ``icon`` | {string\|false} icon to display inside Input. |
| ``iconPosition`` | {'left'\|'right'} icon position inside Input. Default: 'right'. |
| ``hideMobileKeyboard`` | {bool} Try to prevent mobile keyboard appearing. |
| ``minutesStep`` | {number} Step between minutes in the minutes picker. |
| ``minutesPerRow`` | {number} Number of cells per row in the minutes picker. |

### DateTimeInput

Expand Down
2 changes: 2 additions & 0 deletions example/calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ class DateTimeForm extends React.Component<any, any> {
value={this.state.time}
iconPosition='left'
onChange={this.handleChange}
minutesStep={5}
minutesPerRow={3}
/>
<br />
<DateTimeInput
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"keyboard-key": "^1.0.2",
"lodash": "^4.17.15",
"moment": "^2.22.2",
"prop-types": "^15.6.2"
"prop-types": "^15.6.2",
"yarn": "^1.22.10"
}
}
4 changes: 4 additions & 0 deletions src/inputs/TimeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ class TimeInput extends BaseInput<TimeInputProps, TimeInputState> {
tabIndex,
pickerStyle,
pickerWidth,
minutesStep,
minutesPerRow,
} = this.props;
const currentValue = parseValue(value, TIME_FORMAT[timeFormat], localization);
const pickerProps = {
Expand All @@ -167,6 +169,8 @@ class TimeInput extends BaseInput<TimeInputProps, TimeInputState> {
timeFormat,
tabIndex,
localization,
minutesStep,
minutesPerRow,
};
if (this.state.mode === 'hour') {
return <HourPicker {...pickerProps} />;
Expand Down
41 changes: 26 additions & 15 deletions src/pickers/timePicker/MinutePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ import {
isNextPageAvailable,
isPrevPageAvailable,
} from './sharedFunctions';
import { BodyWidth } from 'src/views/CalendarBody/Body';

const MINUTES_STEP = 5;
const MINUTES_ON_PAGE = 12;
const DEFAULT_MINUTES_STEP = 5;
const DEFAULT_MINUTES_PER_ROW = 3;
const PAGE_WIDTH = 3;

type MinutePickerProps = BasePickerProps
Expand All @@ -48,13 +49,22 @@ export interface MinutePickerOnChangeData extends BasePickerOnChangeData {
class MinutePicker
extends SingleSelectionPicker<MinutePickerProps>
implements ProvideHeadingValue {

public static readonly defaultProps: { timeFormat: TimeFormat } = {
timeFormat: '24',
};

protected minutesStep: number;
protected minutesOnPage: number;
protected minutesPerRow: BodyWidth;

constructor(props) {
super(props);
const {minutesStep: minutesStepProp, minutesPerRow: minutesPerRowProp} = props;
this.PAGE_WIDTH = PAGE_WIDTH;
this.minutesStep = minutesStepProp ? minutesStepProp : DEFAULT_MINUTES_STEP;
this.minutesOnPage = Math.floor(60 / this.minutesStep);
this.minutesPerRow = minutesPerRowProp ? minutesPerRowProp : DEFAULT_MINUTES_PER_ROW;
}

public render() {
Expand Down Expand Up @@ -92,7 +102,8 @@ class MinutePicker
disabledItemIndexes={this.getDisabledPositions()}
currentHeadingValue={this.getCurrentDate()}
activeItemIndex={this.getActiveCellPosition()}
localization={localization}/>
localization={localization}
rowWidth={this.minutesPerRow}/>
);
}

Expand All @@ -110,14 +121,14 @@ class MinutePicker
? '0' + this.state.date.hour().toString()
: this.state.date.hour().toString();

return range(0, 60, MINUTES_STEP)
return range(0, 60, this.minutesStep)
.map((minute) => `${minute < 10 ? '0' : ''}${minute}`)
.map((minute) => buildTimeStringWithSuffix(hour, minute, this.props.timeFormat));
}

protected getSelectableCellPositions(): number[] {
const disabled = this.getDisabledPositions();
const all = range(0, MINUTES_ON_PAGE);
const all = range(0, this.minutesOnPage);
if (disabled) {
return all.filter((pos) => {
return disabled.indexOf(pos) < 0;
Expand All @@ -129,11 +140,11 @@ class MinutePicker

protected getInitialDatePosition(): number {
const selectable = this.getSelectableCellPositions();
if (selectable.indexOf(getMinuteCellPosition(this.state.date.minute())) < 0) {
if (selectable.indexOf(this.getMinuteCellPosition(this.state.date.minute())) < 0) {
return selectable[0];
}

return getMinuteCellPosition(this.state.date.minute());
return this.getMinuteCellPosition(this.state.date.minute());
}

protected getDisabledPositions(): number[] {
Expand All @@ -150,20 +161,20 @@ class MinutePicker
disabledByDisable = concat(
disabledByDisable,
disable.filter((date) => date.isSame(this.state.date, 'day'))
.map((date) => getMinuteCellPosition(date.minute())));
.map((date) => this.getMinuteCellPosition(date.minute())));
}
if (minDate) {
if (minDate.isSame(this.state.date, 'hour')) {
disabledByMinDate = concat(
disabledByMinDate,
range(0 , minDate.minute()).map((m) => getMinuteCellPosition(m)));
range(0 , minDate.minute()).map((m) => this.getMinuteCellPosition(m)));
}
}
if (maxDate) {
if (maxDate.isSame(this.state.date, 'hour')) {
disabledByMaxDate = concat(
disabledByMaxDate,
range(maxDate.minute() + MINUTES_STEP, 60).map((m) => getMinuteCellPosition(m)));
range(maxDate.minute() + this.minutesStep, 60).map((m) => this.getMinuteCellPosition(m)));
}
}
const result = sortBy(
Expand All @@ -181,7 +192,7 @@ class MinutePicker
*/
const { value } = this.props;
if (value && value.isSame(this.state.date, 'date')) {
return Math.floor(this.props.value.minutes() / MINUTES_STEP);
return Math.floor(this.props.value.minutes() / this.minutesStep);
}
}

Expand All @@ -201,7 +212,7 @@ class MinutePicker
month: this.state.date.month(),
date: this.state.date.date(),
hour: this.state.date.hour(),
minute: this.buildCalendarValues().indexOf(value) * MINUTES_STEP,
minute: this.buildCalendarValues().indexOf(value) * this.minutesStep,
},
};
this.props.onChange(e, data);
Expand All @@ -228,10 +239,10 @@ class MinutePicker
return { date: prevDate };
}, callback);
}
}

function getMinuteCellPosition(minute: number): number {
return Math.floor(minute / MINUTES_STEP);
private getMinuteCellPosition(minute: number): number {
return Math.floor(minute / this.minutesStep);
}
}

export default MinutePicker;
4 changes: 4 additions & 0 deletions src/views/BaseCalendarView.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { SemanticCOLORS } from 'semantic-ui-react';
import { BodyWidth } from './CalendarBody/Body';

export interface BaseCalendarViewProps {
/** Used for passing calendar dom element to parent component. */
Expand All @@ -24,6 +25,9 @@ export interface BaseCalendarViewProps {
markColor?: SemanticCOLORS;
/** Moment date localization */
localization?: string;
/** Number of cells in a row */
rowWidth?: BodyWidth;

}

export interface SingleSelectionCalendarViewProps {
Expand Down
14 changes: 10 additions & 4 deletions src/views/MinuteView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@ import Header, { HeaderProps } from './CalendarHeader/Header';

import { findHTMLElement } from '../lib';

const MINUTE_CALENDAR_ROW_WIDTH = 3;

type MinuteViewProps =
BaseCalendarViewProps
& SingleSelectionCalendarViewProps
& CalendarWithOptionalHeaderViewProps;

class MinuteView extends BaseCalendarView<MinuteViewProps, any> {
protected MINUTE_CALENDAR_ROW_WIDTH: number;

constructor(props) {
super(props);
this.MINUTE_CALENDAR_ROW_WIDTH = 4;
}

public render() {
const {
values,
Expand All @@ -37,6 +42,7 @@ class MinuteView extends BaseCalendarView<MinuteViewProps, any> {
onMount,
inline,
localization,
rowWidth,
...rest
} = this.props;
const headerProps: HeaderProps = {
Expand All @@ -47,7 +53,7 @@ class MinuteView extends BaseCalendarView<MinuteViewProps, any> {
hasNextPage,
hasPrevPage,
title: currentHeadingValue,
width: MINUTE_CALENDAR_ROW_WIDTH,
width: rowWidth,
displayWeeks: false,
localization,
};
Expand All @@ -56,7 +62,7 @@ class MinuteView extends BaseCalendarView<MinuteViewProps, any> {
<Calendar ref={(e) => this.calendarNode = findHTMLElement(e)} outlineOnFocus={inline} {...rest}>
{ hasHeader && <Header { ...headerProps } /> }
<Body
width={MINUTE_CALENDAR_ROW_WIDTH}
width={rowWidth}
data={values}
hovered={hoveredItemIndex}
onCellHover={onCellHover}
Expand Down