{"version":3,"sources":["../src/devtools-client.ts"],"sourcesContent":["import {\n  FARM_DEVTOOLS_LAUNCH_PARAM,\n  FARM_DEVTOOLS_PATH,\n  type ResolvedFarmDevtoolsConfig,\n} from \"./devtools-config\";\n\ntype ParsedShortcut = {\n  key: string;\n  alt: boolean;\n  ctrl: boolean;\n  meta: boolean;\n  mod: boolean;\n  shift: boolean;\n};\n\nfunction parseShortcut(shortcut: string): ParsedShortcut | null {\n  const tokens = shortcut\n    .toLowerCase()\n    .split(\"+\")\n    .map((token) => token.trim())\n    .filter(Boolean);\n  const key = tokens.find(\n    (token) =>\n      ![\"alt\", \"ctrl\", \"control\", \"meta\", \"cmd\", \"command\", \"mod\", \"shift\"].includes(token),\n  );\n\n  if (!key) {\n    return null;\n  }\n\n  return {\n    key,\n    alt: tokens.includes(\"alt\"),\n    ctrl: tokens.includes(\"ctrl\") || tokens.includes(\"control\"),\n    meta: tokens.includes(\"meta\") || tokens.includes(\"cmd\") || tokens.includes(\"command\"),\n    mod: tokens.includes(\"mod\"),\n    shift: tokens.includes(\"shift\"),\n  };\n}\n\nexport function generateFarmDevtoolsClientRuntime(config: ResolvedFarmDevtoolsConfig): string {\n  if (!config.enabled) {\n    return \"\";\n  }\n\n  const shortcut = config.shortcut ? parseShortcut(config.shortcut) : null;\n  const overlayStyles = `\n    #__farm_devtools_overlay__ {\n      position: fixed;\n      inset: 0;\n      z-index: 2147483646;\n      display: grid;\n      place-items: center;\n      box-sizing: border-box;\n      padding: 20px;\n      background: rgb(0 0 0 / 0);\n      backdrop-filter: blur(6px);\n      -webkit-backdrop-filter: blur(6px);\n      overscroll-behavior: none;\n      isolation: isolate;\n      opacity: 0;\n      pointer-events: none;\n      transition: opacity 150ms ease-out;\n    }\n    #__farm_devtools_overlay__[data-open=\"true\"] {\n      background: rgb(0 0 0 / 0.32);\n      opacity: 1;\n      pointer-events: auto;\n    }\n    #__farm_devtools_overlay__ > iframe {\n      display: block;\n      width: min(1100px, calc(100vw - 48px));\n      height: min(720px, calc(100dvh - 48px));\n      border: 0;\n      border-radius: 12px;\n      background: transparent;\n      box-shadow: 0 24px 80px rgb(0 0 0 / 0.48), 0 4px 18px rgb(0 0 0 / 0.24);\n      transform: scale(0.985) translateY(4px);\n      transition: transform 150ms ease-out;\n    }\n    #__farm_devtools_overlay__[data-open=\"true\"] > iframe {\n      transform: scale(1) translateY(0);\n    }\n    @media (max-width: 700px) {\n      #__farm_devtools_overlay__ { padding: 8px; }\n      #__farm_devtools_overlay__ > iframe {\n        width: calc(100vw - 16px);\n        height: calc(100dvh - 16px);\n        border-radius: 12px;\n      }\n    }\n    @media (prefers-reduced-motion: reduce) {\n      #__farm_devtools_overlay__, #__farm_devtools_overlay__ > iframe { transition: none; }\n    }\n  `;\n\n  return `\n(() => {\n  const overlayId = \"__farm_devtools_overlay__\";\n  const styleId = \"__farm_devtools_overlay_styles__\";\n  const runtimeKey = \"__FARM_DEVTOOLS_RUNTIME__\";\n  const launchParam = ${JSON.stringify(FARM_DEVTOOLS_LAUNCH_PARAM)};\n  const devtoolsPath = ${JSON.stringify(FARM_DEVTOOLS_PATH)};\n  const validViews = new Set([\"overview\", \"routes\", \"api\", \"systems\", \"runtime\", \"raw\", \"inspect\", \"diagnostics\"]);\n  const shortcut = ${JSON.stringify(shortcut)};\n  const isMac = /Mac|iPhone|iPad|iPod/.test(navigator.platform);\n  let returnFocus = null;\n  let restorePage = null;\n  let closeTimer = null;\n\n  const lockPage = () => {\n    const styles = [];\n    for (const element of [document.documentElement, document.body]) {\n      for (const [property, value] of [[\"overflow-x\", \"hidden\"], [\"overflow-y\", \"hidden\"], [\"overscroll-behavior\", \"none\"]]) {\n        const previous = element.style.getPropertyValue(property);\n        const priority = element.style.getPropertyPriority(property);\n        element.style.setProperty(property, value, \"important\");\n        styles.push({ element, property, value, previous, priority });\n      }\n    }\n    return () => {\n      for (const { element, property, value, previous, priority } of styles) {\n        // Do not overwrite a newer style set by the application while the panel was open.\n        if (element.style.getPropertyValue(property) !== value || element.style.getPropertyPriority(property) !== \"important\") continue;\n        if (previous) element.style.setProperty(property, previous, priority);\n        else element.style.removeProperty(property);\n      }\n    };\n  };\n\n  const matchesShortcut = (event) => {\n    if (!shortcut || event.repeat) return false;\n    const expectedCtrl = shortcut.ctrl || (shortcut.mod && !isMac);\n    const expectedMeta = shortcut.meta || (shortcut.mod && isMac);\n    if (\n      Boolean(event.altKey) !== shortcut.alt ||\n      Boolean(event.ctrlKey) !== expectedCtrl ||\n      Boolean(event.metaKey) !== expectedMeta ||\n      Boolean(event.shiftKey) !== shortcut.shift\n    ) return false;\n\n    if (shortcut.key === \".\" || shortcut.key === \"period\") return event.code === \"Period\";\n    if (shortcut.key === \",\" || shortcut.key === \"comma\") return event.code === \"Comma\";\n    if (shortcut.key === \"/\" || shortcut.key === \"slash\") return event.code === \"Slash\";\n    return String(event.key || \"\").toLowerCase() === shortcut.key;\n  };\n\n  const ensureStyles = () => {\n    if (document.getElementById(styleId)) return;\n    const style = document.createElement(\"style\");\n    style.id = styleId;\n    style.textContent = ${JSON.stringify(overlayStyles)};\n    document.head.appendChild(style);\n  };\n\n  const finishClose = () => {\n    if (closeTimer !== null) window.clearTimeout(closeTimer);\n    closeTimer = null;\n    const overlay = document.getElementById(overlayId);\n    overlay?.remove();\n    restorePage?.();\n    restorePage = null;\n    const focusTarget = returnFocus;\n    returnFocus = null;\n    focusTarget?.focus?.({ preventScroll: true });\n  };\n\n  const close = () => {\n    const overlay = document.getElementById(overlayId);\n    if (!overlay || closeTimer !== null) return;\n    overlay.dataset.open = \"false\";\n    closeTimer = window.setTimeout(finishClose, 160);\n  };\n\n  const open = (view = \"overview\") => {\n    if (closeTimer !== null) finishClose();\n    if (document.getElementById(overlayId)) return;\n    ensureStyles();\n    returnFocus = document.activeElement;\n    restorePage = lockPage();\n    const overlay = document.createElement(\"div\");\n    overlay.id = overlayId;\n    overlay.setAttribute(\"role\", \"dialog\");\n    overlay.setAttribute(\"aria-modal\", \"true\");\n    overlay.setAttribute(\"aria-label\", \"Farm.js DevTools overlay\");\n    const frame = document.createElement(\"iframe\");\n    const resolvedView = validViews.has(view) ? view : \"overview\";\n    frame.src = devtoolsPath + \"?embedded=1\" + (resolvedView === \"overview\" ? \"\" : \"#\" + resolvedView);\n    frame.title = \"Farm.js DevTools\";\n    frame.addEventListener(\"load\", () => frame.contentWindow?.focus(), { once: true });\n    overlay.appendChild(frame);\n    overlay.addEventListener(\"pointerdown\", (event) => {\n      if (event.target === overlay) close();\n    });\n    overlay.addEventListener(\"wheel\", (event) => event.preventDefault(), { passive: false });\n    overlay.addEventListener(\"touchmove\", (event) => event.preventDefault(), { passive: false });\n    document.body.appendChild(overlay);\n    requestAnimationFrame(() => {\n      if (overlay.isConnected && closeTimer === null) overlay.dataset.open = \"true\";\n    });\n  };\n\n  const toggle = () => {\n    if (document.getElementById(overlayId)) close();\n    else open();\n  };\n\n  const onKeydown = (event) => {\n    if (event.key === \"Escape\" && document.getElementById(overlayId)) {\n      event.preventDefault();\n      close();\n      return;\n    }\n    if (!matchesShortcut(event)) return;\n    event.preventDefault();\n    event.stopPropagation();\n    toggle();\n  };\n\n  const onMessage = (event) => {\n    if (event.origin !== location.origin) return;\n    const frame = document.querySelector(\"#\" + overlayId + \" > iframe\");\n    if (!frame || event.source !== frame.contentWindow) return;\n    if (event.data?.type === \"farm:devtools:close\") close();\n    if (event.data?.type === \"farm:devtools:keydown\" && matchesShortcut(event.data.event || {})) close();\n  };\n\n  window[runtimeKey]?.dispose?.();\n  window.addEventListener(\"keydown\", onKeydown, true);\n  window.addEventListener(\"message\", onMessage);\n  window[runtimeKey] = {\n    dispose() {\n      finishClose();\n      window.removeEventListener(\"keydown\", onKeydown, true);\n      window.removeEventListener(\"message\", onMessage);\n    },\n  };\n  window.__FARM_DEVTOOLS__ = { open, close, toggle };\n\n  const launchUrl = new URL(location.href);\n  const launchRequest = launchUrl.searchParams.get(launchParam);\n  if (launchRequest !== null) {\n    const hashView = launchUrl.hash.slice(1);\n    const launchView = validViews.has(launchRequest)\n      ? launchRequest\n      : validViews.has(hashView)\n        ? hashView\n        : \"overview\";\n    launchUrl.searchParams.delete(launchParam);\n    if (validViews.has(hashView)) launchUrl.hash = \"\";\n    history.replaceState(\n      history.state,\n      \"\",\n      launchUrl.pathname + launchUrl.search + launchUrl.hash,\n    );\n    const launch = () => requestAnimationFrame(() => open(launchView));\n    if (document.readyState === \"loading\") {\n      document.addEventListener(\"DOMContentLoaded\", launch, { once: true });\n    } else {\n      launch();\n    }\n  }\n})();\n`;\n}\n"],"mappings":";;;;;;;;;AAeA,SAAS,cAAc,UAAyC;AAC9D,QAAM,SAAS,SACZ,YAAY,EACZ,MAAM,GAAG,EACT,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,OAAO;AACjB,QAAM,MAAM,OAAO;AAAA,IACjB,CAAC,UACC,CAAC,CAAC,OAAO,QAAQ,WAAW,QAAQ,OAAO,WAAW,OAAO,OAAO,EAAE,SAAS,KAAK;AAAA,EACxF;AAEA,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA,KAAK,OAAO,SAAS,KAAK;AAAA,IAC1B,MAAM,OAAO,SAAS,MAAM,KAAK,OAAO,SAAS,SAAS;AAAA,IAC1D,MAAM,OAAO,SAAS,MAAM,KAAK,OAAO,SAAS,KAAK,KAAK,OAAO,SAAS,SAAS;AAAA,IACpF,KAAK,OAAO,SAAS,KAAK;AAAA,IAC1B,OAAO,OAAO,SAAS,OAAO;AAAA,EAChC;AACF;AAvBS;AAyBF,SAAS,kCAAkC,QAA4C;AAC5F,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,OAAO,WAAW,cAAc,OAAO,QAAQ,IAAI;AACpE,QAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkDtB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,wBAKe,KAAK,UAAU,0BAA0B,CAAC;AAAA,yBACzC,KAAK,UAAU,kBAAkB,CAAC;AAAA;AAAA,qBAEtC,KAAK,UAAU,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BA+CnB,KAAK,UAAU,aAAa,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiHvD;AAhOgB;","names":[]}