@dotconnor/grommet
Version:
focus on the essential experience
220 lines (190 loc) • 7.63 kB
JavaScript
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
import React, { forwardRef, useContext, useEffect, useMemo, useState } from 'react';
import { ThemeContext } from 'styled-components';
import { Calendar as CalendarIcon } from 'grommet-icons/icons/Calendar';
import { defaultProps } from '../../default-props';
import { Box } from '../Box';
import { Calendar } from '../Calendar';
import { Drop } from '../Drop';
import { DropButton } from '../DropButton';
import { FormContext } from '../Form';
import { Keyboard } from '../Keyboard';
import { MaskedInput } from '../MaskedInput';
import { useForwardedRef } from '../../utils';
import { formatToSchema, valueToText, textToValue } from './utils';
var DateInput = /*#__PURE__*/forwardRef(function (_ref, refArg) {
var buttonProps = _ref.buttonProps,
calendarProps = _ref.calendarProps,
defaultValue = _ref.defaultValue,
disabled = _ref.disabled,
dropProps = _ref.dropProps,
format = _ref.format,
id = _ref.id,
_ref$inline = _ref.inline,
inline = _ref$inline === void 0 ? false : _ref$inline,
inputProps = _ref.inputProps,
name = _ref.name,
_onChange = _ref.onChange,
_onFocus = _ref.onFocus,
valueArg = _ref.value,
rest = _objectWithoutPropertiesLoose(_ref, ["buttonProps", "calendarProps", "defaultValue", "disabled", "dropProps", "format", "id", "inline", "inputProps", "name", "onChange", "onFocus", "value"]);
var theme = useContext(ThemeContext) || defaultProps.theme;
var iconSize = theme.dateInput.icon && theme.dateInput.icon.size || 'medium';
var _useContext = useContext(FormContext),
useFormInput = _useContext.useFormInput;
var ref = useForwardedRef(refArg);
var _useFormInput = useFormInput(name, valueArg, defaultValue),
value = _useFormInput[0],
setValue = _useFormInput[1]; // parse format and build a formal schema we can use elsewhere
var schema = useMemo(function () {
return formatToSchema(format);
}, [format]); // mask is only used when a format is provided
var mask = useMemo(function () {
if (!schema) return undefined;
return schema.map(function (part) {
var _char = part[0].toLowerCase();
if (_char === 'm' || _char === 'd' || _char === 'y') {
return {
placeholder: part,
length: [1, part.length],
regexp: new RegExp("^[0-9]{1," + part.length + "}$")
};
}
return {
fixed: part
};
});
}, [schema]); // textValue is only used when a format is provided
var _useState = useState(schema ? valueToText(value, schema) : undefined),
textValue = _useState[0],
setTextValue = _useState[1]; // We need to distinguish between the caller changing a Form value
// and the user typing a date that he isn't finished with yet.
// To track this, we keep track of the internalValue from interacting
// within this component. If the value has changed outside of this
// component, we reset the textValue.
var _useState2 = useState(value),
internalValue = _useState2[0],
setInternalValue = _useState2[1];
useEffect(function () {
if (schema && !!value !== !!internalValue) {
setTextValue(valueToText(value, schema));
setInternalValue(value);
}
}, [internalValue, schema, value]); // when format and not inline, whether to show the Calendar in a Drop
var _useState3 = useState(),
open = _useState3[0],
setOpen = _useState3[1];
var range = Array.isArray(value);
var calendar = /*#__PURE__*/React.createElement(Calendar, _extends({
ref: inline ? ref : undefined,
id: inline && !format ? id : undefined,
range: range,
date: range ? undefined : value,
dates: range ? [value] : undefined,
onSelect: disabled ? undefined : function (nextValue) {
var normalizedValue;
if (range && Array.isArray(nextValue)) {
normalizedValue = nextValue[0];
} // clicking an edge date removes it
else if (range) normalizedValue = [nextValue, nextValue];else normalizedValue = nextValue;
if (schema) setTextValue(valueToText(normalizedValue, schema));
setValue(normalizedValue);
setInternalValue(normalizedValue);
if (_onChange) _onChange({
value: normalizedValue
});
if (open && !range) setOpen(false);
}
}, calendarProps));
if (!format) {
// When no format is specified, we don't give the user a way to type
if (inline) return calendar;
return /*#__PURE__*/React.createElement(DropButton, _extends({
ref: ref,
id: id,
dropProps: _extends({
align: {
top: 'bottom',
left: 'left'
}
}, dropProps),
dropContent: calendar,
icon: /*#__PURE__*/React.createElement(CalendarIcon, {
size: iconSize
})
}, buttonProps));
}
var input = /*#__PURE__*/React.createElement(FormContext.Provider, {
key: "input" // don't let MaskedInput drive the Form
,
value: {
useFormInput: function useFormInput(_, val) {
return [val, function () {}];
}
}
}, /*#__PURE__*/React.createElement(Keyboard, {
onEsc: open ? function () {
return setOpen(false);
} : undefined
}, /*#__PURE__*/React.createElement(MaskedInput, _extends({
ref: ref,
id: id,
name: name,
icon: /*#__PURE__*/React.createElement(CalendarIcon, {
size: iconSize
}),
reverse: true,
disabled: disabled,
mask: mask
}, inputProps, rest, {
value: textValue,
onChange: function onChange(event) {
var nextTextValue = event.target.value;
setTextValue(nextTextValue);
var nextValue = textToValue(nextTextValue, schema); // update value even when undefined
setValue(nextValue);
setInternalValue(nextValue || '');
if (_onChange) {
event.persist(); // extract from React synthetic event pool
var adjustedEvent = event;
adjustedEvent.value = nextValue;
_onChange(adjustedEvent);
}
},
onFocus: function onFocus(event) {
setOpen(true);
if (_onFocus) _onFocus(event);
}
}))));
if (inline) {
return /*#__PURE__*/React.createElement(Box, null, input, calendar);
}
if (open) {
return [input, /*#__PURE__*/React.createElement(Drop, _extends({
overflow: "visible",
key: "drop",
id: id ? id + "__drop" : undefined,
target: ref.current,
align: _extends({
top: 'bottom',
left: 'left'
}, dropProps),
onEsc: function onEsc() {
return setOpen(false);
},
onClickOutside: function onClickOutside() {
return setOpen(false);
}
}, dropProps), calendar)];
}
return input;
});
DateInput.displayName = 'DateInput';
var DateInputDoc;
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line global-require
DateInputDoc = require('./doc').doc(DateInput);
}
var DateInputWrapper = DateInputDoc || DateInput;
export { DateInputWrapper as DateInput };