Skip to content
This repository has been archived by the owner on Jun 3, 2024. It is now read-only.

Commit

Permalink
Merge pull request #948 from tcbegley/datepicker-disabled-days
Browse files Browse the repository at this point in the history
Add disabled_days prop to datepickers
  • Loading branch information
alexcjohnson authored Apr 23, 2021
2 parents 76e97f7 + 1a890ab commit 74ed663
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## UNRELEASED
### Added
- [#932](https://github.com/plotly/dash-core-components/pull/932). Adds a new copy to clipboard component.
- [#948](https://github.com/plotly/dash-core-components/pull/948)] Adds `disabled_days` prop to `DatePickerRange` and `DatePickerSingle` components. With this prop you can specify days that should be made unselectable in the date picker, in addition to those that fall outside of the range specified by `min_date_allowed` and `max_date_allowed`.


## [1.16.0] - 2021-04-08
Expand Down
8 changes: 8 additions & 0 deletions src/components/DatePickerRange.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ DatePickerRange.propTypes = {
*/
max_date_allowed: PropTypes.string,

/**
* Specifies additional days between min_date_allowed and max_date_allowed
* that should be disabled. Accepted datetime.datetime objects or strings
* in the format 'YYYY-MM-DD'
*/
disabled_days: PropTypes.arrayOf(PropTypes.string),

/**
* Specifies the month that is initially presented when the user
* opens the calendar. Accepts datetime.datetime objects or strings
Expand Down Expand Up @@ -284,6 +291,7 @@ DatePickerRange.defaultProps = {
updatemode: 'singledate',
persisted_props: ['start_date', 'end_date'],
persistence_type: 'local',
disabled_days: [],
};

export const propTypes = DatePickerRange.propTypes;
Expand Down
8 changes: 8 additions & 0 deletions src/components/DatePickerSingle.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ DatePickerSingle.propTypes = {
*/
max_date_allowed: PropTypes.string,

/**
* Specifies additional days between min_date_allowed and max_date_allowed
* that should be disabled. Accepted datetime.datetime objects or strings
* in the format 'YYYY-MM-DD'
*/
disabled_days: PropTypes.arrayOf(PropTypes.string),

/**
* Specifies the month that is initially presented when the user
* opens the calendar. Accepts datetime.datetime objects or strings
Expand Down Expand Up @@ -240,6 +247,7 @@ DatePickerSingle.defaultProps = {
disabled: false,
persisted_props: ['date'],
persistence_type: 'local',
disabled_days: [],
};

export const propTypes = DatePickerSingle.propTypes;
Expand Down
16 changes: 11 additions & 5 deletions src/fragments/DatePickerRange.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,20 @@ export default class DatePickerRange extends Component {
}

isOutsideRange(date) {
const {min_date_allowed, max_date_allowed} = convertToMoment(
this.props,
['min_date_allowed', 'max_date_allowed']
);
const {
max_date_allowed,
min_date_allowed,
disabled_days,
} = convertToMoment(this.props, [
'max_date_allowed',
'min_date_allowed',
'disabled_days',
]);

return (
(min_date_allowed && date.isBefore(min_date_allowed)) ||
(max_date_allowed && date.isAfter(max_date_allowed))
(max_date_allowed && date.isAfter(max_date_allowed)) ||
(disabled_days && disabled_days.some(d => date.isSame(d, 'day')))
);
}

Expand Down
16 changes: 11 additions & 5 deletions src/fragments/DatePickerSingle.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,20 @@ export default class DatePickerSingle extends Component {
}

isOutsideRange(date) {
const {max_date_allowed, min_date_allowed} = convertToMoment(
this.props,
['max_date_allowed', 'min_date_allowed']
);
const {
max_date_allowed,
min_date_allowed,
disabled_days,
} = convertToMoment(this.props, [
'max_date_allowed',
'min_date_allowed',
'disabled_days',
]);

return (
(min_date_allowed && date.isBefore(min_date_allowed)) ||
(max_date_allowed && date.isAfter(max_date_allowed))
(max_date_allowed && date.isAfter(max_date_allowed)) ||
(disabled_days && disabled_days.some(d => date.isSame(d, 'day')))
);
}

Expand Down
2 changes: 2 additions & 0 deletions src/utils/convertToMoment.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export default (newProps, momentProps) => {
undefined
);
}
} else if (Array.isArray(value)) {
dest[key] = value.map(d => moment(d));
} else {
dest[key] = moment(value);

Expand Down
36 changes: 36 additions & 0 deletions tests/integration/calendar/test_date_picker_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,39 @@ def test_dtpr004_max_and_min_dates_are_clickable(dash_dcc):
'#dps-initial-month .DateInput_input.DateInput_input_1[placeholder="End Date"]',
"01/20/2021",
)


def test_dtpr005_disabled_days_arent_clickable(dash_dcc):
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.Label("Operating Date"),
dcc.DatePickerRange(
id="dpr",
min_date_allowed=datetime(2021, 1, 1),
max_date_allowed=datetime(2021, 1, 31),
initial_visible_month=datetime(2021, 1, 1),
disabled_days=[datetime(2021, 1, 10), datetime(2021, 1, 11)],
),
],
style={
"width": "10%",
"display": "inline-block",
"marginLeft": 10,
"marginRight": 10,
"marginBottom": 10,
},
)
dash_dcc.start_server(app)
date = dash_dcc.find_element("#dpr input")
assert not date.get_attribute("value")
assert not any(
dash_dcc.select_date_range("dpr", day_range=(10, 11))
), "Disabled days should not be clickable"
assert all(
dash_dcc.select_date_range("dpr", day_range=(1, 2))
), "Other days should be clickable"

# open datepicker to take snapshot
date.click()
dash_dcc.percy_snapshot("dtpr005 - disabled days")
34 changes: 34 additions & 0 deletions tests/integration/calendar/test_date_picker_single.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,37 @@ def test_dtps012_initial_month(dash_dcc):
"#dps-initial-month .CalendarMonth.CalendarMonth_1[data-visible=true] strong",
"January 2010",
)


def test_dtps013_disabled_days_arent_clickable(dash_dcc):
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.Label("Operating Date"),
dcc.DatePickerSingle(
id="dps",
min_date_allowed=datetime(2021, 1, 1),
max_date_allowed=datetime(2021, 1, 31),
initial_visible_month=datetime(2021, 1, 1),
disabled_days=[datetime(2021, 1, 10)],
),
],
style={
"width": "10%",
"display": "inline-block",
"marginLeft": 10,
"marginRight": 10,
"marginBottom": 10,
},
)
dash_dcc.start_server(app)
date = dash_dcc.find_element("#dps input")
assert not date.get_attribute("value")
assert not dash_dcc.select_date_single(
"dps", day=10
), "Disabled days should not be clickable"
assert dash_dcc.select_date_single("dps", day=1), "Other days should be clickable"

# open datepicker to take snapshot
date.click()
dash_dcc.percy_snapshot("dtps013 - disabled days")

0 comments on commit 74ed663

Please sign in to comment.