import { CodeBlock } from './chunk-SESMNISA.js';
import { Tooltip, Button } from './chunk-FKEFVCK4.js';
import { forwardRef, useState, useRef, useEffect, useImperativeHandle, useCallback, useMemo } from 'react';
import { useTheme, css } from '@emotion/react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { jsxs, jsx } from '@emotion/react/jsx-runtime';

function createMarkdownViewerTypography(theme) {
  const isDark = theme.mode === "dark";
  const tableStripe = isDark ? theme.colors.bg.raised : theme.colors.bg.sunken;
  const tableHover = theme.colors.bg.muted;
  return css`
    color: ${theme.colors.text.primary};
    font-family: ${theme.typography.fontFamily.sans};
    font-size: ${theme.typography.fontSize.md};
    line-height: ${theme.typography.lineHeight.relaxed};
    word-break: break-word;

    /* :first-of-type 而非 :first-child —— Emotion SSR 会在内容前注入 <style>，
       :first-child 会先匹配到 <style> 触发 dev 警告。与 ChatMarkdown 保持一致。 */
    & > :first-of-type {
      margin-top: 0;
    }
    & > :last-child {
      margin-bottom: 0;
    }

    p {
      margin: 0 0 1em;
    }

    strong {
      font-weight: ${theme.typography.fontWeight.bold};
    }
    em {
      font-style: italic;
    }
    del {
      text-decoration: line-through;
      color: ${theme.colors.text.muted};
    }

    a {
      color: ${theme.colors.text.link};
      text-decoration: underline;
      text-underline-offset: 2px;
      text-decoration-thickness: 1px;
      transition: color 150ms ease;
      @media (prefers-reduced-motion: reduce) {
        transition: none;
      }
      &:hover {
        color: ${theme.colors.primary[600]};
        text-decoration-thickness: 2px;
      }
      &:focus-visible {
        outline: 2px solid ${theme.colors.focus};
        outline-offset: 2px;
        border-radius: 2px;
      }
    }

    h1,
    h2,
    h3,
    h4,
    h5,
    h6 {
      margin: 1.6em 0 0.6em;
      font-weight: ${theme.typography.fontWeight.bold};
      line-height: 1.3;
      color: ${theme.colors.text.primary};
      scroll-margin-top: 1em;
    }
    :is(h1, h2, h3, h4, h5, h6):first-of-type {
      margin-top: 0;
    }
    h1 {
      font-size: 2em;
      padding-bottom: 0.3em;
      border-bottom: 1px solid ${theme.colors.border.subtle};
    }
    h2 {
      font-size: 1.5em;
      padding-bottom: 0.25em;
      border-bottom: 1px solid ${theme.colors.border.subtle};
    }
    h3 {
      font-size: 1.25em;
    }
    h4 {
      font-size: 1.1em;
    }
    h5 {
      font-size: 1em;
    }
    h6 {
      font-size: 0.9em;
      color: ${theme.colors.text.secondary};
    }

    ul,
    ol {
      margin: 0 0 1em;
      padding-left: 1.6em;
    }
    li {
      margin: 0.25em 0;
    }
    li > p {
      margin: 0;
    }
    li > p + p {
      margin-top: 0.4em;
    }
    /* GFM task list 视觉更紧凑，复选框对齐文字基线。 */
    li.task-list-item,
    li:has(> input[type='checkbox']) {
      list-style: none;
      margin-left: -1.2em;
    }
    li > input[type='checkbox'] {
      margin-right: 0.5em;
      vertical-align: middle;
    }

    blockquote {
      margin: 0 0 1em;
      padding: 0.6em 1em;
      border-left: 4px solid ${theme.colors.border.default};
      color: ${theme.colors.text.secondary};
      background: ${theme.colors.bg.sunken};
      border-radius: 0 ${theme.radius.md} ${theme.radius.md} 0;
    }
    blockquote > :last-child {
      margin-bottom: 0;
    }

    hr {
      border: 0;
      border-top: 1px solid ${theme.colors.border.subtle};
      margin: 2em 0;
    }

    /* 行内 code；fenced code 由自定义 pre/code renderer 接管为 CodeBlock。 */
    :not(pre) > code {
      font-family: ${theme.typography.fontFamily.mono};
      font-size: 0.9em;
      background: ${theme.colors.bg.sunken};
      color: ${theme.colors.text.primary};
      padding: 0.15em 0.4em;
      border-radius: ${theme.radius.sm};
      border: 1px solid ${theme.colors.border.subtle};
      word-break: break-all;
    }

    /* fallback：caller 用自定义 components 覆盖了 pre/code 时的回落路径。 */
    pre {
      margin: 0 0 1em;
      padding: 1em;
      background: ${theme.colors.bg.sunken};
      border: 1px solid ${theme.colors.border.subtle};
      border-radius: ${theme.radius.md};
      overflow-x: auto;
      font-family: ${theme.typography.fontFamily.mono};
      font-size: 0.9em;
      line-height: 1.6;
    }
    pre code {
      background: transparent;
      padding: 0;
      border: 0;
      border-radius: 0;
      font-size: inherit;
      white-space: pre;
      word-break: normal;
    }

    table {
      margin: 0 0 1em;
      width: 100%;
      border-collapse: collapse;
      border: 1px solid ${theme.colors.border.subtle};
      border-radius: ${theme.radius.md};
      overflow: hidden;
      font-size: 0.95em;
    }
    th,
    td {
      padding: 0.55em 0.85em;
      border-bottom: 1px solid ${theme.colors.border.subtle};
      text-align: left;
      vertical-align: top;
    }
    th {
      font-weight: ${theme.typography.fontWeight.semibold};
      background: ${theme.colors.bg.muted};
      color: ${theme.colors.text.primary};
    }
    tbody tr:nth-of-type(even) td {
      background: ${tableStripe};
    }
    tbody tr:hover td {
      background: ${tableHover};
    }
    tr:last-child td {
      border-bottom: 0;
    }

    img {
      max-width: 100%;
      height: auto;
      border-radius: ${theme.radius.md};
      margin: 0.5em 0;
    }

    /* 内嵌的 CodeBlock 上下间距与正文段落对齐。 */
    [data-slot='markdown-codeblock'] {
      margin: 0 0 1em;
    }
  `;
}
var DEFAULT_TOOLBAR_LABELS = {
  toolbarLabel: "Markdown viewer toolbar",
  copy: "Copy markdown",
  copied: "Copied!",
  download: "Download as .md",
  refresh: "Refresh"
};
function Icon({ size = 16, children }) {
  return /* @__PURE__ */ 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__ */ jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
  /* @__PURE__ */ 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__ */ jsx(Icon, { size, children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) });
var DownloadIcon = ({ size }) => /* @__PURE__ */ jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
  /* @__PURE__ */ jsx("polyline", { points: "7 10 12 15 17 10" }),
  /* @__PURE__ */ jsx("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
] });
var RefreshIcon = ({ size }) => /* @__PURE__ */ jsxs(Icon, { size, children: [
  /* @__PURE__ */ jsx("polyline", { points: "23 4 23 10 17 10" }),
  /* @__PURE__ */ jsx("path", { d: "M20.49 15A9 9 0 1 1 19 6.36L23 10" })
] });
function MarkdownViewerToolbar(props) {
  const {
    getMarkdown,
    config,
    labels,
    canRefresh,
    onRefresh,
    downloadFileName = "document"
  } = props;
  const theme = useTheme();
  const [copied, setCopied] = useState(false);
  const showCopy = config.copy !== false;
  const showDownload = config.download !== false;
  const showRefresh = config.refresh !== false && canRefresh;
  const handleCopy = useCallback(async () => {
    if (typeof navigator === "undefined" || !navigator.clipboard) return;
    try {
      await navigator.clipboard.writeText(getMarkdown());
      setCopied(true);
      window.setTimeout(() => setCopied(false), 2e3);
    } catch {
    }
  }, [getMarkdown]);
  const handleDownload = useCallback(() => {
    if (typeof window === "undefined" || typeof document === "undefined") return;
    if (typeof Blob === "undefined" || typeof URL.createObjectURL !== "function") return;
    const blob = new Blob([getMarkdown()], { type: "text/markdown;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `${downloadFileName}.md`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    window.setTimeout(() => URL.revokeObjectURL(url), 0);
  }, [getMarkdown, downloadFileName]);
  const containerCss = css`
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 6px 10px;
    border-bottom: 1px solid ${theme.colors.border.subtle};
    background: ${theme.colors.bg.muted};
    color: ${theme.colors.text.primary};
  `;
  const spacerCss = css`
    flex: 1;
  `;
  return /* @__PURE__ */ jsxs("div", { role: "toolbar", "aria-label": labels.toolbarLabel, css: containerCss, children: [
    /* @__PURE__ */ jsx("span", { css: spacerCss }),
    showRefresh && /* @__PURE__ */ jsx(Tooltip, { content: labels.refresh, placement: "top", children: /* @__PURE__ */ jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.refresh,
        onClick: () => onRefresh?.(),
        children: /* @__PURE__ */ jsx(RefreshIcon, { size: 15 })
      }
    ) }),
    showCopy && /* @__PURE__ */ jsx(Tooltip, { content: copied ? labels.copied : labels.copy, placement: "top", children: /* @__PURE__ */ jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": copied ? labels.copied : labels.copy,
        onClick: handleCopy,
        children: copied ? /* @__PURE__ */ jsx(CheckIcon, { size: 15 }) : /* @__PURE__ */ jsx(CopyIcon, { size: 15 })
      }
    ) }),
    showDownload && /* @__PURE__ */ jsx(Tooltip, { content: labels.download, placement: "top", children: /* @__PURE__ */ jsx(
      Button,
      {
        type: "button",
        variant: "light",
        color: "default",
        size: "sm",
        isIconOnly: true,
        "aria-label": labels.download,
        onClick: handleDownload,
        children: /* @__PURE__ */ jsx(DownloadIcon, { size: 15 })
      }
    ) })
  ] });
}
MarkdownViewerToolbar.displayName = "MarkdownViewerToolbar";
function baseSlug(text) {
  return text.toLowerCase().trim().replace(/[^\p{L}\p{N}\s-]+/gu, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
}
function createSlugger() {
  const counts = /* @__PURE__ */ new Map();
  return (text) => {
    const base = baseSlug(text) || "section";
    const used = counts.get(base) ?? 0;
    counts.set(base, used + 1);
    return used === 0 ? base : `${base}-${used}`;
  };
}
function extractHeadings(markdown, maxDepth) {
  const lines = markdown.split("\n");
  const slugger = createSlugger();
  const items = [];
  let inFence = false;
  let inFrontmatter = false;
  const cleanInline = (raw) => raw.replace(/`([^`]+)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/__([^_]+)__/g, "$1").replace(/_([^_]+)_/g, "$1").replace(/~~([^~]+)~~/g, "$1").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").trim();
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i] ?? "";
    if (i === 0 && /^---\s*$/.test(line)) {
      inFrontmatter = true;
      continue;
    }
    if (inFrontmatter) {
      if (/^---\s*$/.test(line)) inFrontmatter = false;
      continue;
    }
    if (/^\s{0,3}(```|~~~)/.test(line)) {
      inFence = !inFence;
      continue;
    }
    if (inFence) continue;
    const atx = /^\s{0,3}(#{1,6})\s+(.+?)\s*#*\s*$/.exec(line);
    if (atx) {
      const level = atx[1].length;
      if (level > maxDepth) continue;
      const text = cleanInline(atx[2]);
      items.push({ id: slugger(text), level, text, line: i + 1 });
      continue;
    }
    const next = lines[i + 1] ?? "";
    const isSetextH1 = /^\s{0,3}=+\s*$/.test(next);
    const isSetextH2 = /^\s{0,3}-+\s*$/.test(next);
    if ((isSetextH1 || isSetextH2) && line.trim() !== "") {
      const level = isSetextH1 ? 1 : 2;
      if (level <= maxDepth) {
        const text = cleanInline(line.trim());
        items.push({ id: slugger(text), level, text, line: i + 1 });
      }
      i += 1;
      continue;
    }
  }
  return items;
}
function MarkdownViewerToc(props) {
  const {
    items,
    scrollContainerRef,
    contentRef,
    ariaLabel = "Table of contents",
    className
  } = props;
  const theme = useTheme();
  const [activeId, setActiveId] = useState(items[0]?.id ?? null);
  useEffect(() => {
    setActiveId(items[0]?.id ?? null);
  }, [items]);
  useEffect(() => {
    if (typeof window === "undefined" || typeof IntersectionObserver === "undefined") return;
    const container = contentRef.current;
    if (!container) return;
    if (items.length === 0) return;
    const headings = items.map((it) => container.querySelector(`#${CSS.escape(it.id)}`)).filter((el) => el !== null);
    if (headings.length === 0) return;
    const visible = /* @__PURE__ */ new Set();
    const observer = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          const id = entry.target.id;
          if (entry.isIntersecting) visible.add(id);
          else visible.delete(id);
        }
        const firstVisible = headings.find((h) => visible.has(h.id));
        if (firstVisible) {
          setActiveId(firstVisible.id);
        }
      },
      {
        root: scrollContainerRef.current,
        // 把 viewport 顶部 10%、底部 60% 排除在外 —— 让"中段可见"的标题胜出。
        rootMargin: "-10% 0px -60% 0px",
        threshold: [0, 1]
      }
    );
    for (const h of headings) observer.observe(h);
    return () => observer.disconnect();
  }, [items, contentRef, scrollContainerRef]);
  if (items.length === 0) return null;
  const handleClick = (event, id) => {
    event.preventDefault();
    const container = contentRef.current;
    const target = container?.querySelector(`#${CSS.escape(id)}`);
    if (!target) return;
    setActiveId(id);
    const reduced = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    target.scrollIntoView({ behavior: reduced ? "auto" : "smooth", block: "start" });
  };
  const minLevel = items.reduce((acc, it) => Math.min(acc, it.level), 6);
  const isDark = theme.mode === "dark";
  const scrollbarThumbIdle = isDark ? "rgba(255, 255, 255, 0.18)" : "rgba(0, 0, 0, 0.18)";
  const scrollbarThumbHover = isDark ? "rgba(255, 255, 255, 0.32)" : "rgba(0, 0, 0, 0.32)";
  const navCss = css`
    flex: 0 0 220px;
    min-width: 0;
    align-self: flex-start;
    position: sticky;
    top: 0;
    max-height: 100%;
    overflow-y: auto;
    padding: 4px 0 4px 16px;
    border-inline-start: 1px solid ${theme.colors.border.subtle};
    font-family: ${theme.typography.fontFamily.sans};
    font-size: ${theme.typography.fontSize.sm};
    color: ${theme.colors.text.secondary};

    /* hover-only thin scrollbar，与正文滚动区一致。 */
    scrollbar-width: thin;
    scrollbar-color: transparent transparent;
    transition: scrollbar-color 200ms ease;
    &:hover,
    &:focus-within {
      scrollbar-color: ${scrollbarThumbIdle} transparent;
    }
    &::-webkit-scrollbar {
      width: 8px;
    }
    &::-webkit-scrollbar-track {
      background: transparent;
    }
    &::-webkit-scrollbar-thumb {
      background: transparent;
      border-radius: 999px;
      border: 2px solid transparent;
      background-clip: content-box;
      transition: background-color 200ms ease;
    }
    &:hover::-webkit-scrollbar-thumb,
    &:focus-within::-webkit-scrollbar-thumb {
      background-color: ${scrollbarThumbIdle};
    }
    &::-webkit-scrollbar-thumb:hover {
      background-color: ${scrollbarThumbHover};
    }
    @media (prefers-reduced-motion: reduce) {
      transition: none;
      &::-webkit-scrollbar-thumb {
        transition: none;
      }
    }

    /* host-style isolation —— neutralise outer ul/li/a treatments. */
    ul,
    ol,
    li {
      list-style: none !important;
      margin: 0 !important;
      padding: 0 !important;
    }
    li {
      position: static !important;
    }
    li::before,
    li::after {
      content: none !important;
      display: none !important;
    }
    a {
      background: none !important;
      background-image: none !important;
      padding-bottom: 0 !important;
      text-decoration: none !important;
    }
  `;
  const headingCss = css`
    font-size: 11px;
    font-weight: ${theme.typography.fontWeight.semibold};
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: ${theme.colors.text.muted};
    margin: 0 0 8px;
    padding: 0 8px;
    line-height: 1.4;
  `;
  const itemAnchorCss = (isActive, depth) => {
    const indentStep = Math.max(0, depth - minLevel);
    return css`
      position: relative;
      display: block;
      padding: 5px 10px 5px ${10 + indentStep * 12}px;
      color: ${isActive ? theme.colors.text.primary : theme.colors.text.secondary};
      font-weight: ${isActive ? theme.typography.fontWeight.semibold : theme.typography.fontWeight.regular};
      line-height: 1.45;
      border-radius: ${theme.radius.sm};
      transition:
        color 120ms ease,
        background 120ms ease;
      @media (prefers-reduced-motion: reduce) {
        transition: none;
      }

      /* Active accent bar — sits flush against nav's inline-start border.
         Use logical property so RTL flips with the layout. -17px = 16px nav
         padding + 1px border width. */
      &::before {
        content: '';
        position: absolute;
        inset-inline-start: -17px;
        top: 6px;
        bottom: 6px;
        width: 2px;
        border-radius: 1px;
        background: ${isActive ? theme.colors.primary[500] : "transparent"};
        transition: background 120ms ease;
      }

      &:hover {
        color: ${theme.colors.text.primary};
        background: ${theme.colors.bg.muted};
      }
      &:focus-visible {
        outline: 2px solid ${theme.colors.focus};
        outline-offset: -2px;
      }
    `;
  };
  return /* @__PURE__ */ jsxs("nav", { "aria-label": ariaLabel, className, css: navCss, children: [
    /* @__PURE__ */ jsx("div", { css: headingCss, "aria-hidden": true, children: ariaLabel }),
    /* @__PURE__ */ jsx("ul", { children: items.map((item) => {
      const isActive = item.id === activeId;
      return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
        "a",
        {
          href: `#${item.id}`,
          onClick: (e) => handleClick(e, item.id),
          "aria-current": isActive ? "location" : void 0,
          css: itemAnchorCss(isActive, item.level),
          children: item.text
        }
      ) }, item.id);
    }) })
  ] });
}
MarkdownViewerToc.displayName = "MarkdownViewerToc";
function isExternalHref(href) {
  return /^(https?:|mailto:|tel:|ftp:)/i.test(href);
}
function isAnchorHref(href) {
  return href.startsWith("#");
}
function childrenToText(children) {
  if (children == null || children === false) return "";
  if (typeof children === "string") return children;
  if (typeof children === "number") return String(children);
  if (Array.isArray(children)) return children.map(childrenToText).join("");
  if (typeof children === "object" && "props" in children) {
    const el = children;
    return childrenToText(el.props?.children);
  }
  return "";
}
function extractLanguage(className) {
  if (!className) return void 0;
  const m = /language-([\w+#-]+)/.exec(className);
  return m?.[1];
}
function toCssLength(value) {
  if (value === void 0) return void 0;
  return typeof value === "number" ? `${value}px` : value;
}
var MarkdownViewer = forwardRef(
  function MarkdownViewer2(props, forwardedRef) {
    const {
      source,
      sourceType = "content",
      fetchOptions,
      showToolbar = true,
      toolbar,
      toolbarLabels: toolbarLabelOverrides,
      showToc = false,
      tocPosition = "right",
      tocMaxDepth = 3,
      gfm = true,
      linkTarget = "_blank",
      onLinkClick,
      components: componentOverrides,
      onLoad,
      onError,
      loadingFallback,
      errorFallback,
      maxWidth = "72ch",
      className,
      style,
      id,
      "aria-label": ariaLabel,
      ...rest
    } = props;
    const theme = useTheme();
    const [markdown, setMarkdown] = useState(sourceType === "content" ? source : "");
    const [isLoading, setIsLoading] = useState(sourceType === "url");
    const [error, setError] = useState(null);
    const [refreshNonce, setRefreshNonce] = useState(0);
    const onLoadRef = useRef(onLoad);
    const onErrorRef = useRef(onError);
    useEffect(() => {
      onLoadRef.current = onLoad;
    }, [onLoad]);
    useEffect(() => {
      onErrorRef.current = onError;
    }, [onError]);
    const contentRef = useRef(null);
    const scrollContainerRef = useRef(null);
    useImperativeHandle(forwardedRef, () => scrollContainerRef.current, []);
    useEffect(() => {
      if (sourceType !== "url") {
        setMarkdown(source);
        setIsLoading(false);
        setError(null);
        onLoadRef.current?.(source);
        return;
      }
      const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
      let cancelled = false;
      setIsLoading(true);
      setError(null);
      (async () => {
        try {
          const resp = await fetch(source, { ...fetchOptions, signal: controller?.signal });
          if (!resp.ok) {
            throw new Error(`Failed to fetch markdown (${resp.status} ${resp.statusText})`);
          }
          const text = await resp.text();
          if (cancelled) return;
          setMarkdown(text);
          setIsLoading(false);
          onLoadRef.current?.(text);
        } catch (err) {
          if (cancelled) return;
          if (err instanceof DOMException && err.name === "AbortError") return;
          if (typeof err === "object" && err && "name" in err && err.name === "AbortError") return;
          const e = err instanceof Error ? err : new Error(String(err));
          setError(e);
          setIsLoading(false);
          onErrorRef.current?.(e);
        }
      })();
      return () => {
        cancelled = true;
        controller?.abort();
      };
    }, [source, sourceType, refreshNonce]);
    const handleRefresh = useCallback(() => {
      setRefreshNonce((n) => n + 1);
    }, []);
    const allHeadings = useMemo(() => extractHeadings(markdown, 6), [markdown]);
    const headingIdByLine = useMemo(() => {
      const m = /* @__PURE__ */ new Map();
      for (const h of allHeadings) m.set(h.line, h.id);
      return m;
    }, [allHeadings]);
    const tocItems = useMemo(
      () => showToc ? allHeadings.filter((h) => h.level >= 1 && h.level <= tocMaxDepth) : [],
      [allHeadings, tocMaxDepth, showToc]
    );
    const handleAnchorClick = useCallback(
      (event) => {
        const a = event.currentTarget;
        const href = a.getAttribute("href") ?? "";
        onLinkClick?.(href, event);
        if (event.defaultPrevented) return;
        if (!isAnchorHref(href)) return;
        event.preventDefault();
        const targetId = href.slice(1);
        const target = contentRef.current?.querySelector(`#${CSS.escape(targetId)}`);
        if (!target) return;
        const reduced = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
        target.scrollIntoView({ behavior: reduced ? "auto" : "smooth", block: "start" });
      },
      [onLinkClick]
    );
    const components = useMemo(() => {
      const Heading = (level) => {
        const Tag = `h${level}`;
        const HeadingComp = ({
          children,
          node,
          ...rest2
        }) => {
          const line = node?.position?.start?.line ?? 0;
          const id2 = headingIdByLine.get(line);
          const fallbackId = id2 ?? (baseSlug(childrenToText(children)) || void 0);
          return /* @__PURE__ */ jsx(Tag, { id: id2 ?? fallbackId, ...rest2, children });
        };
        HeadingComp.displayName = `MarkdownHeading${level}`;
        return HeadingComp;
      };
      const Anchor = ({ href, children, ...rest2 }) => {
        const safeHref = href ?? "";
        const external = isExternalHref(safeHref);
        const anchor = isAnchorHref(safeHref);
        const target = anchor ? "_self" : external ? linkTarget : "_self";
        const rel = external && target === "_blank" ? "noreferrer noopener" : void 0;
        return /* @__PURE__ */ jsx(
          "a",
          {
            href: safeHref,
            target: target === "_self" ? void 0 : target,
            rel,
            onClick: handleAnchorClick,
            ...rest2,
            children
          }
        );
      };
      const Pre = ({ children, ...rest2 }) => {
        const only = Array.isArray(children) ? children[0] : children;
        if (only && typeof only === "object" && "props" in only) {
          const codeEl = only;
          const language = extractLanguage(codeEl.props?.className) ?? "text";
          const codeText = childrenToText(codeEl.props?.children).replace(/\n$/, "");
          return /* @__PURE__ */ jsx(
            CodeBlock,
            {
              code: codeText,
              language,
              "data-slot": "markdown-codeblock",
              disableHighlight: language === "text"
            }
          );
        }
        return /* @__PURE__ */ jsx("pre", { ...rest2, children });
      };
      const base = {
        a: Anchor,
        pre: Pre,
        h1: Heading(1),
        h2: Heading(2),
        h3: Heading(3),
        h4: Heading(4),
        h5: Heading(5),
        h6: Heading(6)
      };
      return { ...base, ...componentOverrides ?? {} };
    }, [componentOverrides, linkTarget, handleAnchorClick, headingIdByLine]);
    const labels = useMemo(
      () => ({ ...DEFAULT_TOOLBAR_LABELS, ...toolbarLabelOverrides ?? {} }),
      [toolbarLabelOverrides]
    );
    const typographyCss = useMemo(() => createMarkdownViewerTypography(theme), [theme]);
    const wrapperCss = css`
      display: flex;
      flex-direction: column;
      box-sizing: border-box;
      width: 100%;
      min-width: 0;
      border: 1px solid ${theme.colors.border.subtle};
      border-radius: ${theme.componentRadius.md};
      background: ${theme.colors.bg.surface};
      color: ${theme.colors.text.primary};
      overflow: hidden;
    `;
    const bodyCss = css`
      display: flex;
      flex-direction: ${tocPosition === "left" ? "row-reverse" : "row"};
      min-height: 0;
      flex: 1 1 auto;
    `;
    const isDark = theme.mode === "dark";
    const scrollbarThumbIdle = isDark ? "rgba(255, 255, 255, 0.18)" : "rgba(0, 0, 0, 0.18)";
    const scrollbarThumbHover = isDark ? "rgba(255, 255, 255, 0.32)" : "rgba(0, 0, 0, 0.32)";
    const scrollCss = css`
      flex: 1 1 auto;
      min-width: 0;
      overflow: auto;
      padding: 1.25em 1.5em;

      /* Firefox：细条 + 半透明色，无 hover state，但视觉一致。 */
      scrollbar-width: thin;
      scrollbar-color: transparent transparent;
      transition: scrollbar-color 200ms ease;

      &:hover,
      &:focus-within {
        scrollbar-color: ${scrollbarThumbIdle} transparent;
      }

      /* WebKit：默认完全隐藏轨道；hover 时浮现 thumb，悬停在 thumb 上加深。 */
      &::-webkit-scrollbar {
        width: 8px;
        height: 8px;
      }
      &::-webkit-scrollbar-track {
        background: transparent;
      }
      &::-webkit-scrollbar-thumb {
        background: transparent;
        border-radius: 999px;
        border: 2px solid transparent;
        background-clip: content-box;
        transition: background-color 200ms ease;
      }
      &:hover::-webkit-scrollbar-thumb,
      &:focus-within::-webkit-scrollbar-thumb {
        background-color: ${scrollbarThumbIdle};
      }
      &::-webkit-scrollbar-thumb:hover {
        background-color: ${scrollbarThumbHover};
      }
      &::-webkit-scrollbar-corner {
        background: transparent;
      }

      @media (prefers-reduced-motion: reduce) {
        transition: none;
        &::-webkit-scrollbar-thumb {
          transition: none;
        }
      }
    `;
    const innerMaxWidthCss = css`
      max-width: ${toCssLength(maxWidth) ?? "72ch"};
      margin: 0 auto;
    `;
    const renderBody = () => {
      if (isLoading) {
        if (loadingFallback !== void 0) {
          return /* @__PURE__ */ jsx("div", { "data-slot": "markdown-loading", children: loadingFallback });
        }
        return /* @__PURE__ */ jsxs(
          "div",
          {
            "data-slot": "markdown-loading",
            css: css`
              display: flex;
              align-items: center;
              gap: 8px;
              color: ${theme.colors.text.muted};
              padding: 0.5em 0;
              font-size: ${theme.typography.fontSize.sm};
            `,
            children: [
              /* @__PURE__ */ jsx(
                "span",
                {
                  "aria-hidden": true,
                  css: css`
                width: 14px;
                height: 14px;
                border-radius: 50%;
                border: 2px solid ${theme.colors.border.default};
                border-top-color: ${theme.colors.primary[500]};
                animation: timeui-md-spin 0.7s linear infinite;
                @media (prefers-reduced-motion: reduce) {
                  animation: none;
                }
                @keyframes timeui-md-spin {
                  to {
                    transform: rotate(360deg);
                  }
                }
              `
                }
              ),
              /* @__PURE__ */ jsx("span", { children: "Loading\u2026" })
            ]
          }
        );
      }
      if (error) {
        if (typeof errorFallback === "function") {
          return /* @__PURE__ */ jsx("div", { "data-slot": "markdown-error", children: errorFallback(error) });
        }
        if (errorFallback !== void 0) {
          return /* @__PURE__ */ jsx("div", { "data-slot": "markdown-error", children: errorFallback });
        }
        return /* @__PURE__ */ jsx(
          "div",
          {
            "data-slot": "markdown-error",
            role: "alert",
            css: css`
              padding: 1em;
              border: 1px solid ${theme.colors.danger[500]};
              border-radius: ${theme.radius.md};
              background: ${theme.colors.status.dangerBg};
              color: ${theme.colors.status.danger};
            `,
            children: error.message
          }
        );
      }
      return /* @__PURE__ */ jsx("div", { ref: contentRef, "data-slot": "markdown-content", css: typographyCss, children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: gfm ? [remarkGfm] : [], components, children: markdown }) });
    };
    return /* @__PURE__ */ jsxs(
      "div",
      {
        id,
        role: "article",
        "aria-label": ariaLabel,
        "aria-busy": isLoading || void 0,
        className,
        style,
        css: wrapperCss,
        "data-loading": isLoading || void 0,
        "data-error": error ? "" : void 0,
        "data-toc-position": showToc ? tocPosition : void 0,
        ...rest,
        children: [
          showToolbar && /* @__PURE__ */ jsx(
            MarkdownViewerToolbar,
            {
              getMarkdown: () => markdown,
              config: toolbar ?? {},
              labels,
              canRefresh: sourceType === "url",
              onRefresh: handleRefresh
            }
          ),
          /* @__PURE__ */ jsxs("div", { css: bodyCss, children: [
            /* @__PURE__ */ jsx("div", { ref: scrollContainerRef, css: scrollCss, children: /* @__PURE__ */ jsx("div", { css: innerMaxWidthCss, children: renderBody() }) }),
            showToc && tocItems.length > 0 && !isLoading && !error && /* @__PURE__ */ jsx(
              MarkdownViewerToc,
              {
                items: tocItems,
                scrollContainerRef,
                contentRef
              }
            )
          ] })
        ]
      }
    );
  }
);
MarkdownViewer.displayName = "MarkdownViewer";

export { MarkdownViewer };
//# sourceMappingURL=markdown-viewer.js.map
//# sourceMappingURL=markdown-viewer.js.map