diff --git a/README.md b/README.md index f9bef0c36..e5d1a2d0a 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,9 @@ Displays an input field complete with custom inputs, native input, and a calenda |clearAriaLabel|`aria-label` for the clear button.|n/a|`"Clear value"`| |clearIcon|Content of the clear button. Setting the value explicitly to `null` will hide the icon.|(default icon)|| |closeCalendar|Whether to close the calendar on value selection.|`true`|`false`| +|customInput|Custom input component function. Note that many attributes will be overriden to provide react-date-picker functionality. See customInputOverrides to control this.||| +|customInputStyle|Custom input style property. This will be merged with the existing default style.|{}|{ color: 'red' }| +|customInputOverrides|Tell react-date-picker to not override these attributes with its own custom attributes. Note this may result in loss of functionality.|[]|['aria-label']| |dayAriaLabel|`aria-label` for the day input.|n/a|`"Day"`| |dayPlaceholder|`placeholder` for the day input.|`"--"`|`"dd"`| |disabled|Whether the date picker should be disabled.|`false`|`true`| diff --git a/src/DateInput.jsx b/src/DateInput.jsx index 78844ef90..15e57bcbe 100644 --- a/src/DateInput.jsx +++ b/src/DateInput.jsx @@ -540,20 +540,18 @@ export default class DateInput extends PureComponent { } renderNativeInput() { - const { - disabled, - maxDate, - minDate, - name, - nativeInputAriaLabel, - required, - } = this.props; + const { disabled, maxDate, minDate } = this.props; + const { name, nativeInputAriaLabel, required } = this.props; + const { customInput, customInputOverrides, customInputStyle } = this.props; const { value } = this.state; return ( { + switch (valueType) { + case 'decade': + case 'year': + return 'number'; + case 'month': + return 'month'; + case 'day': + return 'date'; + default: + throw new Error('Invalid valueType.'); + } +}; + +const nativeValueParser = (valueType) => { + switch (valueType) { + case 'century': + case 'decade': + case 'year': + return getYear; + case 'month': + return getISOLocalMonth; + case 'day': + return getISOLocalDate; + default: + throw new Error('Invalid valueType.'); + } +}; + export default function NativeInput({ ariaLabel, + customInput = , + customInputStyle = {}, + customInputOverrides = [], disabled, maxDate, minDate, @@ -19,63 +51,41 @@ export default function NativeInput({ value, valueType, }) { - const nativeInputType = (() => { - switch (valueType) { - case 'decade': - case 'year': - return 'number'; - case 'month': - return 'month'; - case 'day': - return 'date'; - default: - throw new Error('Invalid valueType.'); - } - })(); + const inputStyle = { + visibility: 'hidden', + position: 'absolute', + top: '-9999px', + left: '-9999px', + ...customInputStyle, + }; - const nativeValueParser = (() => { - switch (valueType) { - case 'century': - case 'decade': - case 'year': - return getYear; - case 'month': - return getISOLocalMonth; - case 'day': - return getISOLocalDate; - default: - throw new Error('Invalid valueType.'); - } - })(); + const inputProps = { + 'aria-label': ariaLabel, + disabled, + max: maxDate ? nativeValueParser(valueType)(maxDate) : null, + min: minDate ? nativeValueParser(valueType)(minDate) : null, + name, + onChange, + onFocus: event => event.stopPropagation(), + required, + type: nativeInputType(valueType), + value: value ? nativeValueParser(valueType)(value) : '', + }; - function stopPropagation(event) { - event.stopPropagation(); - } + const filteredInputProps = Object.keys(inputProps) + .reduce((obj, key) => (customInputOverrides && customInputOverrides.includes(key) + ? { ...obj } + : { ...obj, [key]: inputProps[key] }), + {}); - return ( - - ); + return <>{React.cloneElement(customInput, { ...filteredInputProps, style: inputStyle })}; } NativeInput.propTypes = { ariaLabel: PropTypes.string, + customInput: PropTypes.element, + customInputOverrides: PropTypes.arrayOf(PropTypes.string), + customInputStyle: PropTypes.objectOf(PropTypes.any), disabled: PropTypes.bool, maxDate: isMaxDate, minDate: isMinDate,