'use strict';

var react = require('react');
var react$1 = require('@emotion/react');
var react$2 = require('@tiptap/react');
var StarterKit = require('@tiptap/starter-kit');
var Underline = require('@tiptap/extension-underline');
var Link = require('@tiptap/extension-link');
var Placeholder = require('@tiptap/extension-placeholder');
var core = require('@timeui/core');
var jsxRuntime = require('@emotion/react/jsx-runtime');
var reactDom = require('react-dom');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var StarterKit__default = /*#__PURE__*/_interopDefault(StarterKit);
var Underline__default = /*#__PURE__*/_interopDefault(Underline);
var Link__default = /*#__PURE__*/_interopDefault(Link);
var Placeholder__default = /*#__PURE__*/_interopDefault(Placeholder);

// src/RichTextEditor/RichTextEditor.tsx
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 focusColor = colors.focus;
  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 useEdgeFocus = true;
  switch (variant) {
    case "flat": {
      background = colors.default[100];
      border = `${borderThin} solid ${colors.default[200]}`;
      hoverBackground = colors.default[200];
      hoverBorder = colors.border.strong;
      break;
    }
    case "bordered": {
      background = "transparent";
      border = `${borderThin} solid ${colors.border.strong}`;
      hoverBorder = colors.default[600];
      break;
    }
    case "faded": {
      background = colors.default[100];
      border = `${borderThin} solid ${colors.border.strong}`;
      hoverBorder = colors.default[600];
      hoverBackground = colors.default[200];
      break;
    }
    case "underlined": {
      background = "transparent";
      border = "0 solid transparent";
      borderBottom = `${borderThin} solid ${colors.border.strong}`;
      hoverBorderBottom = 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 react$1.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: ${focusColor};
            box-shadow: inset 0 0 0 ${borderThick} ${focusColor};
            ${""}
          }
        ` : `
          &:focus-visible,
          &:focus-within {
            ${focusBorderBottom ? `border-bottom: ${focusBorderBottom};` : ""}
          }
        `}

    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
  `;
}

// 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 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__ */ jsxRuntime.jsx(
  "span",
  {
    "aria-hidden": true,
    css: react$1.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 = react.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 = react$1.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__ */ jsxRuntime.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: react$1.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__ */ jsxRuntime.jsx(Spinner, { size: spinnerSize[size] }) : startIcon,
        children,
        !isLoading && endIcon
      ]
    }
  );
});
Button.displayName = "Button";

// src/utils/env.ts
var isDev = typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production";
function useControllableState(opts) {
  const { value, defaultValue, onChange, name } = opts;
  const [internal, setInternal] = react.useState(defaultValue);
  const isControlled = value !== void 0;
  const current = isControlled ? value : internal;
  const onChangeRef = react.useRef(onChange);
  const isControlledRef = react.useRef(isControlled);
  react.useEffect(() => {
    onChangeRef.current = onChange;
  }, [onChange]);
  react.useEffect(() => {
    isControlledRef.current = isControlled;
  }, [isControlled]);
  const warnedBothRef = react.useRef(false);
  react.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 = react.useRef(isControlled);
  const warnedFlipRef = react.useRef(false);
  react.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 = react.useCallback((next) => {
    if (isControlledRef.current) {
      onChangeRef.current?.(next);
      return;
    }
    setInternal(next);
    onChangeRef.current?.(next);
  }, []);
  return [current, setState];
}
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
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 = react.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 = react$1.useTheme();
    const popoverTokens = theme.components.popover;
    const autoId = react.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 = react.useRef(null);
    const panelRef = react.useRef(null);
    const hoverTimerRef = react.useRef(null);
    const clearHoverTimer = react.useCallback(() => {
      if (hoverTimerRef.current) {
        clearTimeout(hoverTimerRef.current);
        hoverTimerRef.current = null;
      }
    }, []);
    react.useEffect(
      () => () => {
        clearHoverTimer();
      },
      [clearHoverTimer]
    );
    const [position, setPosition] = react.useState(null);
    const [isMounted, setIsMounted] = react.useState(false);
    react.useEffect(() => {
      setIsMounted(true);
    }, []);
    const offsetPx = react.useMemo(
      () => parseOffsetToken(offset, parseOffsetToken(popoverTokens.offset, 8)),
      [offset, popoverTokens.offset]
    );
    const { side: placementSide, align: placementAlign } = react.useMemo(
      () => splitPlacement(placement),
      [placement]
    );
    const updatePosition = react.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]);
    react.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]);
    react.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 = react.useCallback(
      (e) => {
        if (isManual || trigger !== "click") return;
        e.preventDefault();
        setOpen(!open);
      },
      [isManual, trigger, open, setOpen]
    );
    const openWithDelay = react.useCallback(
      (delay) => {
        clearHoverTimer();
        if (delay <= 0) {
          setOpen(true);
          return;
        }
        hoverTimerRef.current = setTimeout(() => setOpen(true), delay);
      },
      [clearHoverTimer, setOpen]
    );
    const closeWithDelay = react.useCallback(
      (delay) => {
        clearHoverTimer();
        if (delay <= 0) {
          setOpen(false);
          return;
        }
        hoverTimerRef.current = setTimeout(() => setOpen(false), delay);
      },
      [clearHoverTimer, setOpen]
    );
    const handleAnchorMouseEnter = react.useCallback(() => {
      if (isManual || trigger !== "hover") return;
      openWithDelay(openDelay);
    }, [isManual, trigger, openDelay, openWithDelay]);
    const handleAnchorMouseLeave = react.useCallback(() => {
      if (isManual || trigger !== "hover") return;
      closeWithDelay(closeDelay);
    }, [isManual, trigger, closeDelay, closeWithDelay]);
    const handleAnchorFocus = react.useCallback(() => {
      if (isManual || trigger !== "focus") return;
      setOpen(true);
    }, [isManual, trigger, setOpen]);
    const handleAnchorBlur = react.useCallback(() => {
      if (isManual || trigger !== "focus") return;
      setOpen(false);
    }, [isManual, trigger, setOpen]);
    const handlePanelMouseEnter = react.useCallback(() => {
      if (isManual || trigger !== "hover") return;
      clearHoverTimer();
    }, [isManual, trigger, clearHoverTimer]);
    const handlePanelMouseLeave = react.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 (!react.isValidElement(anchor)) return null;
      const element = anchor;
      const existingProps = element.props ?? {};
      const majorReactVersion = Number.parseInt(react.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 react.cloneElement(element, composed);
    };
    const handlePanelKeyDown = react.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 = react$1.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 = react$1.css`
      padding: ${popoverTokens.headerPaddingY} ${popoverTokens.paddingX};
      font-size: ${popoverTokens.headerFontSize};
      font-weight: ${popoverTokens.headerFontWeight};
      color: ${textPrimary};
      border-bottom: 1px solid ${hairline};
    `;
    const bodyCss = react$1.css`
      padding: ${popoverTokens.paddingY} ${popoverTokens.paddingX};
      color: ${textPrimary};
    `;
    const footerCss = react$1.css`
      padding: ${popoverTokens.footerPaddingY} ${popoverTokens.paddingX};
      border-top: 1px solid ${hairline};
      color: ${textSecondary};
    `;
    const arrowSize = popoverTokens.arrowSize;
    const arrowInset = popoverTokens.arrowInset;
    const arrowSidePos = react.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__ */ jsxRuntime.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__ */ jsxRuntime.jsx("div", { id: headerId, css: headerCss, children: header }) : null,
          /* @__PURE__ */ jsxRuntime.jsx("div", { css: bodyCss, children }),
          footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { css: footerCss, children: footer }) : null,
          hasArrow ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, "data-popover-arrow": "", style: arrowSidePos }) : null
        ]
      }
    );
    return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
      renderAnchor(),
      open && isMounted && typeof document !== "undefined" ? reactDom.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 = react.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 = react$1.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 = react.useId();
    const safeAutoId = autoId.replace(/:/g, "");
    const baseId = id ?? `timeui-tooltip-${safeAutoId}`;
    const anchorRef = react.useRef(null);
    const panelRef = react.useRef(null);
    const enterTimerRef = react.useRef(null);
    const exitTimerRef = react.useRef(null);
    const clearEnterTimer = react.useCallback(() => {
      if (enterTimerRef.current) {
        clearTimeout(enterTimerRef.current);
        enterTimerRef.current = null;
      }
    }, []);
    const clearExitTimer = react.useCallback(() => {
      if (exitTimerRef.current) {
        clearTimeout(exitTimerRef.current);
        exitTimerRef.current = null;
      }
    }, []);
    react.useEffect(
      () => () => {
        clearEnterTimer();
        clearExitTimer();
      },
      [clearEnterTimer, clearExitTimer]
    );
    const offsetPx = react.useMemo(
      () => parseToken(offset, parseToken(tooltipTokens.offset, 6)),
      [offset, tooltipTokens.offset]
    );
    const openDelayMs = react.useMemo(
      () => parseToken(openDelay, parseToken(tooltipTokens.enterDelay, 120)),
      [openDelay, tooltipTokens.enterDelay]
    );
    const closeDelayMs = react.useMemo(
      () => parseToken(closeDelay, parseToken(tooltipTokens.exitDelay, 80)),
      [closeDelay, tooltipTokens.exitDelay]
    );
    const warmThresholdMs = react.useMemo(
      () => parseToken(void 0, parseToken(tooltipTokens.warmThreshold, 500)),
      [tooltipTokens.warmThreshold]
    );
    const { side: placementSide, align: placementAlign } = react.useMemo(
      () => splitPlacement2(placement),
      [placement]
    );
    const [position, setPosition] = react.useState(null);
    const [isMounted, setIsMounted] = react.useState(false);
    react.useEffect(() => {
      setIsMounted(true);
    }, []);
    const updatePosition = react.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 = react.useCallback(() => {
      const now = Date.now();
      if (lastClosedAt > 0 && now - lastClosedAt < warmThresholdMs) {
        return 0;
      }
      return openDelayMs;
    }, [openDelayMs, warmThresholdMs]);
    const scheduleOpen = react.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 = react.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 (!react.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 react.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 = react$1.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 = react.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__ */ jsxRuntime.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__ */ jsxRuntime.jsx("span", { "aria-hidden": true, "data-tooltip-arrow": "", style: arrowStyle }) : null
        ]
      }
    );
    const shouldRenderPortal = !isDisabled && open && isMounted && typeof document !== "undefined";
    return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
      renderAnchor(),
      shouldRenderPortal ? reactDom.createPortal(renderPanel(), document.body) : null
    ] });
  }
);
Tooltip.displayName = "TimeUI.Tooltip";
var SIZE_TO_BUTTON = {
  xs: "xs",
  sm: "xs",
  md: "sm",
  lg: "md",
  xl: "lg"
};
var SIZE_TO_ICON_PX = {
  xs: 12,
  sm: 14,
  md: 16,
  lg: 18,
  xl: 20
};
function Icon({ size, children }) {
  return /* @__PURE__ */ jsxRuntime.jsx(
    "svg",
    {
      width: size,
      height: size,
      viewBox: "0 0 24 24",
      fill: "none",
      stroke: "currentColor",
      strokeWidth: 1.8,
      strokeLinecap: "round",
      strokeLinejoin: "round",
      "aria-hidden": true,
      focusable: false,
      children
    }
  );
}
var BoldIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 5h6a3.5 3.5 0 0 1 0 7H7z" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 12h7a3.5 3.5 0 0 1 0 7H7z" })
] });
var ItalicIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "19", y1: "4", x2: "10", y2: "4" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "14", y1: "20", x2: "5", y2: "20" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "15", y1: "4", x2: "9", y2: "20" })
] });
var UnderlineIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 4v7a6 6 0 0 0 12 0V4" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "20", x2: "20", y2: "20" })
] });
var StrikeIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "12", x2: "20", y2: "12" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 6a4 4 0 0 0-4-2c-3 0-5 2-5 4 0 1.5 1 2.5 3 3" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 17a4 4 0 0 0 4 3c3 0 5-2 5-4 0-1-.5-2-1.5-2.5" })
] });
var H1Icon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 5v14" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5v14" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 12h8" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 8l3-2v13" })
] });
var H2Icon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 5v14" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5v14" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 12h8" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 8a3 3 0 0 1 5 2c0 2-5 4-5 9h6" })
] });
var H3Icon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 5v14" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5v14" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 12h8" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 7a3 3 0 1 1 3 5 3 3 0 1 1-3 5" })
] });
var BulletListIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "9", y1: "6", x2: "20", y2: "6" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "9", y1: "12", x2: "20", y2: "12" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "9", y1: "18", x2: "20", y2: "18" }),
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "5", cy: "6", r: "1" }),
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "5", cy: "12", r: "1" }),
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "5", cy: "18", r: "1" })
] });
var OrderedListIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "10", y1: "6", x2: "20", y2: "6" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "10", y1: "12", x2: "20", y2: "12" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "10", y1: "18", x2: "20", y2: "18" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 6h2v0" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 4l2 0v4" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 14h2.5a.5.5 0 0 1 0 1L4 17h2.5" })
] });
var BlockquoteIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 9h3v6H4v-3a3 3 0 0 1 2-3z" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 9h3v6h-5v-3a3 3 0 0 1 2-3z" })
] });
var CodeIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 8 4 12 9 16" }),
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "15 8 20 12 15 16" })
] });
var CodeBlockIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2" }),
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 9 6 12 9 15" }),
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "15 9 18 12 15 15" })
] });
var HorizontalRuleIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsx(Icon, { size, children: /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "12", x2: "20", y2: "12" }) });
var LinkIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 14a4 4 0 0 0 5.6 0l3-3a4 4 0 1 0-5.6-5.6l-1.5 1.5" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 10a4 4 0 0 0-5.6 0l-3 3a4 4 0 1 0 5.6 5.6l1.5-1.5" })
] });
var ClearFormatIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 5h14" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 5l-2 14" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 5l-1 7" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "14", y1: "17", x2: "20", y2: "17" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "20", y1: "14", x2: "14", y2: "20" })
] });
var UndoIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 14l-4-4 4-4" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 10h9a5 5 0 0 1 5 5v0a5 5 0 0 1-5 5H9" })
] });
var RedoIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 14l4-4-4-4" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 10h-9a5 5 0 0 0-5 5v0a5 5 0 0 0 5 5h5" })
] });
var FALLBACK_LABELS = {
  toolbarLabel: "Formatting",
  bold: "Bold",
  italic: "Italic",
  underline: "Underline",
  strike: "Strikethrough",
  h1: "Heading 1",
  h2: "Heading 2",
  h3: "Heading 3",
  bulletList: "Bullet list",
  orderedList: "Ordered list",
  blockquote: "Blockquote",
  code: "Inline code",
  codeBlock: "Code block",
  horizontalRule: "Horizontal rule",
  link: "Link",
  promptLink: "Enter URL",
  clearFormat: "Clear formatting",
  undo: "Undo",
  redo: "Redo"
};
function RichTextEditorToolbar({
  editor,
  items,
  size,
  isDisabled = false,
  ariaLabel,
  labels: labelOverrides
}) {
  const theme = react$1.useTheme();
  const i18n = core.useI18n();
  const i18nLabels = i18n.richTextEditor ?? FALLBACK_LABELS;
  const labels = react.useMemo(
    () => ({
      bold: i18nLabels.bold,
      italic: i18nLabels.italic,
      underline: i18nLabels.underline,
      strike: i18nLabels.strike,
      h1: i18nLabels.h1,
      h2: i18nLabels.h2,
      h3: i18nLabels.h3,
      bulletList: i18nLabels.bulletList,
      orderedList: i18nLabels.orderedList,
      blockquote: i18nLabels.blockquote,
      code: i18nLabels.code,
      codeBlock: i18nLabels.codeBlock,
      horizontalRule: i18nLabels.horizontalRule,
      link: i18nLabels.link,
      promptLink: i18nLabels.promptLink,
      clearFormat: i18nLabels.clearFormat,
      undo: i18nLabels.undo,
      redo: i18nLabels.redo,
      ...labelOverrides
    }),
    [i18nLabels, labelOverrides]
  );
  const resolvedAriaLabel = ariaLabel ?? i18nLabels.toolbarLabel;
  const btnSize = SIZE_TO_BUTTON[size];
  const iconPx = SIZE_TO_ICON_PX[size];
  const inputSize = theme.components.input[size];
  const promptForLink = react.useCallback(
    (current) => {
      if (typeof window === "undefined") return null;
      const next = window.prompt(labels.promptLink, current);
      return next;
    },
    [labels.promptLink]
  );
  const containerCss = react$1.css`
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    padding: 8px ${inputSize.paddingX};
    border-bottom: ${theme.borders.width.thin} solid ${theme.colors.border.subtle};
    color: ${theme.colors.text.primary};
  `;
  const separatorCss = react$1.css`
    width: ${theme.borders.width.thin};
    align-self: stretch;
    margin: 2px 4px;
    background: ${theme.colors.border.subtle};
  `;
  const buttonCss = react$1.css`
    &[data-active='true'] {
      background-color: ${theme.colors.default[200]};
      color: ${theme.colors.text.primary};
    }
  `;
  if (!editor) {
    return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "toolbar", "aria-label": resolvedAriaLabel, css: containerCss, "aria-hidden": true, children: items.map(
      (item, i) => item === "separator" ? /* @__PURE__ */ jsxRuntime.jsx("span", { css: separatorCss, "aria-hidden": true }, `sep-${i}`) : null
    ) });
  }
  const isItemDisabled = isDisabled || !editor.isEditable;
  function renderButton(key, label, icon, active, onClick, disabled = false) {
    return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: label, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: btnSize,
        isIconOnly: true,
        "aria-label": label,
        "aria-pressed": active,
        "data-active": active || void 0,
        disabled: isItemDisabled || disabled,
        onMouseDown: (e) => {
          e.preventDefault();
        },
        onClick,
        css: buttonCss,
        children: icon
      }
    ) }, key);
  }
  function handleLink() {
    if (!editor) return;
    const previous = editor.getAttributes("link").href ?? "";
    const url = promptForLink(previous);
    if (url === null) return;
    if (url === "") {
      editor.chain().focus().extendMarkRange("link").unsetLink().run();
      return;
    }
    editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
  }
  const buttons = items.map((item, idx) => {
    if (item === "separator") {
      return /* @__PURE__ */ jsxRuntime.jsx("span", { css: separatorCss, "aria-hidden": true }, `sep-${idx}`);
    }
    switch (item) {
      case "bold":
        return renderButton(
          item,
          labels.bold,
          /* @__PURE__ */ jsxRuntime.jsx(BoldIcon, { size: iconPx }),
          editor.isActive("bold"),
          () => editor.chain().focus().toggleBold().run()
        );
      case "italic":
        return renderButton(
          item,
          labels.italic,
          /* @__PURE__ */ jsxRuntime.jsx(ItalicIcon, { size: iconPx }),
          editor.isActive("italic"),
          () => editor.chain().focus().toggleItalic().run()
        );
      case "underline":
        return renderButton(
          item,
          labels.underline,
          /* @__PURE__ */ jsxRuntime.jsx(UnderlineIcon, { size: iconPx }),
          editor.isActive("underline"),
          () => editor.chain().focus().toggleUnderline().run()
        );
      case "strike":
        return renderButton(
          item,
          labels.strike,
          /* @__PURE__ */ jsxRuntime.jsx(StrikeIcon, { size: iconPx }),
          editor.isActive("strike"),
          () => editor.chain().focus().toggleStrike().run()
        );
      case "h1":
        return renderButton(
          item,
          labels.h1,
          /* @__PURE__ */ jsxRuntime.jsx(H1Icon, { size: iconPx }),
          editor.isActive("heading", { level: 1 }),
          () => editor.chain().focus().toggleHeading({ level: 1 }).run()
        );
      case "h2":
        return renderButton(
          item,
          labels.h2,
          /* @__PURE__ */ jsxRuntime.jsx(H2Icon, { size: iconPx }),
          editor.isActive("heading", { level: 2 }),
          () => editor.chain().focus().toggleHeading({ level: 2 }).run()
        );
      case "h3":
        return renderButton(
          item,
          labels.h3,
          /* @__PURE__ */ jsxRuntime.jsx(H3Icon, { size: iconPx }),
          editor.isActive("heading", { level: 3 }),
          () => editor.chain().focus().toggleHeading({ level: 3 }).run()
        );
      case "bulletList":
        return renderButton(
          item,
          labels.bulletList,
          /* @__PURE__ */ jsxRuntime.jsx(BulletListIcon, { size: iconPx }),
          editor.isActive("bulletList"),
          () => editor.chain().focus().toggleBulletList().run()
        );
      case "orderedList":
        return renderButton(
          item,
          labels.orderedList,
          /* @__PURE__ */ jsxRuntime.jsx(OrderedListIcon, { size: iconPx }),
          editor.isActive("orderedList"),
          () => editor.chain().focus().toggleOrderedList().run()
        );
      case "blockquote":
        return renderButton(
          item,
          labels.blockquote,
          /* @__PURE__ */ jsxRuntime.jsx(BlockquoteIcon, { size: iconPx }),
          editor.isActive("blockquote"),
          () => editor.chain().focus().toggleBlockquote().run()
        );
      case "code":
        return renderButton(
          item,
          labels.code,
          /* @__PURE__ */ jsxRuntime.jsx(CodeIcon, { size: iconPx }),
          editor.isActive("code"),
          () => editor.chain().focus().toggleCode().run()
        );
      case "codeBlock":
        return renderButton(
          item,
          labels.codeBlock,
          /* @__PURE__ */ jsxRuntime.jsx(CodeBlockIcon, { size: iconPx }),
          editor.isActive("codeBlock"),
          () => editor.chain().focus().toggleCodeBlock().run()
        );
      case "horizontalRule":
        return renderButton(
          item,
          labels.horizontalRule,
          /* @__PURE__ */ jsxRuntime.jsx(HorizontalRuleIcon, { size: iconPx }),
          false,
          () => editor.chain().focus().setHorizontalRule().run()
        );
      case "link":
        return renderButton(
          item,
          labels.link,
          /* @__PURE__ */ jsxRuntime.jsx(LinkIcon, { size: iconPx }),
          editor.isActive("link"),
          handleLink
        );
      case "clearFormat":
        return renderButton(
          item,
          labels.clearFormat,
          /* @__PURE__ */ jsxRuntime.jsx(ClearFormatIcon, { size: iconPx }),
          false,
          () => editor.chain().focus().clearNodes().unsetAllMarks().run()
        );
      case "undo":
        return renderButton(
          item,
          labels.undo,
          /* @__PURE__ */ jsxRuntime.jsx(UndoIcon, { size: iconPx }),
          false,
          () => editor.chain().focus().undo().run(),
          !editor.can().chain().focus().undo().run()
        );
      case "redo":
        return renderButton(
          item,
          labels.redo,
          /* @__PURE__ */ jsxRuntime.jsx(RedoIcon, { size: iconPx }),
          false,
          () => editor.chain().focus().redo().run(),
          !editor.can().chain().focus().redo().run()
        );
      default:
        return null;
    }
  });
  return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "toolbar", "aria-label": resolvedAriaLabel, css: containerCss, children: buttons });
}
var SIZE_TO_MIN_HEIGHT = {
  xs: "80px",
  sm: "120px",
  md: "160px",
  lg: "220px",
  xl: "300px"
};
var PRESETS = {
  minimal: ["bold", "italic", "underline"],
  basic: [
    "bold",
    "italic",
    "underline",
    "separator",
    "h1",
    "h2",
    "h3",
    "separator",
    "bulletList",
    "orderedList",
    "separator",
    "link"
  ],
  full: [
    "bold",
    "italic",
    "underline",
    "separator",
    "h1",
    "h2",
    "h3",
    "separator",
    "bulletList",
    "orderedList",
    "separator",
    "link",
    "separator",
    "strike",
    "separator",
    "blockquote",
    "code",
    "codeBlock",
    "horizontalRule",
    "separator",
    "clearFormat",
    "separator",
    "undo",
    "redo"
  ]
};
function resolveToolbarItems(toolbar) {
  if (toolbar === false) return null;
  if (toolbar === void 0) return PRESETS.basic;
  if (Array.isArray(toolbar)) return toolbar;
  return PRESETS[toolbar];
}
function toCssLength(value) {
  if (value === null || value === void 0) return null;
  return typeof value === "number" ? `${value}px` : value;
}
var RichTextEditor = react.forwardRef(
  function RichTextEditor2({
    value,
    defaultValue,
    onChange,
    placeholder,
    size = "md",
    variant = "bordered",
    isDisabled = false,
    isReadOnly = false,
    isInvalid = false,
    minHeight,
    maxHeight = "60vh",
    toolbar,
    extensions,
    onCreate,
    "aria-label": ariaLabel,
    className,
    style,
    ...rest
  }, ref) {
    const theme = react$1.useTheme();
    const containerRef = react.useRef(null);
    const onChangeRef = react.useRef(onChange);
    const onCreateRef = react.useRef(onCreate);
    react.useEffect(() => {
      onChangeRef.current = onChange;
    }, [onChange]);
    react.useEffect(() => {
      onCreateRef.current = onCreate;
    }, [onCreate]);
    const initialContent = value ?? defaultValue ?? "";
    const editable = !isDisabled && !isReadOnly;
    const tiptapExtensions = react.useMemo(() => {
      const list = [
        StarterKit__default.default,
        Underline__default.default,
        Link__default.default.configure({ openOnClick: false, autolink: true }),
        Placeholder__default.default.configure({ placeholder: placeholder ?? "" })
      ];
      if (extensions && extensions.length > 0) {
        list.push(...extensions);
      }
      return list;
    }, [extensions, placeholder]);
    const editor = react$2.useEditor(
      {
        extensions: tiptapExtensions,
        content: initialContent,
        editable,
        // 避免 SSR 阶段 immediatelyRender 触发 hydration mismatch
        immediatelyRender: false,
        onCreate: ({ editor: created }) => {
          onCreateRef.current?.(created);
        },
        onUpdate: ({ editor: updated }) => {
          onChangeRef.current?.(updated.getHTML());
        }
      },
      // 仅在扩展集合 / 可编辑性变化时重建 editor。
      [tiptapExtensions, editable]
    );
    react.useEffect(() => {
      if (!editor) return;
      if (value === void 0) return;
      const current = editor.getHTML();
      if (value === current) return;
      editor.commands.setContent(value, false);
    }, [editor, value]);
    react.useEffect(() => {
      if (!editor) return;
      if (editor.isEditable !== editable) {
        editor.setEditable(editable);
      }
    }, [editor, editable]);
    const toolbarItems = resolveToolbarItems(toolbar);
    const inputSize = theme.components.input[size];
    const minHeightCss = toCssLength(minHeight) ?? SIZE_TO_MIN_HEIGHT[size];
    const maxHeightCss = toCssLength(maxHeight ?? null);
    const variantStyles = getFieldVariantStyles({
      theme,
      variant,
      color: "default",
      isInvalid,
      isDisabled,
      isReadOnly
    });
    const setRef = react.useCallback((node) => {
      containerRef.current = node;
    }, []);
    const containerCss = react$1.css`
      display: flex;
      flex-direction: column;
      box-sizing: border-box;
      width: 100%;
      min-width: 0;
      border-radius: ${theme.componentRadius.md};
      color: ${theme.colors.text.primary};
      font-family: ${theme.typography.fontFamily.sans};
      font-size: ${inputSize.fontSize};
      line-height: 1.6;
      overflow: hidden;
      ${isDisabled ? "pointer-events: none;" : ""}
    `;
    const editorScrollCss = react$1.css`
      flex: 1 1 auto;
      min-height: 0;
      overflow-y: auto;
      ${maxHeightCss ? `max-height: ${maxHeightCss};` : ""}
    `;
    const proseCss = react$1.css`
      .ProseMirror {
        outline: none;
        padding: ${inputSize.paddingX};
        min-height: ${minHeightCss};
        color: inherit;
        font-size: inherit;
        line-height: inherit;
        caret-color: ${theme.colors.text.primary};
      }
      .ProseMirror > * + * {
        margin-top: 0.6em;
      }
      .ProseMirror p {
        margin: 0;
      }
      .ProseMirror h1 {
        margin: 0;
        font-size: ${theme.typography.fontSize["2xl"]};
        font-weight: ${theme.typography.fontWeight.semibold};
        line-height: 1.3;
      }
      .ProseMirror h2 {
        margin: 0;
        font-size: ${theme.typography.fontSize.xl};
        font-weight: ${theme.typography.fontWeight.semibold};
        line-height: 1.3;
      }
      .ProseMirror h3 {
        margin: 0;
        font-size: ${theme.typography.fontSize.lg};
        font-weight: ${theme.typography.fontWeight.semibold};
        line-height: 1.4;
      }
      .ProseMirror ul,
      .ProseMirror ol {
        padding-left: 1.5em;
        margin: 0;
      }
      .ProseMirror li > p {
        margin: 0;
      }
      .ProseMirror blockquote {
        margin: 0;
        padding: 0.4em 0.9em;
        border-left: 3px solid ${theme.colors.border.strong};
        background: ${theme.colors.bg.muted};
        color: ${theme.colors.text.secondary};
        font-style: italic;
        border-radius: ${theme.componentRadius.sm};
      }
      .ProseMirror code {
        font-family: ${theme.typography.fontFamily.mono};
        background: ${theme.colors.bg.muted};
        padding: 0.1em 0.35em;
        border-radius: ${theme.componentRadius.sm};
        font-size: 0.9em;
      }
      .ProseMirror pre {
        margin: 0;
        padding: 0.9em 1em;
        background: ${theme.colors.bg.muted};
        color: ${theme.colors.text.primary};
        border-radius: ${theme.componentRadius.sm};
        overflow-x: auto;
        font-family: ${theme.typography.fontFamily.mono};
        font-size: 0.9em;
        line-height: 1.5;
      }
      .ProseMirror pre code {
        background: transparent;
        padding: 0;
        border-radius: 0;
        font-size: inherit;
      }
      .ProseMirror hr {
        margin: 0.6em 0;
        border: 0;
        border-top: ${theme.borders.width.thin} solid ${theme.colors.border.subtle};
      }
      .ProseMirror a {
        color: ${theme.colors.text.link};
        text-decoration: underline;
        cursor: pointer;
      }
      .ProseMirror p.is-editor-empty:first-of-type::before {
        content: attr(data-placeholder);
        color: ${theme.colors.text.muted};
        pointer-events: none;
        height: 0;
        float: left;
      }
    `;
    const items = toolbarItems ?? [];
    return /* @__PURE__ */ jsxRuntime.jsxs(
      "div",
      {
        ref: mergeRefs(ref, setRef),
        role: "textbox",
        "aria-multiline": "true",
        "aria-label": ariaLabel,
        "aria-disabled": isDisabled || void 0,
        "aria-readonly": isReadOnly || void 0,
        "aria-invalid": isInvalid || void 0,
        "data-variant": variant,
        "data-size": size,
        "data-disabled": isDisabled || void 0,
        "data-readonly": isReadOnly || void 0,
        "data-invalid": isInvalid || void 0,
        className,
        style,
        css: [containerCss, variantStyles, proseCss],
        ...rest,
        children: [
          toolbarItems !== null ? /* @__PURE__ */ jsxRuntime.jsx(
            RichTextEditorToolbar,
            {
              editor,
              items,
              size,
              isDisabled: isDisabled || isReadOnly
            }
          ) : null,
          /* @__PURE__ */ jsxRuntime.jsx("div", { css: editorScrollCss, "data-slot": "editor-scroll", children: /* @__PURE__ */ jsxRuntime.jsx(react$2.EditorContent, { editor }) })
        ]
      }
    );
  }
);
RichTextEditor.displayName = "RichTextEditor";

exports.RichTextEditor = RichTextEditor;
//# sourceMappingURL=rich-text-editor.cjs.map
//# sourceMappingURL=rich-text-editor.cjs.map