From c563340788eecd757594968ac990091d2573cdf5 Mon Sep 17 00:00:00 2001 From: Adriel Dinelli Date: Mon, 1 Mar 2021 17:10:14 -0300 Subject: [PATCH 1/3] Add useFixedPosition prop to render picker In some cases, if the datepicker is rendered inside a div with hidden overflow, it will appear cropped. The useFixedPosition flag will tell this component to render the picker relative to it's wrapper, using refs. --- src/DateTime.js | 17 +++- test/__snapshots__/snapshots.spec.js.snap | 97 ++++++++++++----------- test/testUtils.js | 9 ++- test/tests.spec.js | 6 ++ 4 files changed, 78 insertions(+), 51 deletions(-) diff --git a/src/DateTime.js b/src/DateTime.js index 88a72bfb0..69b27ed22 100644 --- a/src/DateTime.js +++ b/src/DateTime.js @@ -50,6 +50,7 @@ export default class Datetime extends React.Component { renderDay: TYPES.func, renderMonth: TYPES.func, renderYear: TYPES.func, + useFixedPosition: TYPES.bool, } static defaultProps = { @@ -83,13 +84,17 @@ export default class Datetime extends React.Component { constructor( props ) { super( props ); this.state = this.getInitialState(); + this.wrapper = React.createRef(); + this.picker = React.createRef(); } render() { + this.props.useFixedPosition && this._updatePickerFixedPosition(); + return ( { this.renderInput() } -
+
{ this.renderView() }
@@ -112,7 +117,7 @@ export default class Datetime extends React.Component { if ( this.props.renderInput ) { return ( -
+
{ this.props.renderInput( finalInputProps, this._openCalendar, this._closeCalendar ) }
); @@ -127,6 +132,14 @@ export default class Datetime extends React.Component { return this.props.renderView( this.state.currentView, this._renderCalendar ); } + _updatePickerFixedPosition() { + if (this.picker.current && this.wrapper.current) { + const wrapperBounds = this.wrapper.current.getBoundingClientRect(); + this.picker.current.style.left = `${wrapperBounds.left}px`; + this.picker.current.style.top = `${wrapperBounds.top + wrapperBounds.height}px`; + } + } + _renderCalendar = () => { const props = this.props; const state = this.state; diff --git a/test/__snapshots__/snapshots.spec.js.snap b/test/__snapshots__/snapshots.spec.js.snap index 7dcf4ee1b..b885fdb33 100644 --- a/test/__snapshots__/snapshots.spec.js.snap +++ b/test/__snapshots__/snapshots.spec.js.snap @@ -310,7 +310,7 @@ exports[`className: set to arbitraty value 1`] = ` 20 21 { return datetime.find('.rdtSwitch').getDOMNode().innerHTML; - } + }, + + /* + * Get CSS + */ + getPickerStyleProp: (datetime) => { + return datetime.find('.rdtPicker').props().style; + }, }; diff --git a/test/tests.spec.js b/test/tests.spec.js index 498afa2ec..bdca7e04e 100644 --- a/test/tests.spec.js +++ b/test/tests.spec.js @@ -820,6 +820,12 @@ describe('Datetime', () => { }, 0); }); + it('useFixedPosition=true changes rdtPicker position to fixed', () => { + const component = utils.createDatetime({ useFixedPosition: true }); + utils.openDatepicker(component); + expect(utils.getPickerStyleProp(component).position).toEqual('fixed'); + }); + describe('initialValue of type', () => { it('date', () => { const date = new Date(2000, 0, 15, 2, 2, 2, 2), From 9979db1d7c89abbee5df8104809fe68b4ae7b95f Mon Sep 17 00:00:00 2001 From: Adriel Dinelli Date: Mon, 1 Mar 2021 17:28:12 -0300 Subject: [PATCH 2/3] Update README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 867e40d95..ad8aa8aa8 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Below we have all the props that we can use with the `` component. The | **closeOnTab** | `boolean` | `true` | When `true` and the input is focused, pressing the `tab` key will close the datepicker. | **timeConstraints** | `object` | `null` | Add some constraints to the timepicker. It accepts an `object` with the format `{ hours: { min: 9, max: 15, step: 2 }}`, this example means the hours can't be lower than `9` and higher than `15`, and it will change adding or subtracting `2` hours everytime the buttons are clicked. The constraints can be added to the `hours`, `minutes`, `seconds` and `milliseconds`. | **closeOnClickOutside** | `boolean` | `true` | When the calendar is open and `closeOnClickOutside` is `true` (its default value), clickin outside of the calendar or input closes the calendar. If `false` the calendar stays open. +| **useFixedPosition** | `boolean` | `false` | Forces the picker element to render in a fixed window position, calculating it's coordinates based on it's wrapper. Useful for cases when the datepicker is rendered inside a div with hidden overflow that otherwise would be cropping the component. ## Imperative API Besides controlling the selected date, there is a navigation through months, years, decades that react-datetime handles for us. We can interfere in it, stopping view transtions by using the prop `onBeforeNavigate`, but we can also navigate to a specific view and date by using some imperative methods. From e84286930214317493a651afe3de35558fcc66cb Mon Sep 17 00:00:00 2001 From: Adriel Dinelli Date: Mon, 1 Mar 2021 18:20:38 -0300 Subject: [PATCH 3/3] Update typescript definitions --- react-datetime.d.ts | 6 ++++++ typings/DateTime.d.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/react-datetime.d.ts b/react-datetime.d.ts index 1343d0843..e7888c65a 100644 --- a/react-datetime.d.ts +++ b/react-datetime.d.ts @@ -186,6 +186,12 @@ declare module ReactDatetime { When true the picker get closed when clicking outside of the calendar or the input box. When false, it stays open. */ closeOnClickOutside?: boolean; + /* + Forces the picker element to render in a fixed window position, calculating it's coordinates based + on it's wrapper. Useful for cases when the datepicker is rendered inside a div with hidden overflow + that otherwise would be cropping the component. + */ + useFixedPosition?: boolean; } interface DatetimeComponent extends React.ComponentClass { diff --git a/typings/DateTime.d.ts b/typings/DateTime.d.ts index 99bbc4134..cd0fc64a6 100644 --- a/typings/DateTime.d.ts +++ b/typings/DateTime.d.ts @@ -201,6 +201,12 @@ declare namespace ReactDatetimeClass { When true the picker get closed when clicking outside of the calendar or the input box. When false, it stays open. */ closeOnClickOutside?: boolean; + /* + Forces the picker element to render in a fixed window position, calculating it's coordinates based + on it's wrapper. Useful for cases when the datepicker is rendered inside a div with hidden overflow + that otherwise would be cropping the component. + */ + useFixedPosition?: boolean; } export interface DatetimepickerState {