UNPKG

@carbon/react

Version:

React components for the Carbon Design System

862 lines (848 loc) 28.8 kB
/** * Copyright IBM Corp. 2016, 2023 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js'; import PropTypes from 'prop-types'; import React, { useContext, useState, useCallback, useRef, useEffect, useImperativeHandle } from 'react'; import cx from 'classnames'; import flatpickr from 'flatpickr'; import l10n from 'flatpickr/dist/l10n/index'; import DatePickerInput from '../DatePickerInput/DatePickerInput.js'; import { appendToPlugin } from './plugins/appendToPlugin.js'; import carbonFlatpickrFixEventsPlugin from './plugins/fixEventsPlugin.js'; import carbonFlatpickrRangePlugin from './plugins/rangePlugin.js'; import { deprecate } from '../../prop-types/deprecate.js'; import { Escape, Tab, Enter } from '../../internal/keyboard/keys.js'; import { match } from '../../internal/keyboard/match.js'; import { usePrefix } from '../../internal/usePrefix.js'; import { useSavedCallback } from '../../internal/useSavedCallback.js'; import '../FluidForm/FluidForm.js'; import { FormContext } from '../FluidForm/FormContext.js'; import { WarningFilled, WarningAltFilled } from '@carbon/icons-react'; // Weekdays shorthand for English locale // Ensure localization exists before trying to access it function initializeWeekdayShorthand() { if (l10n?.en?.weekdays?.shorthand) { l10n.en.weekdays.shorthand.forEach((_day, index) => { const currentDay = l10n.en.weekdays.shorthand; if (currentDay[index] === 'Thu' || currentDay[index] === 'Th') { currentDay[index] = 'Th'; } else { currentDay[index] = currentDay[index].charAt(0); } }); } } const forEach = Array.prototype.forEach; /** * @param {number} monthNumber The month number. * @param {boolean} shorthand `true` to use shorthand month. * @param {Locale} locale The Flatpickr locale data. * @returns {string} The month string. */ const monthToStr = (monthNumber, shorthand, locale) => locale.months[shorthand ? 'shorthand' : 'longhand'][monthNumber]; /** * @param {object} config Plugin configuration. * @param {boolean} [config.shorthand] `true` to use shorthand month. * @param {string} config.selectorFlatpickrMonthYearContainer The CSS selector for the container of month/year selection UI. * @param {string} config.selectorFlatpickrYearContainer The CSS selector for the container of year selection UI. * @param {string} config.selectorFlatpickrCurrentMonth The CSS selector for the text-based month selection UI. * @param {string} config.classFlatpickrCurrentMonth The CSS class for the text-based month selection UI. * @returns {Plugin} A Flatpickr plugin to use text instead of `<select>` for month picker. */ const carbonFlatpickrMonthSelectPlugin = config => fp => { const setupElements = () => { if (!fp.monthElements) { return; } fp.monthElements.forEach(elem => { if (!elem.parentNode) { return; } elem.parentNode.removeChild(elem); }); fp.monthElements.splice(0, fp.monthElements.length, ...fp.monthElements.map(() => { // eslint-disable-next-line no-underscore-dangle const monthElement = fp._createElement('span', config.classFlatpickrCurrentMonth); monthElement.textContent = monthToStr(fp.currentMonth, config.shorthand === true, fp.l10n); fp.yearElements[0].closest(config.selectorFlatpickrMonthYearContainer).insertBefore(monthElement, fp.yearElements[0].closest(config.selectorFlatpickrYearContainer)); return monthElement; })); }; const updateCurrentMonth = () => { if (fp.monthElements) { const monthStr = monthToStr(fp.currentMonth, config.shorthand === true, fp.l10n); fp.yearElements.forEach(elem => { const currentMonthContainer = elem.closest(config.selectorFlatpickrMonthYearContainer); Array.prototype.forEach.call(currentMonthContainer.querySelectorAll('.cur-month'), monthElement => { monthElement.textContent = monthStr; }); }); } }; const register = () => { fp.loadedPlugins.push('carbonFlatpickrMonthSelectPlugin'); }; return { onMonthChange: updateCurrentMonth, onValueUpdate: updateCurrentMonth, onOpen: updateCurrentMonth, onReady: [setupElements, updateCurrentMonth, register] }; }; /** * Determine if every child in a list of children has no label specified * @param {Array<ReactElement>} children * @returns {boolean} */ function isLabelTextEmpty(children) { return children.every(child => !child.props.labelText); } const rightArrowHTML = `<svg width="16px" height="16px" viewBox="0 0 16 16"> <polygon points="11,8 6,13 5.3,12.3 9.6,8 5.3,3.7 6,3 "/> </svg>`; const leftArrowHTML = `<svg width="16px" height="16px" viewBox="0 0 16 16"> <polygon points="5,8 10,3 10.7,3.7 6.4,8 10.7,12.3 10,13 "/> </svg>`; function updateClassNames(calendar, prefix) { const calendarContainer = calendar.calendarContainer; const daysContainer = calendar.days; if (calendarContainer && daysContainer) { // calendarContainer and daysContainer are undefined if flatpickr detects a mobile device calendarContainer.classList.add(`${prefix}--date-picker__calendar`); calendarContainer.querySelector('.flatpickr-month').classList.add(`${prefix}--date-picker__month`); calendarContainer.querySelector('.flatpickr-weekdays').classList.add(`${prefix}--date-picker__weekdays`); calendarContainer.querySelector('.flatpickr-days').classList.add(`${prefix}--date-picker__days`); forEach.call(calendarContainer.querySelectorAll('.flatpickr-weekday'), item => { const currentItem = item; currentItem.innerHTML = currentItem.innerHTML.replace(/\s+/g, ''); currentItem.classList.add(`${prefix}--date-picker__weekday`); }); forEach.call(daysContainer.querySelectorAll('.flatpickr-day'), item => { item.classList.add(`${prefix}--date-picker__day`); item.setAttribute('role', 'button'); if (item.classList.contains('today') && calendar.selectedDates.length > 0) { item.classList.add('no-border'); } else if (item.classList.contains('today') && calendar.selectedDates.length === 0) { item.classList.remove('no-border'); } }); } } const DatePicker = /*#__PURE__*/React.forwardRef(function DatePicker({ allowInput, appendTo, children, className, closeOnSelect = true, dateFormat = 'm/d/Y', datePickerType, disable, enable, inline, invalid, invalidText, warn, warnText, light = false, locale = 'en', maxDate, minDate, onChange, onClose, onOpen, readOnly = false, short = false, value, parseDate: parseDateProp, ...rest }, ref) { const prefix = usePrefix(); const { isFluid } = useContext(FormContext); const [hasInput, setHasInput] = useState(false); const startInputField = useCallback(node => { if (node !== null) { startInputField.current = node; setHasInput(true); } }, []); const lastStartValue = useRef(''); const calendarRef = useRef(null); const [calendarCloseEvent, setCalendarCloseEvent] = useState(null); // fix datepicker deleting the selectedDate when the calendar closes const handleCalendarClose = useCallback((selectedDates, dateStr, instance) => { if (lastStartValue.current && selectedDates[0] && !startInputField.current.value) { startInputField.current.value = lastStartValue.current; calendarRef.current?.setDate([startInputField.current.value, endInputField?.current?.value], true, calendarRef.current.config.dateFormat); } if (onClose) { onClose(selectedDates, dateStr, instance); } }, [onClose]); const onCalendarClose = (selectedDates, dateStr, instance, e) => { if (e && e.type === 'clickOutside') { return; } setCalendarCloseEvent({ selectedDates, dateStr, instance }); }; useEffect(() => { if (calendarCloseEvent) { const { selectedDates, dateStr, instance } = calendarCloseEvent; handleCalendarClose(selectedDates, dateStr, instance); setCalendarCloseEvent(null); } }, [calendarCloseEvent, handleCalendarClose]); const endInputField = useRef(null); const lastFocusedField = useRef(null); const savedOnChange = useSavedCallback(onChange); const savedOnOpen = useSavedCallback(onOpen); const datePickerClasses = cx(`${prefix}--date-picker`, { [`${prefix}--date-picker--short`]: short, [`${prefix}--date-picker--light`]: light, [`${prefix}--date-picker--simple`]: datePickerType === 'simple', [`${prefix}--date-picker--single`]: datePickerType === 'single', [`${prefix}--date-picker--range`]: datePickerType === 'range', [`${prefix}--date-picker--nolabel`]: datePickerType === 'range' && isLabelTextEmpty(children) }); const wrapperClasses = cx(`${prefix}--form-item`, { [String(className)]: className }); const childrenWithProps = React.Children.toArray(children).map((child, index) => { if (index === 0 && child.type === /*#__PURE__*/React.createElement(DatePickerInput, child.props).type) { return /*#__PURE__*/React.cloneElement(child, { datePickerType, ref: startInputField, readOnly }); } if (index === 1 && child.type === /*#__PURE__*/React.createElement(DatePickerInput, child.props).type) { return /*#__PURE__*/React.cloneElement(child, { datePickerType, ref: endInputField, readOnly }); } if (index === 0) { return /*#__PURE__*/React.cloneElement(child, { ref: startInputField, readOnly }); } if (index === 1) { return /*#__PURE__*/React.cloneElement(child, { ref: endInputField, readOnly }); } }); useEffect(() => { initializeWeekdayShorthand(); }, []); useEffect(() => { if (datePickerType !== 'single' && datePickerType !== 'range') { return; } if (!startInputField.current) { return; } const onHook = (_electedDates, _dateStr, instance) => { updateClassNames(instance, prefix); if (startInputField?.current) { startInputField.current.readOnly = readOnly; } if (endInputField?.current) { endInputField.current.readOnly = readOnly; } }; // Logic to determine if `enable` or `disable` will be passed down. If neither // is provided, we return the default empty disabled array, allowing all dates. const enableOrDisable = enable ? 'enable' : 'disable'; let enableOrDisableArr; if (!enable && !disable) { enableOrDisableArr = []; } else if (enable) { enableOrDisableArr = enable; } else { enableOrDisableArr = disable; } let localeData; if (typeof locale === 'object') { const location = locale.locale ? locale.locale : 'en'; localeData = { ...l10n[location], ...locale }; } else { localeData = l10n[locale]; } /** * parseDate is called before the date is actually set. * It attempts to parse the input value and return a valid date string. * Flatpickr's default parser results in odd dates when given invalid * values, so instead here we normalize the month/day to `1` if given * a value outside the acceptable range. */ let parseDate; if (!parseDateProp && dateFormat === 'm/d/Y') { // This function only supports the default dateFormat. parseDate = date => { // Month must be 1-12. If outside these bounds, `1` should be used. const month = date.split('/')[0] <= 12 && date.split('/')[0] > 0 ? parseInt(date.split('/')[0]) : 1; const year = parseInt(date.split('/')[2]); if (month && year) { // The month and year must be provided to be able to determine // the number of days in the month. const daysInMonth = new Date(year, month, 0).getDate(); // If the day does not fall within the days in the month, `1` should be used. const day = date.split('/')[1] <= daysInMonth && date.split('/')[1] > 0 ? parseInt(date.split('/')[1]) : 1; return new Date(`${year}/${month}/${day}`); } else { // With no month and year, we cannot calculate anything. // Returning false gives flatpickr an invalid date, which will clear the input return false; } }; } else if (parseDateProp) { parseDate = parseDateProp; } const { current: start } = startInputField; const { current: end } = endInputField; const flatpickerConfig = { inline: inline ?? false, onClose: onCalendarClose, disableMobile: true, defaultDate: value, closeOnSelect: closeOnSelect, mode: datePickerType, allowInput: allowInput ?? true, dateFormat: dateFormat, locale: localeData, [enableOrDisable]: enableOrDisableArr, minDate: minDate, maxDate: maxDate, parseDate: parseDate, plugins: [datePickerType === 'range' ? carbonFlatpickrRangePlugin({ input: endInputField.current }) : () => {}, appendTo ? appendToPlugin({ appendTo }) : () => {}, carbonFlatpickrMonthSelectPlugin({ selectorFlatpickrMonthYearContainer: '.flatpickr-current-month', selectorFlatpickrYearContainer: '.numInputWrapper', classFlatpickrCurrentMonth: 'cur-month' }), carbonFlatpickrFixEventsPlugin({ inputFrom: startInputField.current, inputTo: endInputField.current, lastStartValue })], clickOpens: !readOnly, noCalendar: readOnly, nextArrow: rightArrowHTML, prevArrow: leftArrowHTML, onChange: (...args) => { if (!readOnly) { savedOnChange(...args); } }, onReady: onHook, onMonthChange: onHook, onYearChange: onHook, onOpen: (...args) => { onHook(...args); savedOnOpen(...args); }, onValueUpdate: onHook }; const calendar = flatpickr(start, flatpickerConfig); calendarRef.current = calendar; const handleInputFieldKeyDown = event => { const { calendarContainer, selectedDateElem: fpSelectedDateElem, todayDateElem: fpTodayDateElem } = calendar; if (match(event, Escape)) { calendarContainer.classList.remove('open'); } if (match(event, Tab)) { if (!event.shiftKey) { event.preventDefault(); calendarContainer.classList.add('open'); const selectedDateElem = calendarContainer.querySelector('.selected') && fpSelectedDateElem; const todayDateElem = calendarContainer.querySelector('.today') && fpTodayDateElem; (selectedDateElem || todayDateElem || calendarContainer.querySelector('.flatpickr-day[tabindex]') || calendarContainer).focus(); if (event.target === startInputField.current) { lastFocusedField.current = startInputField.current; } else if (event.target === endInputField.current) { lastFocusedField.current = endInputField.current; } } else if (calendarRef.current?.isOpen && event.target === startInputField.current) { calendarRef.current.close(); onCalendarClose(calendarRef.current.selectedDates, '', calendarRef.current, event); } } }; const handleCalendarKeyDown = event => { if (!calendarRef.current || !startInputField.current) return; const lastInputField = datePickerType == 'range' ? endInputField.current : startInputField.current; if (match(event, Tab)) { if (!event.shiftKey) { if (lastFocusedField.current === lastInputField) { lastInputField.focus(); calendarRef.current.close(); onCalendarClose(calendarRef.current.selectedDates, '', calendarRef.current, event); } else { event.preventDefault(); lastInputField.focus(); } } else { event.preventDefault(); (lastFocusedField.current || startInputField.current).focus(); } } }; function handleOnChange(event) { const { target } = event; if (target === start) { lastStartValue.current = start.value; } if (start.value !== '') { return; } if (!calendar.selectedDates) { return; } if (calendar.selectedDates.length === 0) { return; } } function handleKeyPress(event) { if (match(event, Enter) && closeOnSelect && datePickerType == 'single') { calendar.calendarContainer.classList.remove('open'); } } if (start) { start.addEventListener('keydown', handleInputFieldKeyDown); start.addEventListener('change', handleOnChange); start.addEventListener('keypress', handleKeyPress); if (calendar && calendar.calendarContainer) { // Flatpickr's calendar dialog is not rendered in a landmark causing an // error with IBM Equal Access Accessibility Checker so we add an aria // role to the container div. calendar.calendarContainer.setAttribute('role', 'application'); // IBM EAAC requires an aria-label on a role='region' calendar.calendarContainer.setAttribute('aria-label', 'calendar-container'); } } if (end) { end.addEventListener('keydown', handleInputFieldKeyDown); end.addEventListener('change', handleOnChange); end.addEventListener('keypress', handleKeyPress); } if (calendar.calendarContainer) { calendar.calendarContainer.addEventListener('keydown', handleCalendarKeyDown); } //component did unmount equivalent return () => { // Note: if the `startInputField` ref is undefined then calendar will be // of type: Array and `destroy` will not be defined if (calendar && calendar.destroy) { calendar.destroy(); } // prevent a duplicate date selection when a default value is set if (value) { if (startInputField?.current) { startInputField.current.value = ''; } if (endInputField?.current) { // eslint-disable-next-line react-hooks/exhaustive-deps endInputField.current.value = ''; } } if (start) { start.removeEventListener('keydown', handleInputFieldKeyDown); start.removeEventListener('change', handleOnChange); start.removeEventListener('keypress', handleKeyPress); } if (end) { end.removeEventListener('keydown', handleInputFieldKeyDown); end.removeEventListener('change', handleOnChange); end.removeEventListener('keypress', handleKeyPress); } if (calendar.calendarContainer) { calendar.calendarContainer.removeEventListener('keydown', handleCalendarKeyDown); } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [savedOnChange, savedOnOpen, readOnly, closeOnSelect, hasInput, datePickerType]); // this hook allows consumers to access the flatpickr calendar // instance for cases where functions like open() or close() // need to be imperatively called on the calendar useImperativeHandle(ref, () => ({ get calendar() { return calendarRef.current; } })); useEffect(() => { if (calendarRef.current?.set) { calendarRef.current.set({ dateFormat }); } }, [dateFormat]); useEffect(() => { if (calendarRef.current?.set) { calendarRef.current.set('minDate', minDate); } }, [minDate]); useEffect(() => { if (calendarRef.current?.set) { calendarRef.current.set('allowInput', allowInput); } }, [allowInput]); useEffect(() => { if (calendarRef.current?.set) { calendarRef.current.set('maxDate', maxDate); } }, [maxDate]); useEffect(() => { if (calendarRef.current?.set && disable) { calendarRef.current.set('disable', disable); } }, [disable]); useEffect(() => { if (calendarRef.current?.set && enable) { calendarRef.current.set('enable', enable); } }, [enable]); useEffect(() => { if (calendarRef.current?.set && inline) { calendarRef.current.set('inline', inline); } }, [inline]); useEffect(() => { // when value prop is manually reset, this clears the flatpickr calendar instance and text input // run if both: // 1. value prop is set to a falsy value (`""`, `undefined`, `null`, etc) OR an array of all falsy values // 2. flatpickr instance contains values in its `selectedDates` property so it hasn't already been cleared if ((!value || Array.isArray(value) && value.every(date => !date)) && calendarRef.current?.selectedDates.length) { calendarRef.current?.clear(); if (startInputField.current) { startInputField.current.value = ''; } if (endInputField.current) { endInputField.current.value = ''; } } }, [value]); useEffect(() => { const handleMouseDown = event => { if (calendarRef.current && calendarRef.current.isOpen && !calendarRef.current.calendarContainer.contains(event.target) && !startInputField.current.contains(event.target) && !endInputField.current?.contains(event.target)) { // Close the calendar immediately on mousedown closeCalendar(); } }; const closeCalendar = event => { calendarRef.current?.close(); // Remove focus from endDate calendar input onCalendarClose(calendarRef.current?.selectedDates, '', calendarRef.current, { type: 'clickOutside' }); }; document.addEventListener('mousedown', handleMouseDown, true); return () => { document.removeEventListener('mousedown', handleMouseDown, true); }; }, [calendarRef, startInputField, endInputField, onCalendarClose]); useEffect(() => { if (calendarRef.current?.set) { if (value !== undefined) { calendarRef.current.setDate(value); } updateClassNames(calendarRef.current, prefix); //for simple date picker w/o calendar; initial mount may not have value } else if (!calendarRef.current && value) { startInputField.current.value = value; } }, [value, prefix]); //eslint-disable-line react-hooks/exhaustive-deps let fluidError; if (isFluid) { if (invalid) { fluidError = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(WarningFilled, { className: `${prefix}--date-picker__icon ${prefix}--date-picker__icon--invalid` }), /*#__PURE__*/React.createElement("hr", { className: `${prefix}--date-picker__divider` }), /*#__PURE__*/React.createElement("div", { className: `${prefix}--form-requirement` }, invalidText)); } if (warn && !invalid) { fluidError = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(WarningAltFilled, { className: `${prefix}--date-picker__icon ${prefix}--date-picker__icon--warn` }), /*#__PURE__*/React.createElement("hr", { className: `${prefix}--date-picker__divider` }), /*#__PURE__*/React.createElement("div", { className: `${prefix}--form-requirement` }, warnText)); } } return /*#__PURE__*/React.createElement("div", _extends({ className: wrapperClasses, ref: ref }, rest), /*#__PURE__*/React.createElement("div", { className: datePickerClasses }, childrenWithProps), fluidError); }); DatePicker.propTypes = { /** * Flatpickr prop passthrough enables direct date input, and when set to false, * we must clear dates manually by resetting the value prop to a falsy value (such as `""`, `null`, or `undefined`) or an array of all falsy values, making it a controlled input. */ allowInput: PropTypes.bool, /** * The DOM element the Flatpicker should be inserted into. `<body>` by default. */ appendTo: PropTypes.object, /** * The child nodes. */ children: PropTypes.node, /** * The CSS class names. */ className: PropTypes.string, /** * flatpickr prop passthrough. Controls whether the calendar dropdown closes upon selection. */ closeOnSelect: PropTypes.bool, /** * The date format. */ dateFormat: PropTypes.string, /** * The type of the date picker: * * * `simple` - Without calendar dropdown. * * `single` - With calendar dropdown and single date. * * `range` - With calendar dropdown and a date range. */ datePickerType: PropTypes.oneOf(['simple', 'single', 'range']), /** * The flatpickr `disable` option that allows a user to disable certain dates. */ disable: PropTypes.array, /** * The flatpickr `enable` option that allows a user to enable certain dates. */ enable: PropTypes.array, /** * The flatpickr `inline` option. */ inline: PropTypes.bool, /** * Specify whether or not the control is invalid (Fluid only) */ invalid: PropTypes.bool, /** * Provide the text that is displayed when the control is in error state (Fluid Only) */ invalidText: PropTypes.node, /** * `true` to use the light version. */ light: deprecate(PropTypes.bool, 'The `light` prop for `DatePicker` has ' + 'been deprecated in favor of the new `Layer` component. It will be removed in the next major release.'), /** * The language locale used to format the days of the week, months, and numbers. The full list of supported locales can be found here https://github.com/flatpickr/flatpickr/tree/master/src/l10n */ locale: PropTypes.oneOfType([PropTypes.object, PropTypes.oneOf(['ar', // Arabic 'at', // Austria 'az', // Azerbaijan 'be', // Belarusian 'bg', // Bulgarian 'bn', // Bangla 'bs', // Bosnia 'cat', // Catalan 'cs', // Czech 'cy', // Welsh 'da', // Danish 'de', // German 'en', // English 'eo', // Esperanto 'es', // Spanish 'et', // Estonian 'fa', // Persian 'fi', // Finnish 'fo', // Faroese 'fr', // French 'ga', // Gaelic 'gr', // Greek 'he', // Hebrew 'hi', // Hindi 'hr', // Croatian 'hu', // Hungarian 'id', // Indonesian 'is', // Icelandic 'it', // Italian 'ja', // Japanese 'ka', // Georgian 'km', // Khmer 'ko', // Korean 'kz', // Kazakh 'lt', // Lithuanian 'lv', // Latvian 'mk', // Macedonian 'mn', // Mongolian 'ms', // Malaysian 'my', // Burmese 'nl', // Dutch 'no', // Norwegian 'pa', // Punjabi 'pl', // Polish 'pt', // Portuguese 'ro', // Romanian 'ru', // Russian 'si', // Sinhala 'sk', // Slovak 'sl', // Slovenian 'sq', // Albanian 'sr', // Serbian 'sv', // Swedish 'th', // Thai 'tr', // Turkish 'uk', // Ukrainian 'uz', // Uzbek 'uz_latn', // Uzbek Latin 'vn', // Vietnamese 'zh_tw', // Mandarin Traditional 'zh' // Mandarin ])]), /** * The maximum date that a user can pick to. */ maxDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** * The minimum date that a user can start picking from. */ minDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** * The `change` event handler. * `(dates: Date[], dStr: string, fp: Instance, data?: any):void;` */ onChange: PropTypes.func, /** * The `close` event handler. * `(dates: Date[], dStr: string, fp: Instance, data?: any):void;` */ onClose: PropTypes.func, /** * The `open` event handler. * `(dates: Date[], dStr: string, fp: Instance, data?: any):void;` */ onOpen: PropTypes.func, /** * flatpickr prop passthrough. Controls how dates are parsed. */ parseDate: PropTypes.func, /** * whether the DatePicker is to be readOnly * if boolean applies to all inputs * if array applies to each input in order */ readOnly: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]), /** * `true` to use the short version. */ short: PropTypes.bool, /** * The value of the date value provided to flatpickr, could * be a date, a date number, a date string, an array of dates. */ value: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object])), PropTypes.object, PropTypes.number]), /** * Specify whether the control is currently in warning state (Fluid only) */ warn: PropTypes.bool, /** * Provide the text that is displayed when the control is in warning state (Fluid only) */ warnText: PropTypes.node }; export { DatePicker as default };