Skip to content

Commit 2254895

Browse files
committed
Add support for portalContainer prop
Closes #91
1 parent 5c31bc8 commit 2254895

File tree

5 files changed

+46
-13
lines changed

5 files changed

+46
-13
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ Displays an input field complete with custom inputs, native input, and a calenda
111111
| onCalendarOpen | Function called when the calendar opens. | n/a | `() => alert('Calendar opened')` |
112112
| onChange | Function called when the user picks a valid date. If any of the fields were excluded using custom `format`, `new Date(y, 0, 1, 0, 0, 0)`, where `y` is the current year, is going to serve as a "base". | n/a | `(value) => alert('New date is: ', value)` |
113113
| openCalendarOnFocus | Whether to open the calendar on input focus. | `true` | `false` |
114+
| portalContainer | Element to render the calendar in using portal. | n/a | `document.getElementById('my-div')` |
114115
| required | Whether date input should be required. | `false` | `true` |
115116
| returnValue | Which dates shall be passed by the calendar to the onChange function and onClick{Period} functions. Can be `"start"`, `"end"` or `"range"`. The latter will cause an array with start and end values to be passed. | `"start"` | `"range"` |
116117
| showLeadingZeros | Whether leading zeros should be rendered in date inputs. | `false` | `true` |

src/DatePicker.jsx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { PureComponent } from 'react';
2+
import { createPortal } from 'react-dom';
23
import PropTypes from 'prop-types';
34
import makeEventProps from 'make-event-props';
45
import mergeClassNames from 'merge-class-names';
@@ -235,29 +236,36 @@ export default class DatePicker extends PureComponent {
235236
calendarClassName,
236237
className: datePickerClassName, // Unused, here to exclude it from calendarProps
237238
onChange,
239+
portalContainer,
238240
value,
239241
...calendarProps
240242
} = this.props;
241243

242244
const className = `${baseClassName}__calendar`;
245+
const classNames = mergeClassNames(className, `${className}--${isOpen ? 'open' : 'closed'}`);
246+
247+
const calendar = (
248+
<Calendar
249+
className={calendarClassName}
250+
onChange={(value) => this.onChange(value)}
251+
value={value || null}
252+
{...calendarProps}
253+
/>
254+
);
243255

244-
return (
256+
return portalContainer ? (
257+
createPortal(<div className={classNames}>{calendar}</div>, portalContainer)
258+
) : (
245259
<Fit>
246260
<div
247261
ref={(ref) => {
248262
if (ref && !isOpen) {
249263
ref.removeAttribute('style');
250264
}
251265
}}
252-
className={mergeClassNames(className, `${className}--${isOpen ? 'open' : 'closed'}`)}
253-
style={isOpen ? undefined : {}}
266+
className={classNames}
254267
>
255-
<Calendar
256-
className={calendarClassName}
257-
onChange={(value) => this.onChange(value)}
258-
value={value || null}
259-
{...calendarProps}
260-
/>
268+
{calendar}
261269
</div>
262270
</Fit>
263271
);
@@ -364,6 +372,7 @@ DatePicker.propTypes = {
364372
onChange: PropTypes.func,
365373
onFocus: PropTypes.func,
366374
openCalendarOnFocus: PropTypes.bool,
375+
portalContainer: PropTypes.object,
367376
required: PropTypes.bool,
368377
returnValue: PropTypes.oneOf(['start', 'end', 'range']),
369378
showLeadingZeros: PropTypes.bool,

src/DatePicker.less

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,6 @@
9595
&__calendar {
9696
width: 350px;
9797
max-width: 100vw;
98-
position: absolute;
99-
top: 100%;
100-
left: 0;
10198
z-index: 1;
10299

103100
&--closed {

test/Test.jsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState } from 'react';
1+
import React, { useRef, useState } from 'react';
22
import DatePicker from 'react-date-picker/src/entry.nostyle';
33
import 'react-date-picker/src/DatePicker.less';
44
import 'react-calendar/dist/Calendar.css';
@@ -35,12 +35,14 @@ const nineteenNinetyFive = new Date(1995, now.getUTCMonth() + 1, 15, 12);
3535
const fifteenthOfNextMonth = new Date(now.getUTCFullYear(), now.getUTCMonth() + 1, 15, 12);
3636

3737
export default function Test() {
38+
const portalContainer = useRef();
3839
const [disabled, setDisabled] = useState(false);
3940
const [locale, setLocale] = useState(null);
4041
const [maxDate, setMaxDate] = useState(fifteenthOfNextMonth);
4142
const [maxDetail, setMaxDetail] = useState('month');
4243
const [minDate, setMinDate] = useState(nineteenNinetyFive);
4344
const [minDetail, setMinDetail] = useState('century');
45+
const [renderInPortal, setRenderInPortal] = useState(false);
4446
const [returnValue /* , setReturnValue */] = useState('start');
4547
const [required, setRequired] = useState(true);
4648
const [showLeadingZeros, setShowLeadingZeros] = useState(true);
@@ -77,7 +79,9 @@ export default function Test() {
7779
<ValueOptions setValue={setValue} value={value} />
7880
<ViewOptions
7981
disabled={disabled}
82+
renderInPortal={renderInPortal}
8083
setDisabled={setDisabled}
84+
setRenderInPortal={setRenderInPortal}
8185
setShowLeadingZeros={setShowLeadingZeros}
8286
setShowNeighboringMonth={setShowNeighboringMonth}
8387
setShowWeekNumbers={setShowWeekNumbers}
@@ -110,13 +114,15 @@ export default function Test() {
110114
onCalendarClose={() => console.log('Calendar closed')}
111115
onCalendarOpen={() => console.log('Calendar opened')}
112116
onChange={setValue}
117+
portalContainer={renderInPortal ? portalContainer.current : undefined}
113118
required={required}
114119
returnValue={returnValue}
115120
showLeadingZeros={showLeadingZeros}
116121
showNeighboringMonth={showNeighboringMonth}
117122
showWeekNumbers={showWeekNumbers}
118123
value={value}
119124
/>
125+
<div ref={portalContainer} />
120126
<br />
121127
<br />
122128
<button id="submit" type="submit">

test/ViewOptions.jsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import PropTypes from 'prop-types';
33

44
export default function ViewOptions({
55
disabled,
6+
renderInPortal,
67
setDisabled,
8+
setRenderInPortal,
79
setShowLeadingZeros,
810
setShowNeighboringMonth,
911
setShowWeekNumbers,
@@ -35,6 +37,12 @@ export default function ViewOptions({
3537
setShowNeighboringMonth(checked);
3638
}
3739

40+
function onRenderInPortalChange(event) {
41+
const { checked } = event.target;
42+
43+
setRenderInPortal(checked);
44+
}
45+
3846
return (
3947
<fieldset id="viewoptions">
4048
<legend htmlFor="viewoptions">View options</legend>
@@ -73,13 +81,25 @@ export default function ViewOptions({
7381
/>
7482
<label htmlFor="showNeighboringMonth">{"Show neighboring month's days"}</label>
7583
</div>
84+
85+
<div>
86+
<input
87+
checked={renderInPortal}
88+
id="renderInPortal"
89+
onChange={onRenderInPortalChange}
90+
type="checkbox"
91+
/>
92+
<label htmlFor="renderInPortal">Render in portal</label>
93+
</div>
7694
</fieldset>
7795
);
7896
}
7997

8098
ViewOptions.propTypes = {
8199
disabled: PropTypes.bool.isRequired,
100+
renderInPortal: PropTypes.bool.isRequired,
82101
setDisabled: PropTypes.func.isRequired,
102+
setRenderInPortal: PropTypes.func.isRequired,
83103
setShowLeadingZeros: PropTypes.func.isRequired,
84104
setShowNeighboringMonth: PropTypes.func.isRequired,
85105
setShowWeekNumbers: PropTypes.func.isRequired,

0 commit comments

Comments
 (0)