@pallasoft/ps-file-components 1.3.0 → 1.5.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.
Files changed (216) hide show
  1. package/dist/components/ps-document-scanner-loader.d.ts +1 -0
  2. package/dist/components/ps-document-scanner-loader.js +40 -0
  3. package/dist/components/ps-document-scanner-sheet.d.ts +2 -0
  4. package/dist/components/ps-document-scanner-sheet.js +186 -0
  5. package/dist/components/ps-document-scanner.d.ts +2 -0
  6. package/dist/components/ps-document-scanner.js +17 -0
  7. package/dist/components/ps-file-picker-actions.d.ts +10 -0
  8. package/dist/components/ps-file-picker-actions.js +21 -0
  9. package/dist/components/ps-file-picker.d.ts +7 -1
  10. package/dist/components/ps-file-picker.js +30 -6
  11. package/dist/components/ps-file-viewer-pane.d.ts +2 -0
  12. package/dist/components/ps-file-viewer-pane.js +39 -0
  13. package/dist/components/ps-scan-button.d.ts +13 -0
  14. package/dist/components/ps-scan-button.js +9 -0
  15. package/dist/components/ps-scan-camera-view.d.ts +27 -0
  16. package/dist/components/ps-scan-camera-view.js +34 -0
  17. package/dist/components/ps-scan-crop-editor.d.ts +13 -0
  18. package/dist/components/ps-scan-crop-editor.js +69 -0
  19. package/dist/components/ps-scan-denied-steps.d.ts +6 -0
  20. package/dist/components/ps-scan-denied-steps.js +33 -0
  21. package/dist/components/ps-scan-icon-button.d.ts +11 -0
  22. package/dist/components/ps-scan-icon-button.js +9 -0
  23. package/dist/components/ps-scan-illustration.d.ts +1 -0
  24. package/dist/components/ps-scan-illustration.js +6 -0
  25. package/dist/components/ps-scan-loupe.d.ts +10 -0
  26. package/dist/components/ps-scan-loupe.js +31 -0
  27. package/dist/components/ps-scan-page-list.d.ts +14 -0
  28. package/dist/components/ps-scan-page-list.js +22 -0
  29. package/dist/components/ps-scan-page-stack.d.ts +7 -0
  30. package/dist/components/ps-scan-page-stack.js +6 -0
  31. package/dist/components/ps-scan-permission-view.d.ts +11 -0
  32. package/dist/components/ps-scan-permission-view.js +48 -0
  33. package/dist/components/ps-scan-photo-button.d.ts +8 -0
  34. package/dist/components/ps-scan-photo-button.js +20 -0
  35. package/dist/components/ps-scan-review.d.ts +24 -0
  36. package/dist/components/ps-scan-review.js +37 -0
  37. package/dist/components/ps-scan-shutter.d.ts +7 -0
  38. package/dist/components/ps-scan-shutter.js +6 -0
  39. package/dist/components/ps-scan-viewfinder-overlay.d.ts +8 -0
  40. package/dist/components/ps-scan-viewfinder-overlay.js +28 -0
  41. package/dist/components/ps-upload-row.js +1 -1
  42. package/dist/constants/ps-document-scanner-labels.d.ts +80 -0
  43. package/dist/constants/ps-document-scanner-labels.js +83 -0
  44. package/dist/constants/ps-file-picker-labels.d.ts +5 -3
  45. package/dist/constants/ps-file-picker-labels.js +5 -3
  46. package/dist/constants/ps-scan-camera-status.d.ts +11 -0
  47. package/dist/constants/ps-scan-camera-status.js +13 -0
  48. package/dist/constants/ps-scan-chrome-classes.d.ts +12 -0
  49. package/dist/constants/ps-scan-chrome-classes.js +15 -0
  50. package/dist/constants/ps-scan-config.d.ts +48 -0
  51. package/dist/constants/ps-scan-config.js +51 -0
  52. package/dist/constants/ps-scan-corner-order.d.ts +1 -0
  53. package/dist/constants/ps-scan-corner-order.js +4 -0
  54. package/dist/constants/ps-scan-filter.d.ts +7 -0
  55. package/dist/constants/ps-scan-filter.js +9 -0
  56. package/dist/constants/ps-scan-output-format.d.ts +5 -0
  57. package/dist/constants/ps-scan-output-format.js +7 -0
  58. package/dist/constants/ps-scan-platform.d.ts +6 -0
  59. package/dist/constants/ps-scan-platform.js +8 -0
  60. package/dist/constants/ps-scan-step.d.ts +6 -0
  61. package/dist/constants/ps-scan-step.js +8 -0
  62. package/dist/esm/components/ps-document-scanner-loader.js +4 -0
  63. package/dist/esm/components/ps-document-scanner-sheet.js +182 -0
  64. package/dist/esm/components/ps-document-scanner.js +13 -0
  65. package/dist/esm/components/ps-file-picker-actions.js +17 -0
  66. package/dist/esm/components/ps-file-picker.js +31 -7
  67. package/dist/esm/components/ps-file-viewer-pane.js +35 -0
  68. package/dist/esm/components/ps-scan-button.js +5 -0
  69. package/dist/esm/components/ps-scan-camera-view.js +30 -0
  70. package/dist/esm/components/ps-scan-crop-editor.js +65 -0
  71. package/dist/esm/components/ps-scan-denied-steps.js +29 -0
  72. package/dist/esm/components/ps-scan-icon-button.js +5 -0
  73. package/dist/esm/components/ps-scan-illustration.js +2 -0
  74. package/dist/esm/components/ps-scan-loupe.js +27 -0
  75. package/dist/esm/components/ps-scan-page-list.js +18 -0
  76. package/dist/esm/components/ps-scan-page-stack.js +2 -0
  77. package/dist/esm/components/ps-scan-permission-view.js +44 -0
  78. package/dist/esm/components/ps-scan-photo-button.js +16 -0
  79. package/dist/esm/components/ps-scan-review.js +33 -0
  80. package/dist/esm/components/ps-scan-shutter.js +2 -0
  81. package/dist/esm/components/ps-scan-viewfinder-overlay.js +24 -0
  82. package/dist/esm/components/ps-upload-row.js +1 -1
  83. package/dist/esm/constants/ps-document-scanner-labels.js +80 -0
  84. package/dist/esm/constants/ps-file-picker-labels.js +5 -3
  85. package/dist/esm/constants/ps-scan-camera-status.js +10 -0
  86. package/dist/esm/constants/ps-scan-chrome-classes.js +12 -0
  87. package/dist/esm/constants/ps-scan-config.js +48 -0
  88. package/dist/esm/constants/ps-scan-corner-order.js +1 -0
  89. package/dist/esm/constants/ps-scan-filter.js +6 -0
  90. package/dist/esm/constants/ps-scan-output-format.js +4 -0
  91. package/dist/esm/constants/ps-scan-platform.js +5 -0
  92. package/dist/esm/constants/ps-scan-step.js +5 -0
  93. package/dist/esm/hooks/use-ps-focus-trap.js +45 -0
  94. package/dist/esm/hooks/use-ps-scan-camera.js +99 -0
  95. package/dist/esm/hooks/use-ps-scan-live-detection.js +45 -0
  96. package/dist/esm/hooks/use-ps-scan-pages.js +62 -0
  97. package/dist/esm/hooks/use-ps-scan-previews.js +57 -0
  98. package/dist/esm/index.js +8 -0
  99. package/dist/esm/models/ps-document-scanner-props.js +1 -0
  100. package/dist/esm/models/ps-document-scanner-sheet-props.js +1 -0
  101. package/dist/esm/models/ps-file-picker-scan.js +1 -0
  102. package/dist/esm/models/ps-file-viewer-pane-props.js +1 -0
  103. package/dist/esm/models/ps-scan-added-page.js +1 -0
  104. package/dist/esm/models/ps-scan-camera-session.js +1 -0
  105. package/dist/esm/models/ps-scan-decoded-image.js +1 -0
  106. package/dist/esm/models/ps-scan-levels.js +1 -0
  107. package/dist/esm/models/ps-scan-live-detection.js +1 -0
  108. package/dist/esm/models/ps-scan-output-options.js +1 -0
  109. package/dist/esm/models/ps-scan-page.js +1 -0
  110. package/dist/esm/models/ps-scan-pdf-page.js +1 -0
  111. package/dist/esm/models/ps-scan-prepared.js +1 -0
  112. package/dist/esm/models/ps-scan-quad.js +1 -0
  113. package/dist/esm/models/ps-scan-raster.js +1 -0
  114. package/dist/esm/models/ps-scan-rendered-page.js +1 -0
  115. package/dist/esm/models/ps-scan-stability.js +1 -0
  116. package/dist/esm/services/ps-scan-camera-service.js +95 -0
  117. package/dist/esm/services/ps-scan-canvas-service.js +52 -0
  118. package/dist/esm/services/ps-scan-edge-service.js +156 -0
  119. package/dist/esm/services/ps-scan-enhance-service.js +97 -0
  120. package/dist/esm/services/ps-scan-file-name-service.js +25 -0
  121. package/dist/esm/services/ps-scan-geometry-service.js +116 -0
  122. package/dist/esm/services/ps-scan-homography-service.js +46 -0
  123. package/dist/esm/services/ps-scan-hull-service.js +59 -0
  124. package/dist/esm/services/ps-scan-image-filter-service.js +52 -0
  125. package/dist/esm/services/ps-scan-order-service.js +13 -0
  126. package/dist/esm/services/ps-scan-output-service.js +24 -0
  127. package/dist/esm/services/ps-scan-pdf-service.js +56 -0
  128. package/dist/esm/services/ps-scan-pipeline-service.js +40 -0
  129. package/dist/esm/services/ps-scan-platform-service.js +15 -0
  130. package/dist/esm/services/ps-scan-raster-service.js +67 -0
  131. package/dist/esm/services/ps-scan-stability-service.js +41 -0
  132. package/dist/esm/services/ps-scan-template-service.js +5 -0
  133. package/dist/esm/services/ps-scan-warp-service.js +35 -0
  134. package/dist/hooks/use-ps-focus-trap.d.ts +2 -0
  135. package/dist/hooks/use-ps-focus-trap.js +49 -0
  136. package/dist/hooks/use-ps-scan-camera.d.ts +11 -0
  137. package/dist/hooks/use-ps-scan-camera.js +103 -0
  138. package/dist/hooks/use-ps-scan-live-detection.d.ts +3 -0
  139. package/dist/hooks/use-ps-scan-live-detection.js +49 -0
  140. package/dist/hooks/use-ps-scan-pages.d.ts +12 -0
  141. package/dist/hooks/use-ps-scan-pages.js +66 -0
  142. package/dist/hooks/use-ps-scan-previews.d.ts +2 -0
  143. package/dist/hooks/use-ps-scan-previews.js +61 -0
  144. package/dist/index.d.ts +8 -0
  145. package/dist/index.js +8 -0
  146. package/dist/models/ps-document-scanner-props.d.ts +16 -0
  147. package/dist/models/ps-document-scanner-props.js +2 -0
  148. package/dist/models/ps-document-scanner-sheet-props.d.ts +14 -0
  149. package/dist/models/ps-document-scanner-sheet-props.js +2 -0
  150. package/dist/models/ps-file-picker-scan.d.ts +4 -0
  151. package/dist/models/ps-file-picker-scan.js +2 -0
  152. package/dist/models/ps-file-viewer-pane-props.d.ts +12 -0
  153. package/dist/models/ps-file-viewer-pane-props.js +2 -0
  154. package/dist/models/ps-scan-added-page.d.ts +5 -0
  155. package/dist/models/ps-scan-added-page.js +2 -0
  156. package/dist/models/ps-scan-camera-session.d.ts +5 -0
  157. package/dist/models/ps-scan-camera-session.js +2 -0
  158. package/dist/models/ps-scan-decoded-image.d.ts +6 -0
  159. package/dist/models/ps-scan-decoded-image.js +2 -0
  160. package/dist/models/ps-scan-levels.d.ts +4 -0
  161. package/dist/models/ps-scan-levels.js +2 -0
  162. package/dist/models/ps-scan-live-detection.d.ts +5 -0
  163. package/dist/models/ps-scan-live-detection.js +2 -0
  164. package/dist/models/ps-scan-output-options.d.ts +7 -0
  165. package/dist/models/ps-scan-output-options.js +2 -0
  166. package/dist/models/ps-scan-page.d.ts +12 -0
  167. package/dist/models/ps-scan-page.js +2 -0
  168. package/dist/models/ps-scan-pdf-page.d.ts +5 -0
  169. package/dist/models/ps-scan-pdf-page.js +2 -0
  170. package/dist/models/ps-scan-prepared.d.ts +7 -0
  171. package/dist/models/ps-scan-prepared.js +2 -0
  172. package/dist/models/ps-scan-quad.d.ts +2 -0
  173. package/dist/models/ps-scan-quad.js +2 -0
  174. package/dist/models/ps-scan-raster.d.ts +5 -0
  175. package/dist/models/ps-scan-raster.js +2 -0
  176. package/dist/models/ps-scan-rendered-page.d.ts +5 -0
  177. package/dist/models/ps-scan-rendered-page.js +2 -0
  178. package/dist/models/ps-scan-stability.d.ts +8 -0
  179. package/dist/models/ps-scan-stability.js +2 -0
  180. package/dist/services/ps-scan-camera-service.d.ts +14 -0
  181. package/dist/services/ps-scan-camera-service.js +99 -0
  182. package/dist/services/ps-scan-canvas-service.d.ts +9 -0
  183. package/dist/services/ps-scan-canvas-service.js +56 -0
  184. package/dist/services/ps-scan-edge-service.d.ts +9 -0
  185. package/dist/services/ps-scan-edge-service.js +160 -0
  186. package/dist/services/ps-scan-enhance-service.d.ts +9 -0
  187. package/dist/services/ps-scan-enhance-service.js +101 -0
  188. package/dist/services/ps-scan-file-name-service.d.ts +6 -0
  189. package/dist/services/ps-scan-file-name-service.js +29 -0
  190. package/dist/services/ps-scan-geometry-service.d.ts +20 -0
  191. package/dist/services/ps-scan-geometry-service.js +120 -0
  192. package/dist/services/ps-scan-homography-service.d.ts +7 -0
  193. package/dist/services/ps-scan-homography-service.js +50 -0
  194. package/dist/services/ps-scan-hull-service.d.ts +6 -0
  195. package/dist/services/ps-scan-hull-service.js +63 -0
  196. package/dist/services/ps-scan-image-filter-service.d.ts +6 -0
  197. package/dist/services/ps-scan-image-filter-service.js +56 -0
  198. package/dist/services/ps-scan-order-service.d.ts +4 -0
  199. package/dist/services/ps-scan-order-service.js +17 -0
  200. package/dist/services/ps-scan-output-service.d.ts +5 -0
  201. package/dist/services/ps-scan-output-service.js +28 -0
  202. package/dist/services/ps-scan-pdf-service.d.ts +5 -0
  203. package/dist/services/ps-scan-pdf-service.js +60 -0
  204. package/dist/services/ps-scan-pipeline-service.d.ts +10 -0
  205. package/dist/services/ps-scan-pipeline-service.js +44 -0
  206. package/dist/services/ps-scan-platform-service.d.ts +4 -0
  207. package/dist/services/ps-scan-platform-service.js +19 -0
  208. package/dist/services/ps-scan-raster-service.d.ts +6 -0
  209. package/dist/services/ps-scan-raster-service.js +71 -0
  210. package/dist/services/ps-scan-stability-service.d.ts +9 -0
  211. package/dist/services/ps-scan-stability-service.js +45 -0
  212. package/dist/services/ps-scan-template-service.d.ts +3 -0
  213. package/dist/services/ps-scan-template-service.js +9 -0
  214. package/dist/services/ps-scan-warp-service.d.ts +6 -0
  215. package/dist/services/ps-scan-warp-service.js +39 -0
  216. package/package.json +9 -6
@@ -0,0 +1,35 @@
1
+ import { PsScanHomographyService } from './ps-scan-homography-service';
2
+ import { PsScanRasterService } from './ps-scan-raster-service';
3
+ export class PsScanWarpService {
4
+ static warp(source, pixelQuad, width, height) {
5
+ const matrix = PsScanHomographyService.fromUnitSquare(pixelQuad);
6
+ const target = PsScanRasterService.create(width, height);
7
+ const spanX = Math.max(1, width - 1);
8
+ const spanY = Math.max(1, height - 1);
9
+ for (let y = 0; y < height; y += 1)
10
+ for (let x = 0; x < width; x += 1) {
11
+ const point = PsScanHomographyService.apply(matrix, x / spanX, y / spanY);
12
+ PsScanWarpService.sample(source, point.x, point.y, target.data, (y * width + x) * 4);
13
+ }
14
+ return target;
15
+ }
16
+ static sample(source, x, y, out, at) {
17
+ const cx = Math.min(source.width - 1, Math.max(0, x));
18
+ const cy = Math.min(source.height - 1, Math.max(0, y));
19
+ const x0 = Math.floor(cx);
20
+ const y0 = Math.floor(cy);
21
+ const x1 = Math.min(source.width - 1, x0 + 1);
22
+ const y1 = Math.min(source.height - 1, y0 + 1);
23
+ const fx = cx - x0;
24
+ const fy = cy - y0;
25
+ const a = (y0 * source.width + x0) * 4;
26
+ const b = (y0 * source.width + x1) * 4;
27
+ const c = (y1 * source.width + x0) * 4;
28
+ const d = (y1 * source.width + x1) * 4;
29
+ for (let channel = 0; channel < 4; channel += 1) {
30
+ const top = source.data[a + channel] * (1 - fx) + source.data[b + channel] * fx;
31
+ const bottom = source.data[c + channel] * (1 - fx) + source.data[d + channel] * fx;
32
+ out[at + channel] = top * (1 - fy) + bottom * fy;
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,2 @@
1
+ import { type RefObject } from 'react';
2
+ export declare const usePsFocusTrap: (ref: RefObject<HTMLElement | null>, isActive: boolean, onEscape: () => void) => void;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePsFocusTrap = void 0;
4
+ const react_1 = require("react");
5
+ const usePsFocusTrap = (ref, isActive, onEscape) => {
6
+ (0, react_1.useEffect)(() => {
7
+ if (!isActive || ref.current === null)
8
+ return;
9
+ const dialog = ref.current.closest('[role="dialog"]');
10
+ const root = dialog === null ? ref.current : dialog;
11
+ const focusable = () => Array.from(root.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), [tabindex]:not([tabindex="-1"])')).filter((element) => element.offsetParent !== null || element === document.activeElement);
12
+ if (!root.contains(document.activeElement)) {
13
+ root.setAttribute('tabindex', '-1');
14
+ root.focus({ preventScroll: true });
15
+ }
16
+ const onKeyDown = (event) => {
17
+ if (event.key === 'Escape') {
18
+ event.stopPropagation();
19
+ onEscape();
20
+ return;
21
+ }
22
+ if (event.key !== 'Tab')
23
+ return;
24
+ const items = focusable();
25
+ if (items.length === 0) {
26
+ event.preventDefault();
27
+ return;
28
+ }
29
+ const first = items[0];
30
+ const last = items[items.length - 1];
31
+ const current = document.activeElement;
32
+ if (!root.contains(current)) {
33
+ event.preventDefault();
34
+ first.focus();
35
+ }
36
+ else if (event.shiftKey && (current === first || current === root)) {
37
+ event.preventDefault();
38
+ last.focus();
39
+ }
40
+ else if (!event.shiftKey && current === last) {
41
+ event.preventDefault();
42
+ first.focus();
43
+ }
44
+ };
45
+ document.addEventListener('keydown', onKeyDown, true);
46
+ return () => document.removeEventListener('keydown', onKeyDown, true);
47
+ }, [isActive, onEscape]);
48
+ };
49
+ exports.usePsFocusTrap = usePsFocusTrap;
@@ -0,0 +1,11 @@
1
+ import { PsScanCameraStatus } from '../constants/ps-scan-camera-status';
2
+ export declare const usePsScanCamera: (isActive: boolean) => {
3
+ allow: () => void;
4
+ attachVideo: (element: HTMLVideoElement | null) => void;
5
+ canTorch: boolean;
6
+ capture: () => Promise<Blob | null>;
7
+ isTorchOn: boolean;
8
+ status: PsScanCameraStatus;
9
+ toggleTorch: () => Promise<void>;
10
+ videoRef: import("react").MutableRefObject<HTMLVideoElement | null>;
11
+ };
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePsScanCamera = void 0;
4
+ const react_1 = require("react");
5
+ const ps_scan_camera_status_1 = require("../constants/ps-scan-camera-status");
6
+ const ps_scan_config_1 = require("../constants/ps-scan-config");
7
+ const ps_scan_camera_service_1 = require("../services/ps-scan-camera-service");
8
+ const ps_scan_canvas_service_1 = require("../services/ps-scan-canvas-service");
9
+ const usePsScanCamera = (isActive) => {
10
+ const videoRef = (0, react_1.useRef)(null);
11
+ const sessionRef = (0, react_1.useRef)(null);
12
+ const [status, setStatus] = (0, react_1.useState)(ps_scan_camera_status_1.PsScanCameraStatus.Checking);
13
+ const [request, setRequest] = (0, react_1.useState)(0);
14
+ const [canTorch, setCanTorch] = (0, react_1.useState)(false);
15
+ const [isTorchOn, setIsTorchOn] = (0, react_1.useState)(false);
16
+ (0, react_1.useEffect)(() => {
17
+ let isCancelled = false;
18
+ let permission = null;
19
+ const onChange = () => {
20
+ if (permission !== null && permission.state === 'granted')
21
+ setRequest((current) => current + 1);
22
+ };
23
+ ps_scan_camera_service_1.PsScanCameraService.check().then(async (next) => {
24
+ if (isCancelled)
25
+ return;
26
+ if (next === ps_scan_camera_status_1.PsScanCameraStatus.Starting)
27
+ setRequest(1);
28
+ else
29
+ setStatus(next);
30
+ permission = await ps_scan_camera_service_1.PsScanCameraService.permission();
31
+ if (isCancelled || permission === null)
32
+ return;
33
+ permission.addEventListener('change', onChange);
34
+ });
35
+ return () => {
36
+ isCancelled = true;
37
+ if (permission !== null)
38
+ permission.removeEventListener('change', onChange);
39
+ };
40
+ }, []);
41
+ (0, react_1.useEffect)(() => {
42
+ if (!isActive || request === 0)
43
+ return;
44
+ let isCancelled = false;
45
+ setIsTorchOn(false);
46
+ setStatus(ps_scan_camera_status_1.PsScanCameraStatus.Starting);
47
+ ps_scan_camera_service_1.PsScanCameraService.open()
48
+ .then(async (session) => {
49
+ if (isCancelled) {
50
+ ps_scan_camera_service_1.PsScanCameraService.stop(session.stream);
51
+ return;
52
+ }
53
+ sessionRef.current = session;
54
+ setCanTorch(session.canTorch);
55
+ if (videoRef.current !== null)
56
+ await ps_scan_camera_service_1.PsScanCameraService.attach(videoRef.current, session);
57
+ if (!isCancelled)
58
+ setStatus(ps_scan_camera_status_1.PsScanCameraStatus.Ready);
59
+ })
60
+ .catch((error) => {
61
+ if (!isCancelled)
62
+ setStatus(ps_scan_camera_service_1.PsScanCameraService.classify(error));
63
+ });
64
+ return () => {
65
+ isCancelled = true;
66
+ ps_scan_camera_service_1.PsScanCameraService.stop(sessionRef.current === null ? null : sessionRef.current.stream);
67
+ sessionRef.current = null;
68
+ if (videoRef.current !== null)
69
+ videoRef.current.srcObject = null;
70
+ };
71
+ }, [isActive, request]);
72
+ const attachVideo = (0, react_1.useCallback)((element) => {
73
+ videoRef.current = element;
74
+ if (element !== null && sessionRef.current !== null)
75
+ void ps_scan_camera_service_1.PsScanCameraService.attach(element, sessionRef.current);
76
+ }, []);
77
+ const allow = (0, react_1.useCallback)(() => setRequest((current) => current + 1), []);
78
+ const toggleTorch = (0, react_1.useCallback)(async () => {
79
+ const session = sessionRef.current;
80
+ if (session === null)
81
+ return;
82
+ setIsTorchOn(await ps_scan_camera_service_1.PsScanCameraService.setTorch(session.track, !isTorchOn));
83
+ }, [isTorchOn]);
84
+ const capture = (0, react_1.useCallback)(async () => {
85
+ const video = videoRef.current;
86
+ if (video === null ||
87
+ video.videoWidth === 0 ||
88
+ video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA)
89
+ return null;
90
+ return await ps_scan_canvas_service_1.PsScanCanvasService.fromVideo(video, ps_scan_config_1.PsScanConfig.capturedJpegQuality);
91
+ }, []);
92
+ return {
93
+ allow,
94
+ attachVideo,
95
+ canTorch,
96
+ capture,
97
+ isTorchOn,
98
+ status,
99
+ toggleTorch,
100
+ videoRef,
101
+ };
102
+ };
103
+ exports.usePsScanCamera = usePsScanCamera;
@@ -0,0 +1,3 @@
1
+ import { type RefObject } from 'react';
2
+ import type { PsScanLiveDetection } from '../models/ps-scan-live-detection';
3
+ export declare const usePsScanLiveDetection: (videoRef: RefObject<HTMLVideoElement | null>, isActive: boolean, isAuto: boolean, onSteady: () => void) => PsScanLiveDetection;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePsScanLiveDetection = void 0;
4
+ const react_1 = require("react");
5
+ const ps_scan_config_1 = require("../constants/ps-scan-config");
6
+ const ps_scan_canvas_service_1 = require("../services/ps-scan-canvas-service");
7
+ const ps_scan_edge_service_1 = require("../services/ps-scan-edge-service");
8
+ const ps_scan_stability_service_1 = require("../services/ps-scan-stability-service");
9
+ const usePsScanLiveDetection = (videoRef, isActive, isAuto, onSteady) => {
10
+ const [detection, setDetection] = (0, react_1.useState)({ progress: 0, quad: null });
11
+ const isAutoRef = (0, react_1.useRef)(isAuto);
12
+ const onSteadyRef = (0, react_1.useRef)(onSteady);
13
+ isAutoRef.current = isAuto;
14
+ onSteadyRef.current = onSteady;
15
+ (0, react_1.useEffect)(() => {
16
+ if (!isActive) {
17
+ setDetection({ progress: 0, quad: null });
18
+ return;
19
+ }
20
+ let state = ps_scan_stability_service_1.PsScanStabilityService.initial();
21
+ let last = performance.now();
22
+ let timer;
23
+ const tick = () => {
24
+ const video = videoRef.current;
25
+ const now = performance.now();
26
+ if (video !== null && video.videoWidth > 0 && document.visibilityState === 'visible') {
27
+ try {
28
+ const raster = ps_scan_canvas_service_1.PsScanCanvasService.sample(video, ps_scan_config_1.PsScanConfig.liveDetectMaxDimension);
29
+ state = ps_scan_stability_service_1.PsScanStabilityService.next(state, ps_scan_edge_service_1.PsScanEdgeService.detect(raster), now - last);
30
+ }
31
+ catch {
32
+ state = ps_scan_stability_service_1.PsScanStabilityService.initial();
33
+ }
34
+ const progress = isAutoRef.current ? ps_scan_stability_service_1.PsScanStabilityService.progress(state) : 0;
35
+ setDetection({ progress, quad: state.quad });
36
+ if (progress >= 1) {
37
+ state = ps_scan_stability_service_1.PsScanStabilityService.disarm(state);
38
+ onSteadyRef.current();
39
+ }
40
+ }
41
+ last = now;
42
+ timer = setTimeout(tick, ps_scan_config_1.PsScanConfig.liveDetectIntervalMs);
43
+ };
44
+ timer = setTimeout(tick, ps_scan_config_1.PsScanConfig.liveDetectIntervalMs);
45
+ return () => clearTimeout(timer);
46
+ }, [isActive]);
47
+ return detection;
48
+ };
49
+ exports.usePsScanLiveDetection = usePsScanLiveDetection;
@@ -0,0 +1,12 @@
1
+ import type { PsScanAddedPage } from '../models/ps-scan-added-page';
2
+ import type { PsScanPage } from '../models/ps-scan-page';
3
+ import type { PsScanQuad } from '../models/ps-scan-quad';
4
+ export declare const usePsScanPages: () => {
5
+ add: (sources: Blob[]) => Promise<PsScanAddedPage[]>;
6
+ move: (from: number, to: number) => void;
7
+ pages: PsScanPage[];
8
+ remove: (id: string) => void;
9
+ replace: (id: string, source: Blob) => Promise<PsScanAddedPage>;
10
+ setCorners: (id: string, corners: PsScanQuad) => void;
11
+ update: (id: string, patch: Partial<Pick<PsScanPage, "corners" | "filter" | "rotation">>) => void;
12
+ };
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePsScanPages = void 0;
4
+ const react_1 = require("react");
5
+ const ps_scan_filter_1 = require("../constants/ps-scan-filter");
6
+ const ps_scan_order_service_1 = require("../services/ps-scan-order-service");
7
+ const ps_scan_pipeline_service_1 = require("../services/ps-scan-pipeline-service");
8
+ const usePsScanPages = () => {
9
+ const [pages, setPages] = (0, react_1.useState)([]);
10
+ const urls = (0, react_1.useRef)(new Set());
11
+ const counter = (0, react_1.useRef)(0);
12
+ (0, react_1.useEffect)(() => () => {
13
+ urls.current.forEach((url) => URL.revokeObjectURL(url));
14
+ urls.current.clear();
15
+ }, []);
16
+ const build = (0, react_1.useCallback)(async (source) => {
17
+ const prepared = await ps_scan_pipeline_service_1.PsScanPipelineService.prepare(source);
18
+ const sourceUrl = URL.createObjectURL(source);
19
+ counter.current += 1;
20
+ urls.current.add(sourceUrl);
21
+ return {
22
+ isDetected: prepared.isDetected,
23
+ page: {
24
+ corners: prepared.corners,
25
+ filter: ps_scan_filter_1.PsScanFilter.Document,
26
+ height: prepared.height,
27
+ id: `scan-page-${counter.current}`,
28
+ rotation: 0,
29
+ source,
30
+ sourceUrl,
31
+ width: prepared.width,
32
+ },
33
+ };
34
+ }, []);
35
+ const add = (0, react_1.useCallback)(async (sources) => {
36
+ const built = [];
37
+ for (const source of sources)
38
+ built.push(await build(source));
39
+ setPages((current) => [...current, ...built.map((item) => item.page)]);
40
+ return built;
41
+ }, [build]);
42
+ const replace = (0, react_1.useCallback)(async (id, source) => {
43
+ const built = await build(source);
44
+ setPages((current) => current.map((page) => {
45
+ if (page.id !== id)
46
+ return page;
47
+ URL.revokeObjectURL(page.sourceUrl);
48
+ urls.current.delete(page.sourceUrl);
49
+ return { ...built.page, filter: page.filter, id: page.id };
50
+ }));
51
+ return built;
52
+ }, [build]);
53
+ const update = (0, react_1.useCallback)((id, patch) => setPages((current) => current.map((page) => (page.id === id ? { ...page, ...patch } : page))), []);
54
+ const setCorners = (0, react_1.useCallback)((id, corners) => update(id, { corners }), [update]);
55
+ const remove = (0, react_1.useCallback)((id) => setPages((current) => {
56
+ const target = current.find((page) => page.id === id);
57
+ if (target !== undefined) {
58
+ URL.revokeObjectURL(target.sourceUrl);
59
+ urls.current.delete(target.sourceUrl);
60
+ }
61
+ return current.filter((page) => page.id !== id);
62
+ }), []);
63
+ const move = (0, react_1.useCallback)((from, to) => setPages((current) => ps_scan_order_service_1.PsScanOrderService.move(current, from, to)), []);
64
+ return { add, move, pages, remove, replace, setCorners, update };
65
+ };
66
+ exports.usePsScanPages = usePsScanPages;
@@ -0,0 +1,2 @@
1
+ import type { PsScanPage } from '../models/ps-scan-page';
2
+ export declare const usePsScanPreviews: (pages: PsScanPage[]) => Record<string, string>;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePsScanPreviews = void 0;
4
+ const react_1 = require("react");
5
+ const ps_scan_config_1 = require("../constants/ps-scan-config");
6
+ const ps_scan_canvas_service_1 = require("../services/ps-scan-canvas-service");
7
+ const ps_scan_pipeline_service_1 = require("../services/ps-scan-pipeline-service");
8
+ const usePsScanPreviews = (pages) => {
9
+ const rasters = (0, react_1.useRef)(new Map());
10
+ const urls = (0, react_1.useRef)(new Map());
11
+ const [previews, setPreviews] = (0, react_1.useState)({});
12
+ const signature = pages
13
+ .map((page) => `${page.id}:${page.filter}:${page.rotation}:${page.corners.map((point) => `${point.x.toFixed(4)},${point.y.toFixed(4)}`).join(';')}`)
14
+ .join('|');
15
+ (0, react_1.useEffect)(() => {
16
+ let isCancelled = false;
17
+ const timer = setTimeout(async () => {
18
+ const stale = [];
19
+ for (const page of pages) {
20
+ if (isCancelled)
21
+ return;
22
+ let raster = rasters.current.get(page.id);
23
+ if (raster === undefined) {
24
+ raster = await ps_scan_pipeline_service_1.PsScanPipelineService.measure(page.source);
25
+ rasters.current.set(page.id, raster);
26
+ }
27
+ const processed = ps_scan_pipeline_service_1.PsScanPipelineService.process(page, raster, ps_scan_config_1.PsScanConfig.previewMaxDimension);
28
+ const blob = await ps_scan_canvas_service_1.PsScanCanvasService.encode(processed, ps_scan_config_1.PsScanConfig.defaultJpegQuality);
29
+ if (isCancelled)
30
+ return;
31
+ const previous = urls.current.get(page.id);
32
+ if (previous !== undefined)
33
+ stale.push(previous);
34
+ urls.current.set(page.id, URL.createObjectURL(blob));
35
+ }
36
+ if (isCancelled)
37
+ return;
38
+ const ids = new Set(pages.map((page) => page.id));
39
+ urls.current.forEach((url, id) => {
40
+ if (ids.has(id))
41
+ return;
42
+ stale.push(url);
43
+ urls.current.delete(id);
44
+ rasters.current.delete(id);
45
+ });
46
+ setPreviews(Object.fromEntries(urls.current));
47
+ setTimeout(() => stale.forEach((url) => URL.revokeObjectURL(url)), 1000);
48
+ }, ps_scan_config_1.PsScanConfig.previewDebounceMs);
49
+ return () => {
50
+ isCancelled = true;
51
+ clearTimeout(timer);
52
+ };
53
+ }, [signature]);
54
+ (0, react_1.useEffect)(() => () => {
55
+ urls.current.forEach((url) => URL.revokeObjectURL(url));
56
+ urls.current.clear();
57
+ rasters.current.clear();
58
+ }, []);
59
+ return previews;
60
+ };
61
+ exports.usePsScanPreviews = usePsScanPreviews;
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export * from './components/ps-file-list';
5
5
  export * from './components/ps-file-picker';
6
6
  export * from './components/ps-file-viewer-button';
7
7
  export * from './components/ps-file-viewer-content';
8
+ export * from './components/ps-file-viewer-pane';
8
9
  export * from './components/ps-file-viewer';
9
10
  export * from './components/ps-highlighted-text';
10
11
  export * from './components/ps-image-viewer';
@@ -39,6 +40,7 @@ export * from './models/ps-file-selection';
39
40
  export * from './models/ps-file-text-state';
40
41
  export * from './models/ps-file-viewer-button-tone';
41
42
  export * from './models/ps-file-viewer-content-props';
43
+ export * from './models/ps-file-viewer-pane-props';
42
44
  export * from './models/ps-label-set';
43
45
  export * from './models/ps-page-size';
44
46
  export * from './models/ps-pdf-match';
@@ -67,3 +69,9 @@ export * from './hooks/use-ps-active-match-scroll';
67
69
  export * from './hooks/use-ps-file-text';
68
70
  export * from './hooks/use-ps-in-view';
69
71
  export * from './hooks/use-ps-upload-queue';
72
+ export * from './components/ps-document-scanner';
73
+ export * from './constants/ps-document-scanner-labels';
74
+ export * from './constants/ps-scan-filter';
75
+ export * from './constants/ps-scan-output-format';
76
+ export * from './models/ps-document-scanner-props';
77
+ export * from './models/ps-file-picker-scan';
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ __exportStar(require("./components/ps-file-list"), exports);
21
21
  __exportStar(require("./components/ps-file-picker"), exports);
22
22
  __exportStar(require("./components/ps-file-viewer-button"), exports);
23
23
  __exportStar(require("./components/ps-file-viewer-content"), exports);
24
+ __exportStar(require("./components/ps-file-viewer-pane"), exports);
24
25
  __exportStar(require("./components/ps-file-viewer"), exports);
25
26
  __exportStar(require("./components/ps-highlighted-text"), exports);
26
27
  __exportStar(require("./components/ps-image-viewer"), exports);
@@ -55,6 +56,7 @@ __exportStar(require("./models/ps-file-selection"), exports);
55
56
  __exportStar(require("./models/ps-file-text-state"), exports);
56
57
  __exportStar(require("./models/ps-file-viewer-button-tone"), exports);
57
58
  __exportStar(require("./models/ps-file-viewer-content-props"), exports);
59
+ __exportStar(require("./models/ps-file-viewer-pane-props"), exports);
58
60
  __exportStar(require("./models/ps-label-set"), exports);
59
61
  __exportStar(require("./models/ps-page-size"), exports);
60
62
  __exportStar(require("./models/ps-pdf-match"), exports);
@@ -83,3 +85,9 @@ __exportStar(require("./hooks/use-ps-active-match-scroll"), exports);
83
85
  __exportStar(require("./hooks/use-ps-file-text"), exports);
84
86
  __exportStar(require("./hooks/use-ps-in-view"), exports);
85
87
  __exportStar(require("./hooks/use-ps-upload-queue"), exports);
88
+ __exportStar(require("./components/ps-document-scanner"), exports);
89
+ __exportStar(require("./constants/ps-document-scanner-labels"), exports);
90
+ __exportStar(require("./constants/ps-scan-filter"), exports);
91
+ __exportStar(require("./constants/ps-scan-output-format"), exports);
92
+ __exportStar(require("./models/ps-document-scanner-props"), exports);
93
+ __exportStar(require("./models/ps-file-picker-scan"), exports);
@@ -0,0 +1,16 @@
1
+ import type { PsDocumentScannerLabels } from '../constants/ps-document-scanner-labels';
2
+ import type { PsScanOutputFormat } from '../constants/ps-scan-output-format';
3
+ import type { PsLabelSet } from './ps-label-set';
4
+ export interface PsDocumentScannerProps {
5
+ className?: string;
6
+ fileName?: string;
7
+ isAutoCapture?: boolean;
8
+ isOpen: boolean;
9
+ jpegQuality?: number;
10
+ labels?: Partial<PsLabelSet<typeof PsDocumentScannerLabels>>;
11
+ maxDimension?: number;
12
+ maxPages?: number;
13
+ onClose: () => void;
14
+ onComplete: (files: File[]) => void;
15
+ outputFormat?: PsScanOutputFormat;
16
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,14 @@
1
+ import type { PsDocumentScannerLabels } from '../constants/ps-document-scanner-labels';
2
+ import type { PsScanOutputFormat } from '../constants/ps-scan-output-format';
3
+ import type { PsLabelSet } from './ps-label-set';
4
+ export interface PsDocumentScannerSheetProps {
5
+ fileName: string;
6
+ isAutoCapture: boolean;
7
+ jpegQuality: number;
8
+ labels: PsLabelSet<typeof PsDocumentScannerLabels>;
9
+ maxDimension: number;
10
+ maxPages: number;
11
+ onClose: () => void;
12
+ onComplete: (files: File[]) => void;
13
+ outputFormat: PsScanOutputFormat;
14
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ import type { PsDocumentScannerProps } from './ps-document-scanner-props';
2
+ export interface PsFilePickerScan extends Omit<PsDocumentScannerProps, 'fileName' | 'isOpen' | 'onClose' | 'onComplete'> {
3
+ getFileName?: () => string;
4
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { PsFileViewerLabels } from '../constants/ps-file-viewer-labels';
3
+ import type { PsLabelSet } from './ps-label-set';
4
+ export interface PsFileViewerPaneProps {
5
+ contentType: string;
6
+ headerActions?: ReactNode;
7
+ id?: string;
8
+ labels?: PsLabelSet<typeof PsFileViewerLabels>;
9
+ name: string;
10
+ pdfWorkerSrc?: string;
11
+ url: string;
12
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ import type { PsScanPage } from './ps-scan-page';
2
+ export interface PsScanAddedPage {
3
+ isDetected: boolean;
4
+ page: PsScanPage;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ export interface PsScanCameraSession {
2
+ canTorch: boolean;
3
+ stream: MediaStream;
4
+ track: MediaStreamTrack;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ import type { PsScanRaster } from './ps-scan-raster';
2
+ export interface PsScanDecodedImage {
3
+ naturalHeight: number;
4
+ naturalWidth: number;
5
+ raster: PsScanRaster;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ export interface PsScanLevels {
2
+ black: number;
3
+ white: number;
4
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ import type { PsScanQuad } from './ps-scan-quad';
2
+ export interface PsScanLiveDetection {
3
+ progress: number;
4
+ quad: PsScanQuad | null;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ import type { PsScanOutputFormat } from '../constants/ps-scan-output-format';
2
+ export interface PsScanOutputOptions {
3
+ fileName: string;
4
+ format: PsScanOutputFormat;
5
+ jpegQuality: number;
6
+ maxDimension: number;
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ import type { PsScanFilter } from '../constants/ps-scan-filter';
2
+ import type { PsScanQuad } from './ps-scan-quad';
3
+ export interface PsScanPage {
4
+ corners: PsScanQuad;
5
+ filter: PsScanFilter;
6
+ height: number;
7
+ id: string;
8
+ rotation: number;
9
+ source: Blob;
10
+ sourceUrl: string;
11
+ width: number;
12
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ export interface PsScanPdfPage {
2
+ height: number;
3
+ jpeg: Uint8Array;
4
+ width: number;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ import type { PsScanQuad } from './ps-scan-quad';
2
+ export interface PsScanPrepared {
3
+ corners: PsScanQuad;
4
+ height: number;
5
+ isDetected: boolean;
6
+ width: number;
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ import type { PsPoint } from './ps-point';
2
+ export type PsScanQuad = [PsPoint, PsPoint, PsPoint, PsPoint];