{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "eased-mac",
  "title": "Eased Mac",
  "description": "The macOS look the Mac pack shares: the San Francisco font stack, frosted popover and HUD materials in light and dark, hairlines and macOS corner radii, with a native mode that leaves vibrancy to a Tauri or Electron window and a hook that follows the system appearance there.",
  "registryDependencies": [
    "https://eased.dev/r/eased-tokens.json"
  ],
  "files": [
    {
      "path": "src/registry/eased/lib/mac.ts",
      "content": "import { useEffect } from \"react\";\n\n/**\n * The macOS look for the Eased Mac pack: system type, translucent \"vibrancy\" materials and\n * hairlines, in light and dark. Motion stays Eased's (`./motion`); only the material and the\n * geometry follow macOS, so a Mac component still moves like the rest of the library.\n *\n *   macFont          the San Francisco stack, at macOS's 13px body size\n *   macMaterial      frosted panel: translucent tint + backdrop blur/saturate, hairline, shadow\n *   MAC_RADIUS       corner radii macOS uses for popovers, HUDs and controls (px)\n *   useSystemAppearance   puts `.dark` on <html> while the system is dark (Tauri/Electron windows)\n *\n * Dark follows Eased's convention: a `.dark` class or `data-theme=\"dark\"` on an ancestor, so a\n * web app keeps its own theme toggle.\n *\n * Inside a Tauri/Electron window that already draws native vibrancy (Tauri `windowEffects`,\n * `window-vibrancy`, Electron `vibrancy`), pass `\"native\"`: the CSS blur and tint drop out so\n * the real material shows through, and the hairline stays.\n */\n\n/** -apple-system resolves to SF Pro on Apple platforms; elsewhere the platform UI font. */\nexport const macFontFamily = \"font-[-apple-system,BlinkMacSystemFont,system-ui,sans-serif]\";\nexport const macFont = `${macFontFamily} text-[13px] leading-[16px] antialiased`;\n\n/** `css` approximates vibrancy in the browser; `native` leaves it to the window behind. */\nexport type MacMaterialMode = \"css\" | \"native\";\n\n/** The materials the pack draws, after the NSVisualEffectView materials they stand in for. */\nexport type MacMaterialKind = \"popover\" | \"hud\";\n\n/*\n * Values are measured approximations of macOS's materials (estimates, not Apple constants):\n * popover ≈ NSVisualEffectView.Material.popover, hud ≈ .hudWindow. Every class is written out\n * in full (no string building) so Tailwind finds it; dark repeats each one under `in-[.dark]:`\n * and `in-data-[theme=dark]:`.\n */\nconst FILL: Record<MacMaterialKind, string> = {\n  popover:\n    \"bg-[rgb(236_236_236/0.72)] in-[.dark]:bg-[rgb(44_44_46/0.72)] in-data-[theme=dark]:bg-[rgb(44_44_46/0.72)] backdrop-blur-[40px] backdrop-saturate-[1.8]\",\n  hud: \"bg-[rgb(240_240_240/0.78)] in-[.dark]:bg-[rgb(30_30_30/0.72)] in-data-[theme=dark]:bg-[rgb(30_30_30/0.72)] backdrop-blur-[30px] backdrop-saturate-[1.5]\",\n};\n\n/** Half-pixel hairline as an inset ring, so it never changes the box size. */\nconst HAIRLINE =\n  \"shadow-[inset_0_0_0_0.5px_rgb(0_0_0/0.15)] in-[.dark]:shadow-[inset_0_0_0_0.5px_rgb(255_255_255/0.14)] in-data-[theme=dark]:shadow-[inset_0_0_0_0.5px_rgb(255_255_255/0.14)]\";\n\n/**\n * The same hairline as an SVG stroke colour, for shapes a box-shadow can't follow (the popover's\n * arrow). Stroke 1px along the clip edge: the clip keeps the inner half, a 0.5px hairline.\n */\nexport const macHairlineStroke =\n  \"stroke-[rgb(0_0_0/0.15)] in-[.dark]:stroke-[rgb(255_255_255/0.14)] in-data-[theme=dark]:stroke-[rgb(255_255_255/0.14)]\";\n\n/** Text colours on the materials: macOS's label and secondaryLabel. */\nexport const macText =\n  \"text-[rgb(0_0_0/0.85)] in-[.dark]:text-[rgb(255_255_255/0.85)] in-data-[theme=dark]:text-[rgb(255_255_255/0.85)]\";\nexport const macTextSecondary =\n  \"text-[rgb(0_0_0/0.5)] in-[.dark]:text-[rgb(255_255_255/0.55)] in-data-[theme=dark]:text-[rgb(255_255_255/0.55)]\";\n\n/**\n * Classes for a frosted macOS surface. Add a radius and padding. The outer drop shadow is\n * separate (`macShadow`) because a clip-path shape (the popover's arrow) clips box-shadow.\n * Pass `hairline: false` when the shape draws its own (`macHairlineStroke`).\n */\nexport function macMaterial(kind: MacMaterialKind, mode: MacMaterialMode = \"css\", { hairline = true }: { hairline?: boolean } = {}) {\n  return `${mode === \"native\" ? \"\" : FILL[kind]} ${hairline ? HAIRLINE : \"\"} ${macText}`;\n}\n\n/**\n * The floating shadow for a popover-like surface, as a filter so it follows clip-path shapes.\n * Put it on a sibling layer behind the surface, never an ancestor: a `filter` (or opacity < 1)\n * on an ancestor stops the surface's backdrop blur from seeing the page behind it.\n */\nexport const macShadow =\n  \"drop-shadow-[0_8px_24px_rgb(0_0_0/0.22)] in-[.dark]:drop-shadow-[0_8px_24px_rgb(0_0_0/0.45)] in-data-[theme=dark]:drop-shadow-[0_8px_24px_rgb(0_0_0/0.45)]\";\n\n/** Corner radii in px (measured on macOS 14–15; macOS 26 rounds popovers to ~16). */\nexport const MAC_RADIUS = { popover: 11, hud: 18, pill: 9999, control: 6 } as const;\n\n/**\n * Follows the system appearance: toggles `.dark` on <html> from `prefers-color-scheme` and keeps\n * it in step. For a Tauri/Electron window, whose native vibrancy (and the webview's\n * `prefers-color-scheme`) follow the OS; without it dark vibrancy gets light-mode text. Runs in\n * an effect, so it is hydration-safe. Leave it out of a web app that has its own theme toggle.\n */\nexport function useSystemAppearance() {\n  useEffect(() => {\n    const query = window.matchMedia(\"(prefers-color-scheme: dark)\");\n    const apply = () => document.documentElement.classList.toggle(\"dark\", query.matches);\n    apply();\n    query.addEventListener(\"change\", apply);\n    return () => query.removeEventListener(\"change\", apply);\n  }, []);\n}\n",
      "type": "registry:lib",
      "target": "@components/eased/lib/mac.ts"
    }
  ],
  "type": "registry:lib"
}