{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "window-manager",
  "title": "Window Manager",
  "description": "A desktop area with draggable, resizable windows that raise on focus, zoom on double-click and minimize into a tray.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "@tealmac/mac-window"
  ],
  "files": [
    {
      "path": "registry/tealmac/window-manager.tsx",
      "content": "// Adapted from Ballmac UI (https://github.com/vamsiy78/ballmac-ui), MIT License, Copyright (c) 2026 Ballmac.\n\"use client\"\n\nimport * as React from \"react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\nimport {\n  MacWindow,\n  MacWindowContent,\n  MacWindowTitleBar,\n} from \"@/registry/tealmac/mac-window\"\n\ntype ManagedWindow = {\n  /** Unique id. */\n  id: string\n  /** Title shown in the title bar and the tray. */\n  title: string\n  /** What the window shows. */\n  content: React.ReactNode\n  /** Left edge in pixels. Windows without a position cascade. */\n  x?: number\n  /** Top edge in pixels. */\n  y?: number\n  /** Width in pixels. */\n  width?: number\n  /** Height in pixels. */\n  height?: number\n  /** Smallest width it can be resized to. */\n  minWidth?: number\n  /** Smallest height it can be resized to. */\n  minHeight?: number\n}\n\ntype Rect = { x: number; y: number; w: number; h: number }\ntype WinState = Rect & {\n  id: string\n  z: number\n  minimized: boolean\n  maximized: boolean\n  restore?: Rect\n}\n\ntype WindowManagerProps = Omit<React.ComponentProps<\"div\">, \"children\"> & {\n  /** The windows. Add an entry to open one; remove it to close it. */\n  windows: ManagedWindow[]\n  /** Called when a window's close button is pressed. Remove the window from `windows` to actually close it. */\n  onClose?: (id: string) => void\n  /** Content behind the windows, such as desktop icons or a wallpaper. */\n  children?: React.ReactNode\n  /** Accessible name of the desktop. */\n  label?: string\n  /** Accessible name of the strip that holds minimized windows. */\n  trayLabel?: string\n}\n\nconst EDGES = [\"n\", \"s\", \"e\", \"w\", \"ne\", \"nw\", \"se\", \"sw\"] as const\nconst EDGE_STYLE: Record<(typeof EDGES)[number], string> = {\n  n: \"top-[-3px] start-3 end-3 h-1.5 cursor-ns-resize\",\n  s: \"bottom-[-3px] start-3 end-3 h-1.5 cursor-ns-resize\",\n  e: \"end-[-3px] top-3 bottom-3 w-1.5 cursor-ew-resize\",\n  w: \"start-[-3px] top-3 bottom-3 w-1.5 cursor-ew-resize\",\n  ne: \"top-[-4px] end-[-4px] size-3.5 cursor-nesw-resize\",\n  nw: \"top-[-4px] start-[-4px] size-3.5 cursor-nwse-resize\",\n  se: \"bottom-[-4px] end-[-4px] size-3.5 cursor-nwse-resize\",\n  sw: \"bottom-[-4px] start-[-4px] size-3.5 cursor-nesw-resize\",\n}\n\nfunction initial(w: ManagedWindow, index: number, z: number): WinState {\n  return {\n    id: w.id,\n    x: w.x ?? 28 + index * 36,\n    y: w.y ?? 24 + index * 30,\n    w: w.width ?? 380,\n    h: w.height ?? 250,\n    z,\n    minimized: false,\n    maximized: false,\n  }\n}\n\n/**\n * A desktop of real, draggable windows: focus raises a window, the title bar drags, edges and corners resize,\n * double-clicking the title bar zooms, the yellow light tucks a window into the tray.\n * With a window focused, Alt plus an arrow key moves it (Shift for bigger steps), Alt+Shift+arrows resize it.\n */\nfunction WindowManager({\n  windows,\n  onClose,\n  children,\n  label,\n  trayLabel,\n  className,\n  ...props\n}: WindowManagerProps) {\n  label ??= \"Desktop\"\n  trayLabel ??= \"Minimized windows\"\n  const reduce = useReducedMotion()\n  const deskRef = React.useRef<HTMLDivElement>(null)\n  const [states, setStates] = React.useState<WinState[]>(() =>\n    windows.map((w, i) => initial(w, i, i + 1))\n  )\n  const [dragging, setDragging] = React.useState<string | null>(null)\n  const top = React.useRef(windows.length)\n  const gesture = React.useRef<{\n    id: string\n    mode: \"move\" | \"resize\"\n    edge?: string\n    px: number\n    py: number\n    start: Rect\n  } | null>(null)\n\n  // Open windows that were added, and drop the ones that were removed.\n  React.useEffect(() => {\n    setStates((current) => {\n      const known = new Set(current.map((s) => s.id))\n      const added = windows\n        .filter((w) => !known.has(w.id))\n        .map((w, i) => initial(w, current.length + i, ++top.current))\n      const kept = current.filter((s) => windows.some((w) => w.id === s.id))\n      return added.length || kept.length !== current.length\n        ? [...kept, ...added]\n        : current\n    })\n  }, [windows])\n\n  const count = states.length\n  // Keep every window inside the desktop when it opens or when the desktop shrinks.\n  React.useEffect(() => {\n    const el = deskRef.current\n    if (!el) return\n    const fit = () => {\n      const dw = el.clientWidth\n      const dh = el.clientHeight\n      if (!dw || !dh) return\n      setStates((all) => {\n        let changed = false\n        const next = all.map((s) => {\n          if (s.maximized) return s\n          const w = Math.min(s.w, Math.max(160, dw - 16))\n          const h = Math.min(s.h, Math.max(110, dh - 16))\n          const x = Math.max(8, Math.min(s.x, dw - w - 8))\n          const y = Math.max(0, Math.min(s.y, dh - h - 8))\n          if (w === s.w && h === s.h && x === s.x && y === s.y) return s\n          changed = true\n          return { ...s, w, h, x, y }\n        })\n        return changed ? next : all\n      })\n    }\n    fit()\n    const ro = new ResizeObserver(fit)\n    ro.observe(el)\n    return () => ro.disconnect()\n  }, [count])\n\n  const patch = React.useCallback(\n    (\n      id: string,\n      change: Partial<WinState> | ((s: WinState) => Partial<WinState>)\n    ) => {\n      setStates((all) =>\n        all.map((s) =>\n          s.id === id\n            ? { ...s, ...(typeof change === \"function\" ? change(s) : change) }\n            : s\n        )\n      )\n    },\n    []\n  )\n\n  const raise = React.useCallback((id: string) => {\n    setStates((all) => {\n      const me = all.find((s) => s.id === id)\n      if (!me || (me.z === top.current && !me.minimized)) return all\n      return all.map((s) =>\n        s.id === id ? { ...s, z: ++top.current, minimized: false } : s\n      )\n    })\n  }, [])\n\n  const desk = () => ({\n    w: deskRef.current?.clientWidth ?? 800,\n    h: deskRef.current?.clientHeight ?? 500,\n  })\n  const spec = (id: string) => windows.find((w) => w.id === id)\n\n  function begin(\n    e: React.PointerEvent,\n    s: WinState,\n    mode: \"move\" | \"resize\",\n    edge?: string\n  ) {\n    if (s.maximized && mode === \"resize\") return\n    gesture.current = {\n      id: s.id,\n      mode,\n      edge,\n      px: e.clientX,\n      py: e.clientY,\n      start: { x: s.x, y: s.y, w: s.w, h: s.h },\n    }\n    setDragging(s.id)\n    ;(e.currentTarget as HTMLElement).setPointerCapture?.(e.pointerId)\n  }\n\n  function onMove(e: React.PointerEvent) {\n    const g = gesture.current\n    if (!g) return\n    const dx = e.clientX - g.px\n    const dy = e.clientY - g.py\n    const { w: dw, h: dh } = desk()\n    if (g.mode === \"move\") {\n      patch(g.id, {\n        maximized: false,\n        x: Math.min(dw - 80, Math.max(80 - g.start.w, g.start.x + dx)),\n        y: Math.min(dh - 32, Math.max(0, g.start.y + dy)),\n      })\n      return\n    }\n    const win = spec(g.id)\n    const minW = win?.minWidth ?? 220\n    const minH = win?.minHeight ?? 140\n    let { x, y, w, h } = g.start\n    const edge = g.edge ?? \"\"\n    if (edge.includes(\"e\")) w = Math.max(minW, g.start.w + dx)\n    if (edge.includes(\"s\")) h = Math.max(minH, g.start.h + dy)\n    if (edge.includes(\"w\")) {\n      w = Math.max(minW, g.start.w - dx)\n      x = g.start.x + (g.start.w - w)\n    }\n    if (edge.includes(\"n\")) {\n      h = Math.max(minH, g.start.h - dy)\n      y = Math.max(0, g.start.y + (g.start.h - h))\n      h = g.start.h + (g.start.y - y)\n    }\n    patch(g.id, { x, y, w, h })\n  }\n\n  function end() {\n    gesture.current = null\n    setDragging(null)\n  }\n\n  function zoom(s: WinState) {\n    if (s.maximized) patch(s.id, { maximized: false, ...(s.restore ?? {}) })\n    else\n      patch(s.id, {\n        maximized: true,\n        restore: { x: s.x, y: s.y, w: s.w, h: s.h },\n      })\n    raise(s.id)\n  }\n\n  function onKeyDown(e: React.KeyboardEvent, s: WinState) {\n    if (e.target !== e.currentTarget) return\n    const mod = e.metaKey || e.ctrlKey\n    if (mod && e.key.toLowerCase() === \"w\") {\n      e.preventDefault()\n      onClose?.(s.id)\n      return\n    }\n    if (mod && e.key.toLowerCase() === \"m\") {\n      e.preventDefault()\n      patch(s.id, { minimized: true })\n      return\n    }\n    if (!e.altKey) return\n    const dirs: Record<string, [number, number]> = {\n      ArrowLeft: [-1, 0],\n      ArrowRight: [1, 0],\n      ArrowUp: [0, -1],\n      ArrowDown: [0, 1],\n    }\n    const d = dirs[e.key]\n    if (!d) return\n    e.preventDefault()\n    const win = spec(s.id)\n    const step = 16\n    const { w: dw, h: dh } = desk()\n    if (e.shiftKey) {\n      patch(s.id, {\n        maximized: false,\n        w: Math.max(win?.minWidth ?? 220, s.w + d[0] * step),\n        h: Math.max(win?.minHeight ?? 140, s.h + d[1] * step),\n      })\n    } else {\n      patch(s.id, {\n        maximized: false,\n        x: Math.min(dw - 80, Math.max(80 - s.w, s.x + d[0] * step)),\n        y: Math.min(dh - 32, Math.max(0, s.y + d[1] * step)),\n      })\n    }\n  }\n\n  const visible = states.filter((s) => !s.minimized)\n  const activeId = visible.reduce<WinState | null>(\n    (best, s) => (!best || s.z > best.z ? s : best),\n    null\n  )?.id\n  const tray = states.filter((s) => s.minimized)\n\n  return (\n    <div\n      ref={deskRef}\n      data-slot=\"window-manager\"\n      role=\"group\"\n      aria-label={label}\n      onPointerMove={onMove}\n      onPointerUp={end}\n      onPointerCancel={end}\n      className={cn(\"relative isolate overflow-hidden\", className)}\n      {...props}\n    >\n      {children}\n      <AnimatePresence>\n        {states.map((s) => {\n          const win = spec(s.id)\n          if (!win) return null\n          const { w: dw, h: dh } = desk()\n          const rect = s.maximized ? { x: 0, y: 0, w: dw, h: dh } : s\n          return (\n            <motion.div\n              key={s.id}\n              data-slot=\"managed-window\"\n              role=\"group\"\n              aria-label={`${win.title} window. Alt and arrow keys move it; Alt, Shift and arrow keys resize it.`}\n              tabIndex={s.minimized ? -1 : 0}\n              {...(s.minimized ? { inert: true } : {})}\n              onPointerDownCapture={() => raise(s.id)}\n              onFocusCapture={() => raise(s.id)}\n              onKeyDown={(e) => onKeyDown(e, s)}\n              initial={reduce ? { opacity: 0 } : { opacity: 0, scale: 0.92 }}\n              animate={\n                s.minimized\n                  ? reduce\n                    ? { opacity: 0 }\n                    : { opacity: 0, scale: 0.7, y: dh - s.y }\n                  : { opacity: 1, scale: 1, y: 0 }\n              }\n              exit={reduce ? { opacity: 0 } : { opacity: 0, scale: 0.92 }}\n              transition={{\n                duration: reduce ? 0.1 : 0.22,\n                ease: [0.22, 1, 0.36, 1],\n              }}\n              className={cn(\n                \"focus-visible:ring-ring/60 absolute rounded-[14px] outline-none focus-visible:ring-[3px]\",\n                dragging !== s.id &&\n                  \"[transition:left_0.2s,top_0.2s,width_0.2s,height_0.2s] motion-reduce:transition-none\",\n                s.minimized && \"pointer-events-none\"\n              )}\n              style={{\n                left: rect.x,\n                top: rect.y,\n                width: rect.w,\n                height: rect.h,\n                zIndex: s.z,\n              }}\n            >\n              <MacWindow\n                active={activeId === s.id}\n                className=\"size-full\"\n                onClose={() => onClose?.(s.id)}\n                onMinimize={() => patch(s.id, { minimized: true })}\n                onZoom={() => zoom(s)}\n              >\n                <MacWindowTitleBar\n                  title={win.title}\n                  className=\"cursor-grab touch-none active:cursor-grabbing\"\n                  onPointerDown={(e) => {\n                    if ((e.target as HTMLElement).closest(\"button\")) return\n                    begin(e, s, \"move\")\n                  }}\n                  onDoubleClick={(e) => {\n                    if (!(e.target as HTMLElement).closest(\"button\")) zoom(s)\n                  }}\n                />\n                <MacWindowContent>{win.content}</MacWindowContent>\n              </MacWindow>\n              {!s.maximized &&\n                EDGES.map((edge) => (\n                  <span\n                    key={edge}\n                    aria-hidden=\"true\"\n                    onPointerDown={(e) => begin(e, s, \"resize\", edge)}\n                    className={cn(\"absolute z-10 touch-none\", EDGE_STYLE[edge])}\n                  />\n                ))}\n            </motion.div>\n          )\n        })}\n      </AnimatePresence>\n      {tray.length > 0 && (\n        <ul\n          aria-label={trayLabel}\n          className=\"absolute bottom-3 left-1/2 z-[999] flex max-w-[92%] -translate-x-1/2 gap-1.5 rounded-2xl border border-white/20 bg-black/35 p-1.5 shadow-lg backdrop-blur-xl\"\n        >\n          {tray.map((s) => (\n            <li key={s.id}>\n              <button\n                type=\"button\"\n                aria-label={`Restore ${spec(s.id)?.title ?? s.id}`}\n                onClick={() => raise(s.id)}\n                className=\"flex h-8 max-w-40 items-center rounded-xl bg-white/15 px-3 text-[12px] font-medium text-white transition-colors outline-none hover:bg-white/25 focus-visible:ring-[3px] focus-visible:ring-white/60\"\n              >\n                <span className=\"truncate\">{spec(s.id)?.title}</span>\n              </button>\n            </li>\n          ))}\n        </ul>\n      )}\n    </div>\n  )\n}\n\nexport { WindowManager, type WindowManagerProps, type ManagedWindow }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}