1{"version":3,"file":"useWebQRScanner.js","sourceRoot":"","sources":["../src/useWebQRScanner.ts"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react';\n\nimport { BarCodeScanningResult, CameraPictureOptions, MountErrorListener } from './Camera.types';\nimport { captureImageData } from './WebCameraUtils';\n\nconst qrWorkerMethod = ({ data, width, height }: ImageData): any => {\n  // eslint-disable-next-line no-undef\n  const decoded = (self as any).jsQR(data, width, height, {\n    inversionAttempts: 'attemptBoth',\n  });\n\n  let parsed;\n  try {\n    parsed = JSON.parse(decoded);\n  } catch {\n    parsed = decoded;\n  }\n\n  if (parsed?.data) {\n    const nativeEvent: BarCodeScanningResult = {\n      type: 'qr',\n      data: parsed.data,\n      cornerPoints: [],\n      bounds: { origin: { x: 0, y: 0 }, size: { width: 0, height: 0 } },\n    };\n    if (parsed.location) {\n      nativeEvent.cornerPoints = [\n        parsed.location.topLeftCorner,\n        parsed.location.bottomLeftCorner,\n        parsed.location.topRightCorner,\n        parsed.location.bottomRightCorner,\n      ];\n    }\n    return nativeEvent;\n  }\n  return parsed;\n};\n\nconst createWorkerAsyncFunction = <T extends (data: any) => any>(fn: T, deps: string[]) => {\n  const stringifiedFn = [\n    `self.func = ${fn.toString()};`,\n    'self.onmessage = (e) => {',\n    '  const result = self.func(e.data);',\n    '  self.postMessage(result);',\n    '};',\n  ];\n\n  if (deps.length > 0) {\n    stringifiedFn.unshift(`importScripts(${deps.map((dep) => `'${dep}'`).join(', ')});`);\n  }\n\n  const blob = new Blob(stringifiedFn, { type: 'text/javascript' });\n  const worker = new Worker(URL.createObjectURL(blob));\n\n  // First-In First-Out queue of promises\n  const promises: {\n    resolve: (value: ReturnType<T>) => void;\n    reject: (reason?: any) => void;\n  }[] = [];\n\n  worker.onmessage = (e) => promises.shift()?.resolve(e.data);\n\n  return (data: Parameters<T>[0]) => {\n    return new Promise<ReturnType<T>>((resolve, reject) => {\n      promises.push({ resolve, reject });\n      worker.postMessage(data);\n    });\n  };\n};\n\nconst decode = createWorkerAsyncFunction(qrWorkerMethod, [\n  'https://cdn.jsdelivr.net/npm/[email protected]/dist/jsQR.min.js',\n]);\n\nexport function useWebQRScanner(\n  video: React.MutableRefObject<HTMLVideoElement | null>,\n  {\n    isEnabled,\n    captureOptions,\n    interval,\n    onScanned,\n    onError,\n  }: {\n    isEnabled: boolean;\n    captureOptions: Pick<CameraPictureOptions, 'scale' | 'isImageMirror'>;\n    interval?: number;\n    onScanned?: (scanningResult: { nativeEvent: BarCodeScanningResult }) => void;\n    onError?: MountErrorListener;\n  }\n) {\n  const isRunning = React.useRef<boolean>(false);\n  const timeout = React.useRef<number | undefined>(undefined);\n\n  async function scanAsync() {\n    // If interval is 0 then only scan once.\n    if (!isRunning.current || !onScanned) {\n      stop();\n      return;\n    }\n    try {\n      const data = captureImageData(video.current, captureOptions);\n\n      if (data) {\n        const nativeEvent: BarCodeScanningResult | any = await decode(data);\n        if (nativeEvent?.data) {\n          onScanned({\n            nativeEvent,\n          });\n        }\n      }\n    } catch (error) {\n      if (onError) {\n        onError({ nativeEvent: error });\n      }\n    } finally {\n      // If interval is 0 then only scan once.\n      if (interval === 0) {\n        stop();\n        return;\n      }\n      const intervalToUse = !interval || interval < 0 ? 16 : interval;\n      // @ts-ignore: Type 'Timeout' is not assignable to type 'number'\n      timeout.current = setTimeout(() => {\n        scanAsync();\n      }, intervalToUse);\n    }\n  }\n\n  function stop() {\n    isRunning.current = false;\n    clearTimeout(timeout.current);\n  }\n\n  React.useEffect(() => {\n    if (isEnabled) {\n      isRunning.current = true;\n      scanAsync();\n    }\n\n    return () => {\n      if (isEnabled) {\n        stop();\n      }\n    };\n  }, [isEnabled]);\n}\n"]}