import { jsxs, jsx } from 'react/jsx-runtime';
import { forwardRef, useState, useCallback, useMemo, useId, useRef, useEffect } from 'react';
import { Calendar as Calendar$1 } from './primitives/Calendar.js';
import { PopoverAnchor, Popover, PopoverTrigger, PopoverContent } from './primitives/Popover.js';
import { c as cn } from './utils-BJnb9o5c.js';
import { u as useControlledOpen, l as isFixedWidthFormat, m as buildRangeMaskTemplate, d as buildMaskTemplate, b as useOutsideClickClose, e as useCursorRestore, T as TimePickerPanel, j as applyMask, n as dateToTimeValue } from './TimePickerPanel--KDX5QwS.js';
import pureDayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import { dayjs } from '@bigbinary/neeto-commons-frontend/utils';
import { Button } from './primitives/Button.js';
import { Field, FieldLabel, FieldContent, FieldError, FieldDescription } from './primitives/Field.js';
import { c as createLucideIcon } from './createLucideIcon-C8ycilSN.js';
import { X } from './x-_o2T3n6D.js';
import { C as ChevronLeft } from './chevron-left-BDoT8E2-.js';
import { C as ChevronRight } from './chevron-right-DQnrO-ek.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 = [
  ["path", { d: "M8 2v4", key: "1cmpym" }],
  ["path", { d: "M16 2v4", key: "4m81vk" }],
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
  ["path", { d: "M3 10h18", key: "8toen8" }]
];
const Calendar = createLucideIcon("calendar", __iconNode);

const DEFAULT_DATE_FORMAT = "dd/MM/yyyy";
const DEFAULT_TIME_FORMAT = "HH:mm:ss";
const INITIAL_TIME_VALUE = {
  hours: 0,
  minutes: 0,
  seconds: 0
};
const SIZE_CONFIG = {
  small: {
    trigger: "h-8 md:h-7",
    input: "text-base md:text-xs",
    icon: "size-3.5"
  },
  medium: {
    trigger: "h-8",
    input: "text-base md:text-sm",
    icon: "size-4"
  },
  large: {
    trigger: "h-10",
    input: "text-base md:text-sm",
    icon: "size-5"
  }
};

pureDayjs.extend(customParseFormat);
const toBrowserLocalDate = (date) => {
  const d = dayjs(date);
  return new Date(
    d.year(),
    d.month(),
    d.date(),
    d.hour(),
    d.minute(),
    d.second()
  );
};
const toNativeDate = (value) => {
  if (value == null) return null;
  if (value instanceof Date) return value;
  if (typeof value.toDate === "function") {
    return toBrowserLocalDate(value.toDate());
  }
  if (typeof value === "string") {
    const parsed = new Date(value);
    if (!isNaN(parsed.getTime())) return toBrowserLocalDate(parsed);
  }
  return null;
};
const coerceDateValue = (value, type) => {
  if (value == null) return null;
  if (type === "range" && Array.isArray(value)) {
    return [toNativeDate(value[0]), toNativeDate(value[1])];
  }
  return toNativeDate(value);
};
const getInitialCalendarMonth = (value, defaultValue, type) => {
  const initial = coerceDateValue(value ?? defaultValue, type);
  if (initial instanceof Date) return initial;
  if (Array.isArray(initial) && initial[0] instanceof Date) return initial[0];
  return /* @__PURE__ */ new Date();
};
const normalizeToDayjsFormat = (fmt) => fmt.replace(/\byyyy\b/g, "YYYY").replace(/\byy\b/g, "YY").replace(/\bdd\b/g, "DD").replace(/\bd\b/g, "D");
const normalizeToDateFnsFormat = (fmt) => fmt.replace(/YYYY/g, "yyyy").replace(/YY/g, "yy").replace(/DD/g, "dd").replace(/\bD\b/g, "d");
const formatDate = (date, formatStr) => {
  if (!date) return "";
  try {
    return pureDayjs(date).format(normalizeToDayjsFormat(formatStr));
  } catch {
    return "";
  }
};
const parseDate = (str, formatStr) => {
  if (!str) return null;
  const dayjsFmt = normalizeToDayjsFormat(formatStr);
  const parsed = pureDayjs(str, dayjsFmt);
  if (parsed.isValid()) return parsed.toDate();
  const fallbackFormats = [
    "DD/MM/YYYY",
    "MM/DD/YYYY",
    "YYYY-MM-DD",
    "DD-MM-YYYY",
    "DD/MM/YYYY HH:mm:ss",
    "DD/MM/YYYY HH:mm"
  ];
  for (const fmt of fallbackFormats) {
    if (fmt === dayjsFmt) continue;
    const attempt = pureDayjs(str, fmt);
    if (attempt.isValid()) return attempt.toDate();
  }
  return null;
};
const applyTimeToDate = (date, time) => {
  const result = new Date(date);
  result.setHours(time.hours, time.minutes, time.seconds ?? 0, 0);
  return result;
};
const toUserTzDayjs = (date) => dayjs(pureDayjs(date).format("YYYY-MM-DD HH:mm:ss"));
const getDisplayFormat = (dateFormat, timeFormat, showTime) => {
  const fmt = showTime ? `${dateFormat} ${timeFormat}` : dateFormat;
  return normalizeToDateFnsFormat(fmt);
};
const getDatePlaceholder = (dateFormat, timeFormat, showTime, type) => {
  const single = showTime ? `${dateFormat.toUpperCase()} ${timeFormat}` : dateFormat.toUpperCase();
  return type === "range" ? `${single} - ${single}` : single;
};
const isDatePartComplete = (part, maskEnabled, singleDateLen) => maskEnabled ? part.length >= singleDateLen : part.length > 0;
const parseRangeText = (text, displayFormat, maskEnabled, singleDateLen) => {
  const parts = text.split(" - ");
  if (parts.length !== 2) return null;
  if (!isDatePartComplete(parts[0], maskEnabled, singleDateLen) || !isDatePartComplete(parts[1], maskEnabled, singleDateLen))
    return null;
  const from = parseDate(parts[0], displayFormat);
  const to = parseDate(parts[1], displayFormat);
  return from && to ? [from, to] : null;
};
const startOfWeek = (date, weekStartsOn = 0) => {
  const d = new Date(date);
  const diff = (d.getDay() - weekStartsOn + 7) % 7;
  d.setDate(d.getDate() - diff);
  d.setHours(0, 0, 0, 0);
  return d;
};
const weekDaysFrom = (start) => Array.from({ length: 7 }, (_, i) => {
  const d = new Date(start);
  d.setDate(start.getDate() + i);
  return d;
});
const isMonthDisabled = (monthDate, minDate, maxDate) => {
  const monthStart = new Date(monthDate.getFullYear(), monthDate.getMonth(), 1);
  const monthEnd = new Date(
    monthDate.getFullYear(),
    monthDate.getMonth() + 1,
    0,
    23,
    59,
    59,
    999
  );
  if (maxDate && monthStart > maxDate) return true;
  if (minDate && monthEnd < minDate) return true;
  return false;
};
const isYearDisabled = (yearDate, minDate, maxDate) => {
  const yearStart = new Date(yearDate.getFullYear(), 0, 1);
  const yearEnd = new Date(yearDate.getFullYear(), 11, 31, 23, 59, 59, 999);
  if (maxDate && yearStart > maxDate) return true;
  if (minDate && yearEnd < minDate) return true;
  return false;
};
const buildMonth = (year, month) => new Date(year, month, 1);
const isSameMonth = (a, b) => !!a && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
const isSameDay = (a, b) => !!a && !!b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
const orderRange = (from, to) => {
  if (from && to && from.getTime() > to.getTime()) return [to, from];
  return [from, to];
};
const parseGridcellDay = (target) => {
  const el = target;
  const cell = el?.closest('[role="gridcell"][data-day]');
  const dayAttr = cell?.getAttribute("data-day");
  if (!dayAttr) return null;
  const parsed = new Date(dayAttr);
  return Number.isNaN(parsed.getTime()) ? null : parsed;
};
const computeRangePreview = ({
  pendingRange,
  committed,
  hoveredDate,
  rangeStep
}) => {
  let from = pendingRange ? pendingRange[0] : committed?.[0] ?? null;
  let to = pendingRange ? pendingRange[1] : committed?.[1] ?? null;
  if (hoveredDate) {
    if (rangeStep === "from") from = hoveredDate;
    else if (!isSameDay(from, hoveredDate)) to = hoveredDate;
  }
  [from, to] = orderRange(from, to);
  return { from, to };
};
const decadeStartFor = (year) => Math.floor(year / 10) * 10;

const TIMEZONE_OPTIONS = [
  { label: "Local", value: "" },
  { label: "UTC", value: "utc" }
];
const TimezoneSelect = ({
  value,
  onChange,
  className
}) => /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-1.5 text-sm", className), children: [
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: "Timezone" }),
  /* @__PURE__ */ jsx(
    "select",
    {
      value: value ?? "",
      onChange: (e) => onChange(e.target.value || void 0),
      className: cn(
        "rounded-md border border-input bg-background px-2 py-0.5 text-xs",
        "focus:outline-none focus:ring-1 focus:ring-ring"
      ),
      "aria-label": "Select timezone",
      children: TIMEZONE_OPTIONS.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
    }
  )
] });
TimezoneSelect.displayName = "TimezoneSelect";

const DatePickerFooter = ({
  showTime,
  needConfirm,
  timezone,
  onTimezoneChange,
  onNow,
  onOk,
  className
}) => {
  const showOkButton = showTime || needConfirm;
  return /* @__PURE__ */ jsxs(
    "div",
    {
      className: cn(
        "flex items-center border-t border-border px-3 py-2",
        className
      ),
      children: [
        /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onNow, className: "text-xs", children: "Now" }),
        /* @__PURE__ */ jsx("div", { className: "flex-1" }),
        onTimezoneChange && /* @__PURE__ */ jsx(
          TimezoneSelect,
          {
            value: timezone,
            onChange: onTimezoneChange,
            className: "me-2"
          }
        ),
        showOkButton && /* @__PURE__ */ jsx(Button, { size: "sm", onClick: onOk, className: "text-xs", children: "OK" })
      ]
    }
  );
};
DatePickerFooter.displayName = "DatePickerFooter";

const DatePickerField = forwardRef(
  ({
    disabled,
    error,
    className,
    label,
    required,
    helpText,
    labelProps,
    errorId,
    helpTextId,
    children
  }, ref) => /* @__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: [
          children,
          !!error && /* @__PURE__ */ jsx(FieldError, { id: errorId, children: error }),
          helpText && /* @__PURE__ */ jsx(FieldDescription, { id: helpTextId, children: helpText })
        ] })
      ]
    }
  )
);
DatePickerField.displayName = "DatePickerField";

const DatePickerTrigger = forwardRef(
  ({
    containerRef,
    inputRef,
    disabled,
    error,
    hasField,
    className,
    triggerSizeClass,
    inputSizeClass,
    iconSizeClass,
    label,
    ariaDescribedBy,
    placeholder,
    inputText,
    allowClear,
    timezone,
    onInputChange,
    onInputKeyDown,
    onInputFocus,
    onInputBlur,
    onClear
  }, _ref) => /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs(
    "div",
    {
      ref: containerRef,
      className: cn(
        "relative flex w-full cursor-text 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",
        triggerSizeClass,
        !hasField && className
      ),
      onClick: () => {
        if (disabled) return;
        inputRef.current?.focus();
      },
      children: [
        /* @__PURE__ */ jsx(
          Calendar,
          {
            className: cn("shrink-0 text-muted-foreground", iconSizeClass)
          }
        ),
        /* @__PURE__ */ jsx(
          "input",
          {
            ref: inputRef,
            type: "text",
            disabled,
            "aria-label": label || "Pick a date",
            "aria-describedby": ariaDescribedBy,
            "aria-invalid": !!error || void 0,
            placeholder,
            value: inputText,
            onChange: onInputChange,
            onKeyDown: onInputKeyDown,
            onFocus: onInputFocus,
            onBlur: onInputBlur,
            className: cn(
              "min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground",
              "disabled:cursor-not-allowed",
              inputSizeClass
            )
          }
        ),
        timezone && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground", children: timezone.toUpperCase() }),
        allowClear && /* @__PURE__ */ jsx(
          "button",
          {
            type: "button",
            onPointerDown: (e) => e.preventDefault(),
            onClick: onClear,
            className: cn(
              "absolute inset-y-0 end-2 flex items-center text-muted-foreground hover:text-foreground focus:outline-none",
              !(inputText && !disabled) && "invisible"
            ),
            "aria-label": "Clear date",
            tabIndex: -1,
            children: /* @__PURE__ */ jsx(X, { className: iconSizeClass })
          }
        )
      ]
    }
  ) })
);
DatePickerTrigger.displayName = "DatePickerTrigger";

const MonthPicker = ({
  value,
  displayedYear,
  onYearChange,
  onSelect,
  isDisabled,
  locale
}) => {
  const months = Array.from(
    { length: 12 },
    (_, m) => buildMonth(displayedYear, m)
  );
  const monthName = (date) => date.toLocaleString(locale, { month: "short" });
  return /* @__PURE__ */ jsxs("div", { className: "bg-background flex w-[16rem] flex-col gap-3 p-2", children: [
    /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
      /* @__PURE__ */ jsx(
        Button,
        {
          "aria-label": "Previous year",
          size: "icon",
          variant: "ghost",
          onClick: () => onYearChange(displayedYear - 1),
          children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4 rtl:rotate-180" })
        }
      ),
      /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: displayedYear }),
      /* @__PURE__ */ jsx(
        Button,
        {
          "aria-label": "Next year",
          size: "icon",
          variant: "ghost",
          onClick: () => onYearChange(displayedYear + 1),
          children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4 rtl:rotate-180" })
        }
      )
    ] }),
    /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-2", children: months.map((monthDate) => {
      const disabled = isDisabled?.(monthDate) ?? false;
      const selected = isSameMonth(value, monthDate);
      return /* @__PURE__ */ jsx(
        "button",
        {
          "aria-pressed": selected,
          className: cn(
            "rounded-md py-2 text-sm transition-colors",
            "hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
            selected && "bg-primary text-primary-foreground hover:bg-primary"
          ),
          disabled,
          type: "button",
          onClick: () => onSelect(monthDate),
          children: monthName(monthDate)
        },
        monthDate.getMonth()
      );
    }) })
  ] });
};

const RangeCalendar = ({
  todayDate,
  weekStartsOn,
  month,
  onMonthChange,
  selected,
  onSelect,
  disabled,
  fromDate,
  toDate,
  onHoverIn,
  onHoverOut
}) => /* @__PURE__ */ jsx("div", { onMouseOver: onHoverIn, onMouseLeave: onHoverOut, children: /* @__PURE__ */ jsx(
  Calendar$1,
  {
    mode: "range",
    numberOfMonths: 2,
    captionLayout: "dropdown",
    today: todayDate,
    weekStartsOn,
    className: "[&_[data-outside][data-selected=true]]:!bg-transparent [&_[data-outside][data-selected=true]]:after:!bg-transparent [&_[data-outside]_button]:!bg-transparent [&_[data-outside]_button]:!text-muted-foreground",
    month,
    onMonthChange,
    selected,
    onSelect,
    disabled,
    ...fromDate && { fromDate },
    ...toDate && { toDate }
  }
) });

const useRangePicker = ({
  currentValue,
  showTime,
  needConfirm,
  commitValue,
  setPendingDate,
  setOpen
}) => {
  const [pendingRange, setPendingRange] = useState(null);
  const [rangeSelectionStep, setRangeSelectionStep] = useState(
    "from"
  );
  const [hoveredDate, setHoveredDate] = useState(null);
  const committed = currentValue ?? null;
  const resetTransientState = useCallback(() => {
    setPendingRange(null);
    setRangeSelectionStep("from");
    setHoveredDate(null);
  }, []);
  const handleRangeSelect = useCallback(
    (_range, triggerDate) => {
      if (!triggerDate) return;
      if (rangeSelectionStep === "from" || !pendingRange?.[0]) {
        const existingTo = pendingRange?.[1] ?? committed?.[1] ?? null;
        const nextTo = existingTo && triggerDate <= existingTo ? existingTo : null;
        setPendingRange([triggerDate, nextTo]);
        setRangeSelectionStep("to");
        return;
      }
      const [from, to] = orderRange(pendingRange[0], triggerDate);
      setRangeSelectionStep("from");
      setPendingRange(null);
      if (showTime || needConfirm) {
        setPendingDate(from);
        return;
      }
      commitValue([from, to]);
      setOpen(false);
    },
    [
      rangeSelectionStep,
      pendingRange,
      committed,
      showTime,
      needConfirm,
      commitValue,
      setPendingDate,
      setOpen
    ]
  );
  const handleHoverIn = useCallback(
    (e) => {
      const parsed = parseGridcellDay(e.target);
      if (!parsed) return;
      if (hoveredDate && hoveredDate.getTime() === parsed.getTime()) return;
      setHoveredDate(parsed);
    },
    [hoveredDate]
  );
  const handleHoverOut = useCallback(() => setHoveredDate(null), []);
  const memoizedRangeSelected = useMemo(() => {
    const { from, to } = computeRangePreview({
      pendingRange,
      committed,
      hoveredDate,
      rangeStep: rangeSelectionStep
    });
    if (!from && !to) return void 0;
    return { from: from ?? void 0, to: to ?? void 0 };
  }, [pendingRange, committed, hoveredDate, rangeSelectionStep]);
  const getPreviewParts = useCallback(
    () => computeRangePreview({
      pendingRange,
      committed,
      hoveredDate,
      rangeStep: rangeSelectionStep
    }),
    [pendingRange, committed, hoveredDate, rangeSelectionStep]
  );
  return {
    pendingRange,
    rangeSelectionStep,
    hoveredDate,
    handleRangeSelect,
    handleHoverIn,
    handleHoverOut,
    memoizedRangeSelected,
    getPreviewParts,
    resetTransientState
  };
};

const YearPicker = ({
  value,
  displayedYear,
  onYearChange,
  onSelect,
  isDisabled
}) => {
  const decadeStart = decadeStartFor(displayedYear);
  const years = Array.from({ length: 12 }, (_, i) => decadeStart - 1 + i);
  const selectedYear = value?.getFullYear();
  return /* @__PURE__ */ jsxs("div", { className: "bg-background flex w-[16rem] flex-col gap-3 p-2", children: [
    /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
      /* @__PURE__ */ jsx(
        Button,
        {
          "aria-label": "Previous decade",
          size: "icon",
          variant: "ghost",
          onClick: () => onYearChange(decadeStart - 10),
          children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4 rtl:rotate-180" })
        }
      ),
      /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium", children: [
        decadeStart,
        "-",
        decadeStart + 9
      ] }),
      /* @__PURE__ */ jsx(
        Button,
        {
          "aria-label": "Next decade",
          size: "icon",
          variant: "ghost",
          onClick: () => onYearChange(decadeStart + 10),
          children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4 rtl:rotate-180" })
        }
      )
    ] }),
    /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-2", children: years.map((year) => {
      const yearDate = new Date(year, 0, 1);
      const disabled = isDisabled?.(yearDate) ?? false;
      const selected = selectedYear === year;
      const outsideDecade = year < decadeStart || year > decadeStart + 9;
      return /* @__PURE__ */ jsx(
        "button",
        {
          "aria-pressed": selected,
          className: cn(
            "rounded-md py-2 text-sm transition-colors",
            "hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50",
            outsideDecade && "text-muted-foreground",
            selected && "bg-primary text-primary-foreground hover:bg-primary"
          ),
          disabled,
          type: "button",
          onClick: () => onSelect(yearDate),
          children: year
        },
        year
      );
    }) })
  ] });
};

const DatePicker = forwardRef(
  ({
    value,
    defaultValue,
    onChange,
    onBlur,
    type = "date",
    dateFormat = DEFAULT_DATE_FORMAT,
    timeFormat = DEFAULT_TIME_FORMAT,
    showTime = false,
    timePickerFormat = "24",
    showSeconds = false,
    minDate,
    maxDate,
    disabledDate,
    placeholder,
    label,
    error,
    helpText,
    size = "medium",
    disabled = false,
    allowClear = true,
    required = false,
    timezone,
    onTimezoneChange,
    onOk,
    needConfirm = false,
    open: openProp,
    onOpenChange,
    className,
    labelProps,
    picker = "date",
    side = "bottom",
    align = "start",
    trigger,
    weekStartsOn = 0
  }, ref) => {
    const generatedId = useId();
    const errorId = `error_${generatedId}`;
    const helpTextId = `helpText_${generatedId}`;
    const containerRef = useRef(null);
    const inputRef = useRef(null);
    const cursorPosRef = useRef(null);
    const popoverContentId = useRef(
      `datepicker-popover-${generatedId}`
    ).current;
    const { open, setOpen } = useControlledOpen(openProp, onOpenChange);
    const [internalValue, setInternalValue] = useState(
      coerceDateValue(defaultValue, type) ?? null
    );
    const [calendarMonth, setCalendarMonth] = useState(
      () => getInitialCalendarMonth(value, defaultValue, type)
    );
    const [pendingDate, setPendingDate] = useState(null);
    const [pendingTime, setPendingTime] = useState(INITIAL_TIME_VALUE);
    const currentValue = useMemo(
      () => value !== void 0 ? coerceDateValue(value, type) : internalValue,
      [value, type, internalValue]
    );
    const normalizedMinDate = useMemo(
      () => toNativeDate(minDate) ?? void 0,
      [minDate]
    );
    const normalizedMaxDate = useMemo(
      () => toNativeDate(maxDate) ?? void 0,
      [maxDate]
    );
    const displayFormat = getDisplayFormat(dateFormat, timeFormat, showTime);
    const sizeConfig = SIZE_CONFIG[size];
    const maskEnabled = isFixedWidthFormat(displayFormat);
    const defaultPlaceholder = getDatePlaceholder(
      dateFormat,
      timeFormat,
      showTime,
      type
    );
    const maskTemplate = useMemo(
      () => maskEnabled ? type === "range" ? buildRangeMaskTemplate(displayFormat) : buildMaskTemplate(displayFormat) : null,
      [displayFormat, type, maskEnabled]
    );
    const singleDateLen = useMemo(
      () => buildMaskTemplate(displayFormat).pattern.length,
      [displayFormat]
    );
    const calendarDisabled = useCallback(
      (date) => {
        if (disabledDate?.(date)) return true;
        if (normalizedMinDate && date < new Date(new Date(normalizedMinDate).setHours(0, 0, 0, 0)))
          return true;
        if (normalizedMaxDate && date > new Date(new Date(normalizedMaxDate).setHours(23, 59, 59, 999)))
          return true;
        return false;
      },
      [normalizedMinDate, normalizedMaxDate, disabledDate]
    );
    const getDisplayText = useCallback(() => {
      if (type !== "range") {
        return formatDate(currentValue, displayFormat);
      }
      const rangeValue = currentValue;
      if (!rangeValue || !rangeValue[0] && !rangeValue[1]) return "";
      const from = rangeValue[0] ? formatDate(rangeValue[0], displayFormat) : "";
      const to = rangeValue[1] ? formatDate(rangeValue[1], displayFormat) : "";
      return `${from} - ${to}`;
    }, [currentValue, displayFormat, type]);
    const [inputText, setInputText] = useState(() => getDisplayText());
    const commitValue = (date) => {
      if (date === null) {
        setInternalValue(null);
        if (type === "range") {
          onChange?.([null, null], ["", ""]);
        } else {
          onChange?.(null, "");
        }
        setInputText("");
        return;
      }
      const toSerializableDayjs = (d) => {
        const userTzDayjs = toUserTzDayjs(d);
        if (showTime) return userTzDayjs;
        return userTzDayjs.hour(12).minute(0).second(0).millisecond(0);
      };
      if (Array.isArray(date)) {
        setInternalValue(date);
        const formatted2 = [
          formatDate(date[0], displayFormat),
          formatDate(date[1], displayFormat)
        ];
        onChange?.(
          [toSerializableDayjs(date[0]), toSerializableDayjs(date[1])],
          formatted2
        );
        setInputText(`${formatted2[0]} - ${formatted2[1]}`);
        return;
      }
      setInternalValue(date);
      const formatted = formatDate(date, displayFormat);
      onChange?.(toSerializableDayjs(date), formatted);
      setInputText(formatted);
    };
    const {
      pendingRange,
      handleRangeSelect,
      handleHoverIn,
      handleHoverOut,
      memoizedRangeSelected,
      getPreviewParts,
      resetTransientState
    } = useRangePicker({
      currentValue,
      showTime,
      needConfirm,
      commitValue,
      setPendingDate,
      setOpen
    });
    useEffect(() => {
      if (type !== "range" || !open) return;
      const { from, to } = getPreviewParts();
      const fromText = from ? formatDate(from, displayFormat) : "";
      const toText = to ? formatDate(to, displayFormat) : "";
      setInputText(fromText || toText ? `${fromText} - ${toText}` : "");
    }, [type, open, getPreviewParts, displayFormat]);
    const parseAndApplyRange = (text, cursorPos) => {
      const parts = text.split(" - ");
      const separatorIdx = text.indexOf(" - ");
      const editingTo = separatorIdx >= 0 && cursorPos !== null && cursorPos > separatorIdx + 2;
      if (editingTo) {
        const to = parseDate(parts[1] ?? "", displayFormat);
        if (to) setCalendarMonth(to);
      } else {
        if (!isDatePartComplete(parts[0] ?? "", maskEnabled, singleDateLen))
          return;
        const from = parseDate(parts[0] ?? "", displayFormat);
        if (from) setCalendarMonth(from);
      }
      const range = parseRangeText(
        text,
        displayFormat,
        maskEnabled,
        singleDateLen
      );
      if (range) commitValue(range);
    };
    const commitPendingOnClose = useCallback(() => {
      const hasOkButton = showTime || needConfirm;
      if (!hasOkButton || !pendingDate) {
        setInputText(getDisplayText());
        return;
      }
      const finalDate = showTime ? applyTimeToDate(pendingDate, pendingTime) : pendingDate;
      const currentSingle = type === "date" ? currentValue : null;
      const isSame = currentSingle && finalDate.getTime() === currentSingle.getTime();
      if (isSame) {
        setInputText(getDisplayText());
        return;
      }
      commitValue(finalDate);
    }, [
      showTime,
      needConfirm,
      pendingDate,
      pendingTime,
      type,
      currentValue,
      getDisplayText,
      onChange
    ]);
    const closePopover = useCallback(() => {
      if (type === "range" && pendingRange?.[0] && pendingRange?.[1]) {
        commitValue([pendingRange[0], pendingRange[1]]);
      } else {
        commitPendingOnClose();
      }
      resetTransientState();
      setOpen(false);
    }, [
      commitPendingOnClose,
      setOpen,
      type,
      pendingRange,
      resetTransientState
    ]);
    useOutsideClickClose({
      enabled: open,
      containerRef,
      popoverElementId: popoverContentId,
      onClose: closePopover
    });
    const openPopover = () => {
      setOpen(true);
      resetTransientState();
      const dateVal = type === "date" ? currentValue : null;
      if (!dateVal) {
        setPendingDate(null);
        setPendingTime(INITIAL_TIME_VALUE);
        return;
      }
      setCalendarMonth(dateVal);
      setPendingDate(dateVal);
      setPendingTime(dateToTimeValue(dateVal));
    };
    const handleDateSelect = (selected) => {
      if (!selected) return;
      setCalendarMonth(selected);
      if (showTime || needConfirm) {
        setPendingDate(selected);
        return;
      }
      commitValue(selected);
      setOpen(false);
    };
    const handleNow = () => {
      const now = toBrowserLocalDate(/* @__PURE__ */ new Date());
      if (showTime || needConfirm) {
        setPendingDate(now);
        setPendingTime(dateToTimeValue(now));
        return;
      }
      commitValue(now);
      setOpen(false);
    };
    const handleOk = () => {
      if (pendingDate) {
        const finalDate = showTime ? applyTimeToDate(pendingDate, pendingTime) : pendingDate;
        commitValue(finalDate);
        onOk?.(finalDate);
      }
      setOpen(false);
    };
    const handleClear = (e) => {
      e.stopPropagation();
      e.preventDefault();
      commitValue(null);
    };
    const handleInputChange = (e) => {
      let text = e.target.value;
      if (maskTemplate) {
        const masked = applyMask(
          text,
          maskTemplate,
          inputText,
          e.target.selectionStart
        );
        text = masked.text;
        cursorPosRef.current = masked.cursorPosition;
      }
      setInputText(text);
      if (type === "range") {
        parseAndApplyRange(text, e.target.selectionStart);
        return;
      }
      const isComplete = maskTemplate ? text.length >= maskTemplate.pattern.length : true;
      if (!isComplete) return;
      const parsed = parseDate(text, displayFormat);
      if (!parsed) return;
      setCalendarMonth(parsed);
      if (showTime || needConfirm) {
        setPendingDate(parsed);
        setPendingTime(dateToTimeValue(parsed));
        return;
      }
      commitValue(parsed);
    };
    const handleInputKeyDown = (e) => {
      if (e.key === "Escape") {
        setPendingDate(null);
        setPendingTime(INITIAL_TIME_VALUE);
        setInputText(getDisplayText());
        setOpen(false);
        return;
      }
      if (e.key !== "Enter") return;
      if (type === "range") {
        const range = parseRangeText(
          inputText,
          displayFormat,
          maskEnabled,
          singleDateLen
        );
        if (range) commitValue(range);
      } else {
        const parsed = parseDate(inputText, displayFormat);
        if (parsed) commitValue(parsed);
      }
      setOpen(false);
    };
    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);
    };
    useEffect(() => {
      if (!open) setInputText(getDisplayText());
    }, [getDisplayText, open]);
    useCursorRestore([{ inputRef, cursorRef: cursorPosRef }]);
    useEffect(() => {
      if (!open || type !== "date") return;
      const dateVal = currentValue;
      if (dateVal instanceof Date) setCalendarMonth(dateVal);
    }, [open]);
    const hasField = !!(label || error || helpText);
    const showFooter = showTime || needConfirm || !!onTimezoneChange;
    const todayDate = toBrowserLocalDate(/* @__PURE__ */ new Date());
    const handleGridPickerSelect = (date) => {
      commitValue(date);
      setOpen(false);
    };
    const handleSingleDateSelectWithPicker = (selected) => {
      if (!selected) return handleDateSelect(void 0);
      handleDateSelect(
        picker === "week" ? startOfWeek(selected, weekStartsOn) : selected
      );
    };
    const weekHighlightProps = (() => {
      if (picker !== "week" || type !== "date" || !currentValue) return {};
      const weekStart = startOfWeek(currentValue, weekStartsOn);
      const weekDays = weekDaysFrom(weekStart);
      return {
        modifiers: {
          weekStart: [weekDays[0]],
          weekMiddle: weekDays.slice(1, 6),
          weekEnd: [weekDays[6]]
        },
        modifiersClassNames: {
          weekStart: "!bg-primary !text-primary-foreground !rounded-e-none hover:!bg-primary",
          weekMiddle: "!bg-primary !text-primary-foreground !rounded-none hover:!bg-primary",
          weekEnd: "!bg-primary !text-primary-foreground !rounded-s-none hover:!bg-primary"
        }
      };
    })();
    const weekRowHoverClassName = picker === "week" ? "[&_button]:!transition-none [&:hover_button]:!bg-primary [&:hover_button]:!text-primary-foreground [&:hover_button]:!rounded-none [&:hover_button]:cursor-pointer" : void 0;
    const ariaDescribedBy = [error ? errorId : null, helpText ? helpTextId : null].filter(Boolean).join(" ") || void 0;
    const calendarSelected = () => {
      if (showTime || needConfirm) {
        return pendingDate ?? currentValue ?? void 0;
      }
      return currentValue ?? void 0;
    };
    const handleTriggerOpenChange = (nextOpen) => {
      if (nextOpen === open) return;
      if (nextOpen) openPopover();
      else closePopover();
    };
    const triggerContent = /* @__PURE__ */ jsxs(
      Popover,
      {
        open,
        onOpenChange: trigger ? handleTriggerOpenChange : void 0,
        children: [
          trigger ? /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: trigger }) : /* @__PURE__ */ jsx(
            DatePickerTrigger,
            {
              containerRef,
              inputRef,
              disabled,
              error,
              hasField,
              className,
              triggerSizeClass: sizeConfig.trigger,
              inputSizeClass: sizeConfig.input,
              iconSizeClass: sizeConfig.icon,
              label,
              ariaDescribedBy,
              placeholder: placeholder ?? defaultPlaceholder,
              inputText,
              allowClear,
              timezone,
              onInputChange: handleInputChange,
              onInputKeyDown: handleInputKeyDown,
              onInputFocus: () => {
                if (!open) openPopover();
              },
              onInputBlur: handleInputBlur,
              onClear: handleClear
            }
          ),
          open && /* @__PURE__ */ jsxs(
            PopoverContent,
            {
              id: popoverContentId,
              className: "w-auto p-0",
              align,
              side,
              onOpenAutoFocus: (e) => e.preventDefault(),
              onCloseAutoFocus: (e) => e.preventDefault(),
              onPointerDownOutside: (e) => e.preventDefault(),
              onInteractOutside: (e) => e.preventDefault(),
              children: [
                /* @__PURE__ */ jsxs("div", { className: cn("flex", showTime && "flex-row"), children: [
                  type === "date" && picker === "month" ? /* @__PURE__ */ jsx(
                    MonthPicker,
                    {
                      value: currentValue ?? null,
                      displayedYear: calendarMonth.getFullYear(),
                      onYearChange: (year) => setCalendarMonth(
                        new Date(year, calendarMonth.getMonth(), 1)
                      ),
                      onSelect: handleGridPickerSelect,
                      isDisabled: (date) => isMonthDisabled(date, normalizedMinDate, normalizedMaxDate)
                    }
                  ) : type === "date" && picker === "year" ? /* @__PURE__ */ jsx(
                    YearPicker,
                    {
                      value: currentValue ?? null,
                      displayedYear: calendarMonth.getFullYear(),
                      onYearChange: (year) => setCalendarMonth(new Date(year, 0, 1)),
                      onSelect: handleGridPickerSelect,
                      isDisabled: (date) => isYearDisabled(date, normalizedMinDate, normalizedMaxDate)
                    }
                  ) : type === "date" ? /* @__PURE__ */ jsx(
                    Calendar$1,
                    {
                      mode: "single",
                      captionLayout: "dropdown",
                      today: todayDate,
                      month: calendarMonth,
                      onMonthChange: setCalendarMonth,
                      selected: calendarSelected(),
                      onSelect: handleSingleDateSelectWithPicker,
                      disabled: calendarDisabled,
                      weekStartsOn,
                      classNames: weekRowHoverClassName ? { week: cn("mt-2 flex w-full", weekRowHoverClassName) } : void 0,
                      ...weekHighlightProps,
                      ...normalizedMinDate && { fromDate: normalizedMinDate },
                      ...normalizedMaxDate && { toDate: normalizedMaxDate }
                    }
                  ) : /* @__PURE__ */ jsx(
                    RangeCalendar,
                    {
                      todayDate,
                      weekStartsOn,
                      month: calendarMonth,
                      onMonthChange: setCalendarMonth,
                      selected: memoizedRangeSelected,
                      onSelect: handleRangeSelect,
                      disabled: calendarDisabled,
                      fromDate: normalizedMinDate,
                      toDate: normalizedMaxDate,
                      onHoverIn: handleHoverIn,
                      onHoverOut: handleHoverOut
                    }
                  ),
                  showTime && /* @__PURE__ */ jsx("div", { className: "border-inline-start border-border", children: /* @__PURE__ */ jsx(
                    TimePickerPanel,
                    {
                      value: pendingTime,
                      onChange: setPendingTime,
                      format: timePickerFormat,
                      showSeconds,
                      disabled
                    }
                  ) })
                ] }),
                showFooter && /* @__PURE__ */ jsx(
                  DatePickerFooter,
                  {
                    showTime,
                    needConfirm,
                    timezone,
                    onTimezoneChange,
                    onNow: handleNow,
                    onOk: handleOk
                  }
                )
              ]
            }
          )
        ]
      }
    );
    if (!hasField) {
      return /* @__PURE__ */ jsx("div", { ref, className, children: triggerContent });
    }
    return /* @__PURE__ */ jsx(
      DatePickerField,
      {
        ref,
        disabled,
        error,
        className,
        label,
        required,
        helpText,
        labelProps,
        errorId,
        helpTextId,
        children: triggerContent
      }
    );
  }
);
DatePicker.displayName = "DatePicker";

export { DatePicker as D };
//# sourceMappingURL=DatePicker-1OZmK2ki.js.map
