UNPKG

@razorpay/blade

Version:

The Design System that powers Razorpay

207 lines (199 loc) 8.33 kB
import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; import React__default from 'react'; import styled from 'styled-components'; import { SpinWheel } from './SpinWheel.web.js'; import { TimePickerFooter } from './TimePickerFooter.web.js'; import { getNearestStepValue, createDateFromSelection } from './utils.js'; import '../Divider/index.js'; import '../BladeProvider/index.js'; import '../Box/BaseBox/index.js'; import { useIsMobile } from '../../utils/useIsMobile.js'; import '../../tokens/global/index.js'; import '../../utils/makeSize/index.js'; import { jsxs, jsx, Fragment } from 'react/jsx-runtime'; import { BaseBox } from '../Box/BaseBox/BaseBox.web.js'; import useTheme from '../BladeProvider/useTheme.js'; import { makeSize } from '../../utils/makeSize/makeSize.js'; import { size } from '../../tokens/global/size.js'; import { Divider } from '../Divider/Divider.js'; var StyledFadeContainer = /*#__PURE__*/styled(BaseBox).withConfig({ displayName: "TimePickerContentweb__StyledFadeContainer", componentId: "sc-1c0gid8-0" })(["position:relative;border-radius:", "px;&::before{content:'';position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient( to bottom,", " 0px,transparent 48px,transparent calc(100% - 48px),", " 100% );pointer-events:none;z-index:10;border-radius:", "px;}"], function (_ref) { var theme = _ref.theme; return theme.border.radius.small; }, function (_ref2) { var theme = _ref2.theme; return theme.colors.surface.background.gray.intense; }, function (_ref3) { var theme = _ref3.theme; return theme.colors.surface.background.gray.intense; }, function (_ref4) { var theme = _ref4.theme; return theme.border.radius.small; }); /** * Content component for TimePicker dropdown * Contains the time selection wheels and footer */ var TimePickerContent = function TimePickerContent(_ref5) { var setSelectedTime = _ref5.setSelectedTime, selectedHour = _ref5.selectedHour, selectedMinute = _ref5.selectedMinute, selectedPeriod = _ref5.selectedPeriod, timeFormat = _ref5.timeFormat, minuteStep = _ref5.minuteStep, showFooterActions = _ref5.showFooterActions, onApply = _ref5.onApply, onCancel = _ref5.onCancel; var isMobile = useIsMobile(); var _useTheme = useTheme(), theme = _useTheme.theme; var currentHour = selectedHour; var currentMinute = selectedMinute; var currentPeriod = selectedPeriod; var is12HourFormat = timeFormat === '12h'; // Roving tabindex + focus management across wheels var _React$useState = React__default.useState(0), _React$useState2 = _slicedToArray(_React$useState, 2), activeWheelIndex = _React$useState2[0], setActiveWheelIndex = _React$useState2[1]; var hourRef = React__default.useRef(null); var minuteRef = React__default.useRef(null); var periodRef = React__default.useRef(null); var wheelRefs = is12HourFormat ? [hourRef, minuteRef, periodRef] : [hourRef, minuteRef]; var focusWheel = function focusWheel(index) { setActiveWheelIndex(index); // ensure tabindex update applies before focusing requestAnimationFrame(function () { var _wheelRefs$index; (_wheelRefs$index = wheelRefs[index]) === null || _wheelRefs$index === void 0 || (_wheelRefs$index = _wheelRefs$index.current) === null || _wheelRefs$index === void 0 || _wheelRefs$index.focus(); }); }; var handleContainerKeyDown = function handleContainerKeyDown(e) { // Up/Down should be handled by individual wheels; Left/Right move to next wheel if (e.key === 'ArrowRight') { e.preventDefault(); var next = Math.min(activeWheelIndex + 1, wheelRefs.length - 1); if (next !== activeWheelIndex) focusWheel(next); } else if (e.key === 'ArrowLeft') { e.preventDefault(); var prev = Math.max(activeWheelIndex - 1, 0); if (prev !== activeWheelIndex) focusWheel(prev); } }; var handleContainerFocus = function handleContainerFocus(e) { var target = e.target; var idx = wheelRefs.findIndex(function (ref) { return ref.current === target; }); if (idx !== -1 && idx !== activeWheelIndex) { setActiveWheelIndex(idx); } }; // Generate values for each wheel with leading zeros var hourValues = is12HourFormat ? Array.from({ length: 12 }, function (_, i) { return String(i + 1).padStart(2, '0'); }) : Array.from({ length: 24 }, function (_, i) { return String(i).padStart(2, '0'); }); var minuteValues = Array.from({ length: 60 / minuteStep }, function (_, i) { return String(i * minuteStep).padStart(2, '0'); }); var periodValues = ['AM', 'PM']; // Calculate display value for minute wheel positioning when minuteStep > 1 // This allows typed values like "03" to position at nearest step "00" while preserving actual value var displayMinute = minuteStep > 1 ? getNearestStepValue(currentMinute, minuteStep) : undefined; // Handle value changes - directly update selectedTime var handleHourChange = function handleHourChange(value) { var hour = Number(value); var newDate = createDateFromSelection(currentHour, currentMinute, currentPeriod, timeFormat, hour); setSelectedTime(newDate); }; var handleMinuteChange = function handleMinuteChange(value) { var minute = Number(value); var newDate = createDateFromSelection(currentHour, currentMinute, currentPeriod, timeFormat, undefined, minute); setSelectedTime(newDate); }; var handlePeriodChange = function handlePeriodChange(value) { var period = value; var newDate = createDateFromSelection(currentHour, currentMinute, currentPeriod, timeFormat, undefined, undefined, period); setSelectedTime(newDate); }; var handleApply = function handleApply() { var newDate = createDateFromSelection(currentHour, currentMinute, currentPeriod, timeFormat); setSelectedTime(newDate); onApply(); }; return /*#__PURE__*/jsxs(BaseBox, { display: "flex", className: "timepicker-content", flexDirection: "column", height: showFooterActions ? makeSize(size[250]) : makeSize(size[196]), width: isMobile ? '100%' : makeSize(size[198]), "data-allow-scroll": "true", children: [/*#__PURE__*/jsxs(StyledFadeContainer, { theme: theme, display: "flex", flexDirection: "row", justifyContent: "center", alignItems: "flex-start", margin: ['spacing.4', makeSize(size[1])], onKeyDown: handleContainerKeyDown, onFocus: handleContainerFocus, children: [/*#__PURE__*/jsx(BaseBox, { position: "absolute", top: "50%", left: "spacing.0", right: "spacing.0", height: "36px", transform: "translateY(-50%)", backgroundColor: "interactive.background.gray.faded", pointerEvents: "none", zIndex: 1 }), /*#__PURE__*/jsx(SpinWheel, { className: "timepicker-hour-wheel", label: "Hour", values: hourValues, selectedValue: String(currentHour).padStart(2, '0'), onChange: handleHourChange, scrollContainerRef: hourRef, tabIndex: activeWheelIndex === 0 ? 0 : -1 }), /*#__PURE__*/jsx(Divider, { orientation: "vertical" }), /*#__PURE__*/jsx(SpinWheel, { className: "timepicker-minute-wheel", label: "Min", values: minuteValues, selectedValue: String(currentMinute).padStart(2, '0'), displayValue: displayMinute ? String(displayMinute).padStart(2, '0') : undefined, onChange: handleMinuteChange, scrollContainerRef: minuteRef, tabIndex: activeWheelIndex === 1 ? 0 : -1 }), is12HourFormat && /*#__PURE__*/jsxs(Fragment, { children: [/*#__PURE__*/jsx(Divider, { orientation: "vertical" }), /*#__PURE__*/jsx(SpinWheel, { className: "timepicker-period-wheel", label: "Period", values: periodValues, selectedValue: currentPeriod, onChange: handlePeriodChange, scrollContainerRef: periodRef, tabIndex: activeWheelIndex === 2 ? 0 : -1 })] })] }), showFooterActions && /*#__PURE__*/jsx(TimePickerFooter, { onApply: handleApply, onCancel: onCancel })] }); }; export { TimePickerContent }; //# sourceMappingURL=TimePickerContent.web.js.map