@harvest-profit/npk
Version:
NPK UI Design System
164 lines • 7.97 kB
JavaScript
;
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