{"version":3,"sources":["../../src/client/island-runtime.ts"],"sourcesContent":["\"use client\";\n\nimport type { FarmIslandStrategy } from \"../island\";\n\nexport interface ScheduleFarmIslandHydrationOptions<T> {\n  container: Element;\n  strategy?: FarmIslandStrategy | null;\n  signal?: AbortSignal;\n  hydrate: () => T | Promise<T>;\n}\n\ninterface FarmQueuedClick {\n  target?: EventTarget | null;\n}\n\nfunction getPreHydrationClickQueue(): FarmQueuedClick[] | null {\n  const windowWithQueue = window as typeof window & {\n    __FARM_PREHYDRATION_CLICK_QUEUE__?: FarmQueuedClick[];\n  };\n  return Array.isArray(windowWithQueue.__FARM_PREHYDRATION_CLICK_QUEUE__)\n    ? windowWithQueue.__FARM_PREHYDRATION_CLICK_QUEUE__\n    : null;\n}\n\nfunction findQueuedTarget(container: Element): Element | null {\n  const queue = getPreHydrationClickQueue();\n  if (!queue) return null;\n  for (const item of queue) {\n    if (item?.target instanceof Element && container.contains(item.target)) return item.target;\n  }\n  return null;\n}\n\nfunction takeQueuedTargets(container: Element): Element[] {\n  const queue = getPreHydrationClickQueue();\n  if (!queue) return [];\n\n  const targets: Element[] = [];\n  for (let index = queue.length - 1; index >= 0; index--) {\n    const target = queue[index]?.target;\n    if (!(target instanceof Element) || !container.contains(target)) continue;\n    queue.splice(index, 1);\n    targets.unshift(target);\n  }\n  return targets;\n}\n\nfunction runWhenIdle(callback: () => void): () => void {\n  const windowWithIdleCallback = window as typeof window & {\n    requestIdleCallback?: (callback: () => void, options?: { timeout?: number }) => number;\n    cancelIdleCallback?: (handle: number) => void;\n  };\n\n  if (typeof windowWithIdleCallback.requestIdleCallback === \"function\") {\n    const handle = windowWithIdleCallback.requestIdleCallback(callback, { timeout: 2_000 });\n    return () => windowWithIdleCallback.cancelIdleCallback?.(handle);\n  }\n\n  const handle = window.setTimeout(callback, 1);\n  return () => window.clearTimeout(handle);\n}\n\nfunction replayClick(target: Element): void {\n  const clickable = target as Element & { click?: () => void };\n  if (typeof clickable.click === \"function\") {\n    clickable.click();\n    return;\n  }\n  target.dispatchEvent(new MouseEvent(\"click\", { bubbles: true, cancelable: true }));\n}\n\nfunction finishIslandHydration(container: Element, activatingTarget?: Element | null): void {\n  const targets = new Set<Element>();\n  if (activatingTarget?.isConnected) targets.add(activatingTarget);\n  for (const target of takeQueuedTargets(container)) if (target.isConnected) targets.add(target);\n\n  if (!container.isConnected) return;\n  container.setAttribute(\"data-farm-island-hydrated\", \"true\");\n\n  for (const target of targets) {\n    window.setTimeout(() => {\n      if (\n        container.getAttribute(\"data-farm-island-hydrated\") === \"true\" &&\n        container.isConnected &&\n        target.isConnected &&\n        container.contains(target)\n      ) {\n        replayClick(target);\n      }\n    }, 0);\n  }\n}\n\n/**\n * Defer importing and hydrating a server-rendered client boundary until its\n * configured trigger. The returned promise resolves with the hydration result.\n */\nexport function scheduleFarmIslandHydration<T>({\n  container,\n  strategy,\n  signal,\n  hydrate,\n}: ScheduleFarmIslandHydrationOptions<T>): Promise<T | undefined> {\n  const resolvedStrategy = strategy ?? \"load\";\n  if (signal?.aborted) return Promise.resolve(undefined);\n\n  if (resolvedStrategy === \"load\") {\n    return Promise.resolve()\n      .then(() => (signal?.aborted ? undefined : hydrate()))\n      .then((value) => {\n        if (signal?.aborted) return undefined;\n        finishIslandHydration(container);\n        return value;\n      });\n  }\n\n  return new Promise<T | undefined>((resolve, reject) => {\n    let started = false;\n    let cancelled = false;\n    let queuedClickTarget: Element | null = null;\n    const triggerCleanups = new Set<() => void>();\n    let removeAbortListener: (() => void) | null = null;\n\n    const cleanupTriggers = () => {\n      for (const dispose of triggerCleanups) dispose();\n      triggerCleanups.clear();\n    };\n    const cleanup = () => {\n      cleanupTriggers();\n      removeAbortListener?.();\n      removeAbortListener = null;\n    };\n\n    const start = () => {\n      if (started || cancelled) return;\n      started = true;\n      cleanupTriggers();\n      Promise.resolve()\n        .then(hydrate)\n        .then(\n          (value) => {\n            cleanup();\n            if (cancelled || signal?.aborted) return;\n            const target = queuedClickTarget;\n            queuedClickTarget = null;\n            finishIslandHydration(container, target);\n            resolve(value);\n          },\n          (error) => {\n            cleanup();\n            reject(error);\n          },\n        );\n    };\n\n    if (signal) {\n      const abort = () => {\n        cancelled = true;\n        cleanup();\n        takeQueuedTargets(container);\n        resolve(undefined);\n      };\n      signal.addEventListener(\"abort\", abort, { once: true });\n      removeAbortListener = () => signal.removeEventListener(\"abort\", abort);\n    }\n\n    if (resolvedStrategy === \"idle\") {\n      triggerCleanups.add(runWhenIdle(start));\n      return;\n    }\n\n    if (resolvedStrategy === \"visible\") {\n      if (typeof IntersectionObserver !== \"function\") {\n        start();\n        return;\n      }\n\n      // Isolated boundary markers render with display:contents, so the\n      // container itself has no box and can never intersect. Observe its\n      // element children instead; with nothing observable, start now.\n      const targets =\n        container.getClientRects().length > 0 ? [container] : Array.from(container.children);\n      if (targets.length === 0) {\n        start();\n        return;\n      }\n\n      const observer = new IntersectionObserver(\n        (entries) => {\n          if (entries.some((entry) => entry.isIntersecting)) start();\n        },\n        { rootMargin: \"200px\" },\n      );\n      for (const target of targets) observer.observe(target);\n      triggerCleanups.add(() => observer.disconnect());\n      return;\n    }\n\n    const queueActivatingClick = (event: MouseEvent) => {\n      const target =\n        event.target instanceof Element\n          ? event.target.closest(\n              'button,[role=\"button\"],input[type=\"button\"],input[type=\"submit\"],input[type=\"reset\"]',\n            )\n          : null;\n      if (\n        !target ||\n        !container.contains(target) ||\n        target.closest(\"a[href]\") ||\n        event.button !== 0 ||\n        event.metaKey ||\n        event.altKey ||\n        event.ctrlKey ||\n        event.shiftKey\n      ) {\n        return;\n      }\n      queuedClickTarget ??= target;\n      event.preventDefault();\n      event.stopImmediatePropagation();\n      start();\n    };\n    const activateFromQueuedClick = (event: Event) => {\n      const target = (event as CustomEvent<{ target?: EventTarget | null }>).detail?.target;\n      if (!(target instanceof Element) || !container.contains(target)) return;\n\n      queuedClickTarget ??= target;\n      start();\n    };\n\n    document.addEventListener(\"click\", queueActivatingClick, true);\n    triggerCleanups.add(() => document.removeEventListener(\"click\", queueActivatingClick, true));\n    document.addEventListener(\"farm:island-interaction\", activateFromQueuedClick);\n    triggerCleanups.add(() =>\n      document.removeEventListener(\"farm:island-interaction\", activateFromQueuedClick),\n    );\n\n    const queuedTarget = findQueuedTarget(container);\n    if (queuedTarget) {\n      queuedClickTarget = queuedTarget;\n      start();\n    }\n  });\n}\n"],"mappings":"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","names":["handle"]}