Skip to content

Commit

Permalink
Fix time selection in EuiSuperDatePicker (elastic#1704)
Browse files Browse the repository at this point in the history
* Update react-datepicker time selector to not _always_ scroll to preSelection time

* Update react-datepicker time selection scroll-into-view onMount logic

* revert props default changes I made for testing

* fix scroll issue

* fix ie issue

* A few more dark mode fixes (elastic#1700)

* 9.2.0

* Updated documentation.

* Make EuiPopover's repositionOnScroll prop optional in TS (elastic#1705)

* Make EuiPopover's repositionOnScroll prop optional in TS

* changelog

* fix range coloring

* Fix scrollTop target

* changelog
  • Loading branch information
chandlerprall committed Mar 14, 2019
1 parent af436ef commit 6c641cf
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 109 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## [`master`](https://github.com/elastic/eui/tree/master)

**Note: this release is a backport containing changes originally made in `9.0.0`, `9.1.0`, and `9.4.0`**
**Note: this release is a backport containing changes originally made in `9.0.0`, `9.1.0`, `9.3.0`, and `9.4.0`**

- Adjusted the dark theme palette to have a slight blue tint ([#1691](https://github.com/elastic/eui/pull/1691))
- Added button to `EuiSuperDatePicker`'s “Now” tab to trigger the "now" time selection ([#1620](https://github.com/elastic/eui/pull/1620))
Expand All @@ -10,6 +10,7 @@
- Fixed keyboard navigation and UI of `EuiComboBox` items in single selection mode ([#1619](https://github.com/elastic/eui/pull/1619))
- Fixed `EuiComboBox` `activeOptonIndex` error with empty search results ([#1695](https://github.com/elastic/eui/pull/1695))
- Prevent `EuiComboBox` from creating a custom option value when user clicks on a value in the dropdown ([#1728](https://github.com/elastic/eui/pull/1728))
- Fixed `EuiSuperDatePicker` time selection jumping on focus ([#1704](https://github.com/elastic/eui/pull/1704))

## [`6.10.4`](https://github.com/elastic/eui/tree/v6.10.4)

Expand Down
131 changes: 93 additions & 38 deletions packages/react-datepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2634,9 +2634,24 @@ var Time = function (_React$Component) {
}
}, null);

if (preSelection == null) {
// there is no exact pre-selection, find the element closest to the selected time and preselect it
var currH = _this.props.selected ? getHour(_this.props.selected) : getHour(newDate());
var currM = _this.props.selected ? getMinute(_this.props.selected) : getMinute(newDate());
var closestTimeIndex = Math.floor((60 * currH + currM) / _this.props.intervals);
var closestMinutes = closestTimeIndex * _this.props.intervals;
preSelection = setTime(newDate(), {
hour: Math.floor(closestMinutes / 60),
minute: closestMinutes % 60,
second: 0,
millisecond: 0
});
}

_this.timeFormat = "hh:mm A";
_this.state = {
preSelection: preSelection,
needsScrollToPreSelection: false,
readInstructions: false,
isFocused: false
};
Expand All @@ -2645,36 +2660,45 @@ var Time = function (_React$Component) {

Time.prototype.componentDidMount = function componentDidMount() {
// code to ensure selected time will always be in focus within time window when it first appears
this.list.scrollTop = Time.calcCenterPosition(this.props.monthRef ? this.props.monthRef.clientHeight - this.header.clientHeight : this.list.clientHeight, this.centerLi);

if (this.state.preSelection == null) {
// there is no pre-selection, find the element closest to the selected time and preselect it
var currH = this.props.selected ? getHour(this.props.selected) : getHour(newDate());
var currM = this.props.selected ? getMinute(this.props.selected) : getMinute(newDate());
var closestTimeIndex = Math.floor((60 * currH + currM) / this.props.intervals);
var closestMinutes = closestTimeIndex * this.props.intervals;
var closestTime = setTime(newDate(), {
hour: Math.floor(closestMinutes / 60),
minute: closestMinutes % 60,
second: 0,
millisecond: 0
});
this.setState({ preSelection: closestTime });
}
var scrollParent = this.list;

scrollParent.scrollTop = Time.calcCenterPosition(this.props.monthRef ? this.props.monthRef.clientHeight - this.header.clientHeight : this.list.clientHeight, this.selectedLi || this.preselectedLi);
};

Time.prototype.componentDidUpdate = function componentDidUpdate() {
// scroll to the preSelected time
var scrollToElement = this.preselectedLi;
Time.prototype.componentDidUpdate = function componentDidUpdate(prevProps) {
// if selection changed, scroll to the selected item
if (this.props.selected && this.props.selected.isSame(prevProps.selected) === false) {
var scrollToElement = this.selectedLi;

if (scrollToElement) {
// an element matches the selected time, scroll to it
scrollToElement.scrollIntoView({
behavior: "instant",
block: "nearest",
inline: "nearest"
});
}

if (scrollToElement) {
// an element matches the selected time, scroll to it
scrollToElement.scrollIntoView({
behavior: "instant",
block: "nearest",
inline: "nearest"
// update preSelection to the selection
this.setState({
preSelection: this.props.selected
});
}

if (this.state.needsScrollToPreSelection) {
var _scrollToElement = this.preselectedLi;

if (_scrollToElement) {
// an element matches the selected time, scroll to it
_scrollToElement.scrollIntoView({
behavior: "instant",
block: "nearest",
inline: "nearest"
});
}

this.setState({ needsScrollToPreSelection: false });
}
};

Time.prototype.render = function render() {
Expand Down Expand Up @@ -2817,7 +2841,10 @@ var _initialiseProps = function _initialiseProps() {
}
if (!newSelection) return; // Let the input component handle this keydown
event.preventDefault();
_this3.setState({ preSelection: newSelection });
_this3.setState({
preSelection: newSelection,
needsScrollToPreSelection: true
});
};

this.handleClick = function (time) {
Expand Down Expand Up @@ -2880,13 +2907,13 @@ var _initialiseProps = function _initialiseProps() {
onClick: _this3.handleClick.bind(_this3, time),
className: _this3.liClasses(time, activeTime),
ref: function ref(li) {
if (currH === getHour(time) && currM === getMinute(time) || currH === getHour(time) && !_this3.centerLi) {
_this3.centerLi = li;
}

if (li && li.classList.contains("react-datepicker__time-list-item--preselected")) {
_this3.preselectedLi = li;
}

if (li && li.classList.contains("react-datepicker__time-list-item--selected")) {
_this3.selectedLi = li;
}
},
role: "option",
id: i
Expand Down Expand Up @@ -3597,10 +3624,17 @@ var _aFunction = function (it) {
return it;
};

var _aFunction$1 = /*#__PURE__*/Object.freeze({
default: _aFunction,
__moduleExports: _aFunction
});

var aFunction = ( _aFunction$1 && _aFunction ) || _aFunction$1;

// optional / simple context binding

var _ctx = function (fn, that, length) {
_aFunction(fn);
aFunction(fn);
if (that === undefined) return fn;
switch (length) {
case 1: return function (a) {
Expand Down Expand Up @@ -3938,19 +3972,26 @@ _export(_export.S + _export.F, 'Object', { assign: _objectAssign });

var assign = _core.Object.assign;

var assign$1 = createCommonjsModule(function (module) {
module.exports = { "default": assign, __esModule: true };
var assign$1 = /*#__PURE__*/Object.freeze({
default: assign,
__moduleExports: assign
});

unwrapExports(assign$1);
var require$$0 = ( assign$1 && assign ) || assign$1;

var assign$2 = createCommonjsModule(function (module) {
module.exports = { "default": require$$0, __esModule: true };
});

unwrapExports(assign$2);

var _extends$1 = createCommonjsModule(function (module, exports) {

exports.__esModule = true;



var _assign2 = _interopRequireDefault(assign$1);
var _assign2 = _interopRequireDefault(assign$2);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

Expand Down Expand Up @@ -4699,7 +4740,12 @@ var setPrototypeOf$1 = createCommonjsModule(function (module) {
module.exports = { "default": setPrototypeOf, __esModule: true };
});

unwrapExports(setPrototypeOf$1);
var setPrototypeOf$2 = unwrapExports(setPrototypeOf$1);

var setPrototypeOf$3 = /*#__PURE__*/Object.freeze({
default: setPrototypeOf$2,
__moduleExports: setPrototypeOf$1
});

// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])
_export(_export.S, 'Object', { create: _objectCreate });
Expand All @@ -4715,13 +4761,15 @@ module.exports = { "default": create, __esModule: true };

unwrapExports(create$1);

var _setPrototypeOf = ( setPrototypeOf$3 && setPrototypeOf$2 ) || setPrototypeOf$3;

var inherits$1 = createCommonjsModule(function (module, exports) {

exports.__esModule = true;



var _setPrototypeOf2 = _interopRequireDefault(setPrototypeOf$1);
var _setPrototypeOf2 = _interopRequireDefault(_setPrototypeOf);



Expand Down Expand Up @@ -7302,14 +7350,21 @@ emptyFunction.thatReturnsArgument = function (arg) {

var emptyFunction_1 = emptyFunction;

var emptyFunction$1 = /*#__PURE__*/Object.freeze({
default: emptyFunction_1,
__moduleExports: emptyFunction_1
});

var emptyFunction$2 = ( emptyFunction$1 && emptyFunction_1 ) || emptyFunction$1;

/**
* Similar to invariant but only logs a warning if the condition is not met.
* This can be used to log issues in development environments in critical
* paths. Removing the logging code for production environments will keep the
* same logic and follow the same code paths.
*/

var warning = emptyFunction_1;
var warning = emptyFunction$2;

if (process.env.NODE_ENV !== 'production') {
var printWarning = function printWarning(format) {
Expand Down
87 changes: 57 additions & 30 deletions packages/react-datepicker/docs-site/bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -48710,9 +48710,24 @@
}
}, null);

if (preSelection == null) {
// there is no exact pre-selection, find the element closest to the selected time and preselect it
var currH = _this.props.selected ? (0, _date_utils.getHour)(_this.props.selected) : (0, _date_utils.getHour)((0, _date_utils.newDate)());
var currM = _this.props.selected ? (0, _date_utils.getMinute)(_this.props.selected) : (0, _date_utils.getMinute)((0, _date_utils.newDate)());
var closestTimeIndex = Math.floor((60 * currH + currM) / _this.props.intervals);
var closestMinutes = closestTimeIndex * _this.props.intervals;
preSelection = (0, _date_utils.setTime)((0, _date_utils.newDate)(), {
hour: Math.floor(closestMinutes / 60),
minute: closestMinutes % 60,
second: 0,
millisecond: 0
});
}

_this.timeFormat = "hh:mm A";
_this.state = {
preSelection: preSelection,
needsScrollToPreSelection: false,
readInstructions: false,
isFocused: false
};
Expand All @@ -48721,36 +48736,45 @@

Time.prototype.componentDidMount = function componentDidMount() {
// code to ensure selected time will always be in focus within time window when it first appears
this.list.scrollTop = Time.calcCenterPosition(this.props.monthRef ? this.props.monthRef.clientHeight - this.header.clientHeight : this.list.clientHeight, this.centerLi);

if (this.state.preSelection == null) {
// there is no pre-selection, find the element closest to the selected time and preselect it
var currH = this.props.selected ? (0, _date_utils.getHour)(this.props.selected) : (0, _date_utils.getHour)((0, _date_utils.newDate)());
var currM = this.props.selected ? (0, _date_utils.getMinute)(this.props.selected) : (0, _date_utils.getMinute)((0, _date_utils.newDate)());
var closestTimeIndex = Math.floor((60 * currH + currM) / this.props.intervals);
var closestMinutes = closestTimeIndex * this.props.intervals;
var closestTime = (0, _date_utils.setTime)((0, _date_utils.newDate)(), {
hour: Math.floor(closestMinutes / 60),
minute: closestMinutes % 60,
second: 0,
millisecond: 0
});
this.setState({ preSelection: closestTime });
}
var scrollParent = this.list;

scrollParent.scrollTop = Time.calcCenterPosition(this.props.monthRef ? this.props.monthRef.clientHeight - this.header.clientHeight : this.list.clientHeight, this.selectedLi || this.preselectedLi);
};

Time.prototype.componentDidUpdate = function componentDidUpdate() {
// scroll to the preSelected time
var scrollToElement = this.preselectedLi;
Time.prototype.componentDidUpdate = function componentDidUpdate(prevProps) {
// if selection changed, scroll to the selected item
if (this.props.selected && this.props.selected.isSame(prevProps.selected) === false) {
var scrollToElement = this.selectedLi;

if (scrollToElement) {
// an element matches the selected time, scroll to it
scrollToElement.scrollIntoView({
behavior: "instant",
block: "nearest",
inline: "nearest"
if (scrollToElement) {
// an element matches the selected time, scroll to it
scrollToElement.scrollIntoView({
behavior: "instant",
block: "nearest",
inline: "nearest"
});
}

// update preSelection to the selection
this.setState({
preSelection: this.props.selected
});
}

if (this.state.needsScrollToPreSelection) {
var _scrollToElement = this.preselectedLi;

if (_scrollToElement) {
// an element matches the selected time, scroll to it
_scrollToElement.scrollIntoView({
behavior: "instant",
block: "nearest",
inline: "nearest"
});
}

this.setState({ needsScrollToPreSelection: false });
}
};

Time.prototype.render = function render() {
Expand Down Expand Up @@ -48893,7 +48917,10 @@
}
if (!newSelection) return; // Let the input component handle this keydown
event.preventDefault();
_this3.setState({ preSelection: newSelection });
_this3.setState({
preSelection: newSelection,
needsScrollToPreSelection: true
});
};

this.handleClick = function (time) {
Expand Down Expand Up @@ -48956,13 +48983,13 @@
onClick: _this3.handleClick.bind(_this3, time),
className: _this3.liClasses(time, activeTime),
ref: function ref(li) {
if (currH === (0, _date_utils.getHour)(time) && currM === (0, _date_utils.getMinute)(time) || currH === (0, _date_utils.getHour)(time) && !_this3.centerLi) {
_this3.centerLi = li;
}

if (li && li.classList.contains("react-datepicker__time-list-item--preselected")) {
_this3.preselectedLi = li;
}

if (li && li.classList.contains("react-datepicker__time-list-item--selected")) {
_this3.selectedLi = li;
}
},
role: "option",
id: i
Expand Down
Loading

0 comments on commit 6c641cf

Please sign in to comment.