@scanly/react 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,30 @@
1
1
  # @scanly/react
2
2
 
3
- Thin lifecycle adapter around `@scanly/browser`. Decoding remains outside React; unmount disposes the browser session and Worker.
3
+ Thin React adapter over `@scanly/browser` for Scanly SDK v2.1.0. Decoding, Worker ownership, camera runtime, tracking, and memory management remain outside React.
4
+
5
+ ```bash
6
+ npm install @scanly/react
7
+ ```
8
+
9
+ ```tsx
10
+ "use client";
11
+ import { useScanly } from "@scanly/react";
12
+
13
+ export function UploadScanner() {
14
+ const { outcome, scanning, scanFile, cancel } = useScanly();
15
+ return <>
16
+ <input type="file" accept="image/*" onChange={(event) => {
17
+ const file = event.currentTarget.files?.[0];
18
+ if (file) void scanFile(file);
19
+ }} />
20
+ <button onClick={cancel} disabled={!scanning}>Cancel</button>
21
+ <output>{outcome?.ok ? outcome.primary.rawText : ""}</output>
22
+ </>;
23
+ }
24
+ ```
25
+
26
+ `useScanly` owns one `BrowserCaptureSession`, starts it after mount, and disposes its session and Worker on unmount. For camera UI, compose `BrowserCameraSource` from `@scanly/browser` in an effect and stop/dispose it in the effect cleanup.
27
+
28
+ This is the standard public React package for React 18 and 19-compatible peer ranges (`>=18 <20`).
29
+
30
+ Version: 2.1.0 · [React usage](https://github.com/Yangjunjie-Lin/Scanly/blob/main/docs/sdk/usage.md)
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,KAAK,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACxH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7E,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,SAAS,CAAC,OAAO,GAAE,4BAAiC,GAAG,eAAe,CAsBrF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,KAAK,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACxH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7E,MAAM,IAAI,IAAI,CAAC;IACf,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,SAAS,CAAC,OAAO,GAAE,4BAAiC,GAAG,eAAe,CA6DrF"}
package/dist/index.js CHANGED
@@ -1,28 +1,72 @@
1
1
  "use client";
2
- import { useCallback, useEffect, useState } from "react";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
3
  import { BrowserCaptureSession } from "@scanly/browser";
4
4
  export function useScanly(options = {}) {
5
5
  const [session] = useState(() => new BrowserCaptureSession(options));
6
6
  const [outcome, setOutcome] = useState(null);
7
7
  const [scanning, setScanning] = useState(false);
8
+ const mounted = useRef(true);
9
+ const stateEpoch = useRef(0);
10
+ const nextCallId = useRef(0);
11
+ const latestCallId = useRef(0);
12
+ const activeCalls = useRef(new Map());
13
+ const lifecycleGeneration = useRef(0);
8
14
  useEffect(() => {
15
+ const calls = activeCalls.current;
16
+ lifecycleGeneration.current += 1;
17
+ mounted.current = true;
18
+ setScanning(calls.size > 0);
9
19
  session.initialize();
10
20
  session.start();
11
- return () => { void session.dispose(); };
21
+ return () => {
22
+ mounted.current = false;
23
+ stateEpoch.current += 1;
24
+ calls.clear();
25
+ session.cancel();
26
+ const cleanupGeneration = ++lifecycleGeneration.current;
27
+ queueMicrotask(() => {
28
+ if (lifecycleGeneration.current === cleanupGeneration)
29
+ void session.dispose();
30
+ });
31
+ };
12
32
  }, [session]);
13
33
  const scanFile = useCallback(async (file, scanOptions = {}) => {
14
- setScanning(true);
34
+ const callId = ++nextCallId.current;
35
+ const epoch = stateEpoch.current;
36
+ latestCallId.current = callId;
37
+ activeCalls.current.set(callId, epoch);
38
+ if (mounted.current)
39
+ setScanning(true);
15
40
  try {
16
41
  const next = await session.scanFile(file, scanOptions);
17
- setOutcome(next);
42
+ if (mounted.current && stateEpoch.current === epoch && latestCallId.current === callId)
43
+ setOutcome(next);
18
44
  return next;
19
45
  }
20
46
  finally {
47
+ if (stateEpoch.current === epoch) {
48
+ activeCalls.current.delete(callId);
49
+ if (mounted.current)
50
+ setScanning(activeCalls.current.size > 0);
51
+ }
52
+ }
53
+ }, [session]);
54
+ const cancel = useCallback(() => {
55
+ stateEpoch.current += 1;
56
+ activeCalls.current.clear();
57
+ session.cancel();
58
+ if (mounted.current)
59
+ setScanning(false);
60
+ }, [session]);
61
+ const reset = useCallback(() => {
62
+ stateEpoch.current += 1;
63
+ activeCalls.current.clear();
64
+ session.cancel();
65
+ if (mounted.current) {
21
66
  setScanning(false);
67
+ setOutcome(null);
22
68
  }
23
69
  }, [session]);
24
- const cancel = useCallback(() => { session.cancel(); setScanning(false); }, [session]);
25
- const reset = useCallback(() => { session.cancel(); setScanning(false); setOutcome(null); }, [session]);
26
70
  return { session, outcome, scanning, scanFile, cancel, reset };
27
71
  }
28
72
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAkE,MAAM,iBAAiB,CAAC;AAYxH,MAAM,UAAU,SAAS,CAAC,UAAwC,EAAE;IAClE,MAAM,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAqB,IAAI,CAAC,CAAC;IACjE,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,UAAU,EAAE,CAAC;QACrB,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACd,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,EAAE,IAAU,EAAE,cAAsC,EAAE,EAAE,EAAE;QAC1F,WAAW,CAAC,IAAI,CAAC,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YACvD,UAAU,CAAC,IAAI,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACd,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACvF,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACxG,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACjE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,33 +1,43 @@
1
- {
2
- "name": "@scanly/react",
3
- "version": "2.0.0",
4
- "description": "React lifecycle adapter for Scanly browser SDK",
5
- "license": "MIT",
6
- "type": "module",
7
- "sideEffects": false,
8
- "main": "./dist/index.js",
9
- "types": "./dist/index.d.ts",
10
- "exports": {
11
- ".": {
12
- "types": "./dist/index.d.ts",
13
- "import": "./dist/index.js"
14
- }
15
- },
16
- "files": [
17
- "dist",
18
- "README.md"
19
- ],
20
- "scripts": {
21
- "build": "tsc -p tsconfig.build.json"
22
- },
23
- "dependencies": {
24
- "@scanly/browser": "2.0.0"
25
- },
26
- "peerDependencies": {
27
- "react": ">=18 <20"
28
- },
29
- "devDependencies": {
30
- "@types/react": "^18.3.3",
31
- "react": "^18.3.1"
32
- }
33
- }
1
+ {
2
+ "name": "@scanly/react",
3
+ "version": "2.1.0",
4
+ "description": "React adapter for the Scanly browser barcode scanning runtime",
5
+ "keywords": ["barcode", "qr-code", "scanner", "react", "hook", "scanly"],
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Yangjunjie-Lin/Scanly.git",
9
+ "directory": "packages/react"
10
+ },
11
+ "homepage": "https://github.com/Yangjunjie-Lin/Scanly#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/Yangjunjie-Lin/Scanly/issues"
14
+ },
15
+ "license": "MIT",
16
+ "type": "module",
17
+ "sideEffects": false,
18
+ "main": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsc -p tsconfig.build.json"
32
+ },
33
+ "dependencies": {
34
+ "@scanly/browser": "2.1.0"
35
+ },
36
+ "peerDependencies": {
37
+ "react": ">=18 <20"
38
+ },
39
+ "devDependencies": {
40
+ "@types/react": "^18.3.3",
41
+ "react": "^18.3.1"
42
+ }
43
+ }