@razorpay/blade
Version:
The Design System that powers Razorpay
207 lines (199 loc) • 8.33 kB
JavaScript
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