{"version":3,"sources":["../../../../src/sensors/useDeviceMotion/core.ts"],"sourcesContent":["import { batch, observable, type Observable } from \"@legendapp/state\";\nimport {\n  createPermissionAware,\n  createSupported,\n  type DeepMaybeObservable,\n  type PermissionAware,\n  type ReadonlyObservable,\n  type Supportable,\n} from \"@usels/core\";\nimport { resolveWindowSource, type ConfigurableWindow } from \"@shared/configurable\";\nimport { createEventListener } from \"../../browser/useEventListener/core\";\n\ninterface DeviceMotionEventiOS {\n  requestPermission: () => Promise<\"granted\" | \"denied\">;\n}\n\nexport type UseDeviceMotionOptions = ConfigurableWindow;\n\nexport interface UseDeviceMotionReturn extends Supportable, PermissionAware {\n  /**\n   * Whether the device has real motion sensor hardware.\n   * `isSupported` only checks API availability — desktop browsers expose the API\n   * but may fire events with non-zero interval yet all-null values when no hardware exists.\n   * `hasRealData$` becomes `true` on the first event where `interval > 0` AND at least\n   * one of acceleration or rotationRate has a non-null value.\n   */\n  hasRealData$: ReadonlyObservable<boolean>;\n  /** Linear acceleration of the device (without gravity), in m/s² */\n  acceleration$: ReadonlyObservable<{ x: number | null; y: number | null; z: number | null }>;\n  /** Linear acceleration of the device (including gravity), in m/s² */\n  accelerationIncludingGravity$: ReadonlyObservable<{\n    x: number | null;\n    y: number | null;\n    z: number | null;\n  }>;\n  /** Rate of rotation of the device around each axis, in deg/s */\n  rotationRate$: ReadonlyObservable<{\n    alpha: number | null;\n    beta: number | null;\n    gamma: number | null;\n  }>;\n  /** Interval (in ms) at which the device obtains motion data */\n  interval$: ReadonlyObservable<number>;\n}\n\n/**\n * Framework-agnostic reactive wrapper around the\n * [DeviceMotionEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent).\n *\n * Resolves the target window via `resolveWindowSource` (honoring\n * `options.window` for iframe / custom root scenarios), exposes acceleration,\n * rotation rate, and interval as observables, and integrates with the\n * iOS permission flow via `createPermissionAware`.\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function createDeviceMotion(\n  options?: DeepMaybeObservable<UseDeviceMotionOptions>\n): UseDeviceMotionReturn {\n  const opts$ = observable(options);\n  const win$ = resolveWindowSource(opts$.window as unknown as Observable<unknown>);\n\n  const isSupported$ = createSupported(() => {\n    const win = win$.get();\n    return !!win && \"DeviceMotionEvent\" in win;\n  });\n\n  // isRequired$ evaluates after mount (via createSupported's isMounted check), so SSR-safe.\n  const isRequired$ = createSupported(\n    () =>\n      typeof globalThis !== \"undefined\" &&\n      typeof (globalThis as { DeviceMotionEvent?: unknown }).DeviceMotionEvent !== \"undefined\" &&\n      typeof (\n        (globalThis as { DeviceMotionEvent: unknown }).DeviceMotionEvent as DeviceMotionEventiOS\n      ).requestPermission === \"function\"\n  );\n\n  const { permissionState$, permissionGranted$, needsPermission$, ensurePermission } =\n    createPermissionAware({\n      isSupported$,\n      isRequired$,\n      requestPermission: async () => {\n        const result = await (\n          (globalThis as { DeviceMotionEvent: unknown }).DeviceMotionEvent as DeviceMotionEventiOS\n        ).requestPermission();\n        return result === \"granted\";\n      },\n    });\n\n  const acceleration$ = observable<{ x: number | null; y: number | null; z: number | null }>({\n    x: null,\n    y: null,\n    z: null,\n  });\n\n  const accelerationIncludingGravity$ = observable<{\n    x: number | null;\n    y: number | null;\n    z: number | null;\n  }>({ x: null, y: null, z: null });\n\n  const rotationRate$ = observable<{\n    alpha: number | null;\n    beta: number | null;\n    gamma: number | null;\n  }>({ alpha: null, beta: null, gamma: null });\n\n  const interval$ = observable<number>(0);\n  const hasRealData$ = observable<boolean>(false);\n\n  // Always attach the listener. On non-iOS it fires immediately.\n  // On iOS, events are not dispatched until permission is granted,\n  // so the listener is harmless until ensurePermission() is called.\n  createEventListener(win$, \"devicemotion\", (event: Event) => {\n    const e = event as DeviceMotionEvent;\n    batch(() => {\n      const acc = e.acceleration;\n      acceleration$.set({\n        x: acc?.x ?? null,\n        y: acc?.y ?? null,\n        z: acc?.z ?? null,\n      });\n\n      const accGrav = e.accelerationIncludingGravity;\n      accelerationIncludingGravity$.set({\n        x: accGrav?.x ?? null,\n        y: accGrav?.y ?? null,\n        z: accGrav?.z ?? null,\n      });\n\n      const rot = e.rotationRate;\n      rotationRate$.set({\n        alpha: rot?.alpha ?? null,\n        beta: rot?.beta ?? null,\n        gamma: rot?.gamma ?? null,\n      });\n\n      interval$.set(e.interval);\n      const hasValues =\n        acc?.x !== null ||\n        acc?.y !== null ||\n        acc?.z !== null ||\n        rot?.alpha !== null ||\n        rot?.beta !== null ||\n        rot?.gamma !== null;\n      if (e.interval > 0 && hasValues) hasRealData$.set(true);\n    });\n  });\n\n  return {\n    isSupported$,\n    permissionState$,\n    permissionGranted$,\n    needsPermission$,\n    ensurePermission,\n    hasRealData$: hasRealData$ as ReadonlyObservable<boolean>,\n    acceleration$: acceleration$ as ReadonlyObservable<{\n      x: number | null;\n      y: number | null;\n      z: number | null;\n    }>,\n    accelerationIncludingGravity$: accelerationIncludingGravity$ as ReadonlyObservable<{\n      x: number | null;\n      y: number | null;\n      z: number | null;\n    }>,\n    rotationRate$: rotationRate$ as ReadonlyObservable<{\n      alpha: number | null;\n      beta: number | null;\n      gamma: number | null;\n    }>,\n    interval$: interval$ as ReadonlyObservable<number>,\n  };\n}\n"],"mappings":"AAAA,SAAS,OAAO,kBAAmC;AACnD;AAAA,EACE;AAAA,EACA;AAAA,OAKK;AACP,SAAS,2BAAoD;AAC7D,SAAS,2BAA2B;AAAA;AA6C7B,SAAS,mBACd,SACuB;AACvB,QAAM,QAAQ,WAAW,OAAO;AAChC,QAAM,OAAO,oBAAoB,MAAM,MAAwC;AAE/E,QAAM,eAAe,gBAAgB,MAAM;AACzC,UAAM,MAAM,KAAK,IAAI;AACrB,WAAO,CAAC,CAAC,OAAO,uBAAuB;AAAA,EACzC,CAAC;AAGD,QAAM,cAAc;AAAA,IAClB,MACE,OAAO,eAAe,eACtB,OAAQ,WAA+C,sBAAsB,eAC7E,OACG,WAA8C,kBAC/C,sBAAsB;AAAA,EAC5B;AAEA,QAAM,EAAE,kBAAkB,oBAAoB,kBAAkB,iBAAiB,IAC/E,sBAAsB;AAAA,IACpB;AAAA,IACA;AAAA,IACA,mBAAmB,YAAY;AAC7B,YAAM,SAAS,MACZ,WAA8C,kBAC/C,kBAAkB;AACpB,aAAO,WAAW;AAAA,IACpB;AAAA,EACF,CAAC;AAEH,QAAM,gBAAgB,WAAqE;AAAA,IACzF,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,EACL,CAAC;AAED,QAAM,gCAAgC,WAInC,EAAE,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAEhC,QAAM,gBAAgB,WAInB,EAAE,OAAO,MAAM,MAAM,MAAM,OAAO,KAAK,CAAC;AAE3C,QAAM,YAAY,WAAmB,CAAC;AACtC,QAAM,eAAe,WAAoB,KAAK;AAK9C,sBAAoB,MAAM,gBAAgB,CAAC,UAAiB;AAC1D,UAAM,IAAI;AACV,UAAM,MAAM;AACV,YAAM,MAAM,EAAE;AACd,oBAAc,IAAI;AAAA,QAChB,GAAG,KAAK,KAAK;AAAA,QACb,GAAG,KAAK,KAAK;AAAA,QACb,GAAG,KAAK,KAAK;AAAA,MACf,CAAC;AAED,YAAM,UAAU,EAAE;AAClB,oCAA8B,IAAI;AAAA,QAChC,GAAG,SAAS,KAAK;AAAA,QACjB,GAAG,SAAS,KAAK;AAAA,QACjB,GAAG,SAAS,KAAK;AAAA,MACnB,CAAC;AAED,YAAM,MAAM,EAAE;AACd,oBAAc,IAAI;AAAA,QAChB,OAAO,KAAK,SAAS;AAAA,QACrB,MAAM,KAAK,QAAQ;AAAA,QACnB,OAAO,KAAK,SAAS;AAAA,MACvB,CAAC;AAED,gBAAU,IAAI,EAAE,QAAQ;AACxB,YAAM,YACJ,KAAK,MAAM,QACX,KAAK,MAAM,QACX,KAAK,MAAM,QACX,KAAK,UAAU,QACf,KAAK,SAAS,QACd,KAAK,UAAU;AACjB,UAAI,EAAE,WAAW,KAAK,UAAW,cAAa,IAAI,IAAI;AAAA,IACxD,CAAC;AAAA,EACH,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAKA;AAAA,IAKA;AAAA,IAKA;AAAA,EACF;AACF;","names":[]}