import { forwardRef, useId, useRef, useCallback, useEffect, useState, useMemo, useLayoutEffect, isValidElement, version, cloneElement } from 'react';
import { useTheme, css } from '@emotion/react';
import { jsxs, jsx, Fragment } from '@emotion/react/jsx-runtime';
import { createPortal } from 'react-dom';

// src/Button/Button.tsx
function withAlpha(color, alpha) {
  const a = Math.max(0, Math.min(1, alpha));
  const c = color.trim();
  const rgbMatch = c.match(
    /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:[\s,/]+[\d.%]+)?\s*\)$/i
  );
  if (rgbMatch) {
    const [, r, g, b] = rgbMatch;
    return `rgba(${r}, ${g}, ${b}, ${a})`;
  }
  const hexMatch = c.match(/^#([0-9a-f]{3,8})$/i);
  if (hexMatch && hexMatch[1]) {
    let h = hexMatch[1];
    if (h.length === 3) {
      h = h.split("").map((ch) => ch + ch).join("");
    }
    if (h.length === 6 || h.length === 8) {
      const r = parseInt(h.slice(0, 2), 16);
      const g = parseInt(h.slice(2, 4), 16);
      const b = parseInt(h.slice(4, 6), 16);
      return `rgba(${r}, ${g}, ${b}, ${a})`;
    }
  }
  return c;
}
function resolveVariantColor(variant, color) {
  const newVariants = [
    "solid",
    "bordered",
    "light",
    "flat",
    "faded",
    "shadow",
    "ghost"
  ];
  if (variant && newVariants.includes(variant)) {
    return { variant, color: color ?? "default" };
  }
  switch (variant) {
    case "primary":
      return { variant: "solid", color: color ?? "primary" };
    case "secondary":
      return { variant: "solid", color: color ?? "secondary" };
    case "outline":
      return { variant: "bordered", color: color ?? "primary" };
    case "danger":
      return { variant: "solid", color: color ?? "danger" };
    case "ghost":
      return color ? { variant: "ghost", color } : { variant: "light", color: "default" };
    default:
      return { variant: "solid", color: color ?? "default" };
  }
}
var Spinner = ({ size = 14 }) => /* @__PURE__ */ jsx(
  "span",
  {
    "aria-hidden": true,
    css: css`
      width: ${size}px;
      height: ${size}px;
      border: 2px solid currentColor;
      border-right-color: transparent;
      border-radius: 50%;
      display: inline-block;
      flex-shrink: 0;
      animation: timeui-spin 0.7s linear infinite;
      @media (prefers-reduced-motion: reduce) {
        animation: none;
      }
      @keyframes timeui-spin {
        to {
          transform: rotate(360deg);
        }
      }
    `
  }
);
var spinnerSize = {
  xs: 12,
  sm: 14,
  md: 16,
  lg: 18,
  xl: 20
};
var Button = forwardRef(function Button2({
  as,
  variant,
  color,
  size = "md",
  radius: radiusProp,
  isLoading = false,
  isDisabled = false,
  isFullWidth = false,
  isIconOnly = false,
  startIcon,
  endIcon,
  children,
  type,
  title: titleProp,
  "aria-label": ariaLabel,
  ...rest
}, ref) {
  const tooltipTitle = titleProp ?? (isIconOnly ? ariaLabel : void 0);
  const theme = useTheme();
  const Comp = as || "button";
  const isButton = Comp === "button";
  const { variant: v, color: c } = resolveVariantColor(variant, color);
  const scale = theme.colors[c];
  const neutral = theme.colors.default;
  const focusColor = theme.colors.focus;
  const borderThin = theme.borders.width.thin;
  const sizeTokens = theme.components.button[size];
  const sizeRadiusMap = {
    xs: "sm",
    sm: "sm",
    md: "md",
    lg: "lg",
    xl: "lg"
  };
  const radiusKey = radiusProp ?? sizeRadiusMap[size];
  const borderRadius = theme.componentRadius[radiusKey];
  let bg = "transparent";
  let fg = scale.DEFAULT;
  let border = "0 solid transparent";
  let boxShadow = "none";
  let hoverBg = null;
  let hoverFg = null;
  switch (v) {
    case "solid":
      bg = scale.DEFAULT;
      fg = scale.foreground;
      hoverBg = withAlpha(scale.DEFAULT, 0.9);
      break;
    case "bordered":
      bg = "transparent";
      fg = scale[600];
      border = `${borderThin} solid ${scale.DEFAULT}`;
      hoverBg = withAlpha(scale.DEFAULT, 0.12);
      break;
    case "light":
      bg = "transparent";
      fg = scale[600];
      hoverBg = withAlpha(scale.DEFAULT, 0.2);
      break;
    case "flat":
      bg = withAlpha(scale.DEFAULT, 0.2);
      fg = scale[600];
      hoverBg = withAlpha(scale.DEFAULT, 0.3);
      break;
    case "faded":
      bg = neutral[100];
      fg = scale[600];
      border = `${borderThin} solid ${neutral[200]}`;
      break;
    case "shadow":
      bg = scale.DEFAULT;
      fg = scale.foreground;
      boxShadow = `${withAlpha(scale.DEFAULT, 0.4)} 0 10px 15px -3px, ${withAlpha(
        scale.DEFAULT,
        0.4
      )} 0 4px 6px -4px`;
      hoverBg = withAlpha(scale.DEFAULT, 0.9);
      break;
    case "ghost":
      bg = "transparent";
      fg = scale[600];
      border = `${borderThin} solid ${scale.DEFAULT}`;
      hoverBg = scale.DEFAULT;
      hoverFg = scale.foreground;
      break;
  }
  const duration = theme.motion.duration.normal ?? "250ms";
  return /* @__PURE__ */ jsxs(
    Comp,
    {
      ref,
      type: isButton ? type ?? "button" : type,
      disabled: isButton ? isDisabled || isLoading : void 0,
      "aria-label": ariaLabel,
      "aria-disabled": isDisabled || isLoading || void 0,
      "aria-busy": isLoading || void 0,
      title: tooltipTitle,
      "data-variant": v,
      "data-color": c,
      "data-size": size,
      "data-loading": isLoading || void 0,
      "data-icon-only": isIconOnly || void 0,
      css: css`
        position: relative;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: ${isIconOnly ? "0" : sizeTokens.gap};
        box-sizing: border-box;
        height: ${sizeTokens.height};
        min-width: ${isIconOnly ? sizeTokens.height : sizeTokens.minWidth};
        ${isIconOnly ? `width: ${sizeTokens.height};` : ""}
        padding: ${isIconOnly ? "0" : `0 ${sizeTokens.paddingX}`};
        font-family: inherit;
        font-size: ${sizeTokens.fontSize};
        line-height: ${sizeTokens.lineHeight};
        font-weight: 400;
        letter-spacing: normal;
        white-space: nowrap;
        overflow: hidden;
        cursor: pointer;
        user-select: none;
        width: ${isFullWidth ? "100%" : "auto"};
        background-color: ${bg};
        color: ${fg};
        border: ${border};
        border-radius: ${borderRadius};
        box-shadow: ${boxShadow};
        outline: 1.5px solid transparent;
        -webkit-font-smoothing: antialiased;
        transition:
          background-color ${duration},
          color ${duration},
          border-color ${duration},
          transform ${duration},
          opacity ${duration},
          box-shadow ${duration};

        &:hover:not(:disabled):not([aria-disabled='true']) {
          ${hoverBg !== null ? `background-color: ${hoverBg};` : ""}
          ${hoverFg !== null ? `color: ${hoverFg};` : ""}
        }

        &:active:not(:disabled):not([aria-disabled='true']),
        &[data-pressed='true'] {
          transform: scale(0.97);
        }

        &:focus-visible {
          outline: none;
          box-shadow: ${boxShadow === "none" ? "" : `${boxShadow},`} inset 0 0 0 2px ${focusColor};
          z-index: 1;
        }

        &:disabled,
        &[aria-disabled='true'],
        &[data-loading='true'] {
          opacity: 0.5;
          pointer-events: none;
        }

        @media (prefers-reduced-motion: reduce) {
          transition: none;
          &:active:not(:disabled):not([aria-disabled='true']),
          &[data-pressed='true'] {
            transform: none;
          }
        }
      `,
      ...rest,
      children: [
        isLoading ? /* @__PURE__ */ jsx(Spinner, { size: spinnerSize[size] }) : startIcon,
        children,
        !isLoading && endIcon
      ]
    }
  );
});
Button.displayName = "Button";

// src/utils/theme.ts
var get = (obj, path) => {
  let cur = obj;
  for (const k of path) {
    if (cur == null || typeof cur !== "object") return void 0;
    cur = cur[k];
  }
  return cur;
};
var str = (v, fallback = "") => typeof v === "string" ? v : fallback;
var t = (theme) => {
  const palette = theme.tokens?.palette ?? {};
  const grayRamp = palette.gray ?? {};
  const blueRamp = palette.blue ?? {};
  const greenRamp = palette.green ?? {};
  const orangeRamp = palette.orange ?? {};
  const redRamp = palette.red ?? {};
  const bg = theme.colors?.bg ?? {};
  const txt = theme.colors?.text ?? {};
  const border = theme.colors?.border ?? {};
  const action = theme.colors?.action ?? {};
  const status = theme.colors?.status ?? {};
  const primary = action.primary ?? {};
  const secondary = action.secondary ?? {};
  const danger = action.danger ?? {};
  const spacingObj = theme.spacing ?? theme.tokens?.spacing ?? {};
  const radiusObj = theme.radius ?? theme.tokens?.radius ?? {};
  const shadowsObj = theme.shadows ?? theme.tokens?.shadows ?? {};
  const typography = theme.typography ?? theme.tokens?.typography ?? {};
  const fontSize = typography.fontSize ?? {};
  const fontWeight = typography.fontWeight ?? {};
  return {
    space: (k) => str(spacingObj[k], "0"),
    radius: (k) => str(radiusObj[k], "0"),
    shadow: (k) => str(shadowsObj[k], "none"),
    fs: (k) => fontSize[k] ?? "14px",
    fw: (k) => fontWeight[k] ?? 400,
    font: str(typography.fontFamilyBase, "system-ui, sans-serif"),
    motion: {
      duration: (k) => str(
        get(theme, ["motion", "duration", k]) ?? get(theme, ["tokens", "motion", "duration", k]),
        "150ms"
      )
    },
    z: (k) => Number(get(theme, ["zIndex", k]) ?? get(theme, ["tokens", "zIndex", k]) ?? 0),
    color: {
      primary: str(primary.default, str(blueRamp[500], "#1677ff")),
      primaryHover: str(primary.hover, str(blueRamp[400], "#4096ff")),
      primaryActive: str(primary.active, str(blueRamp[600], "#0958d9")),
      primaryDisabled: str(primary.disabled, str(blueRamp[200], "#91caff")),
      secondary: str(secondary.default, str(grayRamp[100], "#f5f5f5")),
      secondaryHover: str(secondary.hover, str(grayRamp[200], "#e5e5e5")),
      dangerAction: str(danger.default, str(redRamp[500], "#f5222d")),
      dangerActionHover: str(danger.hover, str(redRamp[400], "#ff4d4f")),
      text: str(txt.primary, "#171717"),
      textPrimary: str(txt.primary, "#171717"),
      textSecondary: str(txt.secondary, "#404040"),
      textMuted: str(txt.muted, "#737373"),
      textInverse: str(txt.inverse, "#ffffff"),
      textDisabled: str(txt.disabled, "#a3a3a3"),
      textLink: str(txt.link, "#0958d9"),
      bg: str(bg.canvas, "#ffffff"),
      surface: str(bg.surface, "#ffffff"),
      raised: str(bg.raised, "#ffffff"),
      sunken: str(bg.sunken, "#fafafa"),
      muted: str(bg.muted, "#f5f5f5"),
      codeBg: str(bg.muted, "#f5f5f5"),
      overlay: str(bg.overlay, "rgba(0,0,0,0.45)"),
      border: str(border.default, "#e5e5e5"),
      borderSubtle: str(border.subtle, "#f5f5f5"),
      borderStrong: str(border.strong, "#a3a3a3"),
      borderFocus: str(border.focus, "#1677ff"),
      success: str(status.success, str(greenRamp[500], "#52c41a")),
      warning: str(status.warning, str(orangeRamp[500], "#faad14")),
      danger: str(status.danger, str(redRamp[500], "#f5222d")),
      info: str(status.info, str(blueRamp[500], "#1677ff")),
      successBg: str(status.successBg, str(greenRamp[50], "#f6ffed")),
      warningBg: str(status.warningBg, str(orangeRamp[50], "#fff7e6")),
      dangerBg: str(status.dangerBg, str(redRamp[50], "#fff1f0")),
      infoBg: str(status.infoBg, str(blueRamp[50], "#e6f4ff")),
      neutral: (shade) => str(grayRamp[shade], "#999")
    }
  };
};

// src/utils/env.ts
var isDev = typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production";

// src/utils/refs.ts
function mergeRefs(...refs) {
  return (node) => {
    for (const ref of refs) {
      if (!ref) continue;
      if (typeof ref === "function") {
        ref(node);
      } else {
        ref.current = node;
      }
    }
  };
}
function useControllableState(opts) {
  const { value, defaultValue, onChange, name } = opts;
  const [internal, setInternal] = useState(defaultValue);
  const isControlled = value !== void 0;
  const current = isControlled ? value : internal;
  const onChangeRef = useRef(onChange);
  const isControlledRef = useRef(isControlled);
  useEffect(() => {
    onChangeRef.current = onChange;
  }, [onChange]);
  useEffect(() => {
    isControlledRef.current = isControlled;
  }, [isControlled]);
  const warnedBothRef = useRef(false);
  useEffect(() => {
    if (!isDev) return;
    if (warnedBothRef.current) return;
    if (value !== void 0 && defaultValue !== void 0) {
      warnedBothRef.current = true;
      console.warn(
        `[TimeUI] ${name ?? "useControllableState"}: received both \`value\` and \`defaultValue\`. Components must be either controlled or uncontrolled \u2014 \`defaultValue\` will be ignored.`
      );
    }
  }, []);
  const firstControlledRef = useRef(isControlled);
  const warnedFlipRef = useRef(false);
  useEffect(() => {
    if (!isDev) return;
    if (warnedFlipRef.current) return;
    if (firstControlledRef.current !== isControlled) {
      warnedFlipRef.current = true;
      console.warn(
        `[TimeUI] ${name ?? "useControllableState"}: a component is changing from ${firstControlledRef.current ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}. Decide between using a controlled or uncontrolled component for the lifetime of the component.`
      );
    }
  }, [isControlled, name]);
  const setState = useCallback((next) => {
    if (isControlledRef.current) {
      onChangeRef.current?.(next);
      return;
    }
    setInternal(next);
    onChangeRef.current?.(next);
  }, []);
  return [current, setState];
}
function getFieldVariantStyles({
  theme,
  variant,
  color,
  isInvalid = false,
  isDisabled = false,
  isReadOnly = false
}) {
  const colors = theme.colors;
  const borderThin = theme.borders.width.thin;
  const borderThick = theme.borders.width.thick;
  const danger = colors.status.danger;
  const palette = color === "default" ? null : colors[color];
  const focusColor = palette ? palette[500] : colors.focus;
  const focusBgSoft = palette ? palette[100] : null;
  const duration = theme.motion.duration.normal;
  const easing = theme.motion.easing.standard ?? theme.motion.easing.easeInOut;
  let background = "transparent";
  let border = "0 solid transparent";
  let borderBottom = null;
  let hoverBackground = null;
  let hoverBorder = null;
  let hoverBorderBottom = null;
  let focusBorderBottom = null;
  let focusBorderColor = null;
  let focusBackground = null;
  let useEdgeFocus = true;
  switch (variant) {
    case "flat": {
      background = colors.default[100];
      border = `${borderThin} solid ${colors.default[200]}`;
      hoverBackground = colors.default[200];
      hoverBorder = colors.border.strong;
      if (palette) {
        focusBackground = focusBgSoft;
        focusBorderColor = focusColor;
      }
      break;
    }
    case "bordered": {
      background = "transparent";
      border = palette ? `${borderThin} solid ${palette[500]}` : `${borderThin} solid ${colors.border.strong}`;
      hoverBorder = palette ? palette[600] : colors.default[600];
      if (palette) {
        focusBorderColor = focusColor;
      }
      break;
    }
    case "faded": {
      background = palette ? palette[100] : colors.default[100];
      border = palette ? `${borderThin} solid ${palette[200]}` : `${borderThin} solid ${colors.border.strong}`;
      hoverBorder = palette ? palette[500] : colors.default[600];
      hoverBackground = palette ? null : colors.default[200];
      if (palette) {
        focusBorderColor = focusColor;
        focusBackground = focusBgSoft;
      }
      break;
    }
    case "underlined": {
      background = "transparent";
      border = "0 solid transparent";
      borderBottom = `${borderThin} solid ${colors.border.strong}`;
      hoverBorderBottom = palette ? palette[500] : colors.default[600];
      focusBorderBottom = `${borderThick} solid ${focusColor}`;
      useEdgeFocus = false;
      break;
    }
  }
  if (isInvalid) {
    if (variant === "underlined") {
      borderBottom = `${borderThin} solid ${danger}`;
      hoverBorderBottom = danger;
      focusBorderBottom = `${borderThick} solid ${danger}`;
    } else if (variant === "flat") {
      border = `${borderThin} solid ${danger}`;
      hoverBorder = danger;
    } else {
      border = `${borderThin} solid ${danger}`;
      hoverBorder = danger;
    }
  }
  return css`
    background-color: ${background};
    border: ${border};
    ${borderBottom ? `border-bottom: ${borderBottom};` : ""}
    ${isDisabled ? "opacity: 0.5; cursor: not-allowed;" : ""}
    ${isReadOnly ? "cursor: default;" : ""}
    transition:
      background-color ${duration} ${easing},
      color ${duration} ${easing},
      border-color ${duration} ${easing},
      box-shadow ${duration} ${easing};

    &:hover:not(:disabled):not([aria-disabled='true']) {
      ${hoverBackground ? `background-color: ${hoverBackground};` : ""}
      ${hoverBorder ? `border-color: ${hoverBorder};` : ""}
      ${hoverBorderBottom ? `border-bottom-color: ${hoverBorderBottom};` : ""}
    }

    ${useEdgeFocus ? `
          &:focus-visible,
          &:focus-within {
            outline: none;
            border-color: ${focusBorderColor ?? focusColor};
            box-shadow: inset 0 0 0 ${borderThick} ${focusBorderColor ?? focusColor};
            ${focusBackground ? `background-color: ${focusBackground};` : ""}
          }
        ` : `
          &:focus-visible,
          &:focus-within {
            ${focusBorderBottom ? `border-bottom: ${focusBorderBottom};` : ""}
          }
        `}

    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
  `;
}
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;

// src/utils/useScrollLock.ts
var lockCount = 0;
var originalOverflow = null;
var originalPaddingRight = null;
function useScrollLock(lock) {
  useIsomorphicLayoutEffect(() => {
    if (!lock || typeof document === "undefined") return;
    lockCount += 1;
    if (lockCount === 1) {
      const body = document.body;
      const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
      originalOverflow = body.style.overflow;
      originalPaddingRight = body.style.paddingRight;
      body.style.overflow = "hidden";
      if (scrollbarWidth > 0) {
        const currentPaddingRight = parseFloat(window.getComputedStyle(body).paddingRight) || 0;
        body.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`;
      }
    }
    return () => {
      lockCount -= 1;
      if (lockCount === 0) {
        const body = document.body;
        if (originalOverflow !== null) body.style.overflow = originalOverflow;
        if (originalPaddingRight !== null) body.style.paddingRight = originalPaddingRight;
        originalOverflow = null;
        originalPaddingRight = null;
      }
    };
  }, [lock]);
}
var parseOffsetToken = (raw, fallback) => {
  if (raw === void 0) return fallback;
  if (typeof raw === "number") return raw;
  const n = parseFloat(raw);
  return Number.isFinite(n) ? n : fallback;
};
var splitPlacement = (placement) => {
  const [side, alignSuffix] = placement.split("-");
  return { side, align: alignSuffix ?? "center" };
};
var OPPOSITE_SIDE = {
  top: "bottom",
  bottom: "top",
  left: "right",
  right: "left"
};
var sideHasRoom = (side, anchorRect, popoverSize, offset, viewport, padding) => {
  if (side === "top") return anchorRect.top - offset - padding >= popoverSize.height;
  if (side === "bottom")
    return viewport.height - (anchorRect.top + anchorRect.height) - offset - padding >= popoverSize.height;
  if (side === "left") return anchorRect.left - offset - padding >= popoverSize.width;
  return viewport.width - (anchorRect.left + anchorRect.width) - offset - padding >= popoverSize.width;
};
var computePopoverPosition = (anchorRect, popoverSize, placement, offset, viewport, padding = 8) => {
  let { side, align } = splitPlacement(placement);
  if (viewport) {
    const fits = sideHasRoom(side, anchorRect, popoverSize, offset, viewport, padding);
    const opposite = OPPOSITE_SIDE[side];
    const oppositeFits = sideHasRoom(opposite, anchorRect, popoverSize, offset, viewport, padding);
    if (!fits && oppositeFits) {
      side = opposite;
    }
  }
  let top = 0;
  let left = 0;
  if (side === "top") {
    top = anchorRect.top - popoverSize.height - offset;
  } else if (side === "bottom") {
    top = anchorRect.top + anchorRect.height + offset;
  } else if (side === "left") {
    left = anchorRect.left - popoverSize.width - offset;
  } else {
    left = anchorRect.left + anchorRect.width + offset;
  }
  if (side === "top" || side === "bottom") {
    if (align === "start") {
      left = anchorRect.left;
    } else if (align === "end") {
      left = anchorRect.left + anchorRect.width - popoverSize.width;
    } else {
      left = anchorRect.left + anchorRect.width / 2 - popoverSize.width / 2;
    }
  } else {
    if (align === "start") {
      top = anchorRect.top;
    } else if (align === "end") {
      top = anchorRect.top + anchorRect.height - popoverSize.height;
    } else {
      top = anchorRect.top + anchorRect.height / 2 - popoverSize.height / 2;
    }
  }
  if (viewport) {
    if (side === "top" || side === "bottom") {
      const minLeft = padding;
      const maxLeft = viewport.width - popoverSize.width - padding;
      if (maxLeft >= minLeft) {
        left = Math.min(Math.max(left, minLeft), maxLeft);
      }
    } else {
      const minTop = padding;
      const maxTop = viewport.height - popoverSize.height - padding;
      if (maxTop >= minTop) {
        top = Math.min(Math.max(top, minTop), maxTop);
      }
    }
  }
  return { top, left, side, align };
};
var enterTransformStart = (side, distance) => {
  if (side === "top") return `translateY(${distance})`;
  if (side === "bottom") return `translateY(-${distance})`;
  if (side === "left") return `translateX(${distance})`;
  return `translateX(-${distance})`;
};
var Popover = forwardRef(
  function Popover2(props, forwardedRef) {
    const {
      anchor,
      children,
      isOpen,
      defaultOpen = false,
      onOpenChange,
      trigger = "click",
      placement = "bottom",
      offset,
      hasArrow = true,
      closeOnBlur = true,
      closeOnEsc = true,
      header,
      footer,
      openDelay = 0,
      closeDelay = 100,
      className,
      style,
      id,
      "aria-label": ariaLabel
    } = props;
    const theme = useTheme();
    const popoverTokens = theme.components.popover;
    const autoId = useId();
    const safeAutoId = autoId.replace(/:/g, "");
    const baseId = id ?? `timeui-popover-${safeAutoId}`;
    const headerId = header ? `${baseId}-header` : void 0;
    const [open, setOpen] = useControllableState({
      value: isOpen,
      defaultValue: isOpen !== void 0 ? void 0 : defaultOpen,
      onChange: onOpenChange,
      name: "Popover"
    });
    const isManual = trigger === "manual";
    const anchorRef = useRef(null);
    const panelRef = useRef(null);
    const hoverTimerRef = useRef(null);
    const clearHoverTimer = useCallback(() => {
      if (hoverTimerRef.current) {
        clearTimeout(hoverTimerRef.current);
        hoverTimerRef.current = null;
      }
    }, []);
    useEffect(
      () => () => {
        clearHoverTimer();
      },
      [clearHoverTimer]
    );
    const [position, setPosition] = useState(null);
    const [isMounted, setIsMounted] = useState(false);
    useEffect(() => {
      setIsMounted(true);
    }, []);
    const offsetPx = useMemo(
      () => parseOffsetToken(offset, parseOffsetToken(popoverTokens.offset, 8)),
      [offset, popoverTokens.offset]
    );
    const { side: placementSide, align: placementAlign } = useMemo(
      () => splitPlacement(placement),
      [placement]
    );
    const updatePosition = useCallback(() => {
      const anchorEl = anchorRef.current;
      const panelEl = panelRef.current;
      if (!anchorEl || !panelEl) return;
      const aRect = anchorEl.getBoundingClientRect();
      const pRect = panelEl.getBoundingClientRect();
      const next = computePopoverPosition(
        { top: aRect.top, left: aRect.left, width: aRect.width, height: aRect.height },
        { width: pRect.width, height: pRect.height },
        placement,
        offsetPx,
        { width: window.innerWidth, height: window.innerHeight }
      );
      setPosition((prev) => {
        if (prev && prev.top === next.top && prev.left === next.left && prev.side === next.side && prev.align === next.align) {
          return prev;
        }
        return next;
      });
    }, [placement, offsetPx]);
    useIsomorphicLayoutEffect(() => {
      if (!open || !isMounted) {
        setPosition(null);
        return;
      }
      updatePosition();
      const onScrollResize = () => updatePosition();
      window.addEventListener("scroll", onScrollResize, { passive: true, capture: true });
      window.addEventListener("resize", onScrollResize, { passive: true });
      return () => {
        window.removeEventListener("scroll", onScrollResize, true);
        window.removeEventListener("resize", onScrollResize);
      };
    }, [open, isMounted, updatePosition]);
    useEffect(() => {
      if (!open || !closeOnEsc || isManual) return;
      const onKey = (e) => {
        if (e.key === "Escape") {
          e.stopPropagation();
          setOpen(false);
        }
      };
      window.addEventListener("keydown", onKey);
      return () => window.removeEventListener("keydown", onKey);
    }, [open, closeOnEsc, isManual, setOpen]);
    useEffect(() => {
      if (!open || !closeOnBlur || isManual) return;
      const onMouseDown = (e) => {
        const target = e.target;
        if (!target) return;
        if (anchorRef.current?.contains(target)) return;
        if (panelRef.current?.contains(target)) return;
        setOpen(false);
      };
      document.addEventListener("mousedown", onMouseDown);
      return () => document.removeEventListener("mousedown", onMouseDown);
    }, [open, closeOnBlur, isManual, setOpen]);
    const handleAnchorClick = useCallback(
      (e) => {
        if (isManual || trigger !== "click") return;
        e.preventDefault();
        setOpen(!open);
      },
      [isManual, trigger, open, setOpen]
    );
    const openWithDelay = useCallback(
      (delay) => {
        clearHoverTimer();
        if (delay <= 0) {
          setOpen(true);
          return;
        }
        hoverTimerRef.current = setTimeout(() => setOpen(true), delay);
      },
      [clearHoverTimer, setOpen]
    );
    const closeWithDelay = useCallback(
      (delay) => {
        clearHoverTimer();
        if (delay <= 0) {
          setOpen(false);
          return;
        }
        hoverTimerRef.current = setTimeout(() => setOpen(false), delay);
      },
      [clearHoverTimer, setOpen]
    );
    const handleAnchorMouseEnter = useCallback(() => {
      if (isManual || trigger !== "hover") return;
      openWithDelay(openDelay);
    }, [isManual, trigger, openDelay, openWithDelay]);
    const handleAnchorMouseLeave = useCallback(() => {
      if (isManual || trigger !== "hover") return;
      closeWithDelay(closeDelay);
    }, [isManual, trigger, closeDelay, closeWithDelay]);
    const handleAnchorFocus = useCallback(() => {
      if (isManual || trigger !== "focus") return;
      setOpen(true);
    }, [isManual, trigger, setOpen]);
    const handleAnchorBlur = useCallback(() => {
      if (isManual || trigger !== "focus") return;
      setOpen(false);
    }, [isManual, trigger, setOpen]);
    const handlePanelMouseEnter = useCallback(() => {
      if (isManual || trigger !== "hover") return;
      clearHoverTimer();
    }, [isManual, trigger, clearHoverTimer]);
    const handlePanelMouseLeave = useCallback(() => {
      if (isManual || trigger !== "hover") return;
      closeWithDelay(closeDelay);
    }, [isManual, trigger, closeDelay, closeWithDelay]);
    const anchorEventProps = {
      onClick: handleAnchorClick,
      onMouseEnter: handleAnchorMouseEnter,
      onMouseLeave: handleAnchorMouseLeave,
      onFocus: handleAnchorFocus,
      onBlur: handleAnchorBlur,
      "aria-expanded": trigger === "click" ? open : void 0,
      "aria-haspopup": trigger === "click" ? "dialog" : void 0,
      "aria-controls": open ? baseId : void 0
    };
    const renderAnchor = () => {
      if (typeof anchor === "function") {
        return anchor({ isOpen: open, ref: anchorRef });
      }
      if (!isValidElement(anchor)) return null;
      const element = anchor;
      const existingProps = element.props ?? {};
      const majorReactVersion = Number.parseInt(version.split(".")[0] ?? "18", 10);
      const existingRef = majorReactVersion >= 19 ? element.props.ref : element.ref;
      const composed = {
        onClick: (e) => {
          existingProps.onClick?.(e);
          if (!e.defaultPrevented) anchorEventProps.onClick(e);
        },
        onMouseEnter: () => {
          existingProps.onMouseEnter?.();
          anchorEventProps.onMouseEnter();
        },
        onMouseLeave: () => {
          existingProps.onMouseLeave?.();
          anchorEventProps.onMouseLeave();
        },
        onFocus: (e) => {
          existingProps.onFocus?.(e);
          anchorEventProps.onFocus();
        },
        onBlur: (e) => {
          existingProps.onBlur?.(e);
          anchorEventProps.onBlur();
        },
        "aria-expanded": anchorEventProps["aria-expanded"],
        "aria-haspopup": anchorEventProps["aria-haspopup"],
        "aria-controls": anchorEventProps["aria-controls"],
        // React 19 puts ref on props; React 18 warns if props.ref is read.
        ref: mergeRefs(anchorRef, existingRef)
      };
      return cloneElement(element, composed);
    };
    const handlePanelKeyDown = useCallback(
      (e) => {
        if (e.key === "Escape" && closeOnEsc && !isManual) {
          e.stopPropagation();
          setOpen(false);
        }
      },
      [closeOnEsc, isManual, setOpen]
    );
    const surfaceBg = theme.colors.bg.surface ?? theme.colors.bg.canvas;
    const hairline = theme.colors.border.subtle;
    const textPrimary = theme.colors.text.primary;
    const textSecondary = theme.colors.text.secondary;
    const motionEasing = theme.motion.easing;
    const easing = motionEasing.emphasized ?? motionEasing.standard ?? motionEasing.easeInOut;
    const enterTransform = enterTransformStart(
      position?.side ?? placementSide,
      popoverTokens.enterTranslate
    );
    const panelCss = css`
      position: fixed;
      z-index: ${theme.zIndex.popover};
      min-width: ${popoverTokens.minWidth};
      max-width: ${popoverTokens.maxWidth};
      background: ${surfaceBg};
      color: ${textPrimary};
      border-radius: ${popoverTokens.radius};
      box-shadow:
        0 8px 24px rgba(0, 0, 0, 0.12),
        0 0 0 1px ${hairline};
      font-family: inherit;
      font-size: ${popoverTokens.bodyFontSize};
      line-height: ${popoverTokens.bodyLineHeight};
      box-sizing: border-box;
      outline: none;
      animation: timeui-popover-in ${popoverTokens.enterDuration} ${easing};
      @keyframes timeui-popover-in {
        from {
          opacity: 0;
          transform: ${enterTransform};
        }
        to {
          opacity: 1;
          transform: translate(0, 0);
        }
      }
      @media (prefers-reduced-motion: reduce) {
        animation: none;
        transition: none;
        transform: none !important;
      }
    `;
    const headerCss = css`
      padding: ${popoverTokens.headerPaddingY} ${popoverTokens.paddingX};
      font-size: ${popoverTokens.headerFontSize};
      font-weight: ${popoverTokens.headerFontWeight};
      color: ${textPrimary};
      border-bottom: 1px solid ${hairline};
    `;
    const bodyCss = css`
      padding: ${popoverTokens.paddingY} ${popoverTokens.paddingX};
      color: ${textPrimary};
    `;
    const footerCss = css`
      padding: ${popoverTokens.footerPaddingY} ${popoverTokens.paddingX};
      border-top: 1px solid ${hairline};
      color: ${textSecondary};
    `;
    const arrowSize = popoverTokens.arrowSize;
    const arrowInset = popoverTokens.arrowInset;
    const arrowSidePos = useMemo(() => {
      const side = position?.side ?? placementSide;
      const align = position?.align ?? placementAlign;
      const baseStyle = {
        position: "absolute",
        width: arrowSize,
        height: arrowSize,
        background: surfaceBg,
        transform: "rotate(45deg)",
        boxShadow: `1px 1px 0 0 ${hairline}`,
        pointerEvents: "none"
      };
      const centerOffset = `calc(${arrowSize} / -2)`;
      if (side === "top") {
        baseStyle.bottom = centerOffset;
        baseStyle.boxShadow = `1px 1px 0 0 ${hairline}`;
      } else if (side === "bottom") {
        baseStyle.top = centerOffset;
        baseStyle.boxShadow = `-1px -1px 0 0 ${hairline}`;
      } else if (side === "left") {
        baseStyle.right = centerOffset;
        baseStyle.boxShadow = `1px -1px 0 0 ${hairline}`;
      } else {
        baseStyle.left = centerOffset;
        baseStyle.boxShadow = `-1px 1px 0 0 ${hairline}`;
      }
      if (side === "top" || side === "bottom") {
        if (align === "start") {
          baseStyle.left = arrowInset;
        } else if (align === "end") {
          baseStyle.right = arrowInset;
        } else {
          baseStyle.left = `calc(50% - ${arrowSize} / 2)`;
        }
      } else {
        if (align === "start") {
          baseStyle.top = arrowInset;
        } else if (align === "end") {
          baseStyle.bottom = arrowInset;
        } else {
          baseStyle.top = `calc(50% - ${arrowSize} / 2)`;
        }
      }
      return baseStyle;
    }, [position, placementSide, placementAlign, arrowSize, arrowInset, surfaceBg, hairline]);
    const positionStyle = position ? { top: position.top, left: position.left } : { top: -9999, left: -9999, visibility: "hidden" };
    const mergedStyle = { ...positionStyle, ...style };
    const role = trigger === "hover" ? "tooltip" : "dialog";
    const ariaModal = role === "dialog" ? false : void 0;
    const renderPanel = () => /* @__PURE__ */ jsxs(
      "div",
      {
        ref: mergeRefs(panelRef, forwardedRef),
        id: baseId,
        role,
        "aria-modal": ariaModal,
        "aria-label": ariaLabel,
        "aria-labelledby": !ariaLabel && headerId ? headerId : void 0,
        "data-placement": placement,
        "data-side": position?.side ?? placementSide,
        "data-align": position?.align ?? placementAlign,
        tabIndex: -1,
        className,
        style: mergedStyle,
        css: panelCss,
        onKeyDown: handlePanelKeyDown,
        onMouseEnter: handlePanelMouseEnter,
        onMouseLeave: handlePanelMouseLeave,
        children: [
          header ? /* @__PURE__ */ jsx("div", { id: headerId, css: headerCss, children: header }) : null,
          /* @__PURE__ */ jsx("div", { css: bodyCss, children }),
          footer ? /* @__PURE__ */ jsx("div", { css: footerCss, children: footer }) : null,
          hasArrow ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, "data-popover-arrow": "", style: arrowSidePos }) : null
        ]
      }
    );
    return /* @__PURE__ */ jsxs(Fragment, { children: [
      renderAnchor(),
      open && isMounted && typeof document !== "undefined" ? createPortal(renderPanel(), document.body) : null
    ] });
  }
);
Popover.displayName = "TimeUI.Popover";
var lastClosedAt = 0;
var parseToken = (raw, fallback) => {
  if (raw === void 0) return fallback;
  if (typeof raw === "number") return raw;
  const n = parseFloat(raw);
  return Number.isFinite(n) ? n : fallback;
};
var splitPlacement2 = (placement) => {
  const [side, alignSuffix] = placement.split("-");
  return { side, align: alignSuffix ?? "center" };
};
var enterTransformStart2 = (side, distance) => {
  if (side === "top") return `translateY(${distance})`;
  if (side === "bottom") return `translateY(-${distance})`;
  if (side === "left") return `translateX(${distance})`;
  return `translateX(-${distance})`;
};
var Tooltip = forwardRef(
  function Tooltip2(props, forwardedRef) {
    const {
      content,
      children,
      placement = "top",
      offset,
      hasArrow = true,
      isDisabled = false,
      openDelay,
      closeDelay,
      isOpen,
      defaultOpen = false,
      onOpenChange,
      className,
      style,
      id
    } = props;
    const theme = useTheme();
    const tooltipTokens = theme.components.tooltip;
    const isDark = theme.mode === "dark";
    const [open, setOpen] = useControllableState({
      value: isOpen,
      defaultValue: isOpen !== void 0 ? void 0 : defaultOpen,
      onChange: onOpenChange,
      name: "Tooltip"
    });
    const isControlled = isOpen !== void 0;
    const autoId = useId();
    const safeAutoId = autoId.replace(/:/g, "");
    const baseId = id ?? `timeui-tooltip-${safeAutoId}`;
    const anchorRef = useRef(null);
    const panelRef = useRef(null);
    const enterTimerRef = useRef(null);
    const exitTimerRef = useRef(null);
    const clearEnterTimer = useCallback(() => {
      if (enterTimerRef.current) {
        clearTimeout(enterTimerRef.current);
        enterTimerRef.current = null;
      }
    }, []);
    const clearExitTimer = useCallback(() => {
      if (exitTimerRef.current) {
        clearTimeout(exitTimerRef.current);
        exitTimerRef.current = null;
      }
    }, []);
    useEffect(
      () => () => {
        clearEnterTimer();
        clearExitTimer();
      },
      [clearEnterTimer, clearExitTimer]
    );
    const offsetPx = useMemo(
      () => parseToken(offset, parseToken(tooltipTokens.offset, 6)),
      [offset, tooltipTokens.offset]
    );
    const openDelayMs = useMemo(
      () => parseToken(openDelay, parseToken(tooltipTokens.enterDelay, 120)),
      [openDelay, tooltipTokens.enterDelay]
    );
    const closeDelayMs = useMemo(
      () => parseToken(closeDelay, parseToken(tooltipTokens.exitDelay, 80)),
      [closeDelay, tooltipTokens.exitDelay]
    );
    const warmThresholdMs = useMemo(
      () => parseToken(void 0, parseToken(tooltipTokens.warmThreshold, 500)),
      [tooltipTokens.warmThreshold]
    );
    const { side: placementSide, align: placementAlign } = useMemo(
      () => splitPlacement2(placement),
      [placement]
    );
    const [position, setPosition] = useState(null);
    const [isMounted, setIsMounted] = useState(false);
    useEffect(() => {
      setIsMounted(true);
    }, []);
    const updatePosition = useCallback(() => {
      const anchorEl = anchorRef.current;
      const panelEl = panelRef.current;
      if (!anchorEl || !panelEl) return;
      const aRect = anchorEl.getBoundingClientRect();
      const pRect = panelEl.getBoundingClientRect();
      const next = computePopoverPosition(
        { top: aRect.top, left: aRect.left, width: aRect.width, height: aRect.height },
        { width: pRect.width, height: pRect.height },
        placement,
        offsetPx,
        { width: window.innerWidth, height: window.innerHeight }
      );
      setPosition((prev) => {
        if (prev && prev.top === next.top && prev.left === next.left && prev.side === next.side && prev.align === next.align) {
          return prev;
        }
        return next;
      });
    }, [placement, offsetPx]);
    useIsomorphicLayoutEffect(() => {
      if (!open || !isMounted || isDisabled) {
        setPosition(null);
        return;
      }
      updatePosition();
      const onScrollResize = () => updatePosition();
      window.addEventListener("scroll", onScrollResize, { passive: true, capture: true });
      window.addEventListener("resize", onScrollResize, { passive: true });
      return () => {
        window.removeEventListener("scroll", onScrollResize, true);
        window.removeEventListener("resize", onScrollResize);
      };
    }, [open, isMounted, isDisabled, updatePosition]);
    const computeEffectiveEnterDelay = useCallback(() => {
      const now = Date.now();
      if (lastClosedAt > 0 && now - lastClosedAt < warmThresholdMs) {
        return 0;
      }
      return openDelayMs;
    }, [openDelayMs, warmThresholdMs]);
    const scheduleOpen = useCallback(() => {
      if (isControlled || isDisabled) return;
      clearExitTimer();
      clearEnterTimer();
      const delay = computeEffectiveEnterDelay();
      if (delay <= 0) {
        setOpen(true);
        return;
      }
      enterTimerRef.current = setTimeout(() => {
        enterTimerRef.current = null;
        setOpen(true);
      }, delay);
    }, [
      isControlled,
      isDisabled,
      clearExitTimer,
      clearEnterTimer,
      computeEffectiveEnterDelay,
      setOpen
    ]);
    const scheduleClose = useCallback(() => {
      if (isControlled || isDisabled) return;
      clearEnterTimer();
      clearExitTimer();
      const doClose = () => {
        lastClosedAt = Date.now();
        setOpen(false);
      };
      if (closeDelayMs <= 0) {
        doClose();
        return;
      }
      exitTimerRef.current = setTimeout(() => {
        exitTimerRef.current = null;
        doClose();
      }, closeDelayMs);
    }, [isControlled, isDisabled, clearEnterTimer, clearExitTimer, closeDelayMs, setOpen]);
    const renderAnchor = () => {
      if (!isValidElement(children)) return null;
      const element = children;
      const existingProps = element.props ?? {};
      const composedDescribedBy = [existingProps["aria-describedby"], baseId].filter(Boolean).join(" ");
      const composed = {
        onMouseEnter: (e) => {
          existingProps.onMouseEnter?.(e);
          scheduleOpen();
        },
        onMouseLeave: (e) => {
          existingProps.onMouseLeave?.(e);
          scheduleClose();
        },
        onFocus: (e) => {
          existingProps.onFocus?.(e);
          scheduleOpen();
        },
        onBlur: (e) => {
          existingProps.onBlur?.(e);
          scheduleClose();
        },
        "aria-describedby": composedDescribedBy,
        // React 19 把 ref 放进 props；React 18 仍挂在 element.ref 上。
        // 优先读 props.ref 以消除 R19 的 deprecation 警告，fallback 保持 R18 兼容。
        ref: mergeRefs(
          anchorRef,
          element.props.ref ?? element.ref
        )
      };
      return cloneElement(element, composed);
    };
    const bg = isDark ? tooltipTokens.bgDark : tooltipTokens.bgLight;
    const fg = isDark ? tooltipTokens.fgDark : tooltipTokens.fgLight;
    const motionEasing = theme.motion.easing;
    const easing = motionEasing.standard ?? motionEasing.easeInOut;
    const enterTransform = enterTransformStart2(
      position?.side ?? placementSide,
      tooltipTokens.enterTranslate
    );
    const panelCss = css`
      position: fixed;
      z-index: ${theme.zIndex.tooltip};
      max-width: ${tooltipTokens.maxWidth};
      padding: ${tooltipTokens.paddingY} ${tooltipTokens.paddingX};
      background: ${bg};
      color: ${fg};
      border-radius: ${tooltipTokens.radius};
      box-shadow: ${tooltipTokens.shadow};
      font-family: inherit;
      font-size: ${tooltipTokens.fontSize};
      line-height: ${tooltipTokens.lineHeight};
      font-weight: ${tooltipTokens.fontWeight};
      box-sizing: border-box;
      /* tooltip 不应该捕获鼠标 —— 鼠标移到 tooltip 上不会使其保持开启，
       移开 anchor 后立刻进入 exit 流程，符合 tooltip 的 UX 预期。 */
      pointer-events: none;
      /* 触摸屏上 tooltip 不应被显示（无 hover）；用 hover 媒体特性兜底。 */
      @media (hover: none) {
        display: none;
      }
      animation: timeui-tooltip-in ${tooltipTokens.enterDuration} ${easing};
      @keyframes timeui-tooltip-in {
        from {
          opacity: 0;
          transform: ${enterTransform};
        }
        to {
          opacity: 1;
          transform: translate(0, 0);
        }
      }
      @media (prefers-reduced-motion: reduce) {
        animation: none;
        transition: none;
        transform: none !important;
      }
    `;
    const arrowSize = tooltipTokens.arrowSize;
    const arrowStyle = useMemo(() => {
      const side = position?.side ?? placementSide;
      const align = position?.align ?? placementAlign;
      const baseStyle = {
        position: "absolute",
        width: arrowSize,
        height: arrowSize,
        background: bg,
        transform: "rotate(45deg)",
        pointerEvents: "none"
      };
      const centerOffset = `calc(${arrowSize} / -2)`;
      if (side === "top") {
        baseStyle.bottom = centerOffset;
      } else if (side === "bottom") {
        baseStyle.top = centerOffset;
      } else if (side === "left") {
        baseStyle.right = centerOffset;
      } else {
        baseStyle.left = centerOffset;
      }
      if (side === "top" || side === "bottom") {
        if (align === "start") {
          baseStyle.left = "8px";
        } else if (align === "end") {
          baseStyle.right = "8px";
        } else {
          baseStyle.left = `calc(50% - ${arrowSize} / 2)`;
        }
      } else {
        if (align === "start") {
          baseStyle.top = "8px";
        } else if (align === "end") {
          baseStyle.bottom = "8px";
        } else {
          baseStyle.top = `calc(50% - ${arrowSize} / 2)`;
        }
      }
      return baseStyle;
    }, [position, placementSide, placementAlign, arrowSize, bg]);
    const positionStyle = position ? { top: position.top, left: position.left } : { top: -9999, left: -9999, visibility: "hidden" };
    const mergedStyle = { ...positionStyle, ...style };
    const renderPanel = () => /* @__PURE__ */ jsxs(
      "div",
      {
        ref: mergeRefs(panelRef, forwardedRef),
        id: baseId,
        role: "tooltip",
        "data-placement": placement,
        "data-side": position?.side ?? placementSide,
        "data-align": position?.align ?? placementAlign,
        className,
        style: mergedStyle,
        css: panelCss,
        children: [
          content,
          hasArrow ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, "data-tooltip-arrow": "", style: arrowStyle }) : null
        ]
      }
    );
    const shouldRenderPortal = !isDisabled && open && isMounted && typeof document !== "undefined";
    return /* @__PURE__ */ jsxs(Fragment, { children: [
      renderAnchor(),
      shouldRenderPortal ? createPortal(renderPanel(), document.body) : null
    ] });
  }
);
Tooltip.displayName = "TimeUI.Tooltip";

export { Button, Popover, Tooltip, getFieldVariantStyles, isDev, mergeRefs, t, useControllableState, useIsomorphicLayoutEffect, useScrollLock };
//# sourceMappingURL=chunk-FKEFVCK4.js.map
//# sourceMappingURL=chunk-FKEFVCK4.js.map