UNPKG

@yamada-ui/calendar

Version:

Yamada UI calendar component

758 lines (754 loc) • 23.5 kB
"use client" "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/use-range-date-picker.ts var use_range_date_picker_exports = {}; __export(use_range_date_picker_exports, { useRangeDatePicker: () => useRangeDatePicker }); module.exports = __toCommonJS(use_range_date_picker_exports); var import_use_controllable_state = require("@yamada-ui/use-controllable-state"); var import_utils3 = require("@yamada-ui/utils"); var import_dayjs3 = __toESM(require("dayjs")); var import_react2 = require("react"); // src/calendar-utils.ts var import_utils = require("@yamada-ui/utils"); var import_dayjs = __toESM(require("dayjs")); var isAfterDate = (value, date) => (date instanceof Date || date instanceof import_dayjs.default) && (0, import_dayjs.default)(date).isBefore(value, "day"); var isBeforeDate = (value, date) => (date instanceof Date || date instanceof import_dayjs.default) && (0, import_dayjs.default)(date).isAfter(value, "day"); // src/use-calendar-picker.ts var import_core = require("@yamada-ui/core"); var import_form_control = require("@yamada-ui/form-control"); var import_use_disclosure = require("@yamada-ui/use-disclosure"); var import_use_outside_click = require("@yamada-ui/use-outside-click"); var import_utils2 = require("@yamada-ui/utils"); var import_dayjs2 = __toESM(require("dayjs")); var import_react = require("react"); var useCalendarPicker = (props) => { var _a, _b; const { locale: defaultLocale } = (0, import_core.useI18n)(); const { theme } = (0, import_core.useTheme)(); const themeLocale = (_b = (_a = theme.__config) == null ? void 0 : _a.date) == null ? void 0 : _b.locale; const { type, allowInput = true, allowInputBeyond = false, amountOfMonths, animation, autoFocus = true, boundary, calendarColorScheme, calendarSize, calendarVariant, closeDelay, closeOnBlur = true, closeOnEsc = true, dateFormat, defaultIsOpen, defaultMonth, defaultOpen, defaultType, defaultValue, disableOutsideDays, duration = 0.2, enableMultiple, enableRange, eventListeners, excludeDate, firstDayOfWeek, flip, gutter, hiddenOutsideDays, holidays, inputFormat = "YYYY/MM/DD", isLazy, isOpen, lazy = isLazy, lazyBehavior, locale = themeLocale != null ? themeLocale : defaultLocale, matchWidth, maxDate, maxSelectValues, minDate, minSelectValues, modifiers, month, monthFormat, offset, open: openProp, openDelay, paginateBy, parseDate, pattern = /[^0-9\-\/]/g, placement = "bottom-start", preventOverflow, strategy, today, value, weekdayFormat, weekendDays, withControls, withHeader, withLabel, withWeekdays, yearFormat, calendarProps, onChange, onChangeMonth, onChangeType, onClear: onClearProp, onClose: onCloseProp, onDelete, onEnter, onOpen: onOpenProp, __selectType, ...rest } = (0, import_form_control.useFormControlProps)(props); const { "aria-readonly": _ariaReadonly, ...formControlProps } = (0, import_utils2.pickObject)( rest, import_form_control.formControlProperties ); const [containerProps, inputProps] = (0, import_utils2.splitObject)(rest, import_core.layoutStyleProperties); const { open, onClose, onOpen: onInternalOpen } = (0, import_use_disclosure.useDisclosure)({ defaultIsOpen, defaultOpen, isOpen, open: openProp, onClose: onCloseProp, onOpen: onOpenProp }); const containerRef = (0, import_react.useRef)(null); const inputRef = (0, import_react.useRef)(null); const { disabled, readOnly } = formControlProps; const stringToDate = (0, import_react.useCallback)( (value2) => { let date = parseDate == null ? void 0 : parseDate(value2); if (!date && (0, import_dayjs2.default)(value2).isValid()) date = (0, import_dayjs2.default)(value2, inputFormat, locale).toDate(); if (date == null) return void 0; if (excludeDate == null ? void 0 : excludeDate(date)) return void 0; if (!allowInputBeyond) { if (maxDate && isAfterDate(date, maxDate)) date = maxDate; if (minDate && isBeforeDate(date, minDate)) date = minDate; } return date; }, [ allowInputBeyond, excludeDate, inputFormat, locale, maxDate, minDate, parseDate ] ); const dateToString = (0, import_react.useCallback)( (value2) => { if (value2 == null) return void 0; if (excludeDate == null ? void 0 : excludeDate(value2)) return void 0; if (!allowInputBeyond) { if (maxDate && isAfterDate(value2, maxDate)) value2 = maxDate; if (minDate && isBeforeDate(value2, minDate)) value2 = minDate; } return (0, import_dayjs2.default)(value2).locale(locale).format(inputFormat); }, [allowInputBeyond, excludeDate, inputFormat, locale, maxDate, minDate] ); const onOpen = (0, import_react.useCallback)(() => { var _a2; if (disabled || readOnly) return; onInternalOpen(); if (autoFocus && allowInput) (_a2 = inputRef.current) == null ? void 0 : _a2.focus(); }, [autoFocus, allowInput, disabled, readOnly, onInternalOpen]); const onClick = (0, import_react.useCallback)(() => { var _a2; if (open) { if (autoFocus && allowInput) (_a2 = inputRef.current) == null ? void 0 : _a2.focus(); } else { onOpen(); } }, [autoFocus, allowInput, open, onOpen]); const onFocus = (0, import_react.useCallback)(() => { if (!open) onOpen(); }, [open, onOpen]); const onBlur = (0, import_react.useCallback)( (ev) => { const relatedTarget = (0, import_utils2.getEventRelatedTarget)(ev); if ((0, import_utils2.isContains)(containerRef.current, relatedTarget)) return; if (!closeOnBlur) return; if (open) onClose(); }, [closeOnBlur, open, onClose] ); const onKeyDown = (0, import_react.useCallback)( (ev) => { if (ev.key === " ") ev.key = ev.code; if (disabled || readOnly) return; const actions = { Backspace: onDelete, Enter: !open ? (ev2) => { ev2.preventDefault(); ev2.stopPropagation(); onOpen(); } : onEnter, Escape: closeOnEsc ? (ev2) => { ev2.preventDefault(); ev2.stopPropagation(); onClose(); } : void 0, Space: !open ? (ev2) => { ev2.preventDefault(); ev2.stopPropagation(); onOpen(); } : void 0 }; const action = actions[ev.key]; if (!action) return; action(ev); }, [closeOnEsc, disabled, readOnly, open, onClose, onEnter, onDelete, onOpen] ); const onClear = (0, import_react.useCallback)( (ev) => { var _a2; ev.stopPropagation(); onClearProp == null ? void 0 : onClearProp(); if (autoFocus && allowInput && open) (_a2 = inputRef.current) == null ? void 0 : _a2.focus(); }, [autoFocus, allowInput, open, onClearProp] ); (0, import_use_outside_click.useOutsideClick)({ ref: containerRef, enabled: open && closeOnBlur, handler: onClose }); const getContainerProps = (0, import_react.useCallback)( (props2 = {}, ref = null) => ({ ref: (0, import_utils2.mergeRefs)(containerRef, ref), ...containerProps, ...formControlProps, ...props2, onBlur: (0, import_utils2.handlerAll)( props2.onBlur, rest.onBlur, onBlur ), onClick: (0, import_utils2.handlerAll)(props2.onClick, rest.onClick, onClick) }), [containerProps, formControlProps, onBlur, onClick, rest] ); const getPopoverProps = (0, import_react.useCallback)( (props2) => ({ animation, boundary, closeDelay, duration, eventListeners, flip, gutter, lazy, lazyBehavior, matchWidth, modifiers, offset, openDelay, placement, preventOverflow, strategy, ...props2, closeOnBlur: false, closeOnButton: false, isOpen: open, trigger: "never", onClose, onOpen }), [ animation, boundary, closeDelay, duration, eventListeners, flip, gutter, open, lazy, lazyBehavior, matchWidth, modifiers, offset, onClose, onOpen, openDelay, placement, preventOverflow, strategy ] ); const getFieldProps = (0, import_react.useCallback)( (props2 = {}, ref = null) => { return { "aria-haspopup": "dialog", "data-active": (0, import_utils2.dataAttr)(open), "data-not-allowed": (0, import_utils2.dataAttr)(!readOnly && !disabled && !allowInput), role: "combobox", tabIndex: -1, ...formControlProps, ...props2, ref: (0, import_utils2.mergeRefs)(inputRef, ref), onFocus: (0, import_utils2.handlerAll)(props2.onFocus, rest.onFocus, onFocus), onKeyDown: (0, import_utils2.handlerAll)( props2.onKeyDown, rest.onKeyDown, onKeyDown ) }; }, [ allowInput, disabled, readOnly, formControlProps, open, rest, onFocus, onKeyDown ] ); const getCalendarProps = (0, import_react.useCallback)( (props2) => ({ ...props2, type, colorScheme: calendarColorScheme, size: calendarSize, variant: calendarVariant, amountOfMonths, dateFormat, defaultMonth, defaultType, disableOutsideDays, firstDayOfWeek, hiddenOutsideDays, holidays, maxSelectValues, minSelectValues, month, monthFormat, paginateBy, today, weekdayFormat, weekendDays, withControls, withHeader, withLabel, withWeekdays, yearFormat, onChangeMonth, onChangeType, ...calendarProps, defaultValue, enableMultiple, enableRange, excludeDate, locale, maxDate, minDate, value, onChange, __selectType }), [ hiddenOutsideDays, maxSelectValues, minSelectValues, enableMultiple, enableRange, amountOfMonths, calendarColorScheme, calendarProps, calendarSize, calendarVariant, dateFormat, defaultMonth, defaultType, defaultValue, disableOutsideDays, excludeDate, firstDayOfWeek, holidays, locale, maxDate, minDate, month, monthFormat, onChange, onChangeMonth, onChangeType, paginateBy, today, type, value, weekdayFormat, weekendDays, withControls, withHeader, withLabel, withWeekdays, yearFormat, __selectType ] ); const getIconProps = (0, import_react.useCallback)( ({ clear, ...props2 }) => ({ ...props2, ...formControlProps, onClick: (0, import_utils2.handlerAll)(props2.onClick, clear ? onClear : void 0) }), [formControlProps, onClear] ); return { allowInput, containerRef, dateToString, inputFormat, inputRef, locale, open, pattern, stringToDate, formControlProps, getCalendarProps, getContainerProps, getFieldProps, getIconProps, getPopoverProps, inputProps, onClose, onOpen }; }; // src/use-range-date-picker.ts var useRangeDatePicker = ({ allowInputBeyond = false, closeOnSelect = true, defaultValue = [], endPlaceholder, maxSelectValues, placeholder, startPlaceholder, value: valueProp, onChange: onChangeProp, ...rest }) => { var _a, _b; const composition = (0, import_react2.useRef)(false); const startInputRef = (0, import_react2.useRef)(null); const endInputRef = (0, import_react2.useRef)(null); const draftValue = (0, import_react2.useRef)(void 0); const [value, setValue] = (0, import_use_controllable_state.useControllableState)({ defaultValue, value: valueProp, onChange: onChangeProp }); const [startValue, endValue] = value; const minDate = endValue && (0, import_utils3.isNumber)(maxSelectValues) ? (0, import_dayjs3.default)(endValue).subtract(maxSelectValues - 1, "day").toDate() : void 0; const maxDate = startValue && (0, import_utils3.isNumber)(maxSelectValues) ? (0, import_dayjs3.default)(startValue).add(maxSelectValues - 1, "day").toDate() : void 0; const { allowInput, containerRef, dateToString, inputFormat, locale, open, pattern, stringToDate, formControlProps, getCalendarProps, getContainerProps, getFieldProps, getIconProps, getPopoverProps, inputProps, onClose } = useCalendarPicker({ ...rest, allowInputBeyond, autoFocus: false, defaultValue, enableRange: true, maxSelectValues, value, onChange: ([startValue2, endValue2]) => { var _a2, _b2; setStartInputValue((_a2 = dateToString(startValue2)) != null ? _a2 : ""); setEndInputValue((_b2 = dateToString(endValue2)) != null ? _b2 : ""); draftValue.current = [startValue2, endValue2]; setValue([startValue2, endValue2]); if (closeOnSelect && startValue2 && endValue2) onClose(); }, onClear: () => { var _a2; setStartInputValue(""); setEndInputValue(""); setValue([]); draftValue.current = void 0; if (allowInput && open) (_a2 = startInputRef.current) == null ? void 0 : _a2.focus(); }, onClick: (ev) => { var _a2, _b2, _c; if (open) { if (!startValue) { (_a2 = startInputRef.current) == null ? void 0 : _a2.focus(); } else { (_b2 = endInputRef.current) == null ? void 0 : _b2.focus(); } } (_c = rest.onClick) == null ? void 0 : _c.call(rest, ev); }, onClose: () => { var _a2, _b2, _c, _d; const [startValue2, endValue2] = (_a2 = draftValue.current) != null ? _a2 : value; setStartInputValue((_b2 = dateToString(startValue2)) != null ? _b2 : ""); setEndInputValue((_c = dateToString(endValue2)) != null ? _c : ""); draftValue.current = void 0; (_d = rest.onClose) == null ? void 0 : _d.call(rest); }, onDelete: (ev) => { var _a2, _b2, _c, _d; if (!endInputRef.current || endInputRef.current.value.length > 1) return; if (!containerRef.current) return; const activeEl = (0, import_utils3.getActiveElement)(containerRef.current); if (!(0, import_utils3.isContains)(activeEl, endInputRef.current)) return; ev.preventDefault(); ev.stopPropagation(); setEndInputValue(""); setValue([startValue, void 0]); const startInputValue2 = (_b2 = (_a2 = startInputRef.current) == null ? void 0 : _a2.value) != null ? _b2 : ""; const index = startInputValue2.length; (_c = startInputRef.current) == null ? void 0 : _c.focus(); (_d = startInputRef.current) == null ? void 0 : _d.setSelectionRange(index, index); }, onEnter: () => { var _a2, _b2, _c, _d; if (composition.current) return; if (!containerRef.current) return; const activeEl = (0, import_utils3.getActiveElement)(containerRef.current); const start = (0, import_utils3.isContains)(activeEl, startInputRef.current); if (start) { const value2 = dateToString(startValue); if (value2) { setStartInputValue(value2); const endInputValue2 = (_b2 = (_a2 = endInputRef.current) == null ? void 0 : _a2.value) != null ? _b2 : ""; const index = endInputValue2.length; (_c = endInputRef.current) == null ? void 0 : _c.focus(); (_d = endInputRef.current) == null ? void 0 : _d.setSelectionRange(index, index); } } else { const value2 = dateToString(endValue); if (value2) setEndInputValue(value2); } } }); const [startInputValue, setStartInputValue] = (0, import_react2.useState)( (_a = dateToString(startValue)) != null ? _a : "" ); const [endInputValue, setEndInputValue] = (0, import_react2.useState)( (_b = dateToString(endValue)) != null ? _b : "" ); const onStartChange = (0, import_react2.useCallback)( (ev) => { let inputValue = ev.target.value; if (!composition.current) inputValue = inputValue.replace(pattern, ""); let startValue2 = stringToDate(inputValue); if (!!startValue2 && (0, import_dayjs3.default)(startValue2).isValid()) { if (!allowInputBeyond) { if (minDate && isBeforeDate(startValue2, minDate)) startValue2 = minDate; } if (endValue && isAfterDate(startValue2, endValue)) startValue2 = endValue; } else { startValue2 = void 0; } draftValue.current = [startValue2, endValue]; setValue([startValue2, endValue]); setStartInputValue(inputValue); }, [pattern, stringToDate, allowInputBeyond, minDate, setValue, endValue] ); const onEndChange = (0, import_react2.useCallback)( (ev) => { let inputValue = ev.target.value; if (!composition.current) inputValue = inputValue.replace(pattern, ""); let endValue2 = stringToDate(inputValue); if (!!endValue2 && (0, import_dayjs3.default)(endValue2).isValid()) { if (!allowInputBeyond) { if (maxDate && isAfterDate(endValue2, maxDate)) endValue2 = maxDate; } if (startValue && isBeforeDate(endValue2, startValue)) endValue2 = startValue; } else { endValue2 = void 0; } draftValue.current = [startValue, endValue2]; setValue([startValue, endValue2]); setEndInputValue(inputValue); }, [startValue, allowInputBeyond, maxDate, pattern, stringToDate, setValue] ); (0, import_utils3.useUpdateEffect)(() => { setValue(valueProp != null ? valueProp : []); }, [valueProp]); (0, import_utils3.useUpdateEffect)(() => { var _a2; if (startInputRef.current && (0, import_utils3.isActiveElement)(startInputRef.current)) return; setStartInputValue((_a2 = dateToString(startValue)) != null ? _a2 : ""); }, [value]); (0, import_utils3.useUpdateEffect)(() => { var _a2; if (endInputRef.current && (0, import_utils3.isActiveElement)(endInputRef.current)) return; setEndInputValue((_a2 = dateToString(endValue)) != null ? _a2 : ""); }, [value]); (0, import_utils3.useUpdateEffect)(() => { var _a2, _b2; setStartInputValue((_a2 = dateToString(startValue)) != null ? _a2 : ""); setEndInputValue((_b2 = dateToString(endValue)) != null ? _b2 : ""); }, [locale, inputFormat]); const getStartInputProps = (0, import_react2.useCallback)( (props = {}, ref) => { const style = { ...props.style, ...inputProps.style, ...formControlProps.disabled || !allowInput ? { pointerEvents: "none" } : {} }; return { "aria-label": "Start Date", placeholder: startPlaceholder != null ? startPlaceholder : placeholder, tabIndex: !allowInput ? -1 : 0, zIndex: !startInputValue ? 1 : void 0, ...formControlProps, ...inputProps, ...props, ref: (0, import_utils3.mergeRefs)(ref, startInputRef), style, value: startInputValue, onChange: (0, import_utils3.handlerAll)(props.onChange, onStartChange), onClick: (0, import_utils3.handlerAll)(props.onClick, (ev) => { ev.preventDefault(); ev.stopPropagation(); }), onCompositionEnd: (0, import_utils3.handlerAll)(props.onCompositionEnd, () => { composition.current = false; setStartInputValue((prev) => prev.replace(pattern, "")); }), onCompositionStart: (0, import_utils3.handlerAll)( props.onCompositionStart, () => composition.current = true ) }; }, [ inputProps, allowInput, startPlaceholder, placeholder, formControlProps, startInputValue, onStartChange, pattern ] ); const getEndInputProps = (0, import_react2.useCallback)( (props = {}, ref) => { const style = { ...props.style, ...inputProps.style, ...!allowInput ? { pointerEvents: "none" } : {} }; return { "aria-label": "End Date", placeholder: endPlaceholder != null ? endPlaceholder : placeholder, ...formControlProps, ...inputProps, ...props, ref: (0, import_utils3.mergeRefs)(ref, endInputRef), style, cursor: formControlProps.readOnly ? "default" : "text", pointerEvents: formControlProps.disabled ? "none" : "auto", tabIndex: !allowInput || !startInputValue ? -1 : 0, value: endInputValue, onChange: (0, import_utils3.handlerAll)(props.onChange, onEndChange), onClick: (0, import_utils3.handlerAll)(props.onClick, (ev) => { ev.preventDefault(); ev.stopPropagation(); }), onCompositionEnd: (0, import_utils3.handlerAll)(props.onCompositionEnd, () => { composition.current = false; setEndInputValue((prev) => prev.replace(pattern, "")); }), onCompositionStart: (0, import_utils3.handlerAll)( props.onCompositionStart, () => composition.current = true ) }; }, [ startInputValue, inputProps, allowInput, endPlaceholder, placeholder, formControlProps, endInputValue, onEndChange, pattern ] ); return { dateToString, inputValue: [startInputValue, endInputValue], value, getCalendarProps, getContainerProps, getEndInputProps, getFieldProps, getIconProps, getPopoverProps, getStartInputProps, onClose }; }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { useRangeDatePicker }); //# sourceMappingURL=use-range-date-picker.js.map