UNPKG

@itwin/itwinui-react

Version:

A react component library for iTwinUI

475 lines (474 loc) 14.3 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true, }); Object.defineProperty(exports, 'TimePicker', { enumerable: true, get: function () { return TimePicker; }, }); const _interop_require_default = require('@swc/helpers/_/_interop_require_default'); const _interop_require_wildcard = require('@swc/helpers/_/_interop_require_wildcard'); const _classnames = /*#__PURE__*/ _interop_require_default._( require('classnames'), ); const _react = /*#__PURE__*/ _interop_require_wildcard._(require('react')); const _index = require('../../utils/index.js'); const isSameHour = (date1, date2, meridiem) => { let adjustedHours = meridiem ? formatHourFrom12(date1.getHours(), meridiem) : date1.getHours(); if (!!meridiem) return !!date2 && adjustedHours % 12 === date2.getHours() % 12; return !!date2 && adjustedHours === date2.getHours(); }; const isSameMinute = (date1, date2) => !!date2 && date1.getMinutes() === date2.getMinutes(); const isSameSecond = (date1, date2) => !!date2 && date1.getSeconds() === date2.getSeconds(); const isSameTime = (date1, date2, precision, meridiem) => { let isSameTime = true; switch (precision) { case 'seconds': isSameTime = isSameSecond(date1, date2); if (!isSameTime) break; case 'minutes': isSameTime = isSameMinute(date1, date2); if (!isSameTime) break; case 'hours': isSameTime = isSameHour(date1, date2, meridiem); } return isSameTime; }; const isSameMeridiem = (meridiem, date) => !!date && ('AM' === meridiem ? date.getHours() < 12 : date.getHours() >= 12); const formatHourFrom12 = (hour, meridiem) => { let adjustedHour = hour % 12; return 'PM' === meridiem ? adjustedHour + 12 : adjustedHour; }; const setHours = (hour, date) => new Date( date.getFullYear(), date.getMonth(), date.getDate(), hour, date.getMinutes(), date.getSeconds(), ); const defaultCombinedRenderer = (date, precision) => { let dateString = ''; switch (precision) { case 'seconds': dateString = ':' + date.getSeconds().toLocaleString(void 0, { minimumIntegerDigits: 2, }); case 'minutes': dateString = ':' + date.getMinutes().toLocaleString(void 0, { minimumIntegerDigits: 2, }) + dateString; case 'hours': dateString = date.getHours().toLocaleString(void 0, { minimumIntegerDigits: 2, }) + dateString; } return dateString; }; const TimePicker = _react.forwardRef((props, forwardedRef) => { let { date, onChange, use12Hours = false, precision = 'minutes', hourStep = 1, minuteStep = 1, secondStep = 1, setFocusHour = false, hourRenderer = (date) => date.getHours().toLocaleString(void 0, { minimumIntegerDigits: 2, }), minuteRenderer = (date) => date.getMinutes().toLocaleString(void 0, { minimumIntegerDigits: 2, }), secondRenderer = (date) => date.getSeconds().toLocaleString(void 0, { minimumIntegerDigits: 2, }), meridiemRenderer = (meridiem) => meridiem, useCombinedRenderer = false, combinedRenderer = defaultCombinedRenderer, className, ...rest } = props; let [selectedTime, setSelectedTime] = _react.useState(date); let [focusedTime, setFocusedTime] = _react.useState( selectedTime ?? new Date(), ); let [meridiem, setMeridiem] = _react.useState( use12Hours ? (focusedTime?.getHours() > 11 ? 'PM' : 'AM') : void 0, ); _react.useEffect(() => { setFocusedTime(date ?? new Date()); setSelectedTime(date); }, [date]); let onHourClick = (date) => { let adjustedHour = use12Hours ? formatHourFrom12(date.getHours(), meridiem) : date.getHours(); let adjustedSelectedTime = setHours( adjustedHour, selectedTime ?? new Date(), ); updateCurrentTime(adjustedSelectedTime); }; let onTimeClick = (date) => { let adjustedHour = use12Hours ? formatHourFrom12(date.getHours(), meridiem) : date.getHours(); let adjustedSelectedTime = setHours(adjustedHour, date); updateCurrentTime(adjustedSelectedTime); }; let onMeridiemClick = (value) => { let adjustedSelectedTime = selectedTime ?? new Date(); let currentHours = adjustedSelectedTime.getHours(); setMeridiem(value); if ('AM' === value && currentHours > 11) adjustedSelectedTime = setHours(currentHours - 12, adjustedSelectedTime); if ('PM' === value && currentHours <= 12) adjustedSelectedTime = setHours(currentHours + 12, adjustedSelectedTime); updateCurrentTime(adjustedSelectedTime); }; let updateCurrentTime = (time) => { let adjustedTime = time; if ('hours' === precision) adjustedTime = new Date( time.getFullYear(), time.getMonth(), time.getDate(), time.getHours(), 0, 0, ); if ('minutes' === precision) adjustedTime = new Date( time.getFullYear(), time.getMonth(), time.getDate(), time.getHours(), time.getMinutes(), 0, ); setFocusedTime(adjustedTime); setSelectedTime(adjustedTime); onChange?.(adjustedTime); }; let onHourFocus = (date) => { let adjustedHour = use12Hours ? formatHourFrom12(date.getHours(), meridiem) : date.getHours(); setFocusedTime(setHours(adjustedHour, focusedTime)); }; let onTimeFocus = (date) => { let adjustedHour = use12Hours ? formatHourFrom12(date.getHours(), meridiem) : date.getHours(); setFocusedTime(setHours(adjustedHour, date)); }; let onMeridiemFocus = (value) => { let adjustedSelectedTime = selectedTime ?? new Date(); let currentHours = adjustedSelectedTime.getHours(); if ('AM' === value && currentHours > 11) { setMeridiem(value); adjustedSelectedTime = setHours(currentHours - 12, adjustedSelectedTime); } if ('PM' === value && currentHours <= 12) { setMeridiem(value); adjustedSelectedTime = setHours(currentHours + 12, adjustedSelectedTime); } setFocusedTime(adjustedSelectedTime); }; let generateDataList = (size, value, step) => { let data = []; for (let i = 0; i < size; i++) if (i % step === 0) data.push(value(i)); return data; }; let time = _react.useMemo(() => { let time = selectedTime ?? new Date(); let data = []; let hoursArray = Array.from(Array(use12Hours ? 12 : 24).keys()) .filter((i) => i % hourStep === 0) .map((i) => (use12Hours && 0 === i ? 12 : i)); let minutesArray = Array.from(Array(60).keys()).filter( (i) => i % minuteStep === 0, ); let secondsArray = Array.from(Array(60).keys()).filter( (i) => i % secondStep === 0, ); hoursArray.forEach((hour) => { if ('hours' === precision) data.push( new Date( time.getFullYear(), time.getMonth(), time.getDate(), hour, time.getMinutes(), time.getSeconds(), ), ); else minutesArray.forEach((minute) => { if ('minutes' === precision) data.push( new Date( time.getFullYear(), time.getMonth(), time.getDate(), hour, minute, time.getSeconds(), ), ); else secondsArray.forEach((second) => { data.push( new Date( time.getFullYear(), time.getMonth(), time.getDate(), hour, minute, second, ), ); }); }); }); return data; }, [hourStep, minuteStep, secondStep, selectedTime, use12Hours, precision]); let hours = _react.useMemo(() => { let time = selectedTime ?? new Date(); return generateDataList( use12Hours ? 12 : 24, (i) => new Date( time.getFullYear(), time.getMonth(), time.getDate(), use12Hours && 0 === i ? 12 : i, time.getMinutes(), time.getSeconds(), ), hourStep, ); }, [hourStep, selectedTime, use12Hours]); let minutes = _react.useMemo(() => { let time = selectedTime ?? new Date(); return generateDataList( 60, (i) => new Date( time.getFullYear(), time.getMonth(), time.getDate(), time.getHours(), i, time.getSeconds(), ), minuteStep, ); }, [minuteStep, selectedTime]); let seconds = _react.useMemo(() => { let time = selectedTime ?? new Date(); return generateDataList( 60, (i) => new Date( time.getFullYear(), time.getMonth(), time.getDate(), time.getHours(), time.getMinutes(), i, ), secondStep, ); }, [secondStep, selectedTime]); return _react.createElement( _index.Box, { className: (0, _classnames.default)('iui-time-picker', className), ref: forwardedRef, ...rest, }, useCombinedRenderer ? _react.createElement(TimePickerColumn, { data: time, isSameFocused: (val) => isSameTime( val, focusedTime, precision, use12Hours ? meridiem : void 0, ), isSameSelected: (val) => isSameTime( val, selectedTime, precision, use12Hours ? meridiem : void 0, ), onFocusChange: onTimeFocus, onSelectChange: onTimeClick, setFocus: setFocusHour, precision: precision, valueRenderer: combinedRenderer, }) : _react.createElement( _react.Fragment, null, _react.createElement(TimePickerColumn, { data: hours, isSameFocused: (val) => isSameHour(val, focusedTime, use12Hours ? meridiem : void 0), isSameSelected: (val) => isSameHour(val, selectedTime, use12Hours ? meridiem : void 0), onFocusChange: onHourFocus, onSelectChange: onHourClick, setFocus: setFocusHour, valueRenderer: hourRenderer, }), 'hours' !== precision && _react.createElement(TimePickerColumn, { data: minutes, isSameFocused: (val) => isSameMinute(val, focusedTime), isSameSelected: (val) => isSameMinute(val, selectedTime), onFocusChange: (date) => setFocusedTime(date), onSelectChange: (date) => updateCurrentTime(date), valueRenderer: minuteRenderer, }), 'seconds' === precision && _react.createElement(TimePickerColumn, { data: seconds, isSameFocused: (val) => isSameSecond(val, focusedTime), isSameSelected: (val) => isSameSecond(val, selectedTime), onFocusChange: (date) => setFocusedTime(date), onSelectChange: (date) => updateCurrentTime(date), valueRenderer: secondRenderer, }), ), use12Hours && _react.createElement(TimePickerColumn, { data: ['AM', 'PM'], isSameFocused: (val) => isSameMeridiem(val, focusedTime), isSameSelected: (val) => isSameMeridiem(val, selectedTime), onFocusChange: (date) => onMeridiemFocus(date), onSelectChange: (value) => onMeridiemClick(value), valueRenderer: meridiemRenderer, className: 'iui-period', }), ); }); if ('development' === process.env.NODE_ENV) TimePicker.displayName = 'TimePicker'; const TimePickerColumn = (props) => { let { data, onFocusChange, onSelectChange, isSameFocused, isSameSelected, setFocus = false, valueRenderer, precision = 'minutes', className = 'iui-time', } = props; let needFocus = _react.useRef(setFocus); let handleTimeKeyDown = ( event, maxValue, onFocus, onSelect, currentValue, ) => { if (event.altKey) return; switch (event.key) { case 'ArrowDown': if (currentValue + 1 > maxValue) break; onFocus(currentValue + 1); needFocus.current = true; event.preventDefault(); break; case 'ArrowUp': if (currentValue - 1 < 0) break; onFocus(currentValue - 1); needFocus.current = true; event.preventDefault(); break; case 'Enter': case ' ': case 'Spacebar': onSelect(currentValue); event.preventDefault(); break; } }; return _react.createElement( _index.Box, { className: `${className}`, }, _react.createElement( 'ol', null, data.map((value, index) => { let isSameFocus = isSameFocused(value); return _react.createElement( _index.Box, { as: 'li', onKeyDown: (event) => { handleTimeKeyDown( event, data.length - 1, (index) => onFocusChange(data[index]), (index) => onSelectChange(data[index]), index, ); }, className: (0, _classnames.default)({ 'iui-selected': isSameSelected(value), }), key: index, tabIndex: isSameFocus ? 0 : void 0, ref: (ref) => { if (!ref || !isSameFocus) return; setTimeout(() => { ref.scrollIntoView({ block: 'nearest', inline: 'nearest', }); if (needFocus.current) { ref.focus(); needFocus.current = false; } }); }, onClick: () => { onSelectChange(value); }, }, valueRenderer(value, precision), ); }), ), ); };