@razorpay/blade
Version:
The Design System that powers Razorpay
520 lines (516 loc) • 23.5 kB
JavaScript
import _typeof from '@babel/runtime/helpers/typeof';
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
import { DatesProvider } from '@mantine/dates';
import React__default from 'react';
import { FloatingPortal, FloatingFocusManager } from '@floating-ui/react';
import { useI18nContext } from '@razorpay/i18nify-react';
import { MantineProvider } from '@mantine/core';
import dayjs from 'dayjs';
import { Calendar } from './Calendar.web.js';
import { PresetSideBar } from './QuickSelection/PresetSideBar.web.js';
import { useDatesState } from './useDatesState.js';
import { usePopup } from './usePopup.js';
import { CalendarFooter } from './CalendarFooter.web.js';
import { convertIntlToDayjsLocale, loadScript } from './utils.js';
import { shiftTimezone } from './shiftTimezone.js';
import { DatePickerInput } from './DateInput.web.js';
import { DatePickerFilterChip } from './FilterChipDatePicker/DatePickerFilterChip.web.js';
import '../Box/BaseBox/index.js';
import { useControllableState } from '../../utils/useControllable.js';
import '../../utils/index.js';
import { useId } from '../../utils/useId.js';
import '../../utils/makeAccessible/index.js';
import { useIsMobile } from '../../utils/useIsMobile.js';
import '../BottomSheet/index.js';
import '../../utils/logger/index.js';
import '../Box/styledProps/index.js';
import '../../utils/metaAttribute/index.js';
import { componentZIndices } from '../../utils/componentZIndices.js';
import '../../utils/makeAnalyticsAttribute/index.js';
import '../../utils/fireNativeEvent/index.js';
import { useListViewFilterContext } from '../ListView/ListViewFiltersContext.web.js';
import { useFilterChipGroupContext } from '../Dropdown/FilterChipGroupContext.web.js';
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
import useTheme from '../BladeProvider/useTheme.js';
import { fireNativeEvent } from '../../utils/fireNativeEvent/fireNativeEvent.web.js';
import { BaseBox } from '../Box/BaseBox/BaseBox.web.js';
import { logger } from '../../utils/logger/logger.js';
import { getStyledProps } from '../Box/styledProps/getStyledProps.js';
import { metaAttribute } from '../../utils/metaAttribute/metaAttribute.web.js';
import { MetaConstants } from '../../utils/metaAttribute/metaConstants.js';
import { makeAnalyticsAttribute } from '../../utils/makeAnalyticsAttribute/makeAnalyticsAttribute.js';
import { BottomSheet } from '../BottomSheet/BottomSheet.web.js';
import { BottomSheetHeader } from '../BottomSheet/BottomSheetHeader.web.js';
import { BottomSheetBody } from '../BottomSheet/BottomSheetBody.web.js';
import { BottomSheetFooter } from '../BottomSheet/BottomSheetFooter.web.js';
import { makeAccessible } from '../../utils/makeAccessible/makeAccessible.web.js';
var _excluded = ["selectionType", "allowSingleDateInRange", "value", "defaultValue", "onChange", "onApply", "presets", "isOpen", "defaultIsOpen", "onOpenChange", "label", "labelPosition", "accessibilityLabel", "errorText", "helpText", "isDisabled", "isRequired", "successText", "validationState", "size", "autoFocus", "necessityIndicator", "name", "defaultPicker", "picker", "onPickerChange", "zIndex", "format", "inputPlaceHolder", "inputElementType", "onClearButtonClick"];
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var BaseDatePicker = function BaseDatePicker(_ref) {
var selectionType = _ref.selectionType,
allowSingleDateInRange = _ref.allowSingleDateInRange,
value = _ref.value,
defaultValue = _ref.defaultValue,
_onChange = _ref.onChange,
onApply = _ref.onApply,
presets = _ref.presets,
isOpen = _ref.isOpen,
defaultIsOpen = _ref.defaultIsOpen,
onOpenChange = _ref.onOpenChange,
label = _ref.label,
_ref$labelPosition = _ref.labelPosition,
labelPosition = _ref$labelPosition === void 0 ? 'top' : _ref$labelPosition,
accessibilityLabel = _ref.accessibilityLabel,
errorText = _ref.errorText,
helpText = _ref.helpText,
isDisabled = _ref.isDisabled,
isRequired = _ref.isRequired,
successText = _ref.successText,
validationState = _ref.validationState,
size = _ref.size,
autoFocus = _ref.autoFocus,
necessityIndicator = _ref.necessityIndicator,
name = _ref.name,
_ref$defaultPicker = _ref.defaultPicker,
defaultPicker = _ref$defaultPicker === void 0 ? 'day' : _ref$defaultPicker,
picker = _ref.picker,
onPickerChange = _ref.onPickerChange,
_ref$zIndex = _ref.zIndex,
zIndex = _ref$zIndex === void 0 ? componentZIndices.popover : _ref$zIndex,
_ref$format = _ref.format,
format = _ref$format === void 0 ? 'DD/MM/YYYY' : _ref$format,
inputPlaceHolder = _ref.inputPlaceHolder,
_ref$inputElementType = _ref.inputElementType,
inputElementType = _ref$inputElementType === void 0 ? 'datePickerInput' : _ref$inputElementType,
onClearButtonClick = _ref.onClearButtonClick,
props = _objectWithoutProperties(_ref, _excluded);
var _useI18nContext = useI18nContext(),
i18nState = _useI18nContext.i18nState;
var _selectionType = selectionType !== null && selectionType !== void 0 ? selectionType : 'single';
var _useTheme = useTheme(),
theme = _useTheme.theme;
var isSingle = _selectionType === 'single';
var _React$useReducer = React__default.useReducer(function (x) {
return x + 1;
}, 0),
_React$useReducer2 = _slicedToArray(_React$useReducer, 2),
_ = _React$useReducer2[0],
forceRerender = _React$useReducer2[1];
var _React$useState = React__default.useState(null),
_React$useState2 = _slicedToArray(_React$useState, 2),
selectedPreset = _React$useState2[0],
setSelectedPreset = _React$useState2[1];
var referenceRef = React__default.useRef(null);
var _useControllableState = useControllableState({
defaultValue: defaultPicker,
value: picker,
onChange: function onChange(picker) {
onPickerChange === null || onPickerChange === void 0 ? void 0 : onPickerChange(picker);
}
}),
_useControllableState2 = _slicedToArray(_useControllableState, 2),
_picker = _useControllableState2[0],
setPicker = _useControllableState2[1];
var finalFormat = React__default.useMemo(function () {
if (format) {
return format;
}
if (picker === 'month') {
return 'MMMM';
}
if (picker === 'year') {
return 'YYYY';
}
return 'DD/MM/YYYY';
}, [format, picker]);
var finalInputPlaceHolder = React__default.useMemo(function () {
if (inputPlaceHolder) {
return inputPlaceHolder;
}
if (picker === 'month') {
return 'Month';
}
if (picker === 'year') {
return 'Year';
}
return 'DD/MM/YYYY';
}, [inputPlaceHolder, picker]);
var _useDatesState = useDatesState({
level: _picker,
type: isSingle ? 'default' : 'range',
allowDeselect: false,
allowSingleDateInRange: allowSingleDateInRange,
value: value,
defaultValue: defaultValue,
onChange: function onChange(date) {
_onChange === null || _onChange === void 0 ? void 0 : _onChange(date);
fireNativeEvent(referenceRef, ['input']);
if (isSingle) return;
// sync selected preset with value
setSelectedPreset(date);
}
}),
onDateChange = _useDatesState.onDateChange,
onRootMouseLeave = _useDatesState.onRootMouseLeave,
onHoveredDateChange = _useDatesState.onHoveredDateChange,
getControlProps = _useDatesState.getControlProps,
setPickedDate = _useDatesState.setPickedDate,
controlledValue = _useDatesState.controlledValue,
setControlledValue = _useDatesState.setControlledValue,
handleReset = _useDatesState.handleReset;
var _React$useState3 = React__default.useState(controlledValue),
_React$useState4 = _slicedToArray(_React$useState3, 2),
oldValue = _React$useState4[0],
setOldValue = _React$useState4[1];
var _useControllableState3 = useControllableState({
value: isOpen,
defaultValue: defaultIsOpen,
onChange: function onChange(isOpen) {
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
isOpen: isOpen
});
// we need to update old value everytime datepicker is opened or closed
setOldValue(controlledValue);
setPicker(function () {
return defaultPicker;
});
}
}),
_useControllableState4 = _slicedToArray(_useControllableState3, 2),
controllableIsOpen = _useControllableState4[0],
controllableSetIsOpen = _useControllableState4[1];
var currentDate = shiftTimezone('add', new Date());
var hasBothDatesSelected = (controlledValue === null || controlledValue === void 0 ? void 0 : controlledValue[0]) && (controlledValue === null || controlledValue === void 0 ? void 0 : controlledValue[1]);
var _useListViewFilterCon = useListViewFilterContext(),
listViewSelectedFilters = _useListViewFilterCon.listViewSelectedFilters,
setListViewSelectedFilters = _useListViewFilterCon.setListViewSelectedFilters;
var _useFilterChipGroupCo = useFilterChipGroupContext(),
clearFilterCallbackTriggerer = _useFilterChipGroupCo.clearFilterCallbackTriggerer,
setFilterChipGroupSelectedFilters = _useFilterChipGroupCo.setFilterChipGroupSelectedFilters;
var applyButtonDisabled = !hasBothDatesSelected;
if (isSingle) {
applyButtonDisabled = !Boolean(controlledValue);
}
var close = React__default.useCallback(function () {
controllableSetIsOpen(function () {
return false;
});
}, [controllableSetIsOpen]);
var handleApply = function handleApply() {
var updateSelectedFilters = function updateSelectedFilters() {
setFilterChipGroupSelectedFilters(function (prev) {
return [].concat(_toConsumableArray(prev), [label]);
});
};
var storeSelectedFiltersAndValueInListViewContext = function storeSelectedFiltersAndValueInListViewContext() {
setListViewSelectedFilters(function (prev) {
if (isSingle) {
return _objectSpread(_objectSpread({}, prev), {}, _defineProperty({}, label, [controlledValue]));
}
return _objectSpread(_objectSpread({}, prev), {}, _defineProperty({}, label, controlledValue));
});
};
if (isSingle) {
_onChange === null || _onChange === void 0 ? void 0 : _onChange(controlledValue);
fireNativeEvent(referenceRef, ['change']);
setOldValue(controlledValue);
onApply === null || onApply === void 0 ? void 0 : onApply(controlledValue);
close();
storeSelectedFiltersAndValueInListViewContext();
updateSelectedFilters();
return;
}
// only apply if both dates are selected
if (hasBothDatesSelected) {
_onChange === null || _onChange === void 0 ? void 0 : _onChange(controlledValue);
fireNativeEvent(referenceRef, ['change']);
setOldValue(controlledValue);
onApply === null || onApply === void 0 ? void 0 : onApply(controlledValue);
close();
}
storeSelectedFiltersAndValueInListViewContext();
updateSelectedFilters();
};
var handleCancel = function handleCancel() {
setControlledValue(oldValue);
fireNativeEvent(referenceRef, ['change']);
setPickedDate(null);
close();
};
var handleClear = function handleClear() {
fireNativeEvent(referenceRef, ['change']);
handleReset();
close();
setFilterChipGroupSelectedFilters(function (prev) {
return prev.filter(function (filter) {
return filter !== label;
});
});
setListViewSelectedFilters(function (prev) {
var _ref2 = label,
_ = prev[_ref2],
rest = _objectWithoutProperties(prev, [_ref2].map(_toPropertyKey));
return rest;
});
onClearButtonClick === null || onClearButtonClick === void 0 ? void 0 : onClearButtonClick();
};
React__default.useEffect(function () {
if (listViewSelectedFilters[label]) {
setControlledValue(listViewSelectedFilters[label]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
React__default.useEffect(function () {
if (clearFilterCallbackTriggerer) {
handleClear();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [clearFilterCallbackTriggerer]);
var isMobile = useIsMobile();
var defaultInitialFocusRef = React__default.useRef(null);
var titleId = useId('datepicker-title');
var _usePopup = usePopup({
enabled: !isMobile,
placement: 'bottom-start',
open: controllableIsOpen,
onOpenChange: function onOpenChange(isOpen, _, reason) {
controllableSetIsOpen(function () {
return isOpen;
});
if (reason === 'escape-key' || reason === 'outside-press') {
handleCancel();
}
},
referenceRef: referenceRef
}),
context = _usePopup.context,
refs = _usePopup.refs,
isMounted = _usePopup.isMounted,
floatingStyles = _usePopup.floatingStyles,
animationStyles = _usePopup.animationStyles,
getReferenceProps = _usePopup.getReferenceProps,
getFloatingProps = _usePopup.getFloatingProps;
var shouldRenderPresets = !isSingle && !isMobile;
var content = /*#__PURE__*/jsxs(Fragment, {
children: [shouldRenderPresets ? /*#__PURE__*/jsx(PresetSideBar, {
presets: presets,
date: currentDate,
selectedPreset: selectedPreset,
onSelection: function onSelection(preset) {
var presetValue = preset === null || preset === void 0 ? void 0 : preset(currentDate);
setControlledValue(presetValue);
setSelectedPreset(presetValue);
}
}) : null, /*#__PURE__*/jsxs(BaseBox, {
width: "100%",
display: "flex",
flexDirection: "column",
gap: "spacing.5",
padding: {
m: 'spacing.6',
s: 'spacing.0'
}
/* We only need to set height for day picker, for year picker
or month it should be auto. */,
height: _picker === 'day' ? '447px' : 'auto',
backgroundColor: "surface.background.gray.intense",
justifyContent: "space-between",
children: [/*#__PURE__*/jsx(Calendar, _objectSpread(_objectSpread({}, props), {}, {
selectionType: _selectionType,
defaultValue: defaultValue,
onMouseLeave: onRootMouseLeave,
__onDayMouseEnter: function __onDayMouseEnter(_event, date) {
onHoveredDateChange(date);
},
__onDayClick: function __onDayClick(_event, date) {
onDateChange(date, 'day');
},
getMonthControlProps: function getMonthControlProps(date) {
return getControlProps(date);
},
getYearControlProps: function getYearControlProps(date) {
return getControlProps(date);
},
getDayProps: function getDayProps(date) {
return getControlProps(date);
},
onMonthSelect: function onMonthSelect(date) {
var _props$onMonthSelect;
props === null || props === void 0 ? void 0 : (_props$onMonthSelect = props.onMonthSelect) === null || _props$onMonthSelect === void 0 ? void 0 : _props$onMonthSelect.call(props, date);
onDateChange(date, 'month');
},
onYearSelect: function onYearSelect(date) {
var _props$onYearSelect;
props === null || props === void 0 ? void 0 : (_props$onYearSelect = props.onYearSelect) === null || _props$onYearSelect === void 0 ? void 0 : _props$onYearSelect.call(props, date);
onDateChange(date, 'year');
},
onNext: function onNext(data) {
var _props$onNext;
props === null || props === void 0 ? void 0 : (_props$onNext = props.onNext) === null || _props$onNext === void 0 ? void 0 : _props$onNext.call(props, data);
forceRerender();
},
onPrevious: function onPrevious(data) {
var _props$onPrevious;
props === null || props === void 0 ? void 0 : (_props$onPrevious = props.onPrevious) === null || _props$onPrevious === void 0 ? void 0 : _props$onPrevious.call(props, data);
forceRerender();
},
picker: _picker,
showLevelChangeLink: !picker,
onPickerChange: function onPickerChange(picker) {
setPicker(function () {
return picker;
});
forceRerender();
},
selectedValue: controlledValue
})), isMobile ? null : /*#__PURE__*/jsx(CalendarFooter, {
isButtonDisabled: applyButtonDisabled,
onApply: handleApply,
onCancel: handleCancel
})]
})]
});
var dateProviderValue = React__default.useMemo(function () {
var _i18nState$locale;
var locale = convertIntlToDayjsLocale((_i18nState$locale = i18nState === null || i18nState === void 0 ? void 0 : i18nState.locale) !== null && _i18nState$locale !== void 0 ? _i18nState$locale : 'en-IN');
return {
locale: locale
};
}, [i18nState === null || i18nState === void 0 ? void 0 : i18nState.locale]);
// Dynamically load dayjs locales
React__default.useLayoutEffect(function () {
try {
var _i18nState$locale2;
var locale = convertIntlToDayjsLocale((_i18nState$locale2 = i18nState === null || i18nState === void 0 ? void 0 : i18nState.locale) !== null && _i18nState$locale2 !== void 0 ? _i18nState$locale2 : 'en-IN');
// dayjs needs to be loaded into window so that once the locale is loaded it can be parsed
if (!window.dayjs) {
window.dayjs = dayjs;
}
loadScript("https://cdn.jsdelivr.net/npm/dayjs@1/locale/".concat(locale, ".js"), function () {
forceRerender();
});
} catch (e) {
logger({
type: 'warn',
message: 'Failed to load dayjs locale'
});
}
}, [i18nState === null || i18nState === void 0 ? void 0 : i18nState.locale]);
return /*#__PURE__*/jsx(MantineProvider, {
children: /*#__PURE__*/jsx(DatesProvider, {
settings: dateProviderValue,
children: /*#__PURE__*/jsxs(BaseBox, _objectSpread(_objectSpread(_objectSpread({
width: inputElementType === 'chip' ? 'fit-content' : '100%'
}, getStyledProps(props)), metaAttribute({
name: MetaConstants.DatePicker
})), {}, {
children: [inputElementType === 'chip' ? /*#__PURE__*/jsx(DatePickerFilterChip, _objectSpread({
selectionType: _selectionType,
date: controlledValue,
ref: referenceRef,
inputRef: refs.reference,
referenceProps: getReferenceProps(),
name: name,
label: label,
labelPosition: labelPosition,
accessibilityLabel: accessibilityLabel,
size: size,
errorText: errorText,
helpText: helpText,
successText: successText,
isDisabled: isDisabled,
isRequired: isRequired,
validationState: validationState,
autoFocus: autoFocus,
necessityIndicator: necessityIndicator,
format: finalFormat,
placeholder: finalInputPlaceHolder,
onClearButtonChange: handleClear
}, makeAnalyticsAttribute(props))) : /*#__PURE__*/jsx(DatePickerInput, _objectSpread({
selectionType: _selectionType,
date: controlledValue,
ref: referenceRef,
inputRef: refs.reference,
referenceProps: getReferenceProps(),
name: name,
label: label,
labelPosition: labelPosition,
accessibilityLabel: accessibilityLabel,
size: size,
errorText: errorText,
helpText: helpText,
successText: successText,
isDisabled: isDisabled,
isRequired: isRequired,
validationState: validationState,
autoFocus: autoFocus,
necessityIndicator: necessityIndicator,
format: finalFormat,
placeholder: finalInputPlaceHolder
}, makeAnalyticsAttribute(props))), isMobile ? /*#__PURE__*/jsxs(BottomSheet, {
snapPoints: [0.9, 0.9, 1],
isOpen: controllableIsOpen,
onDismiss: function onDismiss() {
handleCancel();
},
children: [/*#__PURE__*/jsx(BottomSheetHeader, {
title: isSingle ? 'Select Date' : 'Select Date Range'
}), /*#__PURE__*/jsxs(BottomSheetBody, {
children: [content, !isSingle && /*#__PURE__*/jsx(PresetSideBar, {
isMobile: true,
presets: presets,
date: currentDate,
selectedPreset: selectedPreset,
onSelection: function onSelection(preset) {
var presetValue = preset === null || preset === void 0 ? void 0 : preset(currentDate);
setControlledValue(presetValue);
setSelectedPreset(presetValue);
}
})]
}), /*#__PURE__*/jsx(BottomSheetFooter, {
children: /*#__PURE__*/jsx(CalendarFooter, {
onCancel: handleCancel,
onApply: handleApply
})
})]
}) : isMounted && /*#__PURE__*/jsx(FloatingPortal, {
children: /*#__PURE__*/jsx(FloatingFocusManager, {
initialFocus: defaultInitialFocusRef,
context: context,
guards: true,
children: /*#__PURE__*/jsx(BaseBox, _objectSpread(_objectSpread(_objectSpread({
ref: refs.setFloating,
style: floatingStyles,
zIndex: zIndex
}, getFloatingProps()), makeAccessible({
labelledBy: titleId
})), {}, {
children: /*#__PURE__*/jsx(BaseBox, {
display: "flex",
flexDirection: "row",
borderColor: "surface.border.gray.subtle",
borderWidth: "thin",
borderStyle: "solid",
borderRadius: "medium",
overflow: "hidden",
minWidth: "320px",
style: _objectSpread(_objectSpread({}, animationStyles), {}, {
boxShadow: "".concat(theme.elevation.lowRaised)
}),
children: content
})
}))
})
})]
}))
})
});
};
export { BaseDatePicker };
//# sourceMappingURL=BaseDatePicker.web.js.map