{"version":3,"sources":["../../../../src/sensors/useFocus/core.ts"],"sourcesContent":["import { observable, type Observable } from \"@legendapp/state\";\nimport { createObserve, onMount, get, type DeepMaybeObservable } from \"@usels/core\";\nimport { resolveWindowSource, type ConfigurableWindow } from \"@shared/configurable\";\nimport type { MaybeEventTarget } from \"../../types\";\nimport { createEventListener } from \"../../browser/useEventListener/core\";\n\nexport interface UseFocusOptions extends ConfigurableWindow {\n  /** Auto-focus the element on mount. Default: false */\n  initialValue?: boolean;\n  /** Replicate :focus-visible behavior. Default: false */\n  focusVisible?: boolean;\n  /** Prevent scroll when focusing. Default: false */\n  preventScroll?: boolean;\n}\n\nexport interface UseFocusReturn {\n  /** Current focus state (read/write) — set(true)→focus(), set(false)→blur() */\n  focused$: Observable<boolean>;\n}\n\n/**\n * Framework-agnostic reactive focus tracking for a target element with\n * optional two-way binding.\n *\n * Exposes `focused$` as a read/write Observable:\n * - Setting `focused$.set(true)` calls `el.focus()`\n * - Setting `focused$.set(false)` calls `el.blur()`\n * - DOM focus/blur events update `focused$` automatically.\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function createFocus(\n  target: MaybeEventTarget,\n  options?: DeepMaybeObservable<UseFocusOptions>\n): UseFocusReturn {\n  const opts$ = observable(options);\n  const focused$ = observable<boolean>(false);\n  const win$ = resolveWindowSource(opts$.window as unknown as Observable<unknown>);\n\n  // --- Event handlers ---\n  createEventListener(\n    target,\n    \"focus\",\n    () => {\n      const win = win$.peek();\n      if (!win) return;\n      const focusVisible = opts$.peek()?.focusVisible ?? false;\n      if (focusVisible) {\n        const el = get(target);\n        if (!el || !(el instanceof Element) || !el.matches(\":focus-visible\")) return;\n      }\n      if (!focused$.peek()) {\n        focused$.set(true);\n      }\n    },\n    { passive: true }\n  );\n\n  createEventListener(\n    target,\n    \"blur\",\n    () => {\n      if (focused$.peek()) {\n        focused$.set(false);\n      }\n    },\n    { passive: true }\n  );\n\n  // --- Two-way binding: focused$ changes → focus/blur the element ---\n  createObserve(() => {\n    const isFocused = focused$.get();\n    const el = get(target);\n    if (!el || !(el instanceof HTMLElement)) return;\n\n    const win = win$.get();\n    if (!win) return;\n\n    if (isFocused) {\n      if (win.document.activeElement !== el) {\n        el.focus({ preventScroll: opts$.peek()?.preventScroll ?? false });\n      }\n    } else {\n      if (win.document.activeElement === el) {\n        el.blur();\n      }\n    }\n  });\n\n  // --- Auto-focus on mount ---\n  onMount(() => {\n    if (opts$.peek()?.initialValue) {\n      const el = get(target);\n      if (el instanceof HTMLElement) {\n        el.focus({ preventScroll: opts$.peek()?.preventScroll ?? false });\n      }\n    }\n  });\n\n  return { focused$ };\n}\n"],"mappings":"AAAA,SAAS,kBAAmC;AAC5C,SAAS,eAAe,SAAS,WAAqC;AACtE,SAAS,2BAAoD;AAE7D,SAAS,2BAA2B;AAAA;AA0B7B,SAAS,YACd,QACA,SACgB;AAChB,QAAM,QAAQ,WAAW,OAAO;AAChC,QAAM,WAAW,WAAoB,KAAK;AAC1C,QAAM,OAAO,oBAAoB,MAAM,MAAwC;AAG/E;AAAA,IACE;AAAA,IACA;AAAA,IACA,MAAM;AACJ,YAAM,MAAM,KAAK,KAAK;AACtB,UAAI,CAAC,IAAK;AACV,YAAM,eAAe,MAAM,KAAK,GAAG,gBAAgB;AACnD,UAAI,cAAc;AAChB,cAAM,KAAK,IAAI,MAAM;AACrB,YAAI,CAAC,MAAM,EAAE,cAAc,YAAY,CAAC,GAAG,QAAQ,gBAAgB,EAAG;AAAA,MACxE;AACA,UAAI,CAAC,SAAS,KAAK,GAAG;AACpB,iBAAS,IAAI,IAAI;AAAA,MACnB;AAAA,IACF;AAAA,IACA,EAAE,SAAS,KAAK;AAAA,EAClB;AAEA;AAAA,IACE;AAAA,IACA;AAAA,IACA,MAAM;AACJ,UAAI,SAAS,KAAK,GAAG;AACnB,iBAAS,IAAI,KAAK;AAAA,MACpB;AAAA,IACF;AAAA,IACA,EAAE,SAAS,KAAK;AAAA,EAClB;AAGA,gBAAc,MAAM;AAClB,UAAM,YAAY,SAAS,IAAI;AAC/B,UAAM,KAAK,IAAI,MAAM;AACrB,QAAI,CAAC,MAAM,EAAE,cAAc,aAAc;AAEzC,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,CAAC,IAAK;AAEV,QAAI,WAAW;AACb,UAAI,IAAI,SAAS,kBAAkB,IAAI;AACrC,WAAG,MAAM,EAAE,eAAe,MAAM,KAAK,GAAG,iBAAiB,MAAM,CAAC;AAAA,MAClE;AAAA,IACF,OAAO;AACL,UAAI,IAAI,SAAS,kBAAkB,IAAI;AACrC,WAAG,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF,CAAC;AAGD,UAAQ,MAAM;AACZ,QAAI,MAAM,KAAK,GAAG,cAAc;AAC9B,YAAM,KAAK,IAAI,MAAM;AACrB,UAAI,cAAc,aAAa;AAC7B,WAAG,MAAM,EAAE,eAAe,MAAM,KAAK,GAAG,iBAAiB,MAAM,CAAC;AAAA,MAClE;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO,EAAE,SAAS;AACpB;","names":[]}