{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "window",
  "title": "Window",
  "description": "The window frame: corner radius, shadow, traffic lights, the inactive state, dragging, resizing, and minimizing into the Dock.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "@cupertinoui/macos-theme"
  ],
  "files": [
    {
      "path": "registry/macos/ui/window.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { MinusIcon, XIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype WindowPosition = { x: number; y: number }\n\ntype WindowSize = { width: number; height: number }\n\ntype WindowInsets = { top?: number; right?: number; bottom?: number; left?: number }\n\ntype ResizeEdge = \"n\" | \"e\" | \"s\" | \"w\" | \"ne\" | \"se\" | \"sw\" | \"nw\"\n\n// Invisible strips along the inside of the frame; the corner squares are\n// clipped to the rounded corners, so they follow the curve.\nconst RESIZE_HANDLES: Record<ResizeEdge, string> = {\n  n: \"inset-x-4 top-0 h-[5px] cursor-ns-resize\",\n  s: \"inset-x-4 bottom-0 h-[5px] cursor-ns-resize\",\n  e: \"inset-y-4 right-0 w-[5px] cursor-ew-resize\",\n  w: \"inset-y-4 left-0 w-[5px] cursor-ew-resize\",\n  nw: \"top-0 left-0 size-4 cursor-nwse-resize\",\n  ne: \"top-0 right-0 size-4 cursor-nesw-resize\",\n  se: \"right-0 bottom-0 size-4 cursor-nwse-resize\",\n  sw: \"bottom-0 left-0 size-4 cursor-nesw-resize\",\n}\n\nconst RESIZE_CURSORS: Record<ResizeEdge, string> = {\n  n: \"ns-resize\",\n  s: \"ns-resize\",\n  e: \"ew-resize\",\n  w: \"ew-resize\",\n  nw: \"nwse-resize\",\n  se: \"nwse-resize\",\n  ne: \"nesw-resize\",\n  sw: \"nesw-resize\",\n}\n\nconst OPPOSITE = { n: \"s\", s: \"n\", e: \"w\", w: \"e\" } as const\n\ntype WindowContextValue = {\n  onClose?: () => void\n  onMinimize?: () => void\n  onZoom?: () => void\n  maximized: boolean\n}\n\n// Lets the traffic lights anywhere inside a window reach its handlers.\nconst WindowContext = React.createContext<WindowContextValue | null>(null)\n\n// Where a draggable window can be grabbed: the title bar, the toolbar, the\n// strip above the sidebar, or anything marked with data-window-drag-region.\nconst DRAG_REGION =\n  '[data-slot=\"window-titlebar\"], [data-slot=\"toolbar\"], [data-slot=\"mac-sidebar-header\"], [data-window-drag-region]'\n\n// Controls inside a drag region keep working instead of moving the window.\nconst NO_DRAG =\n  'button, input, textarea, select, a, [role=\"button\"], [role=\"tab\"], [role=\"switch\"], [role=\"slider\"], [role=\"menuitem\"], [contenteditable=\"true\"], [data-window-no-drag]'\n\nconst reducedMotion = () =>\n  typeof window !== \"undefined\" &&\n  window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n\ntype Point = [x: number, y: number]\n\n// The matrix3d() that maps a width x height box onto the quadrilateral\n// `quad` (top-left, top-right, bottom-right, bottom-left), with a\n// transform-origin of 0 0. This is the square-to-quad projective mapping.\nfunction quadToMatrix(width: number, height: number, quad: [Point, Point, Point, Point]) {\n  const [[x0, y0], [x1, y1], [x2, y2], [x3, y3]] = quad\n  const dx1 = x1 - x2\n  const dx2 = x3 - x2\n  const dx3 = x0 - x1 + x2 - x3\n  const dy1 = y1 - y2\n  const dy2 = y3 - y2\n  const dy3 = y0 - y1 + y2 - y3\n  const det = dx1 * dy2 - dx2 * dy1 || 1e-9\n  const g = (dx3 * dy2 - dx2 * dy3) / det\n  const h = (dx1 * dy3 - dx3 * dy1) / det\n  const a = x1 - x0 + g * x1\n  const b = x3 - x0 + h * x3\n  const d = y1 - y0 + g * y1\n  const e = y3 - y0 + h * y3\n  return `matrix3d(${a / width}, ${d / width}, 0, ${g / width}, ${b / height}, ${e / height}, 0, ${h / height}, 0, 0, 1, 0, ${x0}, ${y0}, 0, 1)`\n}\n\nconst clamp = (value: number) => Math.min(1, Math.max(0, value))\nconst smooth = (t: number) => t * t * (3 - 2 * t)\nconst lerp = (from: number, to: number, t: number) => from + (to - from) * t\n\n// The keyframes that shrink a window into `target` (e.g. its Dock tile).\n// \"genie\" pulls the edge nearest the target into it first, narrowing the\n// window into a funnel, then lets the far edge follow; \"scale\" simply\n// scales it down. Played in reverse to restore.\nfunction minimizeAnimation(\n  element: HTMLElement,\n  target: Element | null | undefined,\n  effect: \"genie\" | \"scale\"\n) {\n  const rect = element.getBoundingClientRect()\n  const width = element.offsetWidth\n  const height = element.offsetHeight\n  // Screen pixels per layout pixel, for windows inside a scaled container.\n  const scale = rect.width / width || 1\n  const goal =\n    target?.getBoundingClientRect() ??\n    new DOMRect(rect.left + rect.width / 2 - 24, window.innerHeight - 56, 48, 48)\n\n  // The target in the window's own, unscaled coordinates, and the window\n  // shrunk to fit inside it.\n  const x = (goal.left + goal.width / 2 - rect.left) / scale\n  const y = (goal.top + goal.height / 2 - rect.top) / scale\n  const fit = Math.max(0.01, Math.min(goal.width / rect.width, goal.height / rect.height))\n  const endWidth = width * fit\n  const endHeight = height * fit\n\n  if (effect === \"scale\") {\n    const origin = `${x}px ${y}px`\n    return {\n      keyframes: [\n        { transformOrigin: origin, transform: \"scale(1)\", opacity: 1 },\n        { transformOrigin: origin, transform: `scale(${fit})`, opacity: 0 },\n      ],\n      options: { duration: 360, easing: \"cubic-bezier(0.45, 0, 0.75, 0.6)\" },\n    }\n  }\n\n  // The edge nearest the target leads; the far edge lags behind it.\n  const below = y > height / 2\n  const nearFrom = below ? height : 0\n  const farFrom = below ? 0 : height\n  const nearTo = y + (below ? endHeight : -endHeight) / 2\n  const farTo = y + (below ? -endHeight : endHeight) / 2\n  const steps = 24\n  const keyframes: Keyframe[] = Array.from({ length: steps + 1 }, (_, step) => {\n    const progress = step / steps\n    const near = smooth(clamp(progress / 0.5))\n    // The far edge narrows and swings toward the target before it travels.\n    const narrow = smooth(clamp((progress - 0.1) / 0.6))\n    const far = smooth(clamp((progress - 0.25) / 0.75))\n    const farHalf = lerp(width / 2, endWidth / 2, narrow)\n    const farCenter = lerp(width / 2, x, narrow)\n    // Keeping the near edge at least 30% as wide as the far edge limits the\n    // perspective, so the content is squeezed rather than tilted away.\n    const nearHalf = Math.max(lerp(width / 2, endWidth / 2, near), farHalf * 0.3)\n    const nearCenter = lerp(width / 2, x, near)\n    const nearY = lerp(nearFrom, nearTo, near)\n    const farY = lerp(farFrom, farTo, far)\n    const top: [Point, Point] = below\n      ? [[farCenter - farHalf, farY], [farCenter + farHalf, farY]]\n      : [[nearCenter - nearHalf, nearY], [nearCenter + nearHalf, nearY]]\n    const bottom: [Point, Point] = below\n      ? [[nearCenter + nearHalf, nearY], [nearCenter - nearHalf, nearY]]\n      : [[farCenter + farHalf, farY], [farCenter - farHalf, farY]]\n    return {\n      offset: progress,\n      transformOrigin: \"0 0\",\n      transform: quadToMatrix(width, height, [...top, ...bottom]),\n      opacity: progress < 0.8 ? 1 : 1 - (progress - 0.8) / 0.2,\n    }\n  })\n\n  return {\n    keyframes,\n    options: { duration: 560, easing: \"cubic-bezier(0.4, 0, 0.9, 0.8)\" },\n  }\n}\n\n// A macOS window frame. Compose it with MacSidebar, WindowMain, Toolbar\n// (or WindowTitlebar) and WindowContent. `inactive` renders the unfocused\n// look: grey traffic lights, dimmed titles and a grey accent color.\n// `draggable` lets people move the window by its title bar or toolbar; the\n// offset is applied with the CSS `translate` property.\n// `onClose`, `onMinimize` and `onZoom` wire up the traffic lights. Setting\n// `minimized` animates the window into `minimizeTo` (e.g. a Dock tile) and\n// back; `maximized` grows it to fill its parent.\n// `resizable` lets people resize it by its edges and corners, between\n// `minSize` and `maxSize`; double-clicking an edge stretches it to the\n// parent's edge (with Option, the opposite edge too).\nfunction Window({\n  className,\n  style,\n  ref,\n  children,\n  inactive = false,\n  draggable = false,\n  bounds,\n  position,\n  defaultPosition,\n  onPositionChange,\n  resizable = false,\n  size,\n  defaultSize,\n  onSizeChange,\n  minSize,\n  maxSize,\n  onClose,\n  onMinimize,\n  onZoom,\n  minimized = false,\n  minimizeTo,\n  minimizeEffect = \"genie\",\n  maximized = false,\n  maximizeInsets,\n  onPointerDown,\n  onPointerMove,\n  onPointerUp,\n  onPointerCancel,\n  onDoubleClick,\n  ...props\n}: Omit<React.ComponentProps<\"div\">, \"draggable\"> & {\n  inactive?: boolean\n  draggable?: boolean\n  bounds?: \"parent\"\n  position?: WindowPosition\n  defaultPosition?: WindowPosition\n  onPositionChange?: (position: WindowPosition) => void\n  resizable?: boolean\n  size?: WindowSize\n  defaultSize?: WindowSize\n  onSizeChange?: (size: WindowSize) => void\n  minSize?: Partial<WindowSize>\n  maxSize?: Partial<WindowSize>\n  onClose?: () => void\n  onMinimize?: () => void\n  onZoom?: () => void\n  minimized?: boolean\n  minimizeTo?: React.RefObject<Element | null>\n  minimizeEffect?: \"genie\" | \"scale\"\n  maximized?: boolean\n  maximizeInsets?: WindowInsets\n}) {\n  const [uncontrolledPosition, setUncontrolledPosition] =\n    React.useState<WindowPosition>(defaultPosition ?? { x: 0, y: 0 })\n  const current = position ?? uncontrolledPosition\n  const [dragging, setDragging] = React.useState(false)\n  const element = React.useRef<HTMLDivElement | null>(null)\n\n  // Until it is resized, the window keeps the size its classes give it.\n  const [uncontrolledSize, setUncontrolledSize] = React.useState(defaultSize)\n  const currentSize = size ?? uncontrolledSize\n  const [resizing, setResizing] = React.useState<ResizeEdge | null>(null)\n\n  function move(next: WindowPosition) {\n    if (position === undefined) setUncontrolledPosition(next)\n    onPositionChange?.(next)\n  }\n\n  // Where the top-left corner should land once the new size is laid out.\n  // A window centered by its classes moves as it grows, so the offset that\n  // keeps the opposite edges in place is only known after layout.\n  const anchor = React.useRef<WindowPosition | null>(null)\n  function setFrame(next: WindowSize, corner: WindowPosition) {\n    anchor.current = corner\n    if (size === undefined) setUncontrolledSize(next)\n    onSizeChange?.(next)\n  }\n  React.useLayoutEffect(() => {\n    const node = element.current\n    const corner = anchor.current\n    if (!node || !corner) return\n    anchor.current = null\n    const next = { x: corner.x - node.offsetLeft, y: corner.y - node.offsetTop }\n    if (next.x !== current.x || next.y !== current.y) move(next)\n  })\n\n  // `hidden` lags behind `minimized` so the window stays visible while it\n  // animates into the Dock.\n  const [hidden, setHidden] = React.useState(minimized)\n  const previousMinimized = React.useRef(minimized)\n  React.useLayoutEffect(() => {\n    const node = element.current\n    if (!node || previousMinimized.current === minimized) return\n    previousMinimized.current = minimized\n    if (reducedMotion()) {\n      setHidden(minimized)\n      return\n    }\n    const { keyframes, options } = minimizeAnimation(node, minimizeTo?.current, minimizeEffect)\n    if (minimized) {\n      const animation = node.animate(keyframes, { ...options, fill: \"forwards\" })\n      animation.finished\n        .then(() => {\n          setHidden(true)\n          animation.cancel()\n        })\n        .catch(() => {})\n    } else {\n      setHidden(false)\n      // Reversed, the ease-in of minimizing becomes an ease-out.\n      node.animate(keyframes, {\n        ...options,\n        direction: \"reverse\",\n        fill: \"backwards\",\n      })\n    }\n  }, [minimized, minimizeTo, minimizeEffect])\n\n  // Zooming in and out morphs the window from its old frame to the new one.\n  const lastRect = React.useRef<DOMRect | null>(null)\n  const previousMaximized = React.useRef(maximized)\n  React.useLayoutEffect(() => {\n    const node = element.current\n    const before = lastRect.current\n    if (!node || previousMaximized.current === maximized) return\n    previousMaximized.current = maximized\n    if (!before || reducedMotion()) return\n    const after = node.getBoundingClientRect()\n    const scale = after.width / node.offsetWidth || 1\n    node.animate(\n      [\n        {\n          transformOrigin: \"0 0\",\n          transform: `translate(${(before.left - after.left) / scale}px, ${(before.top - after.top) / scale}px) scale(${before.width / after.width}, ${before.height / after.height})`,\n        },\n        { transformOrigin: \"0 0\", transform: \"none\" },\n      ],\n      { duration: 380, easing: \"cubic-bezier(0.25, 0.8, 0.3, 1)\" }\n    )\n  }, [maximized])\n  React.useLayoutEffect(() => {\n    if (element.current) lastRect.current = element.current.getBoundingClientRect()\n  })\n\n  const context = React.useMemo(\n    () => ({ onClose, onMinimize, onZoom, maximized }),\n    [onClose, onMinimize, onZoom, maximized]\n  )\n  const drag = React.useRef<{\n    pointer: WindowPosition\n    start: WindowPosition\n    scale: number\n    min: WindowPosition\n    max: WindowPosition\n  } | null>(null)\n\n  const resize = React.useRef<{\n    edge: ResizeEdge\n    pointer: WindowPosition\n    start: WindowSize\n    corner: WindowPosition\n    scale: number\n    min: WindowSize\n    max: WindowSize\n  } | null>(null)\n\n  // The window's top-left corner in its parent's layout, including the\n  // drag offset, and the screen-to-layout scale.\n  function measure(node: HTMLElement) {\n    const rect = node.getBoundingClientRect()\n    return {\n      rect,\n      scale: rect.width / node.offsetWidth || 1,\n      start: { width: node.offsetWidth, height: node.offsetHeight },\n      corner: { x: node.offsetLeft + current.x, y: node.offsetTop + current.y },\n    }\n  }\n\n  function startResize(event: React.PointerEvent<HTMLDivElement>, edge: ResizeEdge) {\n    const node = event.currentTarget\n    const { rect, scale, start, corner } = measure(node)\n    // A window that starts outside its limits doesn't jump to them.\n    const min = {\n      width: Math.min(minSize?.width ?? 240, start.width),\n      height: Math.min(minSize?.height ?? 140, start.height),\n    }\n    const max = {\n      width: Math.max(maxSize?.width ?? Number.POSITIVE_INFINITY, start.width),\n      height: Math.max(maxSize?.height ?? Number.POSITIVE_INFINITY, start.height),\n    }\n    const parent = bounds === \"parent\" ? node.parentElement : null\n    if (parent) {\n      const area = parent.getBoundingClientRect()\n      const roomX = edge.includes(\"e\") ? area.right - rect.right : edge.includes(\"w\") ? rect.left - area.left : 0\n      const roomY = edge.includes(\"s\") ? area.bottom - rect.bottom : edge.includes(\"n\") ? rect.top - area.top : 0\n      max.width = Math.min(max.width, start.width + Math.max(0, roomX / scale))\n      max.height = Math.min(max.height, start.height + Math.max(0, roomY / scale))\n    }\n\n    resize.current = { edge, pointer: { x: event.clientX, y: event.clientY }, start, corner, scale, min, max }\n    node.setPointerCapture(event.pointerId)\n    setResizing(edge)\n    event.preventDefault()\n  }\n\n  function handleResize(event: React.PointerEvent<HTMLDivElement>) {\n    const { edge, pointer, start, corner, scale, min, max } = resize.current!\n    const dx = (event.clientX - pointer.x) / scale\n    const dy = (event.clientY - pointer.y) / scale\n    const fit = (value: number, axis: keyof WindowSize) =>\n      Math.round(Math.min(max[axis], Math.max(min[axis], value)))\n    const width = fit(edge.includes(\"e\") ? start.width + dx : edge.includes(\"w\") ? start.width - dx : start.width, \"width\")\n    const height = fit(edge.includes(\"s\") ? start.height + dy : edge.includes(\"n\") ? start.height - dy : start.height, \"height\")\n    // The edges opposite the one being dragged stay put.\n    setFrame(\n      { width, height },\n      {\n        x: edge.includes(\"w\") ? corner.x + start.width - width : corner.x,\n        y: edge.includes(\"n\") ? corner.y + start.height - height : corner.y,\n      }\n    )\n  }\n\n  // Double-clicking an edge stretches it to the parent's edge, inside the\n  // maximize insets; with Option the opposite edge follows.\n  function fillToEdge(node: HTMLElement, edge: ResizeEdge, both: boolean) {\n    const parent = node.parentElement\n    if (!parent) return\n    const { rect, scale, start, corner } = measure(node)\n    const area = parent.getBoundingClientRect()\n    const room = {\n      n: (rect.top - area.top) / scale - insets.top,\n      s: (area.bottom - rect.bottom) / scale - insets.bottom,\n      w: (rect.left - area.left) / scale - insets.left,\n      e: (area.right - rect.right) / scale - insets.right,\n    }\n    const grows = (side: keyof typeof OPPOSITE) =>\n      edge.includes(side) || (both && edge.includes(OPPOSITE[side]))\n    const reach = (side: keyof typeof OPPOSITE) => (grows(side) ? Math.max(0, room[side]) : 0)\n    const width = Math.min(maxSize?.width ?? Number.POSITIVE_INFINITY, start.width + reach(\"w\") + reach(\"e\"))\n    const height = Math.min(maxSize?.height ?? Number.POSITIVE_INFINITY, start.height + reach(\"n\") + reach(\"s\"))\n    setFrame(\n      { width: Math.max(width, start.width), height: Math.max(height, start.height) },\n      {\n        x: grows(\"w\") && !grows(\"e\") ? corner.x + start.width - Math.max(width, start.width) : corner.x - reach(\"w\"),\n        y: grows(\"n\") && !grows(\"s\") ? corner.y + start.height - Math.max(height, start.height) : corner.y - reach(\"n\"),\n      }\n    )\n  }\n\n  // The handle a pointer event targets, if it belongs to this window.\n  function resizeEdge(event: React.SyntheticEvent<HTMLDivElement>) {\n    const target = event.target as HTMLElement\n    return target.parentElement === event.currentTarget\n      ? (target.dataset.resizeEdge as ResizeEdge | undefined)\n      : undefined\n  }\n\n  // Pointer capture retargets the double-click to the window itself, so the\n  // edge it started on is remembered.\n  const pressedEdge = React.useRef<ResizeEdge | undefined>(undefined)\n\n  function handlePointerDown(event: React.PointerEvent<HTMLDivElement>) {\n    onPointerDown?.(event)\n    if (maximized || event.defaultPrevented || event.button !== 0) return\n\n    const edge = resizable ? resizeEdge(event) : undefined\n    pressedEdge.current = edge\n    if (edge) return startResize(event, edge)\n    if (!draggable) return\n\n    const element = event.currentTarget\n    const target = event.target as HTMLElement\n    const region = target.closest(DRAG_REGION)\n    if (\n      !region ||\n      region.closest('[data-slot=\"window\"]') !== element ||\n      target.closest(NO_DRAG)\n    ) {\n      return\n    }\n\n    // Pointer movement is in screen pixels; divide by any CSS scale applied\n    // to the window (e.g. a scaled-down preview) to get layout pixels.\n    const rect = element.getBoundingClientRect()\n    const scale = rect.width / element.offsetWidth || 1\n    const limit = Number.POSITIVE_INFINITY\n    let min = { x: -limit, y: -limit }\n    let max = { x: limit, y: limit }\n    const parent = bounds === \"parent\" ? element.parentElement : null\n    if (parent) {\n      const area = parent.getBoundingClientRect()\n      min = {\n        x: current.x + (area.left - rect.left) / scale,\n        y: current.y + (area.top - rect.top) / scale,\n      }\n      max = {\n        x: current.x + (area.right - rect.right) / scale,\n        y: current.y + (area.bottom - rect.bottom) / scale,\n      }\n    }\n\n    drag.current = {\n      pointer: { x: event.clientX, y: event.clientY },\n      start: current,\n      scale,\n      min,\n      max,\n    }\n    element.setPointerCapture(event.pointerId)\n    setDragging(true)\n    // Keeps the drag from selecting text.\n    event.preventDefault()\n  }\n\n  function handlePointerMove(event: React.PointerEvent<HTMLDivElement>) {\n    onPointerMove?.(event)\n    if (resize.current) return handleResize(event)\n    const state = drag.current\n    if (!state) return\n    // A window larger than its bounds slides between its two edges.\n    const within = (value: number, a: number, b: number) =>\n      Math.min(Math.max(a, b), Math.max(Math.min(a, b), value))\n    const next = {\n      x: within(state.start.x + (event.clientX - state.pointer.x) / state.scale, state.min.x, state.max.x),\n      y: within(state.start.y + (event.clientY - state.pointer.y) / state.scale, state.min.y, state.max.y),\n    }\n    move(next)\n  }\n\n  function endDrag(event: React.PointerEvent<HTMLDivElement>) {\n    if (!drag.current && !resize.current) return\n    drag.current = null\n    resize.current = null\n    anchor.current = null\n    setDragging(false)\n    setResizing(null)\n    if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n      event.currentTarget.releasePointerCapture(event.pointerId)\n    }\n  }\n\n  const insets = { top: 0, right: 0, bottom: 0, left: 0, ...maximizeInsets }\n\n  // With a fixed width (or height) only the other two edges resize, along\n  // their full length.\n  const fixedWidth = minSize?.width !== undefined && minSize.width === maxSize?.width\n  const fixedHeight = minSize?.height !== undefined && minSize.height === maxSize?.height\n  const handles = (Object.keys(RESIZE_HANDLES) as ResizeEdge[]).filter(\n    (edge) => !(fixedWidth && /[ew]/.test(edge)) && !(fixedHeight && /[ns]/.test(edge))\n  )\n\n  return (\n    <WindowContext.Provider value={context}>\n      <div\n        ref={(node) => {\n          element.current = node\n          if (typeof ref === \"function\") return ref(node)\n          if (ref) ref.current = node\n        }}\n        data-slot=\"window\"\n        data-inactive={inactive || undefined}\n        data-draggable={draggable || undefined}\n        data-dragging={dragging || undefined}\n        data-resizable={resizable || undefined}\n        data-resizing={resizing ?? undefined}\n        data-maximized={maximized || undefined}\n        data-minimized={hidden || undefined}\n        aria-hidden={hidden || undefined}\n        inert={hidden || undefined}\n        className={cn(\n          \"group/window relative isolate flex overflow-hidden rounded-mac-window bg-mac-window text-mac-body text-mac-label shadow-mac-window data-[inactive]:shadow-mac-window-inactive has-[>[data-slot=mac-sidebar]]:bg-transparent\",\n          // The thin light rim drawn on top of everything inside the frame.\n          \"after:pointer-events-none after:absolute after:inset-0 after:z-50 after:rounded-[inherit] after:shadow-[inset_0_0_0_1px_var(--mac-window-rim)]\",\n          // Touch drags on the drag regions move the window instead of scrolling.\n          \"data-[draggable]:[&_:is([data-slot=window-titlebar],[data-slot=toolbar],[data-slot=mac-sidebar-header],[data-window-drag-region])]:touch-none data-[dragging]:select-none\",\n          // While resizing, the content can't take the pointer or change the\n          // cursor, and an iframe can't swallow the moves of a drag.\n          \"data-[resizing]:select-none data-[resizing]:*:pointer-events-none data-[dragging]:[&_iframe]:pointer-events-none\",\n          \"data-[minimized]:invisible\",\n          className\n        )}\n        style={\n          maximized\n            ? {\n                ...style,\n                // Override any positioning from classes, e.g. centering.\n                position: \"absolute\",\n                top: insets.top,\n                left: insets.left,\n                right: \"auto\",\n                bottom: \"auto\",\n                margin: 0,\n                translate: \"none\",\n                width: `calc(100% - ${insets.left + insets.right}px)`,\n                height: `calc(100% - ${insets.top + insets.bottom}px)`,\n              }\n            : {\n                ...style,\n                ...currentSize,\n                translate:\n                  current.x || current.y\n                    ? `${current.x}px ${current.y}px`\n                    : undefined,\n                cursor: resizing ? RESIZE_CURSORS[resizing] : style?.cursor,\n              }\n        }\n        onPointerDown={handlePointerDown}\n        onPointerMove={handlePointerMove}\n        onPointerUp={(event) => {\n          onPointerUp?.(event)\n          endDrag(event)\n        }}\n        onPointerCancel={(event) => {\n          onPointerCancel?.(event)\n          endDrag(event)\n        }}\n        onDoubleClick={(event) => {\n          onDoubleClick?.(event)\n          const edge =\n            resizeEdge(event) ??\n            (event.target === event.currentTarget ? pressedEdge.current : undefined)\n          if (resizable && edge && !event.defaultPrevented) {\n            return fillToEdge(event.currentTarget, edge, event.altKey)\n          }\n          // Double-clicking the title bar zooms the window, as on macOS.\n          const target = event.target as HTMLElement\n          if (\n            onZoom &&\n            !event.defaultPrevented &&\n            target.closest(DRAG_REGION)?.closest('[data-slot=\"window\"]') === event.currentTarget &&\n            !target.closest(NO_DRAG)\n          ) {\n            onZoom()\n          }\n        }}\n        {...props}\n      >\n        {children}\n        {resizable && !maximized && !hidden\n          ? handles.map((edge) => (\n              <div\n                key={edge}\n                aria-hidden=\"true\"\n                data-slot=\"window-resize-handle\"\n                data-resize-edge={edge}\n                className={cn(\n                  \"absolute z-50 touch-none\",\n                  RESIZE_HANDLES[edge],\n                  fixedWidth && \"inset-x-0\",\n                  fixedHeight && \"inset-y-0\"\n                )}\n              />\n            ))\n          : null}\n      </div>\n    </WindowContext.Provider>\n  )\n}\n\n// A plain title bar with the window controls and a centered title,\n// for windows without a toolbar.\nfunction WindowTitlebar({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"window-titlebar\"\n      className={cn(\n        \"relative flex h-8 shrink-0 items-center rounded-t-[inherit] border-b border-mac-separator px-[11px] select-none mac-material-titlebar\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  )\n}\n\nfunction WindowTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"window-title\"\n      className={cn(\n        \"pointer-events-none absolute inset-x-24 truncate text-center text-mac-body font-semibold text-mac-label group-data-[inactive]/window:text-mac-label-tertiary\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction WindowContent({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"window-content\"\n      className={cn(\"min-h-0 min-w-0 flex-1 overflow-auto\", className)}\n      {...props}\n    />\n  )\n}\n\n// Stacks a toolbar or title bar above the content, to the right of a sidebar.\n// It takes on the window's corners at the window's edges, so a glass title\n// bar inside can round its own corners: Chrome doesn't always clip a\n// backdrop filter to an ancestor's rounded corners.\nfunction WindowMain({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"window-main\"\n      className={cn(\n        \"flex min-w-0 flex-1 flex-col rounded-r-[inherit] bg-mac-window first:rounded-l-[inherit]\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction WindowControlButton({\n  className,\n  ...props\n}: React.ComponentProps<\"button\">) {\n  return (\n    <button\n      type=\"button\"\n      className={cn(\n        \"flex size-3.5 items-center justify-center rounded-full shadow-(--mac-traffic-edge) outline-none focus-visible:outline-3 focus-visible:outline-solid focus-visible:outline-mac-accent/50 disabled:[background:var(--mac-traffic-inactive)] group-data-[inactive]/window:[background:var(--mac-traffic-inactive)] group-data-[inactive]/window:shadow-none [&_svg]:size-2.5 [&_svg]:text-black/55 [&_svg]:opacity-0 group-hover/controls:[&_svg]:opacity-100\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\n// The red, yellow and green \"traffic light\" buttons. Without handlers of\n// their own they call the onClose, onMinimize and onZoom of their Window.\nfunction WindowControls({\n  className,\n  onClose,\n  onMinimize,\n  onZoom,\n  ...props\n}: Omit<React.ComponentProps<\"div\">, \"children\"> & {\n  onClose?: () => void\n  onMinimize?: () => void\n  onZoom?: () => void\n}) {\n  const context = React.useContext(WindowContext)\n  onClose ??= context?.onClose\n  onMinimize ??= context?.onMinimize\n  onZoom ??= context?.onZoom\n\n  return (\n    <div\n      data-slot=\"window-controls\"\n      className={cn(\"group/controls flex items-center gap-[9px]\", className)}\n      {...props}\n    >\n      <WindowControlButton\n        aria-label=\"Close\"\n        onClick={onClose}\n        className=\"[background:var(--mac-traffic-close)]\"\n      >\n        <XIcon strokeWidth={3} />\n      </WindowControlButton>\n      <WindowControlButton\n        aria-label=\"Minimize\"\n        onClick={onMinimize}\n        className=\"[background:var(--mac-traffic-minimize)]\"\n      >\n        <MinusIcon strokeWidth={3} />\n      </WindowControlButton>\n      <WindowControlButton\n        aria-label=\"Zoom\"\n        onClick={onZoom}\n        className=\"[background:var(--mac-traffic-zoom)]\"\n      >\n        <svg viewBox=\"0 0 8 8\" fill=\"currentColor\" aria-hidden=\"true\">\n          <path d=\"M1.5 6.5V3.2L4.8 6.5H1.5ZM6.5 1.5V4.8L3.2 1.5H6.5Z\" />\n        </svg>\n      </WindowControlButton>\n    </div>\n  )\n}\n\nexport type { WindowInsets, WindowPosition, WindowSize }\nexport {\n  Window,\n  WindowContent,\n  WindowControls,\n  WindowMain,\n  WindowTitle,\n  WindowTitlebar,\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}