react-native-image-stitcher 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +151 -0
- package/README.md +28 -0
- package/android/src/main/java/io/imagestitcher/rn/IncrementalFirstwinsEngine.kt +3 -2
- package/dist/camera/ARCameraView.d.ts +10 -0
- package/dist/camera/ARCameraView.js +1 -0
- package/dist/camera/Camera.d.ts +191 -0
- package/dist/camera/Camera.js +250 -9
- package/dist/camera/OrientationDriftModal.d.ts +83 -0
- package/dist/camera/OrientationDriftModal.js +159 -0
- package/dist/camera/PanoramaBandOverlay.d.ts +13 -1
- package/dist/camera/PanoramaBandOverlay.js +106 -45
- package/dist/camera/PanoramaSettingsModal.js +15 -1
- package/dist/camera/ViewportCropOverlay.d.ts +35 -31
- package/dist/camera/ViewportCropOverlay.js +39 -30
- package/dist/camera/useDeviceOrientation.d.ts +18 -9
- package/dist/camera/useDeviceOrientation.js +18 -9
- package/dist/camera/useOrientationDrift.d.ts +104 -0
- package/dist/camera/useOrientationDrift.js +120 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +12 -1
- package/dist/stitching/incremental.d.ts +5 -3
- package/ios/Sources/RNImageStitcher/ARSessionBridge.swift +7 -1
- package/ios/Sources/RNImageStitcher/OpenCVIncrementalStitcher.h +4 -3
- package/ios/Sources/RNImageStitcher/OpenCVIncrementalStitcher.mm +9 -7
- package/ios/Sources/RNImageStitcher/RNSARSession.swift +46 -7
- package/package.json +1 -1
- package/src/camera/ARCameraView.tsx +18 -1
- package/src/camera/Camera.tsx +639 -21
- package/src/camera/OrientationDriftModal.tsx +224 -0
- package/src/camera/PanoramaBandOverlay.tsx +135 -49
- package/src/camera/PanoramaSettingsModal.tsx +14 -0
- package/src/camera/ViewportCropOverlay.tsx +52 -30
- package/src/camera/__tests__/useOrientationDrift.test.ts +169 -0
- package/src/camera/useDeviceOrientation.ts +18 -9
- package/src/camera/useOrientationDrift.ts +172 -0
- package/src/index.ts +13 -0
- package/src/stitching/incremental.ts +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,157 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
16
|
|
|
17
17
|
## [Unreleased]
|
|
18
18
|
|
|
19
|
+
## [0.13.0] — 2026-05-29
|
|
20
|
+
|
|
21
|
+
### Added — Layer-2 components absorbed into `<Camera>` (opt-out)
|
|
22
|
+
|
|
23
|
+
The flagship `<Camera>` now ships built-in defaults for every UX
|
|
24
|
+
chrome piece previously exposed only as a Layer-2 component. Hosts
|
|
25
|
+
adopting `<Camera>` directly get a complete capture surface — flash
|
|
26
|
+
button, pan-speed pill, drift-marker guide, header chrome,
|
|
27
|
+
capture-history strip, and post-stitch preview — without having to
|
|
28
|
+
import and wire each piece by hand.
|
|
29
|
+
|
|
30
|
+
All built-ins use the opt-out pattern: enabled by default, disabled
|
|
31
|
+
by setting the corresponding boolean to `false` or by omitting the
|
|
32
|
+
corresponding payload prop. Hosts that want their own chrome can
|
|
33
|
+
opt out per piece and layer custom UI on top of `<Camera>` (the
|
|
34
|
+
Layer-2 components remain exported and are unchanged).
|
|
35
|
+
|
|
36
|
+
#### Flash control
|
|
37
|
+
|
|
38
|
+
- `flash?: 'on' | 'off'` — controlled torch state. Omit to let
|
|
39
|
+
`<Camera>` own it internally.
|
|
40
|
+
- `onFlashChange?` — fires on tap (controlled and uncontrolled both).
|
|
41
|
+
- `showFlashButton?: boolean` (default `true`) — built-in flash button
|
|
42
|
+
in the bottom-left slot. AR mode auto-disables (ARKit / ARCore own
|
|
43
|
+
the device's torch; surfaces "Flash unavailable in AR mode" a11y
|
|
44
|
+
label and greyed styling).
|
|
45
|
+
|
|
46
|
+
#### Pan guidance
|
|
47
|
+
|
|
48
|
+
- `panGuide?: boolean` (default `true`) — built-in
|
|
49
|
+
`IncrementalPanGuide` ("keep the arrow on the line" drift marker).
|
|
50
|
+
- `panoramaGuidance?: boolean` (default `true`) — built-in
|
|
51
|
+
`PanoramaGuidance` pan-speed pill.
|
|
52
|
+
- Both are gyroscope-driven and only subscribe to the sensor while
|
|
53
|
+
recording — no idle cost.
|
|
54
|
+
|
|
55
|
+
#### Header
|
|
56
|
+
|
|
57
|
+
- `headerTitle?: string` — when set, renders a built-in
|
|
58
|
+
`CaptureHeader` at the top of the screen. The existing settings
|
|
59
|
+
gear is absorbed into the header's right side (no duplicate gear).
|
|
60
|
+
- `onHeaderBack?`, `headerBackLabel?`, `headerGuidance?`,
|
|
61
|
+
`headerColors?` — pass-through to `CaptureHeader`.
|
|
62
|
+
|
|
63
|
+
#### Capture history + preview
|
|
64
|
+
|
|
65
|
+
- `thumbnails?: CaptureThumbnailItem[]` — when supplied (even `[]`),
|
|
66
|
+
renders the built-in `CaptureThumbnailStrip` above the bottom
|
|
67
|
+
controls. Hidden during recording so it doesn't overlap the
|
|
68
|
+
panorama band overlay.
|
|
69
|
+
- `thumbnailsMin?`, `thumbnailsMax?` — count-line hints.
|
|
70
|
+
- `onThumbnailPress?` — replaces the strip's built-in
|
|
71
|
+
tap-to-preview modal with a host handler.
|
|
72
|
+
- `capturePreview?` — when set, renders a built-in `CapturePreview`
|
|
73
|
+
modal showing the supplied image. Use for post-stitch
|
|
74
|
+
confirmation; the host clears the prop on dismiss via
|
|
75
|
+
`onCapturePreviewClose`.
|
|
76
|
+
- `capturePreviewActions?` — pass-through action buttons for the
|
|
77
|
+
preview modal.
|
|
78
|
+
|
|
79
|
+
### Migration
|
|
80
|
+
|
|
81
|
+
- Hosts that were importing Layer-2 components (`CaptureHeader`,
|
|
82
|
+
`CaptureControlsBar`, `IncrementalPanGuide`, `PanoramaGuidance`,
|
|
83
|
+
`CaptureThumbnailStrip`, `CapturePreview`) directly can now drop
|
|
84
|
+
those imports and use the corresponding `<Camera>` props.
|
|
85
|
+
- The Layer-2 components remain exported and unchanged in v0.13 for
|
|
86
|
+
backward compatibility. Deprecation of those exports is targeted
|
|
87
|
+
for v0.14.
|
|
88
|
+
- No behaviour change for hosts that already use `<Camera>` and
|
|
89
|
+
don't supply any of the new props — every new built-in defaults
|
|
90
|
+
to the previous (omitted) UX, except the flash button which
|
|
91
|
+
appears in the now-occupied bottom-left slot. Hosts that previously
|
|
92
|
+
rendered chrome in that slot above `<Camera>` can pass
|
|
93
|
+
`showFlashButton={false}`.
|
|
94
|
+
|
|
95
|
+
## [0.12.0] — 2026-05-28
|
|
96
|
+
|
|
97
|
+
### Added — Orientation-aware `<Camera>` (R2-lite)
|
|
98
|
+
|
|
99
|
+
`<Camera>` now works correctly under both portrait-locked and
|
|
100
|
+
non-locked iOS hosts. Pre-v0.12 the component assumed the host
|
|
101
|
+
had restricted `UISupportedInterfaceOrientations` to Portrait;
|
|
102
|
+
removing that restriction broke control layout, camera-preview
|
|
103
|
+
rotation across modal close, and panorama capture mode selection.
|
|
104
|
+
|
|
105
|
+
Five coupled changes:
|
|
106
|
+
|
|
107
|
+
1. **`useOrientationDrift` hook + `OrientationDriftModal`**
|
|
108
|
+
(PR-1). Snapshots device orientation at capture start and
|
|
109
|
+
latches a `drifted: true` flag if the user rotates mid-
|
|
110
|
+
capture. The incremental engine doesn't support cross-
|
|
111
|
+
orientation captures (per the engine spec at
|
|
112
|
+
`incremental.ts:373-403`), so `<Camera>` auto-cancels via
|
|
113
|
+
`incremental.cancel()` and shows the modal to explain.
|
|
114
|
+
|
|
115
|
+
2. **New `onCaptureAbandoned` prop** on `<Camera>`. Fires when
|
|
116
|
+
the SDK auto-cancels an in-flight capture. Currently the only
|
|
117
|
+
reason is `'orientation-drift'`; the union signature keeps the
|
|
118
|
+
prop stable for future reasons (low memory, etc.).
|
|
119
|
+
|
|
120
|
+
3. **4-way home-indicator-edge anchor** for the bottom-controls
|
|
121
|
+
row (Layer A). Combines `useWindowDimensions()` and
|
|
122
|
+
`useDeviceOrientation()` to compute the JS edge that
|
|
123
|
+
corresponds to the device's home-indicator side, then anchors
|
|
124
|
+
shutter / lens / AR toggle there. Matches iOS Camera's
|
|
125
|
+
behaviour: shutter stays within thumb reach regardless of tilt.
|
|
126
|
+
|
|
127
|
+
4. **AR `takePhoto` orientation parameter** (Fix #2). Pre-v0.12
|
|
128
|
+
`RNSARSession.takePhoto` hardcoded `.right` (90° CW) to
|
|
129
|
+
rotate ARKit's sensor-native landscape buffer to portrait,
|
|
130
|
+
assuming portrait hold. Now switches on the device
|
|
131
|
+
orientation passed from `useDeviceOrientation()` so landscape
|
|
132
|
+
captures produce correctly-oriented photos.
|
|
133
|
+
|
|
134
|
+
5. **Modal `supportedOrientations={[all 4]}`** on
|
|
135
|
+
`OrientationDriftModal` and `PanoramaSettingsModal`. RN's iOS
|
|
136
|
+
`Modal` defaults to portrait-only, which force-rotates the
|
|
137
|
+
window scene when opened under a non-locked host — leaving
|
|
138
|
+
the underlying `<Camera>`'s ARSession with stale orientation
|
|
139
|
+
state on dismiss (preview rendered sideways). Declaring all
|
|
140
|
+
four orientations keeps the window aligned through the modal
|
|
141
|
+
cycle.
|
|
142
|
+
|
|
143
|
+
### Added — Comment cleanup across native + JS surfaces
|
|
144
|
+
|
|
145
|
+
Stale "portrait-locked host" comments in
|
|
146
|
+
`useDeviceOrientation.ts`, `incremental.ts`, `StitcherFrame.ts`,
|
|
147
|
+
`OpenCVIncrementalStitcher.{h,mm}`, and
|
|
148
|
+
`IncrementalFirstwinsEngine.kt` rewritten to acknowledge both
|
|
149
|
+
host configurations. Pose-derived orientation detection remains
|
|
150
|
+
the single source of truth — that didn't change; the rationale
|
|
151
|
+
just got more accurate.
|
|
152
|
+
|
|
153
|
+
### Known follow-ups (deferred to v0.12.1 or v0.13)
|
|
154
|
+
|
|
155
|
+
- Portrait + non-AR stitching can regress under fast horizontal
|
|
156
|
+
pans — likely drift detection over-firing on lateral
|
|
157
|
+
acceleration. Needs debounce or motion-aware threshold.
|
|
158
|
+
- Component-render tests (`<OrientationDriftModal>`,
|
|
159
|
+
`<PanoramaBandOverlay>` per-orientation, `<ViewportCropOverlay>`
|
|
160
|
+
per-orientation, `<Camera>` composition) need
|
|
161
|
+
`@testing-library/react-native` + a jest preset flip. Tracked
|
|
162
|
+
for v0.12.1.
|
|
163
|
+
- Portrait-upside-down landscape detection on non-locked hosts —
|
|
164
|
+
the JS dims signal is ambiguous between locked-portrait + flipped
|
|
165
|
+
device and non-locked + screen-flipped-180°. Needs a separate
|
|
166
|
+
signal.
|
|
167
|
+
- Slot/hybrid API on `<Camera>` to absorb `CaptureControlsBar`,
|
|
168
|
+
`IncrementalPanGuide`, `PanoramaGuidance`, etc. — v0.13.
|
|
169
|
+
|
|
19
170
|
## [0.11.1] — 2026-05-28
|
|
20
171
|
|
|
21
172
|
### Fixed — AR-mode composed worklets silently throw
|
package/README.md
CHANGED
|
@@ -140,6 +140,34 @@ See `src/camera/Camera.tsx` for the full TSDoc. Highlights:
|
|
|
140
140
|
| `onFramesDropped(info)` | cv::Stitcher's confidence retry loop dropped one or more input frames. |
|
|
141
141
|
| `onError(err)` | Classified error. `err.code` from a known taxonomy (`STITCH_NEED_MORE_IMGS`, `STITCH_HOMOGRAPHY_FAIL`, `STITCH_CAMERA_PARAMS_FAIL`, `STITCH_OOM`, `CAMERA_PERMISSION_DENIED`, etc.). |
|
|
142
142
|
|
|
143
|
+
## Orientation support
|
|
144
|
+
|
|
145
|
+
`<Camera>` works in any device orientation regardless of host
|
|
146
|
+
configuration. No host setup required — the SDK adapts at runtime.
|
|
147
|
+
|
|
148
|
+
**Portrait-locked host** (Info.plist `UISupportedInterfaceOrientations`
|
|
149
|
+
restricted to Portrait — recommended for kiosks / single-task apps):
|
|
150
|
+
the screen stays portrait; the SDK uses sensor-derived orientation
|
|
151
|
+
for capture-mode selection and overlay layout. This is the simpler
|
|
152
|
+
configuration and the historical default.
|
|
153
|
+
|
|
154
|
+
**Non-locked host** (Info.plist supports all 4 orientations — recommended
|
|
155
|
+
for apps with other landscape-friendly screens): the screen rotates
|
|
156
|
+
with the device. `<Camera>`'s controls (shutter, lens chip, AR toggle)
|
|
157
|
+
anchor to the home-indicator edge so they stay within thumb reach
|
|
158
|
+
regardless of tilt — matching iOS Camera's behaviour. The
|
|
159
|
+
orientation-aware logic combines `useWindowDimensions()` (JS-layout)
|
|
160
|
+
with `useDeviceOrientation()` (sensor) to compute the correct anchor.
|
|
161
|
+
|
|
162
|
+
**Mid-capture rotation safety** — the incremental engine doesn't
|
|
163
|
+
support cross-orientation captures (a portrait capture's keyframes
|
|
164
|
+
can't be mixed with landscape-pan frames). If the user rotates
|
|
165
|
+
mid-capture, `<Camera>` auto-abandons via `incremental.cancel()`,
|
|
166
|
+
fires `onCaptureAbandoned('orientation-drift')` if the host wired
|
|
167
|
+
the callback, and shows the `OrientationDriftModal` to explain why.
|
|
168
|
+
Host opt-in via the `onCaptureAbandoned` prop — the default UX is
|
|
169
|
+
the modal alone.
|
|
170
|
+
|
|
143
171
|
## Lens ↔ AR interaction
|
|
144
172
|
|
|
145
173
|
| Action | `arPreference` | `lens` | UI |
|
|
@@ -38,8 +38,9 @@ import kotlin.math.sqrt
|
|
|
38
38
|
* V12.4 — central 70% (pan) × 85% (perpendicular) post-warp crop
|
|
39
39
|
* V12.6 — orientation detection from R_panToCam at first frame
|
|
40
40
|
* (NOT from JS-passed frameRotationDegrees, which is wrong
|
|
41
|
-
* under
|
|
42
|
-
*
|
|
41
|
+
* under portrait-locked hosts — pose-derived detection
|
|
42
|
+
* works regardless of host orientation config, so it's
|
|
43
|
+
* the single source of truth)
|
|
43
44
|
* V12.7 — rectilinear path: skip cylindrical warp entirely. First
|
|
44
45
|
* frame pasted raw onto canvas; subsequent frames contribute
|
|
45
46
|
* a narrow central strip placed by pose-delta around the
|
|
@@ -60,6 +60,16 @@ export interface ARCameraViewHandle {
|
|
|
60
60
|
*/
|
|
61
61
|
takePhoto: (options?: {
|
|
62
62
|
quality?: number;
|
|
63
|
+
/**
|
|
64
|
+
* v0.12.0 — device orientation at capture time, used to bake
|
|
65
|
+
* correct rotation into the saved JPEG. Pass the value from
|
|
66
|
+
* `useDeviceOrientation()`. Defaults to `'portrait'` on the
|
|
67
|
+
* native side if omitted (preserves pre-v0.12 behavior).
|
|
68
|
+
* Without this, AR-mode photos taken in landscape come out
|
|
69
|
+
* sideways because the native side previously hardcoded the
|
|
70
|
+
* rotate-to-portrait assumption.
|
|
71
|
+
*/
|
|
72
|
+
orientation?: 'portrait' | 'portrait-upside-down' | 'landscape-left' | 'landscape-right';
|
|
63
73
|
}) => Promise<{
|
|
64
74
|
path: string;
|
|
65
75
|
width: number;
|
package/dist/camera/Camera.d.ts
CHANGED
|
@@ -41,6 +41,9 @@
|
|
|
41
41
|
import React from 'react';
|
|
42
42
|
import { type StyleProp, type ViewStyle } from 'react-native';
|
|
43
43
|
import type { DrawableFrameProcessor, ReadonlyFrameProcessor } from 'react-native-vision-camera';
|
|
44
|
+
import { type CaptureHeaderProps } from './CaptureHeader';
|
|
45
|
+
import { type CapturePreviewAction } from './CapturePreview';
|
|
46
|
+
import { type CaptureThumbnailItem } from './CaptureThumbnailStrip';
|
|
44
47
|
export type CaptureSource = 'ar' | 'non-ar';
|
|
45
48
|
export type CameraLens = '1x' | '0.5x';
|
|
46
49
|
export type StitchMode = 'auto' | 'panorama' | 'scans';
|
|
@@ -191,6 +194,194 @@ export interface CameraProps {
|
|
|
191
194
|
onLensChange?: (lens: CameraLens) => void;
|
|
192
195
|
onFramesDropped?: (info: FramesDroppedInfo) => void;
|
|
193
196
|
onError?: (err: CameraError) => void;
|
|
197
|
+
/**
|
|
198
|
+
* v0.12.0 — fires when the SDK auto-abandons an in-progress
|
|
199
|
+
* capture without producing output. `reason` is a string union
|
|
200
|
+
* so future reasons (network loss, low memory, etc.) can be added
|
|
201
|
+
* without breaking the callback signature.
|
|
202
|
+
*
|
|
203
|
+
* Currently the only reason in v0.12 is `'orientation-drift'`:
|
|
204
|
+
* the user rotated the device between Mode A (landscape + vertical
|
|
205
|
+
* pan) and Mode B (portrait + horizontal pan) mid-capture. The
|
|
206
|
+
* engine docstring at `incremental.ts:373-403` is explicit that
|
|
207
|
+
* cross-mode capture is "best-effort, not supported," so the SDK
|
|
208
|
+
* decisively cancels the capture (`incremental.cancel()`) and
|
|
209
|
+
* surfaces `OrientationDriftModal` to explain what happened.
|
|
210
|
+
*
|
|
211
|
+
* Hosts use this callback to clean up their own state (e.g., reset
|
|
212
|
+
* a wizard step, log telemetry, surface their own retry UX in
|
|
213
|
+
* addition to the SDK's built-in modal). No `onCapture` will fire
|
|
214
|
+
* for an abandoned capture.
|
|
215
|
+
*/
|
|
216
|
+
onCaptureAbandoned?: (reason: 'orientation-drift') => void;
|
|
217
|
+
/**
|
|
218
|
+
* v0.13.0 — flash (torch) state. Controlled-or-uncontrolled.
|
|
219
|
+
*
|
|
220
|
+
* - **Uncontrolled** (omit `flash`): `<Camera>` owns the flash
|
|
221
|
+
* state internally. Tapping the built-in flash button toggles
|
|
222
|
+
* it on/off. `onFlashChange` (if supplied) fires for telemetry.
|
|
223
|
+
* - **Controlled** (supply `flash`): the parent owns the state.
|
|
224
|
+
* The built-in button still renders and fires `onFlashChange`
|
|
225
|
+
* on press, but it's a no-op unless the parent updates `flash`
|
|
226
|
+
* in response.
|
|
227
|
+
*
|
|
228
|
+
* Both shapes coexist with the v0.13 "flash button is on by default"
|
|
229
|
+
* built-in (see the bottom-left bar slot in the JSX). Hosts that
|
|
230
|
+
* want their own flash chrome can opt out via `showFlashButton={false}`
|
|
231
|
+
* and drive the underlying torch by controlling `flash` directly.
|
|
232
|
+
*
|
|
233
|
+
* ## AR-mode behaviour
|
|
234
|
+
*
|
|
235
|
+
* In AR mode (`defaultCaptureSource="ar"` or runtime-toggled),
|
|
236
|
+
* ARKit / ARCore own the `AVCaptureDevice` and don't expose the
|
|
237
|
+
* torch through vision-camera's pipeline. The built-in flash
|
|
238
|
+
* button renders as visibly disabled (a11y label "Flash unavailable
|
|
239
|
+
* in AR mode") and `flash` is forced to `'off'` regardless of
|
|
240
|
+
* controlled/uncontrolled state. Hosts that need flash should
|
|
241
|
+
* toggle to non-AR before enabling.
|
|
242
|
+
*/
|
|
243
|
+
flash?: 'on' | 'off';
|
|
244
|
+
/**
|
|
245
|
+
* v0.13.0 — fires when the user taps the built-in flash button.
|
|
246
|
+
* In uncontrolled mode, the internal state has already flipped
|
|
247
|
+
* (single render delay). In controlled mode, the parent must
|
|
248
|
+
* update the `flash` prop in response or the visual toggle is
|
|
249
|
+
* a no-op. Useful in either mode for telemetry.
|
|
250
|
+
*/
|
|
251
|
+
onFlashChange?: (next: 'on' | 'off') => void;
|
|
252
|
+
/**
|
|
253
|
+
* v0.13.0 — show the built-in flash button in the bottom-left
|
|
254
|
+
* slot. Defaults to `true`. Hosts that render their own flash
|
|
255
|
+
* chrome (and drive the underlying torch via the controlled
|
|
256
|
+
* `flash` prop) can opt out by setting this to `false`.
|
|
257
|
+
*/
|
|
258
|
+
showFlashButton?: boolean;
|
|
259
|
+
/**
|
|
260
|
+
* v0.13.0 — show the built-in IncrementalPanGuide ("keep the
|
|
261
|
+
* arrow on the line" drift marker) while recording. Defaults
|
|
262
|
+
* to `true`. The guide is gyroscope-driven and only active
|
|
263
|
+
* during the recording phase (no idle sensor cost). Hosts that
|
|
264
|
+
* want their own pan-guide chrome can opt out via `false`.
|
|
265
|
+
*/
|
|
266
|
+
panGuide?: boolean;
|
|
267
|
+
/**
|
|
268
|
+
* v0.13.0 — show the built-in PanoramaGuidance pan-speed pill
|
|
269
|
+
* ("Pan slowly" / "Slow down" / "Too fast") while recording.
|
|
270
|
+
* Defaults to `true`. Gyroscope-driven, only active during
|
|
271
|
+
* recording. Hosts that want their own speed chrome can opt
|
|
272
|
+
* out via `false`.
|
|
273
|
+
*/
|
|
274
|
+
panoramaGuidance?: boolean;
|
|
275
|
+
/**
|
|
276
|
+
* v0.13.0 — built-in CaptureHeader title. When set, `<Camera>`
|
|
277
|
+
* renders a top-of-screen header showing this title (centred)
|
|
278
|
+
* with an optional back affordance + guidance subtitle + the
|
|
279
|
+
* existing settings gear absorbed into the header's right side.
|
|
280
|
+
*
|
|
281
|
+
* When `headerTitle` is undefined the header is not rendered
|
|
282
|
+
* (matches pre-v0.13 behaviour: top of preview is bare except
|
|
283
|
+
* for the standalone settings gear gated on `showSettingsButton`).
|
|
284
|
+
*
|
|
285
|
+
* Combine with `onHeaderBack`, `headerBackLabel`, `headerGuidance`,
|
|
286
|
+
* and `headerColors` to customise the rest of the header. Hosts
|
|
287
|
+
* that need richer header chrome can omit `headerTitle` and
|
|
288
|
+
* compose their own `<CaptureHeader>` above `<Camera>`.
|
|
289
|
+
*/
|
|
290
|
+
headerTitle?: string;
|
|
291
|
+
/**
|
|
292
|
+
* v0.13.0 — header back-button callback. When supplied (and
|
|
293
|
+
* `headerTitle` is set), the header renders a back affordance
|
|
294
|
+
* on the left. Omitted ⇒ no back button (the title stays
|
|
295
|
+
* centred).
|
|
296
|
+
*/
|
|
297
|
+
onHeaderBack?: () => void;
|
|
298
|
+
/**
|
|
299
|
+
* v0.13.0 — header back-button label. Defaults to "‹ Back".
|
|
300
|
+
* No effect unless `headerTitle` and `onHeaderBack` are both set.
|
|
301
|
+
*/
|
|
302
|
+
headerBackLabel?: string;
|
|
303
|
+
/**
|
|
304
|
+
* v0.13.0 — optional second-line subtitle shown below the
|
|
305
|
+
* header title. E.g. "Photograph the promotional cola end cap."
|
|
306
|
+
* Renders nothing when undefined. No effect unless `headerTitle`
|
|
307
|
+
* is set.
|
|
308
|
+
*/
|
|
309
|
+
headerGuidance?: string;
|
|
310
|
+
/**
|
|
311
|
+
* v0.13.0 — colour overrides for the built-in header. Defaults
|
|
312
|
+
* are white-on-black to stay legible over the camera preview.
|
|
313
|
+
* No effect unless `headerTitle` is set.
|
|
314
|
+
*/
|
|
315
|
+
headerColors?: CaptureHeaderProps['colors'];
|
|
316
|
+
/**
|
|
317
|
+
* v0.13.0 — when provided (even as `[]`), `<Camera>` renders a
|
|
318
|
+
* built-in `CaptureThumbnailStrip` above the bottom controls
|
|
319
|
+
* showing the host's capture history. Each item is a plain
|
|
320
|
+
* `{ id, uri, width?, height? }` object; the strip handles
|
|
321
|
+
* aspect-ratio rendering, tap-to-preview, and the count line.
|
|
322
|
+
*
|
|
323
|
+
* Omit (`undefined`) to skip the strip entirely. Hosts using
|
|
324
|
+
* the strip independently (e.g. on a non-camera screen) can keep
|
|
325
|
+
* importing `CaptureThumbnailStrip` directly from the library —
|
|
326
|
+
* the prop here is the convenience wiring for in-`<Camera>` use.
|
|
327
|
+
*
|
|
328
|
+
* Captures emitted by `<Camera>`'s `onCapture` are NOT added to
|
|
329
|
+
* this array automatically — the host owns the canonical list
|
|
330
|
+
* (typically persisted to its own DB) and updates the prop in
|
|
331
|
+
* response. This matches the SDK's "Camera owns runtime state,
|
|
332
|
+
* host persists" pattern.
|
|
333
|
+
*/
|
|
334
|
+
thumbnails?: CaptureThumbnailItem[];
|
|
335
|
+
/**
|
|
336
|
+
* v0.13.0 — minimum-photos hint for the count line. Renders
|
|
337
|
+
* "n / minPhotos min" with the success colour when reached,
|
|
338
|
+
* warning colour otherwise.
|
|
339
|
+
*/
|
|
340
|
+
thumbnailsMin?: number;
|
|
341
|
+
/**
|
|
342
|
+
* v0.13.0 — maximum-photos hint for the count line. Renders
|
|
343
|
+
* "· maxPhotos max" suffix. No enforcement — the host decides
|
|
344
|
+
* what to do at the cap.
|
|
345
|
+
*/
|
|
346
|
+
thumbnailsMax?: number;
|
|
347
|
+
/**
|
|
348
|
+
* v0.13.0 — tap handler for thumbnails. When set, replaces the
|
|
349
|
+
* strip's built-in tap-to-preview modal; the host shows its own
|
|
350
|
+
* preview UI (e.g. with delete / recapture buttons gated on
|
|
351
|
+
* sync state). Omit to use the built-in preview.
|
|
352
|
+
*/
|
|
353
|
+
onThumbnailPress?: (item: CaptureThumbnailItem) => void;
|
|
354
|
+
/**
|
|
355
|
+
* v0.13.0 — when set, `<Camera>` renders a built-in `CapturePreview`
|
|
356
|
+
* modal as `visible`. Use this for post-stitch confirmation:
|
|
357
|
+
* after `onCapture` emits, the host stores the result and sets
|
|
358
|
+
* `capturePreview` to the new image, with `capturePreviewActions`
|
|
359
|
+
* = `[Discard, Save]` (or similar). Setting `undefined` hides
|
|
360
|
+
* the modal.
|
|
361
|
+
*
|
|
362
|
+
* Hosts using the modal for thumbnail tap-to-preview can leave
|
|
363
|
+
* this undefined and let the built-in strip's preview handle
|
|
364
|
+
* that case.
|
|
365
|
+
*/
|
|
366
|
+
capturePreview?: {
|
|
367
|
+
imageUri: string;
|
|
368
|
+
imageWidth?: number;
|
|
369
|
+
imageHeight?: number;
|
|
370
|
+
title?: string;
|
|
371
|
+
};
|
|
372
|
+
/**
|
|
373
|
+
* v0.13.0 — action buttons rendered along the bottom of the
|
|
374
|
+
* `CapturePreview` modal. Empty array (or undefined) renders
|
|
375
|
+
* no buttons, only the close affordance.
|
|
376
|
+
*/
|
|
377
|
+
capturePreviewActions?: CapturePreviewAction[];
|
|
378
|
+
/**
|
|
379
|
+
* v0.13.0 — fires when the user dismisses the `capturePreview`
|
|
380
|
+
* modal (tap close, backdrop tap, hardware back on Android).
|
|
381
|
+
* The host is expected to clear the `capturePreview` prop in
|
|
382
|
+
* response.
|
|
383
|
+
*/
|
|
384
|
+
onCapturePreviewClose?: () => void;
|
|
194
385
|
/**
|
|
195
386
|
* Optional host-supplied vision-camera frame processor.
|
|
196
387
|
*
|