import { jsx, jsxs, Fragment } from "react/jsx-runtime";
import * as React from "react";
import { X } from "lucide-react";
import { Sheet, SheetContent, SheetTitle } from "../Sheet/sheet.js";
import { Button } from "../Button/button.js";
import { ScrollArea } from "../ScrollArea/scroll-area.js";
import { ChromeHeader } from "../../patterns/header-canonical/chrome-header.js";
import { useIsNarrowViewport } from "../../hooks/use-is-narrow-viewport.js";
import { cn } from "../../lib/utils.js";
const AppShellContext = React.createContext(null);
function useAppShell() {
  const ctx = React.useContext(AppShellContext);
  if (!ctx) throw new Error("AppShellAside must be used within <AppShell>");
  return ctx;
}
const XL_BREAKPOINT_PX = 1280;
function useIsXl() {
  const [isXl, setIsXl] = React.useState(() => {
    if (typeof window === "undefined") return false;
    return window.matchMedia(`(min-width: ${XL_BREAKPOINT_PX}px)`).matches;
  });
  React.useEffect(() => {
    const mq = window.matchMedia(`(min-width: ${XL_BREAKPOINT_PX}px)`);
    const handler = (e) => setIsXl(e.matches);
    mq.addEventListener("change", handler);
    return () => mq.removeEventListener("change", handler);
  }, []);
  return isXl;
}
const ASIDE_WIDTH_MIN = 240;
const ASIDE_WIDTH_MAX = 640;
const ASIDE_WIDTH_DEFAULT = 320;
function resolveAsideWidth(width, isXl) {
  if (typeof width === "number") {
    return Math.max(ASIDE_WIDTH_MIN, Math.min(ASIDE_WIDTH_MAX, width));
  }
  if (width && typeof width === "object") {
    const v = (isXl ? width.xl ?? width.md : width.md) ?? ASIDE_WIDTH_DEFAULT;
    return Math.max(ASIDE_WIDTH_MIN, Math.min(ASIDE_WIDTH_MAX, v));
  }
  return ASIDE_WIDTH_DEFAULT;
}
function SkipToMain() {
  return /* @__PURE__ */ jsx(
    "a",
    {
      href: "#app-shell-main",
      className: cn(
        "sr-only focus:not-sr-only",
        "focus:fixed focus:top-2 focus:left-2 focus:z-50",
        "focus:px-3 focus:py-2 focus:rounded-md",
        "focus:bg-surface focus:text-foreground focus:shadow-[var(--elevation-200)]",
        "focus:outline-none focus:ring-2 focus:ring-primary"
      ),
      children: "Skip to main content"
    }
  );
}
const AppShell = React.forwardRef(
  ({
    layout = "primary-sidebar",
    sidebar,
    header,
    globalHeader,
    aside,
    asideOpen: asideOpenProp,
    onAsideOpenChange,
    children,
    className,
    ...props
  }, ref) => {
    const [asideOpenInternal, setAsideOpenInternal] = React.useState(false);
    const isControlled = asideOpenProp !== void 0;
    const asideOpen = isControlled ? asideOpenProp : asideOpenInternal;
    const setAsideOpen = React.useCallback(
      (open) => {
        if (!isControlled) setAsideOpenInternal(open);
        onAsideOpenChange == null ? void 0 : onAsideOpenChange(open);
      },
      [isControlled, onAsideOpenChange]
    );
    const isMobile = useIsNarrowViewport();
    React.useEffect(() => {
      const onKey = (e) => {
        if (e.key === "." && (e.metaKey || e.ctrlKey)) {
          e.preventDefault();
          setAsideOpen(!asideOpen);
        }
      };
      window.addEventListener("keydown", onKey);
      return () => window.removeEventListener("keydown", onKey);
    }, [asideOpen, setAsideOpen]);
    const ctxValue = React.useMemo(
      () => ({ layout, asideOpen, setAsideOpen, isMobile }),
      [layout, asideOpen, setAsideOpen, isMobile]
    );
    if (layout === "primary-header") {
      return /* @__PURE__ */ jsx(AppShellContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxs(
        "div",
        {
          ref,
          className: cn("flex h-svh w-full flex-col overflow-hidden bg-canvas", className),
          ...props,
          children: [
            /* @__PURE__ */ jsx(SkipToMain, {}),
            globalHeader && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: globalHeader }),
            /* @__PURE__ */ jsxs("div", { className: "flex flex-1 min-h-0 w-full", children: [
              sidebar,
              /* @__PURE__ */ jsxs("div", { className: "flex flex-col flex-1 min-w-0 min-h-0 overflow-hidden", children: [
                header && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: header }),
                /* @__PURE__ */ jsx(
                  "main",
                  {
                    id: "app-shell-main",
                    tabIndex: -1,
                    className: "flex-1 min-w-0 min-h-0 overflow-y-auto focus:outline-none",
                    children
                  }
                )
              ] }),
              aside
            ] })
          ]
        }
      ) });
    }
    return /* @__PURE__ */ jsx(AppShellContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxs(
      "div",
      {
        ref,
        className: cn("flex h-svh w-full overflow-hidden bg-canvas", className),
        ...props,
        children: [
          /* @__PURE__ */ jsx(SkipToMain, {}),
          sidebar,
          /* @__PURE__ */ jsxs("div", { className: "flex flex-col flex-1 min-w-0 min-h-0 overflow-hidden", children: [
            header && // Header 在 main column 內(main col sibling,非 main descendant)。ChromeHeader 自
            // 2026-05-20 起 render `<header>`(chrome-header.tsx);依 W3C HTML-AAM,`<div>` wrapper
            // 不 scope out banner(只有 main/article/aside/nav/section 能)→ 仍得 implicit banner ✓
            // (對齊 app-shell.spec.md「W3C ARIA in HTML banner rule」段)。
            /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: header }),
            /* @__PURE__ */ jsx(
              "main",
              {
                id: "app-shell-main",
                tabIndex: -1,
                className: "flex-1 min-h-0 overflow-y-auto focus:outline-none",
                children
              }
            )
          ] }),
          aside
        ]
      }
    ) });
  }
);
AppShell.displayName = "AppShell";
const AppShellAside = React.forwardRef(
  ({ title, width, children, className }, ref) => {
    const { asideOpen, setAsideOpen, isMobile } = useAppShell();
    const isXl = useIsXl();
    const resolvedWidth = resolveAsideWidth(width, isXl);
    const renderFrame = (titleNode) => /* @__PURE__ */ jsxs(Fragment, { children: [
      /* @__PURE__ */ jsxs(ChromeHeader, { children: [
        titleNode,
        /* @__PURE__ */ jsx(
          Button,
          {
            iconOnly: true,
            dismiss: true,
            size: "sm",
            startIcon: X,
            "aria-label": "關閉",
            onClick: () => setAsideOpen(false)
          }
        )
      ] }),
      /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1 min-h-0", children })
    ] });
    if (isMobile) {
      return /* @__PURE__ */ jsx(Sheet, { open: asideOpen, onOpenChange: setAsideOpen, children: /* @__PURE__ */ jsx(
        SheetContent,
        {
          side: "right",
          className: "w-[min(90vw,var(--app-shell-aside-modal-width))] flex flex-col p-0 [&>button]:hidden",
          style: { ["--app-shell-aside-modal-width"]: `${resolvedWidth}px` },
          children: renderFrame(/* @__PURE__ */ jsx(SheetTitle, { className: "flex-1", children: title }))
        }
      ) });
    }
    if (!asideOpen) return null;
    return /* @__PURE__ */ jsx(
      "aside",
      {
        ref,
        "aria-label": title,
        className: cn(
          "flex flex-col h-full min-h-0 overflow-hidden",
          "bg-surface border-l border-divider",
          className
        ),
        style: { width: resolvedWidth },
        children: renderFrame(/* @__PURE__ */ jsx("h2", { className: "text-body-lg font-medium flex-1 truncate", children: title }))
      }
    );
  }
);
AppShellAside.displayName = "AppShellAside";
export {
  AppShell,
  AppShellAside,
  useAppShell
};
//# sourceMappingURL=app-shell.js.map
