UNPKG

@mantine/dates

Version:

Calendars, date and time pickers based on Mantine components

354 lines (353 loc) 12 kB
"use client"; import { padTime } from "./utils/pad-time/pad-time.mjs"; import { SpinInput } from "../SpinInput/SpinInput.mjs"; import { TimePickerProvider } from "./TimePicker.context.mjs"; import { AmPmInput } from "./AmPmInput/AmPmInput.mjs"; import { AmPmControlsList } from "./TimeControlsList/AmPmControlsList.mjs"; import { TimeControlsList } from "./TimeControlsList/TimeControlsList.mjs"; import { TimePresets } from "./TimePresets/TimePresets.mjs"; import { clampTime } from "./utils/clamp-time/clamp-time.mjs"; import { getParsedTime } from "./utils/get-parsed-time/get-parsed-time.mjs"; import { getTimeString } from "./utils/get-time-string/get-time-string.mjs"; import { useTimePicker } from "./use-time-picker.mjs"; import TimePicker_module_default from "./TimePicker.module.mjs"; import { useRef, useState } from "react"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import { CloseButton, InputBase, Popover, createVarsResolver, factory, getFontSize, useProps, useResolvedStylesApi, useStyles } from "@mantine/core"; import { useId, useMergedRef } from "@mantine/hooks"; //#region packages/@mantine/dates/src/components/TimePicker/TimePicker.tsx const defaultProps = { type: "time", hoursStep: 1, minutesStep: 1, secondsStep: 1, format: "24h", amPmLabels: { am: "AM", pm: "PM" }, pasteSplit: getParsedTime, maxDropdownContentHeight: 200, hoursPlaceholder: "--", minutesPlaceholder: "--", secondsPlaceholder: "--", minHoursDigits: 2 }; const varsResolver = createVarsResolver((_theme, { size }) => ({ dropdown: { "--control-font-size": getFontSize(size) } })); const DURATION_HOURS_MAX = Infinity; const TimePicker = factory((_props) => { const props = useProps([ "Input", "InputWrapper", "TimePicker" ], defaultProps, _props); const { classNames, className, style, styles, unstyled, vars, onClick, type, format: _format, value, defaultValue, onChange, hoursStep, minutesStep, secondsStep, withSeconds, hoursInputLabel, minutesInputLabel, secondsInputLabel, amPmInputLabel, amPmLabels, clearable, clearSectionMode, onMouseDown, onFocusCapture, onBlurCapture, min, max, popoverProps, withDropdown, rightSection, onFocus, onBlur, clearButtonProps, hoursInputProps, minutesInputProps, secondsInputProps, amPmSelectProps, readOnly, disabled, size, name, form, hiddenInputProps, labelProps, pasteSplit, hoursRef, minutesRef, secondsRef, amPmRef, presets, closeDropdownOnPresetSelect, maxDropdownContentHeight, scrollAreaProps, attributes, reverseTimeControlsList, hoursPlaceholder, minutesPlaceholder, secondsPlaceholder, minHoursDigits, ...others } = props; const isDuration = type === "duration"; const format = isDuration ? "24h" : _format; const resolvedHoursPlaceholder = isDuration && hoursPlaceholder === "--" ? "-".repeat(minHoursDigits) : hoursPlaceholder; const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi({ classNames, styles, props }); const getStyles = useStyles({ name: "TimePicker", classes: TimePicker_module_default, props, className, style, classNames, styles, unstyled, attributes, vars, varsResolver }); const controller = useTimePicker({ value, defaultValue, onChange, format, amPmLabels, withSeconds, min, max, clearable, disabled, readOnly, pasteSplit, type }); const _hoursRef = useMergedRef(controller.refs.hours, hoursRef); const _minutesRef = useMergedRef(controller.refs.minutes, minutesRef); const _secondsRef = useMergedRef(controller.refs.seconds, secondsRef); const _amPmRef = useMergedRef(controller.refs.amPm, amPmRef); const hoursInputId = useId(); const hasFocusRef = useRef(false); const [dropdownOpened, setDropdownOpened] = useState(false); const handleFocus = (event) => { if (!hasFocusRef.current) { hasFocusRef.current = true; onFocus?.(event); } }; const handlePresetSelect = (timeString) => { controller.setTimeString(timeString); if (closeDropdownOnPresetSelect) { setDropdownOpened(false); popoverProps?.onChange?.(false); } }; const handleBlur = (event) => { if (!event.currentTarget.contains(event.relatedTarget)) { const computedValue = controller.values; const timeString = getTimeString({ ...computedValue, format, amPmLabels, withSeconds: !!withSeconds }); if (timeString.valid && (min || max)) { const clamped = clampTime(timeString.value, min, max); if (clamped.timeString !== timeString.value) controller.setTimeString(clamped.timeString); } hasFocusRef.current = false; onBlur?.(event); } }; return /* @__PURE__ */ jsx(TimePickerProvider, { value: { getStyles, scrollAreaProps, maxDropdownContentHeight }, children: /* @__PURE__ */ jsxs(Popover, { opened: dropdownOpened, transitionProps: { duration: 0 }, position: "bottom-start", withRoles: false, disabled: disabled || readOnly || !withDropdown || isDuration, ...popoverProps, children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsxs(InputBase, { component: "div", size, disabled, onClick: (event) => { onClick?.(event); controller.focus("hours"); if (!disabled) setDropdownOpened(true); }, onMouseDown: (event) => { event.preventDefault(); onMouseDown?.(event); }, onFocusCapture: (event) => { setDropdownOpened(true); onFocusCapture?.(event); }, onBlurCapture: (event) => { setDropdownOpened(false); onBlurCapture?.(event); }, rightSection, __clearSection: /* @__PURE__ */ jsx(CloseButton, { ...clearButtonProps, size, onClick: (event) => { controller.clear(); clearButtonProps?.onClick?.(event); }, onMouseDown: (event) => { event.preventDefault(); clearButtonProps?.onMouseDown?.(event); } }), __clearable: controller.isClearable, __clearSectionMode: clearSectionMode, labelProps: { htmlFor: hoursInputId, ...labelProps }, style, className, classNames: resolvedClassNames, styles: resolvedStyles, attributes, __staticSelector: "TimePicker", ...others, children: [/* @__PURE__ */ jsx("div", { ...getStyles("fieldsRoot"), dir: "ltr", children: /* @__PURE__ */ jsxs("div", { ...getStyles("fieldsGroup"), onBlur: handleBlur, children: [ /* @__PURE__ */ jsx(SpinInput, { id: hoursInputId, ...hoursInputProps, ...getStyles("field", { className: hoursInputProps?.className, style: isDuration ? { width: `calc(${Math.max(minHoursDigits, padTime(controller.values.hours ?? 0).length)}ch + 0.3em)`, ...hoursInputProps?.style } : hoursInputProps?.style }), value: controller.values.hours, onChange: controller.setHours, onNextInput: () => controller.focus("minutes"), min: format === "12h" ? 1 : 0, max: isDuration ? DURATION_HOURS_MAX : format === "12h" ? 12 : 23, allowTemporaryZero: format === "12h", disableAutoAdvance: isDuration, focusable: true, step: hoursStep, ref: _hoursRef, "aria-label": hoursInputLabel, readOnly, disabled, onPaste: controller.onPaste, onFocus: (event) => { handleFocus(event); hoursInputProps?.onFocus?.(event); }, onBlur: (event) => { const actualInputValue = event.currentTarget.value; if (format === "12h" && (actualInputValue ? parseInt(actualInputValue, 10) : null) === 0) controller.setHours(12); hoursInputProps?.onBlur?.(event); }, placeholder: resolvedHoursPlaceholder }), /* @__PURE__ */ jsx("span", { children: ":" }), /* @__PURE__ */ jsx(SpinInput, { ...minutesInputProps, ...getStyles("field", { className: minutesInputProps?.className, style: minutesInputProps?.style }), value: controller.values.minutes, onChange: controller.setMinutes, min: 0, max: 59, focusable: true, step: minutesStep, ref: _minutesRef, onPreviousInput: () => controller.focus("hours"), onNextInput: () => withSeconds ? controller.focus("seconds") : controller.focus("amPm"), "aria-label": minutesInputLabel, tabIndex: -1, readOnly, disabled, onPaste: controller.onPaste, onFocus: (event) => { handleFocus(event); minutesInputProps?.onFocus?.(event); }, placeholder: minutesPlaceholder }), withSeconds && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", { children: ":" }), /* @__PURE__ */ jsx(SpinInput, { ...secondsInputProps, ...getStyles("field", { className: secondsInputProps?.className, style: secondsInputProps?.style }), value: controller.values.seconds, onChange: controller.setSeconds, min: 0, max: 59, focusable: true, step: secondsStep, ref: _secondsRef, onPreviousInput: () => controller.focus("minutes"), onNextInput: () => controller.focus("amPm"), "aria-label": secondsInputLabel, tabIndex: -1, readOnly, disabled, onPaste: controller.onPaste, onFocus: (event) => { handleFocus(event); secondsInputProps?.onFocus?.(event); }, placeholder: secondsPlaceholder })] }), format === "12h" && !isDuration && /* @__PURE__ */ jsx(AmPmInput, { ...amPmSelectProps, inputType: withDropdown ? "input" : "select", labels: amPmLabels, value: controller.values.amPm, onChange: controller.setAmPm, ref: _amPmRef, "aria-label": amPmInputLabel, onPreviousInput: () => withSeconds ? controller.focus("seconds") : controller.focus("minutes"), readOnly, disabled, tabIndex: -1, onPaste: controller.onPaste, onFocus: (event) => { handleFocus(event); amPmSelectProps?.onFocus?.(event); } }) ] }) }), /* @__PURE__ */ jsx("input", { type: "hidden", name, form, value: controller.hiddenInputValue, ...hiddenInputProps })] }) }), /* @__PURE__ */ jsx(Popover.Dropdown, { ...getStyles("dropdown"), onMouseDown: (event) => event.preventDefault(), children: presets ? /* @__PURE__ */ jsx(TimePresets, { value: controller.hiddenInputValue, onChange: handlePresetSelect, format, presets, amPmLabels, withSeconds: withSeconds || false }) : /* @__PURE__ */ jsxs("div", { ...getStyles("controlsListGroup"), children: [ /* @__PURE__ */ jsx(TimeControlsList, { min: format === "12h" ? 1 : 0, max: format === "12h" ? 12 : 23, step: hoursStep, value: controller.values.hours, onSelect: controller.setHours, reversed: reverseTimeControlsList }), /* @__PURE__ */ jsx(TimeControlsList, { min: 0, max: 59, step: minutesStep, value: controller.values.minutes, onSelect: controller.setMinutes, reversed: reverseTimeControlsList }), withSeconds && /* @__PURE__ */ jsx(TimeControlsList, { min: 0, max: 59, step: secondsStep, value: controller.values.seconds, onSelect: controller.setSeconds, reversed: reverseTimeControlsList }), format === "12h" && /* @__PURE__ */ jsx(AmPmControlsList, { labels: amPmLabels, value: controller.values.amPm, onSelect: controller.setAmPm }) ] }) })] }) }); }); TimePicker.displayName = "@mantine/dates/TimePicker"; TimePicker.classes = TimePicker_module_default; TimePicker.varsResolver = varsResolver; //#endregion export { TimePicker }; //# sourceMappingURL=TimePicker.mjs.map