UNPKG

@harvest-profit/npk

Version:
164 lines 7.97 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const useMask_1 = __importDefault(require("../hooks/useMask")); const masks_1 = require("../Input/masks"); const BaseInput_1 = require("../BaseInput/BaseInput"); // Handles the individual segments of the date/time input const InputSegment = ({ segment, setIsFocused: externalSetIsFocused, value: externalValue, onChange: externalOnChange, onChangeFullValue, dateValue, ...props }) => { let mask = null; let placeholder = ''; let defaultAriaValueNow = undefined; const today = new Date(); const maskProps = { dateValue }; switch (segment) { case 'year': mask = masks_1.calendarYearMask; placeholder = 'yyyy'; defaultAriaValueNow = today.getFullYear(); break; case 'month': mask = masks_1.calendarMonthMask; placeholder = 'mm'; defaultAriaValueNow = today.getMonth() + 1; break; case 'monthName': mask = masks_1.calendarMonthNameMask; placeholder = 'mmm'; defaultAriaValueNow = today.getMonth() + 1; break; case 'day': mask = masks_1.calendarDayMask; placeholder = 'dd'; defaultAriaValueNow = today.getDate(); break; case 'hour': mask = masks_1.calendarHourMask; placeholder = '––'; defaultAriaValueNow = today.getHours(); break; case 'minute': mask = masks_1.calendarMinuteMask; placeholder = '––'; defaultAriaValueNow = today.getMinutes(); break; case 'TOD': mask = masks_1.calendarTimeOfDayMask; defaultAriaValueNow = today.getHours() > 11 ? '1' : '0'; placeholder = 'AM'; break; } const formatValue = (inputValue) => { if (inputValue === '0' && segment !== 'minute') return ''; let strValue = `${inputValue}`; if (inputValue instanceof Date) strValue = inputValue.toISOString(); if (strValue === 'null' || strValue === 'undefined') strValue = ''; return mask(maskProps).formatter(`${strValue || ''}`); }; const inputContext = (0, react_1.useContext)(BaseInput_1.BaseInputContext) || {}; const [value, setValue] = (0, react_1.useState)(formatValue(externalValue) || ''); const validatingValueRef = (0, react_1.useRef)(value); const [isFocused, setIsFocused] = (0, react_1.useState)(false); const [isPasted, setIsPasted] = (0, react_1.useState)(false); const inputMask = (0, useMask_1.default)({ mask: mask(maskProps), // Since we are using a span[contentEditable] as the input, we need to use the valueRef to get the current value instead of relying on event.target.value. valueRef: validatingValueRef, navigateWithArrows: true, // On top of input validation, we also need to process the key strokes to update the value since we are using a span[contentEditable] as the input. // This allows us to autocomplete certain values (e.g. a = AM, p = PM) and also handle backspace/delete. onKeyDown: (e, specialKey) => { let newValue = validatingValueRef.current; if (!specialKey) { newValue = newValue + e.key; } else if (e.key === 'Backspace' || e.key === 'Delete') { if (segment === 'TOD') newValue = ''; newValue = newValue.slice(0, newValue.length - 1); } else { if (e.key !== 'Tab') e.preventDefault(); return; } if (segment === 'TOD') { setValue((0, masks_1.calendarTimeOfDayMask)().autoComplete(newValue, e.key)); } else if (segment === 'monthName') { setValue((0, masks_1.calendarMonthNameMask)().autoComplete(newValue, e.key)); } else { setValue(newValue); } if ((e.metaKey || e.ctrlKey) && e.key === 'v') setValue(''); if (!e.metaKey && !e.ctrlKey) e.preventDefault(); } }); (0, react_1.useEffect)(() => { // if the value is a complete value (2 digits for month, day, hour, minute, 4 digits for year) // We want to set the validatingValueRef to an empty string so that when the input is focused again, // the user can type in a complete new value instead of having to delete the old value if (['month', 'day', 'hour', 'minute'].includes(segment) && value.length === 2) { validatingValueRef.current = ''; } else if (['year'].includes(segment) && value.length === 4) { validatingValueRef.current = ''; } else if (['monthName'].includes(segment) && value.length >= 3) { validatingValueRef.current = ''; } else { validatingValueRef.current = value; } // Publish the change to the parent component if the value is different const emptyIfZero = (val) => val === '0' ? '' : val; if (externalOnChange && formatValue(externalValue) !== formatValue(value)) externalOnChange(emptyIfZero(value)); }, [value]); (0, react_1.useEffect)(() => { if ((!isFocused || isPasted) && formatValue(externalValue) !== formatValue(value)) { setValue(formatValue(externalValue)); if (isPasted) setIsPasted(false); } }, [externalValue]); const onBlur = (e) => { setIsFocused(false); if (externalSetIsFocused) externalSetIsFocused(false); setValue(inputMask.formatter(value)); }; const onFocus = (e) => { setTimeout(() => { setIsFocused(true); if (externalSetIsFocused) externalSetIsFocused(true); }, 100); }; // Use a placeholder if the value is empty const valueIsEmpty = value === '' || value === undefined || value === null; const passthroughprops = [...Object.keys(props).filter(key => key.startsWith('aria'))]; const filteredProps = { ...passthroughprops.reduce((agg, key) => ({ ...agg, [key]: props[key] }), {}) }; const onPaste = (event) => { setIsPasted(true); // Get the text from the clipboard const pastedData = event.clipboardData.getData('text'); onChangeFullValue(new Date(pastedData)); event.preventDefault(); }; return ((0, jsx_runtime_1.jsxs)("span", { tabIndex: 0, "data-component": "input-segment", onKeyDown: inputMask.onKeyDown, onClick: e => e.preventDefault(), onBlur: onBlur, onFocus: onFocus, enterKeyHint: "next", inputMode: "numeric", contentEditable: true, suppressContentEditableWarning: true, role: "spinbutton", style: { minWidth: segment === 'year' ? '2.35em' : '1.35em', caretColor: 'transparent' }, "data-placeholder": valueIsEmpty, "aria-labelledby": `${inputContext['aria-labelledby'] || `${inputContext.labelingIds.label || ''} ${inputContext.labelingIds.additional || ''}`} ${inputContext.labelingIds.uuid}-${segment}`, "aria-valuenow": defaultAriaValueNow, "aria-valuetext": valueIsEmpty ? 'Empty' : value, onPaste: onPaste, ...inputMask.aria || {}, ...filteredProps, children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": true, id: `${inputContext.labelingIds.uuid}-${segment}`, "aria-label": props['aria-label'] }), valueIsEmpty ? placeholder : value] })); }; exports.default = InputSegment; //# sourceMappingURL=InputSegment.js.map