UNPKG

@harvest-profit/npk

Version:
207 lines 12.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); 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 = __importStar(require("react")); const BaseInput_1 = __importDefault(require("../BaseInput")); const Group_1 = __importDefault(require("../Input/Group")); const Calendar_1 = __importDefault(require("../Calendar")); const Menu_1 = __importDefault(require("../Menu")); const Button_1 = __importDefault(require("../Button")); const regular_1 = require("@harvest-profit/npk/icons/regular"); const InputSegment_1 = __importDefault(require("./InputSegment")); const utils_1 = require("../Calendar/utils"); const GranularityInclude = ({ children, active }) => active ? children : null; const hourAndTODfromDate = (date) => { if (!date) return {}; const hours = date.getHours(); const tod = hours >= 12 ? 'PM' : 'AM'; const hour = hours % 12 || 12; // Convert to 12-hour format return { hour, tod }; }; // Shifts focus to the next input segment const useDateGroupFocus = () => { const onMouseDown = (e) => { if (document.activeElement === e.target) return; if (!e.target.ariaHidden && e.target.dataset.component === 'input-segment') return; const rootNode = e.target?.dataset?.component === 'input-group' ? e.target : e.target?.closest('[data-component="input-group"]'); if (rootNode && rootNode.contains(document.activeElement)) { e.preventDefault(); return; } const focusNearest = (node) => { if (!node) return; if (node.ariaHidden) focusNearest(node.nextElementSibling); if (node.dataset.component === 'input-group') focusNearest(node.firstElementChild); node.focus(); }; focusNearest(e.target); }; return { onMouseDown }; }; // Simple hook to manage state and call a callback when the value changes const useOnChangeState = (initialValue, cb) => { const [state, setState] = (0, react_1.useState)(initialValue); return [state, (newValue) => { if (newValue === state) return; setState(newValue); if (cb && newValue) cb(newValue); }]; }; // Controls the individual segments of the date input const DateInputInternal = ({ onChange = (_value) => null, value, includeYear = true, monthAsName = false, granularity = 'day', excludeGroup = false, ...props }) => { let updateValue = new Date(); // When updating a new date, we build off the current date and then set individual values let segmentDateValue = value; // We then use a date segment and a time segment for the values of the segments let segmentTimeValue = value; // If "value" is not a complete date, we do not fill out the input. Time will be null if the time is 00:00:00.000 if (value instanceof Date && !isNaN(value.getTime())) { updateValue = value; if (value.getHours() === 0 && value.getMinutes() === 0 && value.getMilliseconds() === 0) { segmentTimeValue = null; } } else { segmentDateValue = null; segmentTimeValue = null; } const toMonthValue = monthAsName ? utils_1.monthIndexToAbbrev : utils_1.monthIndexToHuman; const fromMonthValue = monthAsName ? utils_1.monthAbbrevToIndex : utils_1.monthHumanToIndex; // Specify the rules of getting and setting the values of the segments const [monthValue, setMonthValue] = useOnChangeState(toMonthValue(segmentDateValue?.getMonth()), (month) => onChange(new Date(new Date(updateValue).setMonth(fromMonthValue(month))))); const [dayValue, setDayValue] = useOnChangeState(segmentDateValue?.getDate(), (day => onChange(new Date(new Date(updateValue).setDate(day))))); const [yearValue, setYearValue] = useOnChangeState(segmentDateValue?.getFullYear(), (year => onChange(new Date(new Date(updateValue).setFullYear(year))))); const [minuteValue, setMinuteValue] = useOnChangeState(segmentTimeValue?.getMinutes(), (minutes => onChange(new Date(new Date(updateValue).setMinutes(minutes))))); const [todValue, setTODValue] = useOnChangeState(hourAndTODfromDate(segmentTimeValue).tod, (tod) => { const hours = new Date(updateValue).getHours(); if (tod === 'AM' && hours >= 12) { onChange(new Date(new Date(updateValue).setHours(hours - 12))); } else if (tod === 'PM' && hours < 12) { onChange(new Date(new Date(updateValue).setHours(hours + 12))); } }); const [hourValue, setHourValue] = useOnChangeState(hourAndTODfromDate(segmentTimeValue).hour, (hour) => { const intHours = parseInt(hour); if (todValue === 'AM' && intHours === 12) { // hours are tricky because of the 12-hour format. Native date objects are 24-hour format onChange(new Date(new Date(updateValue).setHours(0))); } else if (todValue === 'PM' && intHours < 12) { onChange(new Date(new Date(updateValue).setHours(intHours + 12))); } else { onChange(new Date(new Date(updateValue).setHours(hour))); } }); const ref = (0, react_1.useRef)(null); const [isInputSegmentInFocus, setInputSegmentFocused] = (0, react_1.useState)(false); const [isFocused, setIsFocused] = (0, react_1.useState)(false); (0, react_1.useEffect)(() => { if (!isFocused) { // if the input is out of focus, we will accept updates from outside changes setMonthValue(toMonthValue(segmentDateValue?.getMonth())); setDayValue(segmentDateValue?.getDate()); setYearValue(segmentDateValue?.getFullYear()); setHourValue(hourAndTODfromDate(segmentTimeValue).hour); setTODValue(hourAndTODfromDate(segmentTimeValue).tod); setMinuteValue(segmentDateValue?.getMinutes()); } }, [`${value}`]); (0, react_1.useEffect)(() => { setTimeout(() => { if (ref.current) { if (!isFocused && ref.current.contains(document.activeElement)) { setIsFocused(true); if (props.onFocus) props.onFocus({ target: ref.current }); } else if (isFocused && !ref.current.contains(document.activeElement)) { setIsFocused(false); if (props.onBlur) props.onBlur({ target: ref.current }); } } }, 10); }, [isInputSegmentInFocus]); const dateParts = []; if (['day', 'month', 'minute'].includes(granularity)) { dateParts.push((0, jsx_runtime_1.jsx)(InputSegment_1.default, { segment: monthAsName ? 'monthName' : 'month', setIsFocused: setInputSegmentFocused, value: monthValue, onChange: setMonthValue })); } if (['day', 'minute'].includes(granularity)) { dateParts.push((0, jsx_runtime_1.jsx)(InputSegment_1.default, { segment: "day", setIsFocused: setInputSegmentFocused, value: dayValue, onChange: setDayValue, onOldChange: (day => onChange(new Date(new Date(updateValue).setDate(day)))) })); } if (includeYear && ['day', 'month', 'year', 'minute'].includes(granularity)) { dateParts.push((0, jsx_runtime_1.jsx)(InputSegment_1.default, { segment: "year", setIsFocused: setInputSegmentFocused, value: yearValue, onChange: setYearValue, onOldChange: (year => onChange(new Date(new Date(updateValue).setFullYear(year)))) })); } const contents = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [dateParts.map((part, index) => { return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [index !== 0 && (0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", "data-component": "input-segment", children: monthAsName ? ' ' : '/' }), part] }, index)); }), (0, jsx_runtime_1.jsxs)(GranularityInclude, { active: ['minute'].includes(granularity), children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", "data-component": "input-segment", children: ", " }), (0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", "data-component": "input-segment" })] }), (0, jsx_runtime_1.jsxs)(GranularityInclude, { active: ['minute', 'time'].includes(granularity), children: [(0, jsx_runtime_1.jsx)(InputSegment_1.default, { segment: "hour", setIsFocused: setInputSegmentFocused, value: hourValue, onChange: setHourValue }), (0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", "data-component": "input-segment", children: ":" }), (0, jsx_runtime_1.jsx)(InputSegment_1.default, { segment: "minute", setIsFocused: setInputSegmentFocused, value: minuteValue, onChange: setMinuteValue }), (0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", "data-component": "input-segment" }), (0, jsx_runtime_1.jsx)(InputSegment_1.default, { segment: "TOD", setIsFocused: setInputSegmentFocused, value: todValue, onChange: setTODValue })] })] })); const dateGroupProps = useDateGroupFocus(); if (excludeGroup) { return ((0, jsx_runtime_1.jsx)(BaseInput_1.default, { containsSegments: true, contentsRef: ref, ...dateGroupProps, ...props, children: contents })); } return ((0, jsx_runtime_1.jsx)(Group_1.default, { containsSegments: true, contentsRef: ref, ...dateGroupProps, ...props, children: contents })); }; const DateInput = ({ visibleMonths = 1, autoDismiss = true, presets = false, picker = false, output = 'ISO', includeYear = true, monthAsName = false, onChange: onExternalChange = (_value) => null, value: externalValue, granularity = 'day', excludeGroup, ...props }) => { let value = externalValue; let onChange = onExternalChange; switch (output) { case 'ISO': value = (0, utils_1.fromISO)(value); onChange = (newValue) => onExternalChange((0, utils_1.toISO)(newValue)); break; case 'timestamp': value = (0, utils_1.fromTimestamp)(value); onChange = (newValue) => onExternalChange((0, utils_1.toTimestamp)(newValue)); break; default: break; } const extraProps = {}; if (picker) { extraProps.trailingVisual = ((0, jsx_runtime_1.jsxs)(Menu_1.default, { arrow: true, placement: "bottom", autoDismiss: false, children: [(0, jsx_runtime_1.jsx)(Button_1.default, { invisible: true, icon: regular_1.CalendarIcon, "aria-label": "Pick a date", tabIndex: -1 }), (0, jsx_runtime_1.jsx)(Menu_1.default.Overlay, { children: (0, jsx_runtime_1.jsx)(Calendar_1.default, { visibleMonths: visibleMonths, presets: presets, value: value, onChange: onChange, output: "date", autoDismiss: autoDismiss }) })] })); } return ((0, jsx_runtime_1.jsx)(DateInputInternal, { onChange: onChange, value: value, granularity: granularity, excludeGroup: excludeGroup, includeYear: includeYear, monthAsName: monthAsName, ...props, ...extraProps })); }; exports.default = DateInput; //# sourceMappingURL=DateInput.js.map