import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
import { forwardRef, useId, useRef, useCallback, useState, useMemo, useEffect } from 'react';
import { Popover, PopoverAnchor, PopoverContent } from './primitives/Popover.js';
import { Field, FieldLabel, FieldContent, FieldError, FieldDescription } from './primitives/Field.js';
import { c as cn } from './utils-BJnb9o5c.js';
import { u as useControlledOpen, c as coerceToTimeValue, f as formatTimeWithPattern, a as formatTimeDisplay, t as timeValueEquals, b as useOutsideClickClose, d as buildMaskTemplate, g as getDefaultTimeMaskFormat, e as useCursorRestore, S as SIZE_CONFIG, T as TimePickerPanel, h as timeValueToDayjs, i as getTimePlaceholder, j as applyMask, p as parseTimeWithPattern, k as parseTimeString } from './TimePickerPanel--KDX5QwS.js';
import { c as createLucideIcon } from './createLucideIcon-C8ycilSN.js';
import { X } from './x-_o2T3n6D.js';

/**
 * @license lucide-react v0.577.0 - ISC
 *
 * This source code is licensed under the ISC license.
 * See the LICENSE file in the root directory of this source tree.
 */


const __iconNode = [
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
  ["path", { d: "M12 6v6l4 2", key: "mmk7yg" }]
];
const Clock = createLucideIcon("clock", __iconNode);

const TimePicker = forwardRef(
  ({
    value,
    onChange,
    onBlur,
    type = "time",
    format = "24",
    displayFormat,
    showSeconds = false,
    minuteStep = 1,
    secondStep = 1,
    disabled = false,
    placeholder,
    label,
    error,
    helpText,
    size = "medium",
    required = false,
    timezone,
    open: openProp,
    onOpenChange,
    needConfirm = true,
    onOk,
    labelProps,
    className
  }, ref) => {
    const generatedId = useId();
    const errorId = `error_${generatedId}`;
    const helpTextId = `helpText_${generatedId}`;
    const containerRef = useRef(null);
    const fromInputRef = useRef(null);
    const toInputRef = useRef(null);
    const fromCursorRef = useRef(null);
    const toCursorRef = useRef(null);
    const popoverContentId = useRef(
      `timepicker-popover-${generatedId}`
    ).current;
    const committedRef = useRef({ from: null, to: null });
    const { open, setOpen } = useControlledOpen(openProp, onOpenChange);
    const isRange = type === "range";
    const getInitialTimes = useCallback(() => {
      if (isRange) {
        if (!value || !Array.isArray(value)) {
          return { from: null, to: null };
        }
        return {
          from: coerceToTimeValue(value[0]),
          to: coerceToTimeValue(value[1])
        };
      }
      return {
        from: coerceToTimeValue(value),
        to: null
      };
    }, [value, isRange]);
    const formatOne = useCallback(
      (time) => displayFormat ? formatTimeWithPattern(time, displayFormat) : formatTimeDisplay(time, format, showSeconds),
      [displayFormat, format, showSeconds]
    );
    const [activeSide, setActiveSide] = useState("from");
    const [fromTime, setFromTime] = useState(() => getInitialTimes().from);
    const [toTime, setToTime] = useState(() => getInitialTimes().to);
    const [fromText, setFromText] = useState(
      () => formatOne(getInitialTimes().from)
    );
    const [toText, setToText] = useState(() => formatOne(getInitialTimes().to));
    const parseOne = (text) => displayFormat ? parseTimeWithPattern(text, displayFormat) : parseTimeString(text, format);
    const emitChange = (from, to) => {
      if (isRange) {
        if (!from || !to) {
          onChange?.(null, ["", ""]);
          return;
        }
        onChange?.(
          [timeValueToDayjs(from), timeValueToDayjs(to)],
          [formatOne(from), formatOne(to)]
        );
        return;
      }
      if (!from) {
        onChange?.(null, "");
        return;
      }
      onChange?.(timeValueToDayjs(from), formatOne(from));
    };
    const commitPendingOnClose = useCallback(() => {
      if (!needConfirm) {
        setFromText(formatOne(fromTime));
        setToText(formatOne(toTime));
        return;
      }
      const { from: committedFrom, to: committedTo } = committedRef.current;
      const unchanged = timeValueEquals(fromTime, committedFrom) && timeValueEquals(toTime, committedTo);
      if (unchanged) return;
      emitChange(fromTime, toTime);
      committedRef.current = { from: fromTime, to: toTime };
    }, [needConfirm, fromTime, toTime, formatOne, isRange, onChange]);
    const closePopover = useCallback(() => {
      commitPendingOnClose();
      setOpen(false);
    }, [commitPendingOnClose, setOpen]);
    useOutsideClickClose({
      enabled: open,
      containerRef,
      popoverElementId: popoverContentId,
      onClose: closePopover
    });
    const maskTemplate = useMemo(
      () => displayFormat ? null : buildMaskTemplate(getDefaultTimeMaskFormat(format, showSeconds)),
      [displayFormat, format, showSeconds]
    );
    const handleOk = () => {
      if (isRange && activeSide === "from" && fromTime && !toTime) {
        setActiveSide("to");
        toInputRef.current?.focus();
        return;
      }
      committedRef.current = { from: fromTime, to: toTime };
      emitChange(fromTime, toTime);
      if (isRange) {
        if (fromTime && toTime) {
          onOk?.([timeValueToDayjs(fromTime), timeValueToDayjs(toTime)]);
        } else {
          onOk?.(null);
        }
      } else {
        onOk?.(fromTime ? timeValueToDayjs(fromTime) : null);
      }
      setOpen(false);
    };
    const handlePanelChange = (time) => {
      if (!isRange) {
        setFromTime(time);
        setFromText(formatOne(time));
        if (!needConfirm) emitChange(time, null);
        return;
      }
      if (activeSide === "from") {
        setFromTime(time);
        setFromText(formatOne(time));
        if (!needConfirm) emitChange(time, toTime);
        return;
      }
      setToTime(time);
      setToText(formatOne(time));
      if (!needConfirm) emitChange(fromTime, time);
    };
    const buildInputChangeHandler = (side) => (e) => {
      let text = e.target.value;
      const previousText = side === "from" ? fromText : toText;
      if (maskTemplate) {
        const masked = applyMask(
          text,
          maskTemplate,
          previousText,
          e.target.selectionStart
        );
        text = masked.text;
        if (side === "from") fromCursorRef.current = masked.cursorPosition;
        else toCursorRef.current = masked.cursorPosition;
      }
      if (side === "from") setFromText(text);
      else setToText(text);
      const parsed = parseOne(text);
      if (!parsed) return;
      if (side === "from") {
        setFromTime(parsed);
        if (!needConfirm) emitChange(parsed, toTime);
      } else {
        setToTime(parsed);
        if (!needConfirm) emitChange(fromTime, parsed);
      }
    };
    const handleInputKeyDown = (e) => {
      if (e.key === "Escape") {
        const { from, to } = committedRef.current;
        setFromTime(from);
        setToTime(to);
        setFromText(formatOne(from));
        setToText(formatOne(to));
        setOpen(false);
        return;
      }
      if (e.key !== "Enter") return;
      if (needConfirm) {
        handleOk();
        return;
      }
      setFromText(formatOne(fromTime));
      setToText(formatOne(toTime));
      setOpen(false);
    };
    const handleInputFocus = (side) => {
      setActiveSide(side);
      if (!open) setOpen(true);
    };
    const handleInputBlur = (e) => {
      const next = e.relatedTarget;
      if (next && containerRef.current?.contains(next)) return;
      const popoverEl = document.getElementById(popoverContentId);
      if (next && popoverEl?.contains(next)) return;
      onBlur?.(e);
    };
    const handleClear = (e) => {
      e.stopPropagation();
      e.preventDefault();
      setFromTime(null);
      setToTime(null);
      setFromText("");
      setToText("");
      committedRef.current = { from: null, to: null };
      onChange?.(null, isRange ? ["", ""] : "");
    };
    useEffect(() => {
      if (value === void 0) return;
      const next = getInitialTimes();
      setFromTime(next.from);
      setToTime(next.to);
      if (open) return;
      setFromText(formatOne(next.from));
      setToText(formatOne(next.to));
      committedRef.current = { from: next.from, to: next.to };
    }, [value, getInitialTimes, formatOne, open]);
    useEffect(() => {
      if (!open) return;
      committedRef.current = { from: fromTime, to: toTime };
    }, [open]);
    useCursorRestore([
      { inputRef: fromInputRef, cursorRef: fromCursorRef },
      { inputRef: toInputRef, cursorRef: toCursorRef }
    ]);
    const singlePlaceholder = getTimePlaceholder(
      format,
      showSeconds,
      displayFormat
    );
    const hasField = !!(label || error || helpText);
    const sizeConfig = SIZE_CONFIG[size];
    const hasAnyValue = !!(fromText || toText);
    const activeTime = activeSide === "from" ? fromTime : toTime;
    const ariaDescribedBy = [error ? errorId : null, helpText ? helpTextId : null].filter(Boolean).join(" ") || void 0;
    const inputBaseClass = cn(
      "min-w-0 bg-transparent outline-none placeholder:text-muted-foreground",
      "disabled:cursor-not-allowed",
      sizeConfig.input
    );
    const triggerContent = /* @__PURE__ */ jsxs(Popover, { open, children: [
      /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs(
        "div",
        {
          ref: containerRef,
          className: cn(
            "relative flex w-full items-center gap-2 rounded-md border border-input bg-transparent pe-8 ps-3",
            "focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
            disabled && "cursor-not-allowed opacity-50",
            !!error && "border-destructive ring-destructive/20 ring-3",
            sizeConfig.trigger,
            !hasField && className
          ),
          children: [
            timezone ? /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground", children: timezone.toUpperCase() }) : /* @__PURE__ */ jsx(
              Clock,
              {
                className: cn(
                  "shrink-0 text-muted-foreground",
                  sizeConfig.icon
                )
              }
            ),
            isRange ? /* @__PURE__ */ jsxs(Fragment, { children: [
              /* @__PURE__ */ jsx(
                "input",
                {
                  ref: fromInputRef,
                  type: "text",
                  disabled,
                  "aria-label": label ? `${label} start time` : "Pick a start time",
                  "aria-describedby": ariaDescribedBy,
                  "aria-invalid": !!error || void 0,
                  placeholder: placeholder ?? singlePlaceholder,
                  value: fromText,
                  onChange: buildInputChangeHandler("from"),
                  onKeyDown: handleInputKeyDown,
                  onFocus: () => handleInputFocus("from"),
                  onBlur: handleInputBlur,
                  className: cn(inputBaseClass, "flex-1")
                }
              ),
              /* @__PURE__ */ jsx(
                "span",
                {
                  "aria-hidden": "true",
                  className: "shrink-0 text-muted-foreground",
                  children: "~"
                }
              ),
              /* @__PURE__ */ jsx(
                "input",
                {
                  ref: toInputRef,
                  type: "text",
                  disabled,
                  "aria-label": label ? `${label} end time` : "Pick an end time",
                  "aria-describedby": ariaDescribedBy,
                  "aria-invalid": !!error || void 0,
                  placeholder: placeholder ?? singlePlaceholder,
                  value: toText,
                  onChange: buildInputChangeHandler("to"),
                  onKeyDown: handleInputKeyDown,
                  onFocus: () => handleInputFocus("to"),
                  onBlur: handleInputBlur,
                  className: cn(inputBaseClass, "flex-1")
                }
              )
            ] }) : /* @__PURE__ */ jsx(
              "input",
              {
                ref: fromInputRef,
                type: "text",
                disabled,
                "aria-label": label || "Pick a time",
                "aria-describedby": ariaDescribedBy,
                "aria-invalid": !!error || void 0,
                placeholder: placeholder ?? singlePlaceholder,
                value: fromText,
                onChange: buildInputChangeHandler("from"),
                onKeyDown: handleInputKeyDown,
                onFocus: () => handleInputFocus("from"),
                onBlur: handleInputBlur,
                className: cn(inputBaseClass, "flex-1")
              }
            ),
            /* @__PURE__ */ jsx(
              "button",
              {
                type: "button",
                onPointerDown: (e) => e.preventDefault(),
                onClick: handleClear,
                className: cn(
                  "absolute inset-y-0 end-2 flex items-center text-muted-foreground hover:text-foreground focus:outline-none",
                  !(hasAnyValue && !disabled) && "invisible"
                ),
                "aria-label": isRange ? "Clear time range" : "Clear time",
                tabIndex: -1,
                children: /* @__PURE__ */ jsx(X, { className: sizeConfig.icon })
              }
            )
          ]
        }
      ) }),
      open && /* @__PURE__ */ jsxs(
        PopoverContent,
        {
          id: popoverContentId,
          className: "w-auto p-0",
          align: "start",
          onOpenAutoFocus: (e) => e.preventDefault(),
          onCloseAutoFocus: (e) => e.preventDefault(),
          onPointerDownOutside: (e) => e.preventDefault(),
          onInteractOutside: (e) => e.preventDefault(),
          children: [
            /* @__PURE__ */ jsx(
              TimePickerPanel,
              {
                value: activeTime ?? void 0,
                onChange: handlePanelChange,
                format,
                showSeconds,
                minuteStep,
                secondStep,
                disabled
              }
            ),
            needConfirm && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end border-t border-border px-3 py-2", children: /* @__PURE__ */ jsx(
              "button",
              {
                type: "button",
                onClick: handleOk,
                className: "rounded bg-primary px-3 py-1 text-sm font-medium text-primary-foreground hover:bg-primary/90 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
                children: "OK"
              }
            ) })
          ]
        }
      )
    ] });
    if (!hasField) {
      return /* @__PURE__ */ jsx("div", { ref, className, children: triggerContent });
    }
    return /* @__PURE__ */ jsxs(
      Field,
      {
        ref,
        "data-disabled": disabled || void 0,
        "data-invalid": !!error || void 0,
        className,
        children: [
          label && /* @__PURE__ */ jsxs(
            FieldLabel,
            {
              ...labelProps,
              children: [
                label,
                required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-destructive", children: "*" })
              ]
            }
          ),
          /* @__PURE__ */ jsxs(FieldContent, { children: [
            triggerContent,
            !!error && /* @__PURE__ */ jsx(FieldError, { id: errorId, children: error }),
            helpText && /* @__PURE__ */ jsx(FieldDescription, { id: helpTextId, children: helpText })
          ] })
        ]
      }
    );
  }
);
TimePicker.displayName = "TimePicker";

export { TimePicker as T };
//# sourceMappingURL=TimePicker-CNz4odcf.js.map
