From 4a7f458a3f50bf638d58df2de1816e1c74a4caf6 Mon Sep 17 00:00:00 2001 From: Akira Sudoh Date: Fri, 10 Jan 2020 09:39:22 +0900 Subject: [PATCH] fix(DatePicker): fix calendar dropdown position (#4846) This change inroduces a Flatpickr plugin that ensures that the calendar dropdown is put in the correct floating position even if the floating menu container is changed via `appendTo` and the floating menu container has significant offset from ``. Fixes #4818. --- .../src/components/DatePicker/DatePicker.js | 7 +- .../DatePicker/plugins/appendToPlugin.js | 64 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 packages/react/src/components/DatePicker/plugins/appendToPlugin.js diff --git a/packages/react/src/components/DatePicker/DatePicker.js b/packages/react/src/components/DatePicker/DatePicker.js index ca800fdf8552..f546d0f91083 100644 --- a/packages/react/src/components/DatePicker/DatePicker.js +++ b/packages/react/src/components/DatePicker/DatePicker.js @@ -12,6 +12,7 @@ import flatpickr from 'flatpickr'; import l10n from 'flatpickr/dist/l10n/index'; import { settings } from 'carbon-components'; import DatePickerInput from '../DatePickerInput'; +import carbonFlatpickrAppendToPlugin from './plugins/appendToPlugin'; import carbonFlatpickrFixEventsPlugin from './plugins/fixEventsPlugin'; import carbonFlatpickrRangePlugin from './plugins/rangePlugin'; import { match, keys } from '../../internal/keyboard'; @@ -340,7 +341,6 @@ export default class DatePicker extends Component { this.cal = new flatpickr(this.inputField, { disableMobile: true, defaultDate: value, - appendTo, mode: datePickerType, allowInput: true, dateFormat: dateFormat, @@ -351,6 +351,11 @@ export default class DatePicker extends Component { datePickerType === 'range' ? new carbonFlatpickrRangePlugin({ input: this.toInputField }) : () => {}, + appendTo + ? carbonFlatpickrAppendToPlugin({ + appendTo, + }) + : () => {}, carbonFlatpickrMonthSelectPlugin({ selectorFlatpickrMonthYearContainer: '.flatpickr-current-month', selectorFlatpickrYearContainer: '.numInputWrapper', diff --git a/packages/react/src/components/DatePicker/plugins/appendToPlugin.js b/packages/react/src/components/DatePicker/plugins/appendToPlugin.js new file mode 100644 index 000000000000..bbf0976ee853 --- /dev/null +++ b/packages/react/src/components/DatePicker/plugins/appendToPlugin.js @@ -0,0 +1,64 @@ +/** + * @license + * + * Copyright IBM Corp. 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @param {object} config Plugin configuration. + * @returns {Plugin} A Flatpickr plugin to put adjust the position of calendar dropdown. + */ +export default config => fp => { + /** + * Adjusts the floating meun position after Flatpicker sets it. + */ + const handlePreCalendarPosition = () => { + Promise.resolve().then(() => { + const { + calendarContainer, + config: fpConfig, + _positionElement: positionElement, + } = fp; + const { appendTo } = fpConfig; + const { + left: containerLeft, + top: containerTop, + } = appendTo.getBoundingClientRect(); + const { + left: refLeft, + bottom: refBottom, + } = positionElement.getBoundingClientRect(); + if ( + (appendTo !== appendTo.ownerDocument.body || + containerLeft !== 0 || + containerTop !== 0) && + appendTo.ownerDocument.defaultView + .getComputedStyle(appendTo) + .getPropertyValue('position') === 'static' + ) { + throw new Error( + 'Floating menu container must not have `position:static`.' + ); + } + // `2` for negative mergin on calendar dropdown + calendarContainer.style.top = `${refBottom - containerTop + 2}px`; + calendarContainer.style.left = `${refLeft - containerLeft}px`; + }); + }; + + /** + * Registers this Flatpickr plugin. + */ + const register = () => { + fp.loadedPlugins.push('carbonFlatpickrAppendToPlugin'); + }; + + return { + appendTo: config.appendTo, + onReady: register, + onPreCalendarPosition: handlePreCalendarPosition, + }; +};