@pallasoft/ps-file-components 1.5.0 → 2.0.1
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/dist/components/ps-document-scanner-loader.d.ts +1 -1
- package/dist/components/ps-document-scanner-sheet.d.ts +1 -1
- package/dist/components/ps-document-scanner-sheet.js +40 -110
- package/dist/components/ps-document-scanner.d.ts +1 -1
- package/dist/components/ps-document-scanner.js +2 -3
- package/dist/components/ps-file-delete-confirm.js +1 -1
- package/dist/components/ps-scan-camera-view.d.ts +2 -9
- package/dist/components/ps-scan-camera-view.js +3 -12
- package/dist/components/ps-scan-crop-editor.d.ts +4 -4
- package/dist/components/ps-scan-crop-editor.js +9 -9
- package/dist/components/ps-scan-permission-view.d.ts +2 -3
- package/dist/components/ps-scan-permission-view.js +2 -2
- package/dist/components/ps-scan-photo-button.d.ts +2 -3
- package/dist/components/ps-scan-photo-button.js +5 -5
- package/dist/components/ps-scan-preview.d.ts +12 -0
- package/dist/components/ps-scan-preview.js +10 -0
- package/dist/components/ps-scan-shutter.d.ts +1 -2
- package/dist/components/ps-scan-shutter.js +1 -1
- package/dist/components/ps-upload-modal.js +1 -1
- package/dist/constants/ps-document-scanner-labels.d.ts +5 -34
- package/dist/constants/ps-document-scanner-labels.js +5 -34
- package/dist/constants/ps-scan-chrome-classes.d.ts +0 -2
- package/dist/constants/ps-scan-chrome-classes.js +0 -2
- package/dist/constants/ps-scan-config.d.ts +24 -31
- package/dist/constants/ps-scan-config.js +24 -31
- package/dist/constants/ps-scan-step.d.ts +1 -1
- package/dist/constants/ps-scan-step.js +1 -1
- package/dist/esm/components/ps-document-scanner-sheet.js +41 -111
- package/dist/esm/components/ps-document-scanner.js +2 -3
- package/dist/esm/components/ps-file-delete-confirm.js +2 -2
- package/dist/esm/components/ps-scan-camera-view.js +3 -12
- package/dist/esm/components/ps-scan-crop-editor.js +9 -9
- package/dist/esm/components/ps-scan-permission-view.js +2 -2
- package/dist/esm/components/ps-scan-photo-button.js +5 -5
- package/dist/esm/components/ps-scan-preview.js +6 -0
- package/dist/esm/components/ps-scan-shutter.js +1 -1
- package/dist/esm/components/ps-upload-modal.js +2 -2
- package/dist/esm/constants/ps-document-scanner-labels.js +5 -34
- package/dist/esm/constants/ps-scan-chrome-classes.js +0 -2
- package/dist/esm/constants/ps-scan-config.js +24 -31
- package/dist/esm/constants/ps-scan-step.js +1 -1
- package/dist/esm/hooks/use-ps-scan-live-detection.js +17 -21
- package/dist/esm/hooks/use-ps-scan-photo.js +42 -0
- package/dist/esm/index.js +0 -2
- package/dist/esm/services/ps-scan-camera-service.js +2 -2
- package/dist/esm/services/ps-scan-canny-service.js +93 -0
- package/dist/esm/services/ps-scan-canvas-service.js +7 -1
- package/dist/esm/services/ps-scan-edge-service.js +73 -137
- package/dist/esm/services/ps-scan-file-name-service.js +2 -11
- package/dist/esm/services/ps-scan-geometry-service.js +36 -0
- package/dist/esm/services/ps-scan-hull-service.js +0 -39
- package/dist/esm/services/ps-scan-image-filter-service.js +0 -21
- package/dist/esm/services/ps-scan-morphology-service.js +44 -0
- package/dist/esm/services/ps-scan-pipeline-service.js +9 -19
- package/dist/esm/services/ps-scan-polygon-service.js +75 -0
- package/dist/esm/services/ps-scan-region-service.js +52 -0
- package/dist/esm/services/ps-scan-stability-service.js +9 -22
- package/dist/esm/services/ps-scan-warp-service.js +8 -2
- package/dist/esm/services/ps-scan-yield-service.js +5 -0
- package/dist/hooks/use-ps-scan-live-detection.d.ts +1 -1
- package/dist/hooks/use-ps-scan-live-detection.js +16 -20
- package/dist/hooks/use-ps-scan-photo.d.ts +9 -0
- package/dist/hooks/use-ps-scan-photo.js +46 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/dist/models/ps-document-scanner-props.d.ts +0 -4
- package/dist/models/ps-document-scanner-sheet-props.d.ts +0 -4
- package/dist/models/ps-scan-gradient.d.ts +4 -0
- package/dist/models/ps-scan-live-detection.d.ts +0 -1
- package/dist/models/ps-scan-located.d.ts +5 -0
- package/dist/models/ps-scan-photo.d.ts +9 -0
- package/dist/models/ps-scan-region.d.ts +5 -0
- package/dist/models/ps-scan-result.d.ts +6 -0
- package/dist/models/ps-scan-stability.d.ts +0 -3
- package/dist/services/ps-scan-camera-service.js +2 -2
- package/dist/services/ps-scan-canny-service.d.ts +7 -0
- package/dist/services/ps-scan-canny-service.js +97 -0
- package/dist/services/ps-scan-canvas-service.js +7 -1
- package/dist/services/ps-scan-edge-service.d.ts +5 -5
- package/dist/services/ps-scan-edge-service.js +73 -137
- package/dist/services/ps-scan-file-name-service.d.ts +1 -3
- package/dist/services/ps-scan-file-name-service.js +2 -11
- package/dist/services/ps-scan-geometry-service.d.ts +2 -0
- package/dist/services/ps-scan-geometry-service.js +36 -0
- package/dist/services/ps-scan-hull-service.d.ts +0 -2
- package/dist/services/ps-scan-hull-service.js +0 -39
- package/dist/services/ps-scan-image-filter-service.d.ts +0 -1
- package/dist/services/ps-scan-image-filter-service.js +0 -21
- package/dist/services/ps-scan-morphology-service.d.ts +7 -0
- package/dist/services/ps-scan-morphology-service.js +48 -0
- package/dist/services/ps-scan-pipeline-service.d.ts +2 -5
- package/dist/services/ps-scan-pipeline-service.js +9 -19
- package/dist/services/ps-scan-polygon-service.d.ts +8 -0
- package/dist/services/ps-scan-polygon-service.js +79 -0
- package/dist/services/ps-scan-region-service.d.ts +4 -0
- package/dist/services/ps-scan-region-service.js +56 -0
- package/dist/services/ps-scan-stability-service.d.ts +1 -3
- package/dist/services/ps-scan-stability-service.js +9 -22
- package/dist/services/ps-scan-warp-service.d.ts +1 -1
- package/dist/services/ps-scan-warp-service.js +8 -2
- package/dist/services/ps-scan-yield-service.d.ts +3 -0
- package/dist/services/ps-scan-yield-service.js +9 -0
- package/package.json +3 -5
- package/dist/components/ps-scan-page-list.d.ts +0 -14
- package/dist/components/ps-scan-page-list.js +0 -22
- package/dist/components/ps-scan-page-stack.d.ts +0 -7
- package/dist/components/ps-scan-page-stack.js +0 -6
- package/dist/components/ps-scan-review.d.ts +0 -24
- package/dist/components/ps-scan-review.js +0 -37
- package/dist/constants/ps-scan-filter.d.ts +0 -7
- package/dist/constants/ps-scan-filter.js +0 -9
- package/dist/constants/ps-scan-output-format.d.ts +0 -5
- package/dist/constants/ps-scan-output-format.js +0 -7
- package/dist/esm/components/ps-scan-page-list.js +0 -18
- package/dist/esm/components/ps-scan-page-stack.js +0 -2
- package/dist/esm/components/ps-scan-review.js +0 -33
- package/dist/esm/constants/ps-scan-filter.js +0 -6
- package/dist/esm/constants/ps-scan-output-format.js +0 -4
- package/dist/esm/hooks/use-ps-scan-pages.js +0 -62
- package/dist/esm/hooks/use-ps-scan-previews.js +0 -57
- package/dist/esm/services/ps-scan-enhance-service.js +0 -97
- package/dist/esm/services/ps-scan-order-service.js +0 -13
- package/dist/esm/services/ps-scan-output-service.js +0 -24
- package/dist/esm/services/ps-scan-pdf-service.js +0 -56
- package/dist/hooks/use-ps-scan-pages.d.ts +0 -12
- package/dist/hooks/use-ps-scan-pages.js +0 -66
- package/dist/hooks/use-ps-scan-previews.d.ts +0 -2
- package/dist/hooks/use-ps-scan-previews.js +0 -61
- package/dist/models/ps-scan-added-page.d.ts +0 -5
- package/dist/models/ps-scan-levels.d.ts +0 -4
- package/dist/models/ps-scan-output-options.d.ts +0 -7
- package/dist/models/ps-scan-page.d.ts +0 -12
- package/dist/models/ps-scan-pdf-page.d.ts +0 -5
- package/dist/services/ps-scan-enhance-service.d.ts +0 -9
- package/dist/services/ps-scan-enhance-service.js +0 -101
- package/dist/services/ps-scan-order-service.d.ts +0 -4
- package/dist/services/ps-scan-order-service.js +0 -17
- package/dist/services/ps-scan-output-service.d.ts +0 -5
- package/dist/services/ps-scan-output-service.js +0 -28
- package/dist/services/ps-scan-pdf-service.d.ts +0 -5
- package/dist/services/ps-scan-pdf-service.js +0 -60
- /package/dist/esm/models/{ps-scan-added-page.js → ps-scan-gradient.js} +0 -0
- /package/dist/esm/models/{ps-scan-levels.js → ps-scan-located.js} +0 -0
- /package/dist/esm/models/{ps-scan-output-options.js → ps-scan-photo.js} +0 -0
- /package/dist/esm/models/{ps-scan-page.js → ps-scan-region.js} +0 -0
- /package/dist/esm/models/{ps-scan-pdf-page.js → ps-scan-result.js} +0 -0
- /package/dist/models/{ps-scan-added-page.js → ps-scan-gradient.js} +0 -0
- /package/dist/models/{ps-scan-levels.js → ps-scan-located.js} +0 -0
- /package/dist/models/{ps-scan-output-options.js → ps-scan-photo.js} +0 -0
- /package/dist/models/{ps-scan-page.js → ps-scan-region.js} +0 -0
- /package/dist/models/{ps-scan-pdf-page.js → ps-scan-result.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PsDocumentScannerLoader: import("react").LazyExoticComponent<({ fileName,
|
|
1
|
+
export declare const PsDocumentScannerLoader: import("react").LazyExoticComponent<({ fileName, jpegQuality, labels, maxDimension, onClose, onComplete, }: import("../models/ps-document-scanner-sheet-props").PsDocumentScannerSheetProps) => import("react").ReactPortal | null>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { PsDocumentScannerSheetProps } from '../models/ps-document-scanner-sheet-props';
|
|
2
|
-
export declare const PsDocumentScannerSheet: ({ fileName,
|
|
2
|
+
export declare const PsDocumentScannerSheet: ({ fileName, jpegQuality, labels, maxDimension, onClose, onComplete, }: PsDocumentScannerSheetProps) => import("react").ReactPortal | null;
|
|
@@ -12,81 +12,52 @@ const ps_scan_step_1 = require("../constants/ps-scan-step");
|
|
|
12
12
|
const use_ps_focus_trap_1 = require("../hooks/use-ps-focus-trap");
|
|
13
13
|
const use_ps_scan_camera_1 = require("../hooks/use-ps-scan-camera");
|
|
14
14
|
const use_ps_scan_live_detection_1 = require("../hooks/use-ps-scan-live-detection");
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const ps_scan_output_service_1 = require("../services/ps-scan-output-service");
|
|
15
|
+
const use_ps_scan_photo_1 = require("../hooks/use-ps-scan-photo");
|
|
16
|
+
const ps_scan_file_name_service_1 = require("../services/ps-scan-file-name-service");
|
|
18
17
|
const ps_scan_pipeline_service_1 = require("../services/ps-scan-pipeline-service");
|
|
19
|
-
const ps_scan_template_service_1 = require("../services/ps-scan-template-service");
|
|
20
18
|
const ps_scan_camera_view_1 = require("./ps-scan-camera-view");
|
|
21
19
|
const ps_scan_crop_editor_1 = require("./ps-scan-crop-editor");
|
|
22
20
|
const ps_scan_icon_button_1 = require("./ps-scan-icon-button");
|
|
23
21
|
const ps_scan_permission_view_1 = require("./ps-scan-permission-view");
|
|
24
|
-
const
|
|
25
|
-
const PsDocumentScannerSheet = ({ fileName,
|
|
22
|
+
const ps_scan_preview_1 = require("./ps-scan-preview");
|
|
23
|
+
const PsDocumentScannerSheet = ({ fileName, jpegQuality, labels, maxDimension, onClose, onComplete, }) => {
|
|
26
24
|
const tier = (0, ps_core_components_1.usePsViewport)();
|
|
27
25
|
const zIndex = (0, ps_core_components_1.usePsLayerZIndex)(ps_design_system_1.PallasoftZIndex.Modal);
|
|
28
26
|
const content = (0, react_1.useRef)(null);
|
|
29
|
-
const {
|
|
27
|
+
const { clear, detectAgain, load, photo, setCorners } = (0, use_ps_scan_photo_1.usePsScanPhoto)();
|
|
30
28
|
const [step, setStep] = (0, react_1.useState)(ps_scan_step_1.PsScanStep.Camera);
|
|
31
|
-
const [
|
|
32
|
-
const [activeId, setActiveId] = (0, react_1.useState)('');
|
|
33
|
-
const [retakeId, setRetakeId] = (0, react_1.useState)('');
|
|
29
|
+
const [result, setResult] = (0, react_1.useState)(null);
|
|
34
30
|
const [announcement, setAnnouncement] = (0, react_1.useState)('');
|
|
35
31
|
const [error, setError] = (0, react_1.useState)('');
|
|
36
|
-
const [isBusy, setIsBusy] = (0, react_1.useState)(false);
|
|
37
32
|
const [isCapturing, setIsCapturing] = (0, react_1.useState)(false);
|
|
38
|
-
const [isAuto, setIsAuto] = (0, react_1.useState)(isAutoCapture);
|
|
39
33
|
const [flashKey, setFlashKey] = (0, react_1.useState)(0);
|
|
40
34
|
const camera = (0, use_ps_scan_camera_1.usePsScanCamera)(step === ps_scan_step_1.PsScanStep.Camera);
|
|
41
35
|
const isReady = camera.status === ps_scan_camera_status_1.PsScanCameraStatus.Ready;
|
|
42
|
-
const isFull = pages.length >= maxPages;
|
|
43
|
-
const previews = (0, use_ps_scan_previews_1.usePsScanPreviews)(pages);
|
|
44
|
-
const page = pages.find((item) => item.id === activeId);
|
|
45
|
-
const lastPage = pages[pages.length - 1];
|
|
46
36
|
const isDesktop = tier === ps_design_system_1.PallasoftViewportTier.Desktop;
|
|
47
37
|
const isCameraStep = step === ps_scan_step_1.PsScanStep.Camera;
|
|
48
38
|
const showsCamera = isReady || camera.status === ps_scan_camera_status_1.PsScanCameraStatus.Starting;
|
|
39
|
+
const detection = (0, use_ps_scan_live_detection_1.usePsScanLiveDetection)(camera.videoRef, isCameraStep && isReady);
|
|
49
40
|
(0, ps_core_components_1.usePsScrollLock)(true);
|
|
50
41
|
(0, ps_core_components_1.usePsRestoreFocus)(true);
|
|
51
42
|
(0, use_ps_focus_trap_1.usePsFocusTrap)(content, true, onClose);
|
|
43
|
+
(0, react_1.useEffect)(() => () => {
|
|
44
|
+
if (result !== null)
|
|
45
|
+
URL.revokeObjectURL(result.url);
|
|
46
|
+
}, [result]);
|
|
52
47
|
const edgeMessage = (isDetected) => isDetected ? labels.edgesFound : labels.edgesNotFound;
|
|
53
|
-
const
|
|
48
|
+
const accept = async (source) => {
|
|
54
49
|
setError('');
|
|
55
50
|
try {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
setActiveId(retakeId);
|
|
60
|
-
setRetakeId('');
|
|
61
|
-
setStep(ps_scan_step_1.PsScanStep.Crop);
|
|
62
|
-
setAnnouncement(edgeMessage(added.isDetected));
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
const room = Math.max(0, maxPages - pages.length);
|
|
66
|
-
if (images.length > room)
|
|
67
|
-
setError(labels.maxPages);
|
|
68
|
-
const added = await add(images.slice(0, room));
|
|
69
|
-
if (added.length === 0)
|
|
70
|
-
return;
|
|
71
|
-
const position = pages.length + added.length;
|
|
72
|
-
setActiveId(added[added.length - 1].page.id);
|
|
73
|
-
setAnnouncement(ps_scan_template_service_1.PsScanTemplateService.fill(labels.pageAdded, { position }));
|
|
74
|
-
if (after === null)
|
|
75
|
-
return;
|
|
76
|
-
if (added.length === 1) {
|
|
77
|
-
setCropReturn(after);
|
|
78
|
-
setStep(ps_scan_step_1.PsScanStep.Crop);
|
|
79
|
-
setAnnouncement(edgeMessage(added[0].isDetected));
|
|
80
|
-
}
|
|
81
|
-
else
|
|
82
|
-
setStep(ps_scan_step_1.PsScanStep.Review);
|
|
51
|
+
const added = await load(source);
|
|
52
|
+
setAnnouncement(edgeMessage(added.isDetected));
|
|
53
|
+
setStep(ps_scan_step_1.PsScanStep.Crop);
|
|
83
54
|
}
|
|
84
55
|
catch {
|
|
85
56
|
setError(labels.processFailed);
|
|
86
57
|
}
|
|
87
58
|
};
|
|
88
|
-
const capture = async (
|
|
89
|
-
if (isCapturing
|
|
59
|
+
const capture = async () => {
|
|
60
|
+
if (isCapturing)
|
|
90
61
|
return;
|
|
91
62
|
setIsCapturing(true);
|
|
92
63
|
try {
|
|
@@ -94,93 +65,52 @@ const PsDocumentScannerSheet = ({ fileName, isAutoCapture, jpegQuality, labels,
|
|
|
94
65
|
if (blob === null)
|
|
95
66
|
return;
|
|
96
67
|
setFlashKey((current) => current + 1);
|
|
97
|
-
await
|
|
68
|
+
await accept(blob);
|
|
98
69
|
}
|
|
99
70
|
finally {
|
|
100
71
|
setIsCapturing(false);
|
|
101
72
|
}
|
|
102
73
|
};
|
|
103
|
-
const
|
|
104
|
-
const autoDetect = async () => {
|
|
105
|
-
if (page === undefined)
|
|
106
|
-
return;
|
|
107
|
-
const prepared = await ps_scan_pipeline_service_1.PsScanPipelineService.prepare(page.source);
|
|
108
|
-
setCorners(page.id, prepared.corners);
|
|
109
|
-
setAnnouncement(edgeMessage(prepared.isDetected));
|
|
110
|
-
};
|
|
111
|
-
const keep = () => setStep(cropReturn === ps_scan_step_1.PsScanStep.Camera && !isFull ? ps_scan_step_1.PsScanStep.Camera : ps_scan_step_1.PsScanStep.Review);
|
|
74
|
+
const autoDetect = async () => setAnnouncement(edgeMessage(await detectAgain()));
|
|
112
75
|
const retake = () => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
setCropReturn(ps_scan_step_1.PsScanStep.Review);
|
|
117
|
-
setRetakeId(page.id);
|
|
118
|
-
setStep(ps_scan_step_1.PsScanStep.Camera);
|
|
119
|
-
};
|
|
120
|
-
const openCamera = () => {
|
|
121
|
-
setRetakeId('');
|
|
122
|
-
setCropReturn(ps_scan_step_1.PsScanStep.Camera);
|
|
76
|
+
clear();
|
|
77
|
+
setResult(null);
|
|
78
|
+
setError('');
|
|
123
79
|
setStep(ps_scan_step_1.PsScanStep.Camera);
|
|
124
80
|
};
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
setRetakeId('');
|
|
129
|
-
if (page === undefined)
|
|
130
|
-
setActiveId(lastPage.id);
|
|
131
|
-
setStep(ps_scan_step_1.PsScanStep.Review);
|
|
132
|
-
};
|
|
133
|
-
const editCrop = () => {
|
|
134
|
-
setCropReturn(ps_scan_step_1.PsScanStep.Review);
|
|
81
|
+
const adjust = () => {
|
|
82
|
+
setResult(null);
|
|
83
|
+
setError('');
|
|
135
84
|
setStep(ps_scan_step_1.PsScanStep.Crop);
|
|
136
85
|
};
|
|
137
|
-
const
|
|
138
|
-
if (
|
|
86
|
+
const flatten = async () => {
|
|
87
|
+
if (photo === null)
|
|
139
88
|
return;
|
|
140
|
-
|
|
141
|
-
const rest = pages.filter((item) => item.id !== page.id);
|
|
142
|
-
remove(page.id);
|
|
143
|
-
setAnnouncement(labels.pageDeleted);
|
|
144
|
-
if (rest.length === 0) {
|
|
145
|
-
setActiveId('');
|
|
146
|
-
openCamera();
|
|
147
|
-
}
|
|
148
|
-
else
|
|
149
|
-
setActiveId(rest[Math.min(index, rest.length - 1)].id);
|
|
150
|
-
};
|
|
151
|
-
const finish = async () => {
|
|
152
|
-
setIsBusy(true);
|
|
89
|
+
setResult(null);
|
|
153
90
|
setError('');
|
|
91
|
+
setStep(ps_scan_step_1.PsScanStep.Preview);
|
|
154
92
|
try {
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
format: outputFormat,
|
|
158
|
-
jpegQuality,
|
|
159
|
-
maxDimension,
|
|
160
|
-
});
|
|
161
|
-
onComplete(files);
|
|
162
|
-
onClose();
|
|
93
|
+
const rendered = await ps_scan_pipeline_service_1.PsScanPipelineService.render(photo.source, photo.corners, maxDimension, jpegQuality);
|
|
94
|
+
setResult({ ...rendered, url: URL.createObjectURL(rendered.blob) });
|
|
163
95
|
}
|
|
164
96
|
catch {
|
|
165
97
|
setError(labels.processFailed);
|
|
166
|
-
setIsBusy(false);
|
|
167
98
|
}
|
|
168
99
|
};
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
const fromLibrary = (files) => addFiles(files, ps_scan_step_1.PsScanStep.Review);
|
|
100
|
+
const use = () => {
|
|
101
|
+
if (result === null)
|
|
102
|
+
return;
|
|
103
|
+
onComplete([
|
|
104
|
+
new File([result.blob], ps_scan_file_name_service_1.PsScanFileNameService.build(fileName), { type: 'image/jpeg' }),
|
|
105
|
+
]);
|
|
106
|
+
onClose();
|
|
107
|
+
};
|
|
178
108
|
if (typeof document === 'undefined')
|
|
179
109
|
return null;
|
|
180
110
|
return (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { "aria-label": labels.title, "aria-modal": 'true', className: isDesktop
|
|
181
111
|
? 'fixed inset-0 flex items-center justify-center bg-black/70 p-6 backdrop-blur-sm animate-ps-fade-in'
|
|
182
112
|
: 'fixed inset-0 bg-black animate-ps-fade-in', role: 'dialog', style: { zIndex }, children: (0, jsx_runtime_1.jsx)(ps_core_components_1.PsLayer, { zIndex: zIndex, children: (0, jsx_runtime_1.jsxs)("div", { className: isDesktop
|
|
183
113
|
? 'relative h-[min(52rem,calc(100dvh-3rem))] w-[min(76rem,calc(100vw-3rem))] overflow-hidden rounded-2xl bg-black text-white shadow-2xl ring-1 ring-white/10 animate-ps-scale-in'
|
|
184
|
-
: 'relative h-full overflow-hidden bg-black text-white', ref: content, children: [(0, jsx_runtime_1.jsx)("p", { "aria-live": 'polite', className: 'sr-only', role: 'status', children: announcement }), isCameraStep && showsCamera ? ((0, jsx_runtime_1.jsx)(ps_scan_camera_view_1.PsScanCameraView, { canTorch: camera.canTorch, detection: detection, flashKey: flashKey,
|
|
114
|
+
: 'relative h-full overflow-hidden bg-black text-white', ref: content, children: [(0, jsx_runtime_1.jsx)("p", { "aria-live": 'polite', className: 'sr-only', role: 'status', children: announcement }), isCameraStep && showsCamera ? ((0, jsx_runtime_1.jsx)(ps_scan_camera_view_1.PsScanCameraView, { canTorch: camera.canTorch, detection: detection, flashKey: flashKey, isBusy: isCapturing, isReady: isReady, isTorchOn: camera.isTorchOn, labels: labels, onCapture: capture, onClose: onClose, onFile: accept, onToggleTorch: camera.toggleTorch, videoRef: camera.videoRef, videoTarget: camera.attachVideo })) : null, isCameraStep && !showsCamera ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ps_scan_permission_view_1.PsScanPermissionView, { labels: labels, onAllow: camera.allow, onFile: accept, status: camera.status }), (0, jsx_runtime_1.jsx)("div", { className: 'absolute left-4 top-[max(1rem,env(safe-area-inset-top))] flex gap-2', children: (0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { iconKey: ps_icons_1.PsIconKey.Close, label: labels.close, onClick: onClose }) })] })) : null, step === ps_scan_step_1.PsScanStep.Crop && photo !== null ? ((0, jsx_runtime_1.jsx)(ps_scan_crop_editor_1.PsScanCropEditor, { labels: labels, onAutoDetect: autoDetect, onChange: setCorners, onContinue: flatten, onRetake: retake, photo: photo })) : null, step === ps_scan_step_1.PsScanStep.Preview ? ((0, jsx_runtime_1.jsx)(ps_scan_preview_1.PsScanPreview, { error: error, labels: labels, onAdjust: adjust, onRetake: retake, onUse: use, result: result })) : null, isCameraStep && error !== '' ? ((0, jsx_runtime_1.jsx)("p", { className: 'absolute inset-x-4 bottom-36 mx-auto max-w-sm rounded-ps-control bg-danger px-3 py-2 text-center text-sm text-white', role: 'alert', children: error })) : null] }) }) }), document.body);
|
|
185
115
|
};
|
|
186
116
|
exports.PsDocumentScannerSheet = PsDocumentScannerSheet;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { PsDocumentScannerProps } from '../models/ps-document-scanner-props';
|
|
2
|
-
export declare const PsDocumentScanner: ({ fileName,
|
|
2
|
+
export declare const PsDocumentScanner: ({ fileName, isOpen, jpegQuality, labels, maxDimension, onClose, onComplete, }: PsDocumentScannerProps) => import("react").JSX.Element | null;
|
|
@@ -6,12 +6,11 @@ const react_1 = require("react");
|
|
|
6
6
|
const ps_core_components_1 = require("@pallasoft/ps-core-components");
|
|
7
7
|
const ps_document_scanner_labels_1 = require("../constants/ps-document-scanner-labels");
|
|
8
8
|
const ps_scan_config_1 = require("../constants/ps-scan-config");
|
|
9
|
-
const ps_scan_output_format_1 = require("../constants/ps-scan-output-format");
|
|
10
9
|
const ps_document_scanner_loader_1 = require("./ps-document-scanner-loader");
|
|
11
|
-
const PsDocumentScanner = ({ fileName = ps_scan_config_1.PsScanConfig.defaultFileName,
|
|
10
|
+
const PsDocumentScanner = ({ fileName = ps_scan_config_1.PsScanConfig.defaultFileName, isOpen, jpegQuality = ps_scan_config_1.PsScanConfig.defaultJpegQuality, labels, maxDimension = ps_scan_config_1.PsScanConfig.defaultMaxDimension, onClose, onComplete, }) => {
|
|
12
11
|
const isHydrated = (0, ps_core_components_1.usePsHydrated)();
|
|
13
12
|
if (!isOpen || !isHydrated)
|
|
14
13
|
return null;
|
|
15
|
-
return ((0, jsx_runtime_1.jsx)(react_1.Suspense, { fallback: null, children: (0, jsx_runtime_1.jsx)(ps_document_scanner_loader_1.PsDocumentScannerLoader, { fileName: fileName,
|
|
14
|
+
return ((0, jsx_runtime_1.jsx)(react_1.Suspense, { fallback: null, children: (0, jsx_runtime_1.jsx)(ps_document_scanner_loader_1.PsDocumentScannerLoader, { fileName: fileName, jpegQuality: jpegQuality, labels: { ...ps_document_scanner_labels_1.PsDocumentScannerLabels, ...labels }, maxDimension: maxDimension, onClose: onClose, onComplete: onComplete }) }));
|
|
16
15
|
};
|
|
17
16
|
exports.PsDocumentScanner = PsDocumentScanner;
|
|
@@ -4,5 +4,5 @@ exports.PsFileDeleteConfirm = void 0;
|
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const ps_core_components_1 = require("@pallasoft/ps-core-components");
|
|
6
6
|
const ps_popovers_1 = require("@pallasoft/ps-popovers");
|
|
7
|
-
const PsFileDeleteConfirm = ({ fileName, isDeleting, isOpen, labels, onCancel, onConfirm, }) => ((0, jsx_runtime_1.jsx)(ps_popovers_1.PsModal, { eyebrow: fileName,
|
|
7
|
+
const PsFileDeleteConfirm = ({ fileName, isDeleting, isOpen, labels, onCancel, onConfirm, }) => ((0, jsx_runtime_1.jsx)(ps_popovers_1.PsModal, { eyebrow: fileName, footer: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ps_core_components_1.PsButton, { disabled: isDeleting, onClick: onCancel, type: 'button', variant: 'surface', children: labels.deleteCancel }), (0, jsx_runtime_1.jsx)(ps_core_components_1.PsButton, { isLoading: isDeleting, onClick: onConfirm, type: 'button', variant: 'danger', children: labels.delete })] }), isOpen: isOpen, onClose: onCancel, size: 'sm', title: labels.deleteConfirm, children: (0, jsx_runtime_1.jsxs)("p", { className: 'text-sm text-ink/70', children: [(0, jsx_runtime_1.jsx)("span", { className: 'font-medium text-ink', children: fileName }), " ", labels.deleteConfirmBody] }) }));
|
|
8
8
|
exports.PsFileDeleteConfirm = PsFileDeleteConfirm;
|
|
@@ -6,22 +6,15 @@ export interface PsScanCameraViewProps {
|
|
|
6
6
|
canTorch: boolean;
|
|
7
7
|
detection: PsScanLiveDetection;
|
|
8
8
|
flashKey: number;
|
|
9
|
-
isAuto: boolean;
|
|
10
9
|
isBusy: boolean;
|
|
11
|
-
isFull: boolean;
|
|
12
|
-
isMultiple: boolean;
|
|
13
10
|
isReady: boolean;
|
|
14
11
|
isTorchOn: boolean;
|
|
15
12
|
labels: PsLabelSet<typeof PsDocumentScannerLabels>;
|
|
16
|
-
lastPreview: string | undefined;
|
|
17
13
|
onCapture: () => void;
|
|
18
14
|
onClose: () => void;
|
|
19
|
-
|
|
20
|
-
onFiles: (files: File[]) => void;
|
|
21
|
-
onToggleAuto: () => void;
|
|
15
|
+
onFile: (file: File) => void;
|
|
22
16
|
onToggleTorch: () => void;
|
|
23
|
-
pageCount: number;
|
|
24
17
|
videoRef: RefObject<HTMLVideoElement | null>;
|
|
25
18
|
videoTarget: RefCallback<HTMLVideoElement>;
|
|
26
19
|
}
|
|
27
|
-
export declare const PsScanCameraView: ({ canTorch, detection, flashKey,
|
|
20
|
+
export declare const PsScanCameraView: ({ canTorch, detection, flashKey, isBusy, isReady, isTorchOn, labels, onCapture, onClose, onFile, onToggleTorch, videoRef, videoTarget, }: PsScanCameraViewProps) => import("react").JSX.Element;
|
|
@@ -7,28 +7,19 @@ const ps_core_components_1 = require("@pallasoft/ps-core-components");
|
|
|
7
7
|
const ps_design_system_1 = require("@pallasoft/ps-design-system");
|
|
8
8
|
const ps_icons_1 = require("@pallasoft/ps-icons");
|
|
9
9
|
const ps_scan_chrome_classes_1 = require("../constants/ps-scan-chrome-classes");
|
|
10
|
-
const ps_scan_template_service_1 = require("../services/ps-scan-template-service");
|
|
11
|
-
const ps_scan_button_1 = require("./ps-scan-button");
|
|
12
10
|
const ps_scan_icon_button_1 = require("./ps-scan-icon-button");
|
|
13
|
-
const ps_scan_page_stack_1 = require("./ps-scan-page-stack");
|
|
14
11
|
const ps_scan_photo_button_1 = require("./ps-scan-photo-button");
|
|
15
12
|
const ps_scan_shutter_1 = require("./ps-scan-shutter");
|
|
16
13
|
const ps_scan_viewfinder_overlay_1 = require("./ps-scan-viewfinder-overlay");
|
|
17
|
-
const PsScanCameraView = ({ canTorch, detection, flashKey,
|
|
14
|
+
const PsScanCameraView = ({ canTorch, detection, flashKey, isBusy, isReady, isTorchOn, labels, onCapture, onClose, onFile, onToggleTorch, videoRef, videoTarget, }) => {
|
|
18
15
|
const [areaRef, area] = (0, ps_core_components_1.usePsElementSize)();
|
|
19
16
|
const [video, setVideo] = (0, react_1.useState)({ height: 0, width: 0 });
|
|
20
|
-
const hint =
|
|
21
|
-
? labels.maxPages
|
|
22
|
-
: detection.quad === null
|
|
23
|
-
? labels.hintFind
|
|
24
|
-
: isAuto
|
|
25
|
-
? labels.hintHold
|
|
26
|
-
: labels.hintFound;
|
|
17
|
+
const hint = detection.quad === null ? labels.hintFind : labels.hintFound;
|
|
27
18
|
const measure = () => {
|
|
28
19
|
const element = videoRef.current;
|
|
29
20
|
if (element !== null)
|
|
30
21
|
setVideo({ height: element.videoHeight, width: element.videoWidth });
|
|
31
22
|
};
|
|
32
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: 'relative h-full min-h-0 overflow-hidden bg-black text-white', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'absolute inset-0', ref: areaRef, children: [(0, jsx_runtime_1.jsx)("video", { "aria-hidden": 'true', autoPlay: true, className: ps_design_system_1.PallasoftClassNameService.merge('size-full object-cover transition-opacity duration-300', isReady ? 'opacity-100' : 'opacity-0'), muted: true, onLoadedMetadata: measure, onResize: measure, playsInline: true, ref: videoTarget }), isReady ? ((0, jsx_runtime_1.jsx)(ps_scan_viewfinder_overlay_1.PsScanViewfinderOverlay, { area: area, quad: detection.quad, video: video })) : null] }), isReady ? null : ((0, jsx_runtime_1.jsxs)("div", { className: 'absolute inset-0 flex flex-col items-center justify-center gap-3 text-sm text-white/75', role: 'status', children: [(0, jsx_runtime_1.jsx)(ps_core_components_1.PsSpinner, { color: 'current', label: labels.cameraStarting, size: 'small' }), (0, jsx_runtime_1.jsx)("span", { children: labels.cameraStarting })] })), flashKey > 0 ? ((0, jsx_runtime_1.jsx)("div", { "aria-hidden": 'true', className: 'pointer-events-none absolute inset-0 bg-white animate-ps-fade-out' }, flashKey)) : null, (0, jsx_runtime_1.jsxs)("div", { className: 'absolute inset-x-0 top-0 flex items-start justify-between gap-3 bg-gradient-to-b from-black/60 to-transparent px-4 pb-10 pt-[max(1rem,env(safe-area-inset-top))]', children: [(0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { iconKey: ps_icons_1.PsIconKey.Close, label: labels.close, onClick: onClose }), (0, jsx_runtime_1.
|
|
23
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: 'relative h-full min-h-0 overflow-hidden bg-black text-white', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'absolute inset-0', ref: areaRef, children: [(0, jsx_runtime_1.jsx)("video", { "aria-hidden": 'true', autoPlay: true, className: ps_design_system_1.PallasoftClassNameService.merge('size-full object-cover transition-opacity duration-300', isReady ? 'opacity-100' : 'opacity-0'), muted: true, onLoadedMetadata: measure, onResize: measure, playsInline: true, ref: videoTarget }), isReady ? ((0, jsx_runtime_1.jsx)(ps_scan_viewfinder_overlay_1.PsScanViewfinderOverlay, { area: area, quad: detection.quad, video: video })) : null] }), isReady ? null : ((0, jsx_runtime_1.jsxs)("div", { className: 'absolute inset-0 flex flex-col items-center justify-center gap-3 text-sm text-white/75', role: 'status', children: [(0, jsx_runtime_1.jsx)(ps_core_components_1.PsSpinner, { color: 'current', label: labels.cameraStarting, size: 'small' }), (0, jsx_runtime_1.jsx)("span", { children: labels.cameraStarting })] })), flashKey > 0 ? ((0, jsx_runtime_1.jsx)("div", { "aria-hidden": 'true', className: 'pointer-events-none absolute inset-0 bg-white animate-ps-fade-out' }, flashKey)) : null, (0, jsx_runtime_1.jsxs)("div", { className: 'absolute inset-x-0 top-0 flex items-start justify-between gap-3 bg-gradient-to-b from-black/60 to-transparent px-4 pb-10 pt-[max(1rem,env(safe-area-inset-top))]', children: [(0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { iconKey: ps_icons_1.PsIconKey.Close, label: labels.close, onClick: onClose }), (0, jsx_runtime_1.jsx)("div", { className: 'flex items-center gap-2', children: canTorch && isReady ? ((0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { iconKey: ps_icons_1.PsIconKey.Flash, isPressed: isTorchOn, label: isTorchOn ? labels.torchOff : labels.torchOn, onClick: onToggleTorch })) : null })] }), isReady ? ((0, jsx_runtime_1.jsx)("div", { className: 'absolute inset-x-0 top-[calc(max(1rem,env(safe-area-inset-top))+3.75rem)] flex justify-center px-4', children: (0, jsx_runtime_1.jsx)("p", { "aria-live": 'polite', className: ps_scan_chrome_classes_1.PsScanChromeClasses.pill, children: hint }) })) : null, (0, jsx_runtime_1.jsxs)("div", { className: 'absolute inset-x-0 bottom-0 grid grid-cols-[1fr_auto_1fr] items-center gap-4 bg-gradient-to-t from-black/80 to-transparent px-5 pb-[max(1.5rem,env(safe-area-inset-bottom))] pt-12', children: [(0, jsx_runtime_1.jsx)("div", { className: 'flex justify-start', children: (0, jsx_runtime_1.jsx)(ps_scan_photo_button_1.PsScanPhotoButton, { isIconOnly: true, label: labels.choosePhoto, onFile: onFile }) }), (0, jsx_runtime_1.jsx)(ps_scan_shutter_1.PsScanShutter, { disabled: !isReady || isBusy, label: labels.capture, onCapture: onCapture }), (0, jsx_runtime_1.jsx)("span", { "aria-hidden": 'true' })] })] }));
|
|
33
24
|
};
|
|
34
25
|
exports.PsScanCameraView = PsScanCameraView;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { PsDocumentScannerLabels } from '../constants/ps-document-scanner-labels';
|
|
2
2
|
import type { PsLabelSet } from '../models/ps-label-set';
|
|
3
|
-
import type {
|
|
3
|
+
import type { PsScanPhoto } from '../models/ps-scan-photo';
|
|
4
4
|
import type { PsScanQuad } from '../models/ps-scan-quad';
|
|
5
5
|
export interface PsScanCropEditorProps {
|
|
6
6
|
labels: PsLabelSet<typeof PsDocumentScannerLabels>;
|
|
7
7
|
onAutoDetect: () => void;
|
|
8
8
|
onChange: (corners: PsScanQuad) => void;
|
|
9
|
-
|
|
9
|
+
onContinue: () => void;
|
|
10
10
|
onRetake: () => void;
|
|
11
|
-
|
|
11
|
+
photo: PsScanPhoto;
|
|
12
12
|
}
|
|
13
|
-
export declare const PsScanCropEditor: ({ labels, onAutoDetect, onChange,
|
|
13
|
+
export declare const PsScanCropEditor: ({ labels, onAutoDetect, onChange, onContinue, onRetake, photo, }: PsScanCropEditorProps) => import("react").JSX.Element;
|
|
@@ -12,19 +12,19 @@ const ps_scan_geometry_service_1 = require("../services/ps-scan-geometry-service
|
|
|
12
12
|
const ps_scan_button_1 = require("./ps-scan-button");
|
|
13
13
|
const ps_scan_icon_button_1 = require("./ps-scan-icon-button");
|
|
14
14
|
const ps_scan_loupe_1 = require("./ps-scan-loupe");
|
|
15
|
-
const PsScanCropEditor = ({ labels, onAutoDetect, onChange,
|
|
15
|
+
const PsScanCropEditor = ({ labels, onAutoDetect, onChange, onContinue, onRetake, photo, }) => {
|
|
16
16
|
const [areaRef, area] = (0, ps_core_components_1.usePsElementSize)();
|
|
17
17
|
const stageRef = (0, react_1.useRef)(null);
|
|
18
18
|
const [activeIndex, setActiveIndex] = (0, react_1.useState)(null);
|
|
19
19
|
const hintId = 'ps-scan-crop-hint';
|
|
20
|
-
const size = ps_scan_geometry_service_1.PsScanGeometryService.fit(area, { height:
|
|
20
|
+
const size = ps_scan_geometry_service_1.PsScanGeometryService.fit(area, { height: photo.height, width: photo.width });
|
|
21
21
|
const cornerLabels = [
|
|
22
22
|
labels.cornerTopLeft,
|
|
23
23
|
labels.cornerTopRight,
|
|
24
24
|
labels.cornerBottomRight,
|
|
25
25
|
labels.cornerBottomLeft,
|
|
26
26
|
];
|
|
27
|
-
const outline =
|
|
27
|
+
const outline = photo.corners
|
|
28
28
|
.map((point) => `${point.x * size.width},${point.y * size.height}`)
|
|
29
29
|
.join(' L');
|
|
30
30
|
const move = (index, event) => {
|
|
@@ -36,7 +36,7 @@ const PsScanCropEditor = ({ labels, onAutoDetect, onChange, onKeep, onRetake, pa
|
|
|
36
36
|
x: (event.clientX - rect.left) / rect.width,
|
|
37
37
|
y: (event.clientY - rect.top) / rect.height,
|
|
38
38
|
});
|
|
39
|
-
const next =
|
|
39
|
+
const next = photo.corners.map((corner, at) => (at === index ? point : corner));
|
|
40
40
|
if (ps_scan_geometry_service_1.PsScanGeometryService.isUsable(next))
|
|
41
41
|
onChange(next);
|
|
42
42
|
};
|
|
@@ -56,14 +56,14 @@ const PsScanCropEditor = ({ labels, onAutoDetect, onChange, onKeep, onRetake, pa
|
|
|
56
56
|
if (delta === undefined)
|
|
57
57
|
return;
|
|
58
58
|
event.preventDefault();
|
|
59
|
-
onChange(ps_scan_geometry_service_1.PsScanGeometryService.nudge(
|
|
59
|
+
onChange(ps_scan_geometry_service_1.PsScanGeometryService.nudge(photo.corners, index, delta[0], delta[1]));
|
|
60
60
|
};
|
|
61
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: 'flex h-full min-h-0 flex-col bg-black text-white animate-ps-fade-in', children: [(0, jsx_runtime_1.jsxs)("header", { className: 'grid shrink-0 grid-cols-[2.75rem_1fr_2.75rem] items-center gap-3 px-4 pb-1 pt-[max(1rem,env(safe-area-inset-top))]', children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": 'true' }), (0, jsx_runtime_1.jsx)("h2", { className: 'truncate text-center text-base font-semibold', children: labels.cropTitle }), (0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { iconKey: ps_icons_1.PsIconKey.Spark, label: labels.autoDetect, onClick: onAutoDetect })] }), (0, jsx_runtime_1.
|
|
61
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: 'flex h-full min-h-0 flex-col bg-black text-white animate-ps-fade-in', children: [(0, jsx_runtime_1.jsxs)("header", { className: 'grid shrink-0 grid-cols-[2.75rem_1fr_2.75rem] items-center gap-3 px-4 pb-1 pt-[max(1rem,env(safe-area-inset-top))]', children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": 'true' }), (0, jsx_runtime_1.jsx)("h2", { className: 'truncate text-center text-base font-semibold', children: labels.cropTitle }), (0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { iconKey: ps_icons_1.PsIconKey.Spark, label: labels.autoDetect, onClick: onAutoDetect })] }), (0, jsx_runtime_1.jsxs)("p", { className: 'shrink-0 px-6 text-center text-sm text-white/65', id: hintId, children: [photo.isDetected ? labels.edgesFound : labels.edgesNotFound, " ", labels.cropHint] }), (0, jsx_runtime_1.jsx)("div", { className: 'flex min-h-0 flex-1 items-center justify-center px-8 py-6', ref: areaRef, children: (0, jsx_runtime_1.jsxs)("div", { className: 'relative touch-none select-none', ref: stageRef, style: { height: size.height, width: size.width }, children: [(0, jsx_runtime_1.jsx)("img", { alt: '', className: 'absolute inset-0 size-full rounded-sm', draggable: false, src: photo.sourceUrl }), (0, jsx_runtime_1.jsxs)("svg", { "aria-hidden": 'true', className: 'pointer-events-none absolute inset-0 size-full overflow-visible', viewBox: `0 0 ${Math.max(1, size.width)} ${Math.max(1, size.height)}`, children: [(0, jsx_runtime_1.jsx)("path", { className: 'fill-black/55', d: `M0 0H${size.width}V${size.height}H0Z M${outline}Z`, fillRule: 'evenodd' }), (0, jsx_runtime_1.jsx)("path", { className: 'fill-none stroke-primary', d: `M${outline}Z`, strokeLinejoin: 'round', strokeWidth: '2.5' })] }), ps_scan_corner_order_1.PsScanCornerOrder.map((key, index) => ((0, jsx_runtime_1.jsx)("button", { "aria-describedby": hintId, "aria-label": cornerLabels[index], className: 'ps-focus-ring absolute flex size-11 -translate-x-1/2 -translate-y-1/2 cursor-grab touch-none items-center justify-center rounded-full active:cursor-grabbing', onKeyDown: (event) => nudge(index, event), onPointerCancel: release, onPointerDown: (event) => {
|
|
62
62
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
63
63
|
setActiveIndex(index);
|
|
64
64
|
}, onPointerMove: (event) => move(index, event), onPointerUp: release, style: {
|
|
65
|
-
left: `${
|
|
66
|
-
top: `${
|
|
67
|
-
}, type: 'button', children: (0, jsx_runtime_1.jsx)("span", { className: ps_design_system_1.PallasoftClassNameService.merge('size-6 rounded-full border-[3px] border-white bg-primary shadow-lg transition-transform duration-150', activeIndex === index ? 'scale-125' : '') }) }, key))), activeIndex === null ? null : ((0, jsx_runtime_1.jsx)(ps_scan_loupe_1.PsScanLoupe, { corners:
|
|
65
|
+
left: `${photo.corners[index].x * 100}%`,
|
|
66
|
+
top: `${photo.corners[index].y * 100}%`,
|
|
67
|
+
}, type: 'button', children: (0, jsx_runtime_1.jsx)("span", { className: ps_design_system_1.PallasoftClassNameService.merge('size-6 rounded-full border-[3px] border-white bg-primary shadow-lg transition-transform duration-150', activeIndex === index ? 'scale-125' : '') }) }, key))), activeIndex === null ? null : ((0, jsx_runtime_1.jsx)(ps_scan_loupe_1.PsScanLoupe, { corners: photo.corners, point: photo.corners[activeIndex], source: photo.sourceUrl, stage: size }))] }) }), (0, jsx_runtime_1.jsxs)("footer", { className: 'mx-auto grid w-full max-w-md shrink-0 grid-cols-2 gap-3 px-4 pb-[max(1.25rem,env(safe-area-inset-bottom))] pt-2', children: [(0, jsx_runtime_1.jsx)(ps_scan_button_1.PsScanButton, { isLarge: true, onClick: onRetake, children: labels.retake }), (0, jsx_runtime_1.jsx)(ps_scan_button_1.PsScanButton, { isLarge: true, isPrimary: true, onClick: onContinue, children: labels.continue })] })] }));
|
|
68
68
|
};
|
|
69
69
|
exports.PsScanCropEditor = PsScanCropEditor;
|
|
@@ -2,10 +2,9 @@ import { PsDocumentScannerLabels } from '../constants/ps-document-scanner-labels
|
|
|
2
2
|
import { PsScanCameraStatus } from '../constants/ps-scan-camera-status';
|
|
3
3
|
import type { PsLabelSet } from '../models/ps-label-set';
|
|
4
4
|
export interface PsScanPermissionViewProps {
|
|
5
|
-
isMultiple: boolean;
|
|
6
5
|
labels: PsLabelSet<typeof PsDocumentScannerLabels>;
|
|
7
6
|
onAllow: () => void;
|
|
8
|
-
|
|
7
|
+
onFile: (file: File) => void;
|
|
9
8
|
status: PsScanCameraStatus;
|
|
10
9
|
}
|
|
11
|
-
export declare const PsScanPermissionView: ({
|
|
10
|
+
export declare const PsScanPermissionView: ({ labels, onAllow, onFile, status, }: PsScanPermissionViewProps) => import("react").JSX.Element;
|
|
@@ -9,7 +9,7 @@ const ps_scan_button_1 = require("./ps-scan-button");
|
|
|
9
9
|
const ps_scan_denied_steps_1 = require("./ps-scan-denied-steps");
|
|
10
10
|
const ps_scan_illustration_1 = require("./ps-scan-illustration");
|
|
11
11
|
const ps_scan_photo_button_1 = require("./ps-scan-photo-button");
|
|
12
|
-
const PsScanPermissionView = ({
|
|
12
|
+
const PsScanPermissionView = ({ labels, onAllow, onFile, status, }) => {
|
|
13
13
|
if (status === ps_scan_camera_status_1.PsScanCameraStatus.Checking || status === ps_scan_camera_status_1.PsScanCameraStatus.Starting)
|
|
14
14
|
return ((0, jsx_runtime_1.jsxs)("div", { className: 'flex h-full flex-col items-center justify-center gap-3 text-sm text-white/75', role: 'status', children: [(0, jsx_runtime_1.jsx)(ps_core_components_1.PsSpinner, { color: 'current', label: labels.cameraStarting, size: 'small' }), (0, jsx_runtime_1.jsx)("span", { children: labels.cameraStarting })] }));
|
|
15
15
|
const screens = {
|
|
@@ -43,6 +43,6 @@ const PsScanPermissionView = ({ isMultiple, labels, onAllow, onFiles, status, })
|
|
|
43
43
|
const screen = screens[status];
|
|
44
44
|
const isPrimer = status === ps_scan_camera_status_1.PsScanCameraStatus.Prompt;
|
|
45
45
|
const canRetry = status === ps_scan_camera_status_1.PsScanCameraStatus.Denied || status === ps_scan_camera_status_1.PsScanCameraStatus.Busy;
|
|
46
|
-
return ((0, jsx_runtime_1.jsx)("div", { className: 'flex h-full min-h-0 flex-col overflow-y-auto', children: (0, jsx_runtime_1.jsxs)("div", { className: 'm-auto flex w-full max-w-sm flex-col items-center gap-6 px-6 pb-[max(1.5rem,env(safe-area-inset-bottom))] pt-20 text-center animate-ps-slide-up', children: [isPrimer ? ((0, jsx_runtime_1.jsx)(ps_scan_illustration_1.PsScanIllustration, {})) : ((0, jsx_runtime_1.jsx)("span", { className: 'flex size-20 items-center justify-center rounded-full bg-white/10 text-white', children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-9', iconKey: screen.iconKey }) })), (0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-col gap-2', children: [(0, jsx_runtime_1.jsx)("h2", { className: 'text-xl font-semibold leading-tight text-white sm:text-2xl', children: screen.title }), (0, jsx_runtime_1.jsx)("p", { className: 'text-sm leading-6 text-white/70', children: screen.body })] }), status === ps_scan_camera_status_1.PsScanCameraStatus.Denied ? (0, jsx_runtime_1.jsx)(ps_scan_denied_steps_1.PsScanDeniedSteps, { labels: labels }) : null, (0, jsx_runtime_1.jsxs)("div", { className: 'flex w-full flex-col gap-3', children: [isPrimer || canRetry ? ((0, jsx_runtime_1.jsx)(ps_scan_button_1.PsScanButton, { className: 'w-full', isLarge: true, isPrimary: true, leadingIcon: isPrimer ? ((0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-4', iconKey: ps_icons_1.PsIconKey.Camera })) : undefined, onClick: onAllow, children: isPrimer ? labels.allowCamera : labels.tryAgain })) : null, (0, jsx_runtime_1.jsx)(ps_scan_photo_button_1.PsScanPhotoButton, { className: 'w-full',
|
|
46
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: 'flex h-full min-h-0 flex-col overflow-y-auto', children: (0, jsx_runtime_1.jsxs)("div", { className: 'm-auto flex w-full max-w-sm flex-col items-center gap-6 px-6 pb-[max(1.5rem,env(safe-area-inset-bottom))] pt-20 text-center animate-ps-slide-up', children: [isPrimer ? ((0, jsx_runtime_1.jsx)(ps_scan_illustration_1.PsScanIllustration, {})) : ((0, jsx_runtime_1.jsx)("span", { className: 'flex size-20 items-center justify-center rounded-full bg-white/10 text-white', children: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-9', iconKey: screen.iconKey }) })), (0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-col gap-2', children: [(0, jsx_runtime_1.jsx)("h2", { className: 'text-xl font-semibold leading-tight text-white sm:text-2xl', children: screen.title }), (0, jsx_runtime_1.jsx)("p", { className: 'text-sm leading-6 text-white/70', children: screen.body })] }), status === ps_scan_camera_status_1.PsScanCameraStatus.Denied ? (0, jsx_runtime_1.jsx)(ps_scan_denied_steps_1.PsScanDeniedSteps, { labels: labels }) : null, (0, jsx_runtime_1.jsxs)("div", { className: 'flex w-full flex-col gap-3', children: [isPrimer || canRetry ? ((0, jsx_runtime_1.jsx)(ps_scan_button_1.PsScanButton, { className: 'w-full', isLarge: true, isPrimary: true, leadingIcon: isPrimer ? ((0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-4', iconKey: ps_icons_1.PsIconKey.Camera })) : undefined, onClick: onAllow, children: isPrimer ? labels.allowCamera : labels.tryAgain })) : null, (0, jsx_runtime_1.jsx)(ps_scan_photo_button_1.PsScanPhotoButton, { className: 'w-full', label: labels.choosePhoto, onFile: onFile })] })] }) }));
|
|
47
47
|
};
|
|
48
48
|
exports.PsScanPermissionView = PsScanPermissionView;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export interface PsScanPhotoButtonProps {
|
|
2
2
|
className?: string;
|
|
3
3
|
isIconOnly?: boolean;
|
|
4
|
-
isMultiple: boolean;
|
|
5
4
|
label: string;
|
|
6
|
-
|
|
5
|
+
onFile: (file: File) => void;
|
|
7
6
|
}
|
|
8
|
-
export declare const PsScanPhotoButton: ({ className, isIconOnly,
|
|
7
|
+
export declare const PsScanPhotoButton: ({ className, isIconOnly, label, onFile, }: PsScanPhotoButtonProps) => import("react").JSX.Element;
|
|
@@ -6,15 +6,15 @@ const react_1 = require("react");
|
|
|
6
6
|
const ps_icons_1 = require("@pallasoft/ps-icons");
|
|
7
7
|
const ps_scan_button_1 = require("./ps-scan-button");
|
|
8
8
|
const ps_scan_icon_button_1 = require("./ps-scan-icon-button");
|
|
9
|
-
const PsScanPhotoButton = ({ className, isIconOnly = false,
|
|
9
|
+
const PsScanPhotoButton = ({ className, isIconOnly = false, label, onFile, }) => {
|
|
10
10
|
const input = (0, react_1.useRef)(null);
|
|
11
11
|
const open = () => input.current?.click();
|
|
12
12
|
const onChange = (event) => {
|
|
13
|
-
const
|
|
13
|
+
const file = event.target.files === null ? undefined : event.target.files[0];
|
|
14
14
|
event.target.value = '';
|
|
15
|
-
if (
|
|
16
|
-
|
|
15
|
+
if (file !== undefined)
|
|
16
|
+
onFile(file);
|
|
17
17
|
};
|
|
18
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [isIconOnly ? ((0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { className: className, iconKey: ps_icons_1.PsIconKey.Image, label: label, onClick: open })) : ((0, jsx_runtime_1.jsx)(ps_scan_button_1.PsScanButton, { className: className, isLarge: true, leadingIcon: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-4', iconKey: ps_icons_1.PsIconKey.Image }), onClick: open, children: label })), (0, jsx_runtime_1.jsx)("input", { accept: 'image/*', "aria-hidden": 'true', className: 'sr-only',
|
|
18
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [isIconOnly ? ((0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { className: className, iconKey: ps_icons_1.PsIconKey.Image, label: label, onClick: open })) : ((0, jsx_runtime_1.jsx)(ps_scan_button_1.PsScanButton, { className: className, isLarge: true, leadingIcon: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-4', iconKey: ps_icons_1.PsIconKey.Image }), onClick: open, children: label })), (0, jsx_runtime_1.jsx)("input", { accept: 'image/*', "aria-hidden": 'true', className: 'sr-only', onChange: onChange, ref: input, tabIndex: -1, type: 'file' })] }));
|
|
19
19
|
};
|
|
20
20
|
exports.PsScanPhotoButton = PsScanPhotoButton;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PsDocumentScannerLabels } from '../constants/ps-document-scanner-labels';
|
|
2
|
+
import type { PsLabelSet } from '../models/ps-label-set';
|
|
3
|
+
import type { PsScanResult } from '../models/ps-scan-result';
|
|
4
|
+
export interface PsScanPreviewProps {
|
|
5
|
+
error: string;
|
|
6
|
+
labels: PsLabelSet<typeof PsDocumentScannerLabels>;
|
|
7
|
+
onAdjust: () => void;
|
|
8
|
+
onRetake: () => void;
|
|
9
|
+
onUse: () => void;
|
|
10
|
+
result: PsScanResult | null;
|
|
11
|
+
}
|
|
12
|
+
export declare const PsScanPreview: ({ error, labels, onAdjust, onRetake, onUse, result, }: PsScanPreviewProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsScanPreview = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const ps_core_components_1 = require("@pallasoft/ps-core-components");
|
|
6
|
+
const ps_icons_1 = require("@pallasoft/ps-icons");
|
|
7
|
+
const ps_scan_button_1 = require("./ps-scan-button");
|
|
8
|
+
const ps_scan_icon_button_1 = require("./ps-scan-icon-button");
|
|
9
|
+
const PsScanPreview = ({ error, labels, onAdjust, onRetake, onUse, result, }) => ((0, jsx_runtime_1.jsxs)("div", { className: 'flex h-full min-h-0 flex-col bg-black text-white animate-ps-fade-in', children: [(0, jsx_runtime_1.jsxs)("header", { className: 'grid shrink-0 grid-cols-[2.75rem_1fr_2.75rem] items-center gap-3 px-4 pb-1 pt-[max(1rem,env(safe-area-inset-top))]', children: [(0, jsx_runtime_1.jsx)(ps_scan_icon_button_1.PsScanIconButton, { iconKey: ps_icons_1.PsIconKey.Crop, label: labels.cropTitle, onClick: onAdjust }), (0, jsx_runtime_1.jsx)("h2", { className: 'truncate text-center text-base font-semibold', children: labels.previewTitle }), (0, jsx_runtime_1.jsx)("span", { "aria-hidden": 'true' })] }), (0, jsx_runtime_1.jsx)("div", { className: 'flex min-h-0 flex-1 items-center justify-center px-6 py-4', children: result === null ? ((0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-col items-center gap-3 text-sm text-white/75', role: 'status', children: [(0, jsx_runtime_1.jsx)(ps_core_components_1.PsSpinner, { color: 'current', label: labels.preparing, size: 'small' }), (0, jsx_runtime_1.jsx)("span", { children: labels.preparing })] })) : ((0, jsx_runtime_1.jsx)("img", { alt: labels.previewAlt, className: 'max-h-full max-w-full rounded-sm bg-white object-contain shadow-[0_24px_60px_-20px_rgb(0_0_0/0.9)] animate-ps-fade-in', src: result.url })) }), error === '' ? null : ((0, jsx_runtime_1.jsx)("p", { className: 'mx-auto mb-2 max-w-sm rounded-ps-control bg-danger px-3 py-2 text-center text-sm text-white', role: 'alert', children: error })), (0, jsx_runtime_1.jsxs)("footer", { className: 'mx-auto grid w-full max-w-md shrink-0 grid-cols-2 gap-3 px-4 pb-[max(1.25rem,env(safe-area-inset-bottom))] pt-2', children: [(0, jsx_runtime_1.jsx)(ps_scan_button_1.PsScanButton, { isLarge: true, onClick: onRetake, children: labels.retake }), (0, jsx_runtime_1.jsx)(ps_scan_button_1.PsScanButton, { disabled: result === null, isLarge: true, isPrimary: true, leadingIcon: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { "aria-hidden": 'true', className: 'size-4', iconKey: ps_icons_1.PsIconKey.Check }), onClick: onUse, children: labels.useScan })] })] }));
|
|
10
|
+
exports.PsScanPreview = PsScanPreview;
|
|
@@ -2,6 +2,5 @@ export interface PsScanShutterProps {
|
|
|
2
2
|
disabled: boolean;
|
|
3
3
|
label: string;
|
|
4
4
|
onCapture: () => void;
|
|
5
|
-
progress: number;
|
|
6
5
|
}
|
|
7
|
-
export declare const PsScanShutter: ({ disabled, label, onCapture
|
|
6
|
+
export declare const PsScanShutter: ({ disabled, label, onCapture }: PsScanShutterProps) => import("react").JSX.Element;
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PsScanShutter = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
-
const PsScanShutter = ({ disabled, label, onCapture
|
|
5
|
+
const PsScanShutter = ({ disabled, label, onCapture }) => ((0, jsx_runtime_1.jsxs)("button", { "aria-label": label, className: 'ps-focus-ring group relative flex size-[4.75rem] shrink-0 items-center justify-center rounded-full disabled:opacity-40', disabled: disabled, onClick: onCapture, title: label, type: 'button', children: [(0, jsx_runtime_1.jsx)("svg", { "aria-hidden": 'true', className: 'absolute inset-0 size-full -rotate-90', viewBox: '0 0 76 76', children: (0, jsx_runtime_1.jsx)("circle", { className: 'stroke-white', cx: '38', cy: '38', fill: 'none', r: '35', strokeWidth: '4' }) }), (0, jsx_runtime_1.jsx)("span", { className: 'size-[3.75rem] rounded-full bg-white transition-transform duration-150 group-active:scale-90' })] }));
|
|
6
6
|
exports.PsScanShutter = PsScanShutter;
|
|
@@ -11,6 +11,6 @@ const PsUploadModal = ({ isOpen, labels, onClose, queue }) => {
|
|
|
11
11
|
const text = { ...ps_upload_labels_1.PsUploadLabels, ...labels };
|
|
12
12
|
const summary = ps_upload_queue_service_1.PsUploadQueueService.summary(queue.items);
|
|
13
13
|
const title = queue.isBusy ? text.title : summary.failed > 0 ? text.titleFailed : text.titleDone;
|
|
14
|
-
return ((0, jsx_runtime_1.jsx)(ps_popovers_1.PsModal, {
|
|
14
|
+
return ((0, jsx_runtime_1.jsx)(ps_popovers_1.PsModal, { footer: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [queue.isBusy ? ((0, jsx_runtime_1.jsx)(ps_core_components_1.PsButton, { onClick: () => queue.items.forEach((item) => queue.cancel(item.id)), type: 'button', variant: 'surface', children: text.cancelAll })) : null, (0, jsx_runtime_1.jsx)(ps_core_components_1.PsButton, { onClick: onClose, type: 'button', variant: 'primary', children: text.finish })] }), isOpen: isOpen, onClose: onClose, size: 'md', title: title, children: (0, jsx_runtime_1.jsx)("ul", { className: 'flex flex-col gap-2', children: queue.items.map((item) => ((0, jsx_runtime_1.jsx)(ps_upload_row_1.PsUploadRow, { item: item, labels: text, onCancel: () => queue.cancel(item.id), onRemove: () => queue.remove(item.id), onRetry: () => queue.retry(item.id) }, item.id))) }) }));
|
|
15
15
|
};
|
|
16
16
|
exports.PsUploadModal = PsUploadModal;
|