'use strict';

var react = require('react');
var react$1 = require('@emotion/react');
var state = require('@codemirror/state');
var view = require('@codemirror/view');
var language = require('@codemirror/language');
var commands = require('@codemirror/commands');
var search = require('@codemirror/search');
var autocomplete = require('@codemirror/autocomplete');
var lint = require('@codemirror/lint');
var langJavascript = require('@codemirror/lang-javascript');
var langPython = require('@codemirror/lang-python');
var langCss = require('@codemirror/lang-css');
var langHtml = require('@codemirror/lang-html');
var langJson = require('@codemirror/lang-json');
var highlight = require('@lezer/highlight');
var core = require('@timeui/core');
var jsxRuntime = require('@emotion/react/jsx-runtime');
var reactDom = require('react-dom');

// src/CodeEditor/CodeEditor.tsx
function createCodeEditorTheme(theme, isDark) {
  const editorTheme = view.EditorView.theme(
    {
      "&": {
        color: theme.colors.text.primary,
        backgroundColor: theme.colors.bg.surface,
        fontFamily: theme.typography.fontFamily.mono,
        height: "100%"
      },
      ".cm-content": {
        caretColor: theme.colors.primary[500],
        padding: "8px 0"
      },
      ".cm-cursor, .cm-dropCursor": {
        borderLeftColor: theme.colors.primary[500]
      },
      "&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": {
        backgroundColor: isDark ? `${theme.colors.primary[200]}44` : `${theme.colors.primary[200]}88`
      },
      ".cm-panels": {
        backgroundColor: theme.colors.bg.muted,
        color: theme.colors.text.primary
      },
      ".cm-panels.cm-panels-top": {
        borderBottom: `1px solid ${theme.colors.border.subtle}`
      },
      ".cm-panels.cm-panels-bottom": {
        borderTop: `1px solid ${theme.colors.border.subtle}`
      },
      ".cm-searchMatch": {
        backgroundColor: `${theme.colors.primary[200]}66`,
        outline: `1px solid ${theme.colors.primary[200]}`
      },
      ".cm-searchMatch.cm-searchMatch-selected": {
        backgroundColor: `${theme.colors.primary[200]}88`
      },
      ".cm-activeLine": {
        backgroundColor: isDark ? `${theme.colors.bg.muted}88` : `${theme.colors.bg.sunken}88`
      },
      ".cm-selectionMatch": {
        backgroundColor: `${theme.colors.primary[100]}88`
      },
      "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": {
        backgroundColor: `${theme.colors.primary[200]}66`
      },
      ".cm-gutters": {
        backgroundColor: theme.colors.bg.muted,
        color: theme.colors.text.disabled,
        border: "none",
        borderRight: `1px solid ${theme.colors.border.subtle}`
      },
      ".cm-activeLineGutter": {
        backgroundColor: isDark ? `${theme.colors.bg.sunken}88` : `${theme.colors.bg.canvas}88`
      },
      ".cm-foldPlaceholder": {
        backgroundColor: "transparent",
        border: "none",
        color: theme.colors.text.muted
      },
      ".cm-tooltip": {
        border: `1px solid ${theme.colors.border.default}`,
        backgroundColor: theme.colors.bg.surface,
        boxShadow: theme.shadows.md,
        borderRadius: theme.componentRadius.sm
      },
      ".cm-tooltip .cm-tooltip-arrow:before": {
        borderTopColor: "transparent",
        borderBottomColor: "transparent"
      },
      ".cm-tooltip .cm-tooltip-arrow:after": {
        borderTopColor: theme.colors.bg.surface,
        borderBottomColor: theme.colors.bg.surface
      },
      ".cm-tooltip-autocomplete": {
        "& > ul > li[aria-selected]": {
          backgroundColor: isDark ? theme.colors.primary[600] : theme.colors.primary[100],
          color: isDark ? theme.colors.primary[100] : theme.colors.primary[600]
        }
      }
    },
    { dark: isDark }
  );
  const highlightStyle = language.HighlightStyle.define([
    { tag: highlight.tags.comment, color: theme.colors.text.disabled, fontStyle: "italic" },
    { tag: highlight.tags.lineComment, color: theme.colors.text.disabled, fontStyle: "italic" },
    { tag: highlight.tags.blockComment, color: theme.colors.text.disabled, fontStyle: "italic" },
    { tag: highlight.tags.docComment, color: theme.colors.text.disabled, fontStyle: "italic" },
    {
      tag: highlight.tags.keyword,
      color: isDark ? theme.colors.primary[200] : theme.colors.primary[600]
    },
    {
      tag: [highlight.tags.deleted, highlight.tags.character, highlight.tags.propertyName, highlight.tags.macroName],
      color: isDark ? theme.colors.primary[200] : theme.colors.primary[600]
    },
    {
      tag: [highlight.tags.function(highlight.tags.variableName), highlight.tags.definition(highlight.tags.variableName), highlight.tags.labelName],
      color: isDark ? theme.colors.primary[200] : theme.colors.primary[500]
    },
    {
      tag: [highlight.tags.color, highlight.tags.constant(highlight.tags.name), highlight.tags.standard(highlight.tags.name)],
      color: isDark ? theme.colors.primary[200] : theme.colors.primary[600]
    },
    {
      tag: [highlight.tags.definition(highlight.tags.name), highlight.tags.separator],
      color: theme.colors.text.primary
    },
    {
      // Type names, class names — use cyan-ish tone
      tag: [
        highlight.tags.typeName,
        highlight.tags.className,
        highlight.tags.changed,
        highlight.tags.annotation,
        highlight.tags.modifier,
        highlight.tags.self,
        highlight.tags.namespace
      ],
      color: isDark ? "#79b8ff" : "#0086b3"
    },
    {
      tag: [highlight.tags.number],
      // orange for numbers — use warning color if available
      color: isDark ? theme.colors.warning[200] : theme.colors.warning[600]
    },
    {
      tag: [
        highlight.tags.operator,
        highlight.tags.operatorKeyword,
        highlight.tags.escape,
        highlight.tags.regexp,
        highlight.tags.link,
        highlight.tags.special(highlight.tags.string)
      ],
      color: theme.colors.text.secondary
    },
    {
      tag: [highlight.tags.url],
      color: theme.colors.text.link
    },
    {
      tag: [highlight.tags.meta],
      color: theme.colors.text.muted
    },
    {
      tag: highlight.tags.strong,
      fontWeight: "bold"
    },
    {
      tag: highlight.tags.emphasis,
      fontStyle: "italic"
    },
    {
      tag: highlight.tags.strikethrough,
      textDecoration: "line-through"
    },
    {
      tag: highlight.tags.link,
      color: theme.colors.text.link,
      textDecoration: "underline"
    },
    {
      tag: highlight.tags.heading,
      fontWeight: "bold",
      color: theme.colors.text.primary
    },
    {
      tag: [highlight.tags.atom, highlight.tags.bool, highlight.tags.special(highlight.tags.variableName)],
      color: isDark ? theme.colors.primary[200] : theme.colors.primary[600]
    },
    {
      // green tones for strings
      tag: [highlight.tags.processingInstruction, highlight.tags.string, highlight.tags.inserted],
      color: isDark ? "#85e89d" : "#22863a"
    },
    {
      tag: highlight.tags.invalid,
      color: isDark ? theme.colors.danger[200] : theme.colors.danger[600]
    }
  ]);
  return [editorTheme, language.syntaxHighlighting(highlightStyle)];
}
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";

// 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] = 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 FALLBACK_LABELS = {
  toolbarLabel: "Code editor toolbar",
  copy: "Copy",
  copied: "Copied!",
  lineWrap: "Toggle line wrap",
  lineNumbers: "Toggle line numbers",
  fullscreen: "Fullscreen",
  exitFullscreen: "Exit fullscreen",
  language: "Language",
  aiSuggest: "AI suggestions"
};
var LANGUAGE_OPTIONS = [
  { value: "javascript", label: "JavaScript" },
  { value: "typescript", label: "TypeScript" },
  { value: "python", label: "Python" },
  { value: "css", label: "CSS" },
  { value: "html", label: "HTML" },
  { value: "json", label: "JSON" }
];
function Icon({ size = 16, 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 CopyIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
] });
var CheckIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsx(Icon, { size, children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) });
var WrapTextIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 6h16" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 12h10a3 3 0 0 1 0 6H4" }),
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "12 15 9 18 12 21" })
] });
var HashIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "9", x2: "20", y2: "9" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "15", x2: "20", y2: "15" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "10", y1: "3", x2: "8", y2: "21" }),
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "3", x2: "14", y2: "21" })
] });
var MaximizeIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 8V5a2 2 0 0 0-2-2h-3" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 16v3a2 2 0 0 0 2 2h3" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
] });
var MinimizeIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 3v3a2 2 0 0 1-2 2H3" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 8h-3a2 2 0 0 1-2-2V3" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 16h3a2 2 0 0 1 2 2v3" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 21v-3a2 2 0 0 1 2-2h3" })
] });
var SparklesIcon = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5Z" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 13l.75 2.25L22 16l-2.25.75L19 19l-.75-2.25L16 16l2.25-.75Z" }),
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 17l.5 1.5L7 19l-1.5.5L5 21l-.5-1.5L3 19l1.5-.5Z" })
] });
function CodeEditorToolbar({
  getValue,
  language,
  onLanguageChange,
  lineWrap,
  onLineWrapToggle,
  showLineNumbers,
  onLineNumbersToggle,
  isFullscreen,
  onFullscreenToggle,
  config,
  labelOverrides,
  hasAI,
  onAISuggest,
  "aria-label": ariaLabelProp
}) {
  const theme = react$1.useTheme();
  const i18n = core.useI18n();
  const i18nLabels = i18n.codeEditor ?? FALLBACK_LABELS;
  const labels = { ...i18nLabels, ...labelOverrides };
  const resolvedAriaLabel = ariaLabelProp ?? labels.toolbarLabel;
  const [copied, setCopied] = react.useState(false);
  const handleCopy = react.useCallback(() => {
    if (typeof navigator === "undefined" || !navigator.clipboard) return;
    navigator.clipboard.writeText(getValue()).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2e3);
    }).catch(() => {
    });
  }, [getValue]);
  const showCopy = config.showCopy !== false;
  const showLineWrap = config.showLineWrap !== false;
  const showLineNums = config.showLineNumbers !== false;
  const showLangSelect = config.showLanguageSelect !== false;
  const showFullscreen = config.showFullscreen !== false;
  const containerCss = react$1.css`
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    padding: 6px 10px;
    border-bottom: ${theme.borders.width.thin} solid ${theme.colors.border.subtle};
    color: ${theme.colors.text.primary};
    background-color: ${theme.colors.bg.muted};
    border-radius: ${theme.componentRadius.md} ${theme.componentRadius.md} 0 0;
  `;
  const separatorCss = react$1.css`
    width: ${theme.borders.width.thin};
    align-self: stretch;
    min-height: 16px;
    margin: 2px 4px;
    background: ${theme.colors.border.subtle};
  `;
  const langSelectCss = react$1.css`
    appearance: none;
    -webkit-appearance: none;
    background-color: transparent;
    border: 1px solid ${theme.colors.border.subtle};
    border-radius: ${theme.componentRadius.sm};
    color: ${theme.colors.text.secondary};
    font-family: ${theme.typography.fontFamily.sans};
    font-size: ${theme.typography.fontSize.xs};
    height: 28px;
    padding: 0 24px 0 8px;
    cursor: pointer;
    outline: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23888' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 6px center;
    transition: border-color 0.15s ease;

    &:hover {
      border-color: ${theme.colors.border.default};
      color: ${theme.colors.text.primary};
    }

    &:focus {
      border-color: ${theme.colors.primary[500]};
      box-shadow: 0 0 0 2px ${theme.colors.primary[100]};
    }
  `;
  const activeButtonCss = (active) => react$1.css`
    ${active ? `
      background-color: ${theme.colors.default[200]};
      color: ${theme.colors.text.primary};
    ` : ""}
  `;
  const spacerCss = react$1.css`
    flex: 1;
  `;
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "toolbar", "aria-label": resolvedAriaLabel, css: containerCss, children: [
    showLangSelect && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.language, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      "select",
      {
        "aria-label": labels.language,
        value: language,
        onChange: (e) => onLanguageChange(e.target.value),
        css: langSelectCss,
        children: LANGUAGE_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
      }
    ) }),
    showLangSelect && (showLineWrap || showLineNums || showCopy || showFullscreen || hasAI) && /* @__PURE__ */ jsxRuntime.jsx("span", { css: separatorCss, "aria-hidden": true }),
    showLineWrap && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.lineWrap, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.lineWrap,
        "aria-pressed": lineWrap,
        "data-active": lineWrap || void 0,
        onClick: onLineWrapToggle,
        css: activeButtonCss(lineWrap),
        children: /* @__PURE__ */ jsxRuntime.jsx(WrapTextIcon, { size: 15 })
      }
    ) }),
    showLineNums && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.lineNumbers, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.lineNumbers,
        "aria-pressed": showLineNumbers,
        "data-active": showLineNumbers || void 0,
        onClick: onLineNumbersToggle,
        css: activeButtonCss(showLineNumbers),
        children: /* @__PURE__ */ jsxRuntime.jsx(HashIcon, { size: 15 })
      }
    ) }),
    /* @__PURE__ */ jsxRuntime.jsx("span", { css: spacerCss }),
    showCopy && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: copied ? labels.copied : labels.copy, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": copied ? labels.copied : labels.copy,
        onClick: handleCopy,
        children: copied ? /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { size: 15 }) : /* @__PURE__ */ jsxRuntime.jsx(CopyIcon, { size: 15 })
      }
    ) }),
    hasAI && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: labels.aiSuggest, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.aiSuggest,
        onClick: onAISuggest,
        children: /* @__PURE__ */ jsxRuntime.jsx(SparklesIcon, { size: 15 })
      }
    ) }),
    showFullscreen && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: isFullscreen ? labels.exitFullscreen : labels.fullscreen, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": isFullscreen ? labels.exitFullscreen : labels.fullscreen,
        "aria-pressed": isFullscreen,
        onClick: onFullscreenToggle,
        children: isFullscreen ? /* @__PURE__ */ jsxRuntime.jsx(MinimizeIcon, { size: 15 }) : /* @__PURE__ */ jsxRuntime.jsx(MaximizeIcon, { size: 15 })
      }
    ) })
  ] });
}
function getLanguageExtension(language) {
  switch (language) {
    case "javascript":
      return langJavascript.javascript();
    case "typescript":
      return langJavascript.javascript({ typescript: true });
    case "python":
      return langPython.python();
    case "css":
      return langCss.css();
    case "html":
      return langHtml.html();
    case "json":
      return langJson.json();
    default:
      return langJavascript.javascript();
  }
}
function toCssLength(value) {
  if (value === null || value === void 0) return null;
  return typeof value === "number" ? `${value}px` : value;
}
function resolveToolbarConfig(toolbar) {
  if (toolbar === false) return false;
  if (toolbar === true || toolbar === void 0) return {};
  return toolbar;
}
var SIZE_TO_FONT = {
  xs: "11px",
  sm: "12px",
  md: "13px",
  lg: "14px",
  xl: "16px"
};
var SIZE_TO_MIN_HEIGHT = {
  xs: "80px",
  sm: "120px",
  md: "200px",
  lg: "280px",
  xl: "360px"
};
var CodeEditor = react.forwardRef(function CodeEditor2({
  value,
  defaultValue,
  onChange,
  language: languageProp = "javascript",
  onLanguageChange,
  size = "md",
  variant = "bordered",
  placeholder,
  isDisabled = false,
  isReadOnly = false,
  isInvalid = false,
  showLineNumbers: showLineNumbersProp = true,
  onShowLineNumbersChange,
  lineWrap: lineWrapProp = false,
  onLineWrapChange,
  toolbar,
  minHeight,
  maxHeight,
  extensions: extraExtensions,
  onAISuggest,
  className,
  "aria-label": ariaLabel,
  "aria-labelledby": ariaLabelledby,
  "aria-describedby": ariaDescribedby
}, ref) {
  const theme = react$1.useTheme();
  const isDark = theme.mode === "dark";
  const [language$1, setLanguageInternal] = react.useState(languageProp);
  const [lineWrap, setLineWrap] = react.useState(lineWrapProp);
  const [showLineNumbers, setShowLineNumbers] = react.useState(showLineNumbersProp);
  const [isFullscreen, setIsFullscreen] = react.useState(false);
  react.useEffect(() => {
    setLanguageInternal(languageProp);
  }, [languageProp]);
  react.useEffect(() => {
    setLineWrap(lineWrapProp);
  }, [lineWrapProp]);
  react.useEffect(() => {
    setShowLineNumbers(showLineNumbersProp);
  }, [showLineNumbersProp]);
  const setLanguage = react.useCallback(
    (lang) => {
      setLanguageInternal(lang);
      onLanguageChange?.(lang);
    },
    [onLanguageChange]
  );
  const toggleLineWrap = react.useCallback(() => {
    setLineWrap((prev) => {
      const next = !prev;
      onLineWrapChange?.(next);
      return next;
    });
  }, [onLineWrapChange]);
  const toggleLineNumbers = react.useCallback(() => {
    setShowLineNumbers((prev) => {
      const next = !prev;
      onShowLineNumbersChange?.(next);
      return next;
    });
  }, [onShowLineNumbersChange]);
  const getValue = react.useCallback(
    () => viewRef.current?.state.doc.toString() ?? value ?? defaultValue ?? "",
    [value, defaultValue]
  );
  const languageCompartment = react.useMemo(() => new state.Compartment(), []);
  const themeCompartment = react.useMemo(() => new state.Compartment(), []);
  const lineWrapCompartment = react.useMemo(() => new state.Compartment(), []);
  const lineNumbersCompartment = react.useMemo(() => new state.Compartment(), []);
  const readOnlyCompartment = react.useMemo(() => new state.Compartment(), []);
  const editorRef = react.useRef(null);
  const viewRef = react.useRef(null);
  const onChangeRef = react.useRef(onChange);
  react.useEffect(() => {
    onChangeRef.current = onChange;
  }, [onChange]);
  const lastExternalValue = react.useRef(value);
  const buildExtensions = react.useCallback(() => {
    const exts = [
      view.highlightSpecialChars(),
      commands.history(),
      view.drawSelection(),
      view.dropCursor(),
      state.EditorState.allowMultipleSelections.of(true),
      language.indentOnInput(),
      language.syntaxHighlighting(language.defaultHighlightStyle, { fallback: true }),
      language.bracketMatching(),
      autocomplete.closeBrackets(),
      autocomplete.autocompletion(),
      view.rectangularSelection(),
      view.crosshairCursor(),
      view.highlightActiveLine(),
      view.highlightActiveLineGutter(),
      search.highlightSelectionMatches(),
      view.keymap.of([
        ...autocomplete.closeBracketsKeymap,
        ...commands.defaultKeymap,
        ...search.searchKeymap,
        ...commands.historyKeymap,
        ...language.foldKeymap,
        ...autocomplete.completionKeymap,
        ...lint.lintKeymap
      ]),
      language.foldGutter(),
      view.EditorView.updateListener.of((update) => {
        if (update.docChanged) {
          const newValue = update.state.doc.toString();
          lastExternalValue.current = newValue;
          onChangeRef.current?.(newValue);
        }
      })
    ];
    if (placeholder) {
      exts.push(view.placeholder(placeholder));
    }
    if (extraExtensions && extraExtensions.length > 0) {
      exts.push(...extraExtensions);
    }
    return exts;
  }, [placeholder, extraExtensions]);
  react.useEffect(() => {
    if (!editorRef.current) return;
    const initialDoc = value ?? defaultValue ?? "";
    lastExternalValue.current = initialDoc;
    const startState = state.EditorState.create({
      doc: initialDoc,
      extensions: [
        ...buildExtensions(),
        lineNumbersCompartment.of(showLineNumbers ? view.lineNumbers() : []),
        lineWrapCompartment.of(lineWrap ? view.EditorView.lineWrapping : []),
        readOnlyCompartment.of([
          state.EditorState.readOnly.of(isReadOnly || isDisabled),
          view.EditorView.editable.of(!isDisabled)
        ]),
        languageCompartment.of(getLanguageExtension(language$1)),
        themeCompartment.of(createCodeEditorTheme(theme, isDark))
      ]
    });
    const view$1 = new view.EditorView({
      state: startState,
      parent: editorRef.current
    });
    viewRef.current = view$1;
    return () => {
      view$1.destroy();
      viewRef.current = null;
    };
  }, []);
  react.useEffect(() => {
    const view = viewRef.current;
    if (!view) return;
    if (value === void 0) return;
    const current = view.state.doc.toString();
    if (current === value) return;
    lastExternalValue.current = value;
    view.dispatch({
      changes: { from: 0, to: view.state.doc.length, insert: value }
    });
  }, [value]);
  react.useEffect(() => {
    viewRef.current?.dispatch({
      effects: languageCompartment.reconfigure(getLanguageExtension(language$1))
    });
  }, [language$1, languageCompartment]);
  react.useEffect(() => {
    viewRef.current?.dispatch({
      effects: themeCompartment.reconfigure(createCodeEditorTheme(theme, isDark))
    });
  }, [theme, isDark, themeCompartment]);
  react.useEffect(() => {
    viewRef.current?.dispatch({
      effects: lineWrapCompartment.reconfigure(lineWrap ? view.EditorView.lineWrapping : [])
    });
  }, [lineWrap, lineWrapCompartment]);
  react.useEffect(() => {
    viewRef.current?.dispatch({
      effects: lineNumbersCompartment.reconfigure(showLineNumbers ? view.lineNumbers() : [])
    });
  }, [showLineNumbers, lineNumbersCompartment]);
  react.useEffect(() => {
    viewRef.current?.dispatch({
      effects: readOnlyCompartment.reconfigure([
        state.EditorState.readOnly.of(isReadOnly || isDisabled),
        view.EditorView.editable.of(!isDisabled)
      ])
    });
  }, [isReadOnly, isDisabled, readOnlyCompartment]);
  const toolbarConfig = resolveToolbarConfig(toolbar);
  const hasToolbar = toolbarConfig !== false;
  const handleAISuggest = react.useCallback(() => {
    if (!onAISuggest || !viewRef.current) return;
    const view = viewRef.current;
    const pos = view.state.selection.main.head;
    const code = view.state.doc.toString();
    onAISuggest(code, pos).then((suggestions) => {
      const best = suggestions[0];
      if (!best) return;
      view.dispatch({
        changes: { from: pos, to: pos, insert: best.text }
      });
    });
  }, [onAISuggest]);
  const minHeightCss = toCssLength(minHeight) ?? SIZE_TO_MIN_HEIGHT[size];
  const maxHeightCss = toCssLength(maxHeight ?? null);
  const fontSizeCss = SIZE_TO_FONT[size];
  const getVariantBorder = (v) => {
    if (v === "flat") return "none";
    if (v === "bordered")
      return `${theme.borders.width.thin} solid ${isInvalid ? theme.colors.danger[500] : theme.colors.border.default}`;
    if (v === "faded")
      return `${theme.borders.width.thin} solid ${isInvalid ? theme.colors.danger[500] : theme.colors.border.subtle}`;
    return "none";
  };
  const getVariantBg = (v) => {
    if (v === "faded") return theme.colors.bg.muted;
    return theme.colors.bg.surface;
  };
  const containerCss = react$1.css`
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    width: 100%;
    min-width: 0;
    font-family: ${theme.typography.fontFamily.mono};
    font-size: ${fontSizeCss};
    line-height: 1.6;
    border-radius: ${theme.componentRadius.md};
    border: ${getVariantBorder(variant)};
    background-color: ${getVariantBg(variant)};
    overflow: hidden;
    transition:
      border-color 0.15s ease,
      box-shadow 0.15s ease;
    ${isDisabled ? "opacity: 0.6; pointer-events: none;" : ""}
    ${isFullscreen ? `
        position: fixed;
        inset: 0;
        z-index: ${theme.zIndex.modal};
        border-radius: 0;
        border: none;
        max-height: 100vh;
      ` : ""}

    &:focus-within {
      ${variant !== "flat" ? `
        border-color: ${isInvalid ? theme.colors.danger[500] : theme.colors.primary[500]};
        box-shadow: 0 0 0 2px ${isInvalid ? theme.colors.danger[100] : theme.colors.primary[100]};
      ` : ""}
    }
  `;
  const editorScrollCss = react$1.css`
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    ${maxHeightCss && !isFullscreen ? `max-height: ${maxHeightCss};` : ""}

    /* CodeMirror editor sizing */
    .cm-editor {
      font-size: ${fontSizeCss};
      min-height: ${minHeightCss};
      height: ${isFullscreen ? "100%" : "auto"};
    }

    .cm-scroller {
      overflow: auto;
      font-family: ${theme.typography.fontFamily.mono};
      min-height: ${minHeightCss};
    }
  `;
  return /* @__PURE__ */ jsxRuntime.jsxs(
    "div",
    {
      ref,
      role: "group",
      css: containerCss,
      "data-variant": variant,
      "data-size": size,
      "data-fullscreen": isFullscreen || void 0,
      "data-disabled": isDisabled || void 0,
      "data-readonly": isReadOnly || void 0,
      "data-invalid": isInvalid || void 0,
      className,
      "aria-label": ariaLabel,
      "aria-labelledby": ariaLabelledby,
      "aria-describedby": ariaDescribedby,
      children: [
        hasToolbar && /* @__PURE__ */ jsxRuntime.jsx(
          CodeEditorToolbar,
          {
            getValue,
            language: language$1,
            onLanguageChange: setLanguage,
            lineWrap,
            onLineWrapToggle: toggleLineWrap,
            showLineNumbers,
            onLineNumbersToggle: toggleLineNumbers,
            isFullscreen,
            onFullscreenToggle: () => setIsFullscreen((v) => !v),
            config: toolbarConfig,
            hasAI: !!onAISuggest,
            onAISuggest: handleAISuggest
          }
        ),
        /* @__PURE__ */ jsxRuntime.jsx("div", { ref: editorRef, css: editorScrollCss, "data-slot": "code-editor-mount" })
      ]
    }
  );
});
CodeEditor.displayName = "CodeEditor";

exports.CodeEditor = CodeEditor;
//# sourceMappingURL=code-editor.cjs.map
//# sourceMappingURL=code-editor.cjs.map