@ai-matrx/capture 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/LICENSE +21 -0
- package/README.md +40 -1
- package/dist/index.cjs +19 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +116 -0
- package/dist/index.d.ts +116 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +984 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +342 -0
- package/dist/react.d.ts +342 -0
- package/dist/react.js +977 -0
- package/dist/react.js.map +1 -0
- package/package.json +95 -7
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* features/capture-camera/ — EXTRACTION SOURCE for the `@ai-matrx/capture`
|
|
6
|
+
* package (aidream/apps/shared/capture). Everything outside `host/` must stay
|
|
7
|
+
* free of app imports beyond React, lucide-react and `cn` — those are the
|
|
8
|
+
* documented substitution points when this directory is mirrored into the
|
|
9
|
+
* package (icons → inlined SVGs, cn → tailwind-merge), exactly like
|
|
10
|
+
* `@ai-matrx/media` was extracted from `features/files`.
|
|
11
|
+
*
|
|
12
|
+
* The package is the OPINIONATED iPhone-style camera chrome: translucent
|
|
13
|
+
* top/bottom bars over a full-bleed feed, the two-tap options grid, zoom
|
|
14
|
+
* pills, shutter, VIDEO·PHOTO·UPLOAD mode selector, recents thumb, flip
|
|
15
|
+
* button, rule-of-thirds grid, countdown timer, and the iOS-style sheet.
|
|
16
|
+
* It renders and orchestrates UI state ONLY — the host injects the engine
|
|
17
|
+
* (stream + capture callbacks) and everything persisted (upload, gallery,
|
|
18
|
+
* thumbnails). No fetch, no storage, no getUserMedia in this layer.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** The two persistent capture modes; Upload is an immediate action. */
|
|
22
|
+
type CaptureCameraMode = "photo" | "video";
|
|
23
|
+
/** Timer options genuinely supported (a countdown before the shutter). */
|
|
24
|
+
type CaptureTimerSetting = 0 | 3 | 10;
|
|
25
|
+
/** Output aspect for photo capture (center-cropped from the full sensor). */
|
|
26
|
+
type CaptureAspect = "full" | "4:3" | "1:1" | "16:9";
|
|
27
|
+
/**
|
|
28
|
+
* THE CLOUD LAW of this package: cloud integration is WHAT the system does,
|
|
29
|
+
* not an optional add-on. Every `CameraCapture` REQUIRES this port — the
|
|
30
|
+
* type system refuses a camera with no cloud. How the host fulfills it
|
|
31
|
+
* (fileHandler, a client SDK, a domain uploader) is injected; that it is
|
|
32
|
+
* fulfilled is not negotiable.
|
|
33
|
+
*/
|
|
34
|
+
interface CaptureCloudPort {
|
|
35
|
+
/** Content of the bottom-left recents thumbnail (latest cloud/session
|
|
36
|
+
* media). Null renders the placeholder — the button still opens the
|
|
37
|
+
* library. */
|
|
38
|
+
recentsThumb: React.ReactNode;
|
|
39
|
+
/** Opens the host's cloud media library (tiled gallery). */
|
|
40
|
+
onOpenLibrary: () => void;
|
|
41
|
+
/** Persists an edited image produced by the edit sheet. */
|
|
42
|
+
onSaveEdited: (blob: Blob, suggestedName: string) => void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The engine port — everything the chrome needs from the host's camera
|
|
46
|
+
* runtime. The host owns lease acquisition/release, capture and recording;
|
|
47
|
+
* the chrome never touches getUserMedia.
|
|
48
|
+
*/
|
|
49
|
+
interface CaptureCameraEngine {
|
|
50
|
+
/** Live stream for the preview, or null while connecting/blocked. */
|
|
51
|
+
stream: MediaStream | null;
|
|
52
|
+
/** The preview <video> element ref the host's capture path reads from. */
|
|
53
|
+
videoRef: React.RefObject<HTMLVideoElement | null>;
|
|
54
|
+
/** Camera unavailable: permission denied or unsupported. */
|
|
55
|
+
blocked: null | {
|
|
56
|
+
reason: "permission-denied" | "not-supported";
|
|
57
|
+
};
|
|
58
|
+
/** Take a photo NOW (any timer countdown already elapsed). The chrome's
|
|
59
|
+
* current aspect setting rides along; the host center-crops the full
|
|
60
|
+
* sensor frame to it ("full" = untouched). */
|
|
61
|
+
onCapturePhoto: (opts?: {
|
|
62
|
+
aspect?: CaptureAspect;
|
|
63
|
+
}) => void;
|
|
64
|
+
/** Start / stop video recording. */
|
|
65
|
+
onStartRecording: () => void;
|
|
66
|
+
onStopRecording: () => void;
|
|
67
|
+
recording: boolean;
|
|
68
|
+
/** Elapsed recording seconds (host-owned monotonic clock). */
|
|
69
|
+
recordElapsedSeconds: number;
|
|
70
|
+
/** Open the device files picker (the Upload lane). */
|
|
71
|
+
onUpload: () => void;
|
|
72
|
+
/** Flip to the next camera; null hides the flip button. */
|
|
73
|
+
onFlipCamera: (() => void) | null;
|
|
74
|
+
}
|
|
75
|
+
/** One tile in the two-tap options grid. */
|
|
76
|
+
interface CaptureOptionTile {
|
|
77
|
+
id: string;
|
|
78
|
+
label: string;
|
|
79
|
+
icon: React.ReactNode;
|
|
80
|
+
/** Highlight state (iPhone: yellow when engaged/auto). */
|
|
81
|
+
active?: boolean;
|
|
82
|
+
/** Small value read-out under the icon (e.g. "3s", "4:3"). */
|
|
83
|
+
valueLabel?: string;
|
|
84
|
+
disabled?: boolean;
|
|
85
|
+
onPress: () => void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Slot-based extensibility — how domain layers (e.g. commerce intake) attach
|
|
89
|
+
* their own affordances without forking the chrome. Typed slots, not a plugin
|
|
90
|
+
* registry, on purpose.
|
|
91
|
+
*/
|
|
92
|
+
interface CaptureCameraSlots {
|
|
93
|
+
/** Extra buttons in the top bar, before the options-grid button. */
|
|
94
|
+
topBarTrailing?: React.ReactNode;
|
|
95
|
+
/** Center of the top bar (e.g. current-item label + count). */
|
|
96
|
+
topBarCenter?: React.ReactNode;
|
|
97
|
+
/** Honesty chips under the top bar (QR confirmation, etc.). */
|
|
98
|
+
statusChips?: React.ReactNode;
|
|
99
|
+
/** Rows rendered inside the bottom bar ABOVE the mode selector
|
|
100
|
+
* (filmstrip, notes/voice row, process button…). */
|
|
101
|
+
aboveModeSelector?: React.ReactNode;
|
|
102
|
+
/** A compact action pinned right of the mode selector (Next/Break). */
|
|
103
|
+
modeRowTrailing?: React.ReactNode;
|
|
104
|
+
/** Extra tiles appended to the options grid. */
|
|
105
|
+
optionTiles?: CaptureOptionTile[];
|
|
106
|
+
/** Extra entries in the mode row after UPLOAD (e.g. SCAN). Selecting one
|
|
107
|
+
* is an immediate host action — the chrome keeps its current mode. */
|
|
108
|
+
extraModes?: {
|
|
109
|
+
id: string;
|
|
110
|
+
label: string;
|
|
111
|
+
onSelect: () => void;
|
|
112
|
+
}[];
|
|
113
|
+
/** Free overlays rendered above everything (sheets, pagers). */
|
|
114
|
+
overlays?: React.ReactNode;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* CaptureSheet — the iOS-style system sheet used over the camera: a light,
|
|
119
|
+
* heavily-rounded card sliding over the lower portion of the screen with a
|
|
120
|
+
* circular ✕ close top-right; content is an icon + bold title + body text
|
|
121
|
+
* with a filled primary action and a tinted secondary one. `variant="busy"`
|
|
122
|
+
* is the transient state (small spinner + label, like the OS "Connecting…"
|
|
123
|
+
* sheet). Deliberately light-on-dark regardless of app theme — it mirrors
|
|
124
|
+
* the OS presentation over camera chrome.
|
|
125
|
+
*
|
|
126
|
+
* Package source (`@ai-matrx/capture`) — presentational only.
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
interface CaptureSheetAction {
|
|
130
|
+
label: string;
|
|
131
|
+
onPress: () => void;
|
|
132
|
+
kind?: "primary" | "secondary";
|
|
133
|
+
}
|
|
134
|
+
interface CaptureSheetProps {
|
|
135
|
+
open: boolean;
|
|
136
|
+
onClose: () => void;
|
|
137
|
+
/** Standard content sheet by default; "busy" renders spinner + label. */
|
|
138
|
+
variant?: "content" | "busy";
|
|
139
|
+
icon?: React__default.ReactNode;
|
|
140
|
+
title?: string;
|
|
141
|
+
body?: React__default.ReactNode;
|
|
142
|
+
actions?: CaptureSheetAction[];
|
|
143
|
+
/** The busy variant's label ("Connecting…"). */
|
|
144
|
+
busyLabel?: string;
|
|
145
|
+
}
|
|
146
|
+
declare function CaptureSheet({ open, onClose, variant, icon, title, body, actions, busyLabel, }: CaptureSheetProps): React__default.JSX.Element | null;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* CameraCapture — the opinionated iPhone-style camera surface, assembled.
|
|
150
|
+
*
|
|
151
|
+
* Layout (matching the iOS Camera app):
|
|
152
|
+
* - Full-bleed live feed with a semi-transparent near-black bar across the
|
|
153
|
+
* top and bottom — controls read clearly while the feed shows through.
|
|
154
|
+
* - Top bar: close (host-provided), center slot, torch, host extras, and the
|
|
155
|
+
* grid button revealing the two-tap OptionsGridPanel.
|
|
156
|
+
* - Over the feed's bottom edge: real zoom pills (only when the track
|
|
157
|
+
* reports a zoom range).
|
|
158
|
+
* - Bottom bar: injected rows → VIDEO·PHOTO·UPLOAD mode selector → recents
|
|
159
|
+
* thumb · shutter · flip.
|
|
160
|
+
* - Overlays: rule-of-thirds grid, timer countdown, recording chip, blocked
|
|
161
|
+
* sheet (iOS system-sheet presentation).
|
|
162
|
+
*
|
|
163
|
+
* The chrome owns UI state only (options panel, grid, timer, countdown).
|
|
164
|
+
* Capture behavior, streams and persistence come from the injected
|
|
165
|
+
* `CaptureCameraEngine`; domain features attach through `CaptureCameraSlots`.
|
|
166
|
+
*
|
|
167
|
+
* Package source (`@ai-matrx/capture`).
|
|
168
|
+
*/
|
|
169
|
+
|
|
170
|
+
interface CameraCaptureProps {
|
|
171
|
+
engine: CaptureCameraEngine;
|
|
172
|
+
/** THE CLOUD LAW: the cloud port is REQUIRED — a camera with no cloud
|
|
173
|
+
* library/persistence is not a valid instance of this system. */
|
|
174
|
+
cloud: CaptureCloudPort;
|
|
175
|
+
mode: CaptureCameraMode;
|
|
176
|
+
onModeChange: (mode: CaptureCameraMode) => void;
|
|
177
|
+
/** The live preview element (host wires its runtime's `CameraPreview`). */
|
|
178
|
+
preview: React__default.ReactNode;
|
|
179
|
+
/** Close affordance top-left; omitted = no close button. */
|
|
180
|
+
onClose?: () => void;
|
|
181
|
+
/** Body + actions for the camera-blocked iOS-style sheet. */
|
|
182
|
+
blockedSheet?: {
|
|
183
|
+
body: React__default.ReactNode;
|
|
184
|
+
actions: CaptureSheetAction[];
|
|
185
|
+
};
|
|
186
|
+
/** Hide all chrome except honesty chips (host renders its own toggle). */
|
|
187
|
+
controlsHidden?: boolean;
|
|
188
|
+
shutterDisabled?: boolean;
|
|
189
|
+
slots?: CaptureCameraSlots;
|
|
190
|
+
}
|
|
191
|
+
declare function CameraCapture({ engine, cloud, mode, onModeChange, preview, onClose, blockedSheet, controlsHidden, shutterDisabled, slots, }: CameraCaptureProps): React__default.JSX.Element;
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* CountdownOverlay — the big centered timer digits (iPhone timer capture):
|
|
195
|
+
* one large white numeral per second, scaling in as it changes.
|
|
196
|
+
*
|
|
197
|
+
* Package source (`@ai-matrx/capture`) — presentational only.
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
declare function CountdownOverlay({ seconds }: {
|
|
201
|
+
seconds: number | null;
|
|
202
|
+
}): React__default.JSX.Element | null;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* GridOverlay — the rule-of-thirds composition grid over the viewfinder.
|
|
206
|
+
* Genuinely supported (pure CSS), toggled from the options grid.
|
|
207
|
+
*
|
|
208
|
+
* Package source (`@ai-matrx/capture`) — presentational only.
|
|
209
|
+
*/
|
|
210
|
+
|
|
211
|
+
declare function GridOverlay({ visible }: {
|
|
212
|
+
visible: boolean;
|
|
213
|
+
}): React__default.JSX.Element | null;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* ImageEditSheet — instant in-browser image editing, core to the package
|
|
217
|
+
* (THE CLOUD LAW's sibling: capture without instant edit is half a system).
|
|
218
|
+
* v1 covers the basics that belong in the browser — crop (free + 1:1, 4:3,
|
|
219
|
+
* 16:9 presets), rotate 90°, flip — full-screen dark chrome in the iOS
|
|
220
|
+
* editing style: Cancel/Save top bar, the image letterboxed center, a
|
|
221
|
+
* draggable/resizable crop frame with corner handles, tool row bottom.
|
|
222
|
+
* Heavier AI edits ride host-injected actions, not this sheet.
|
|
223
|
+
*
|
|
224
|
+
* Output is a JPEG re-encode of the ORIGINAL pixels (rotation/flip/crop
|
|
225
|
+
* applied on canvas) — never a screenshot of the preview.
|
|
226
|
+
*
|
|
227
|
+
* Package source (`@ai-matrx/capture`) — browser canvas only, no app deps.
|
|
228
|
+
*/
|
|
229
|
+
|
|
230
|
+
interface ImageEditSheetProps {
|
|
231
|
+
open: boolean;
|
|
232
|
+
/** Source image URL (object URL or resolvable src). */
|
|
233
|
+
src: string | null;
|
|
234
|
+
onClose: () => void;
|
|
235
|
+
/** Receives the edited JPEG. The host persists it (cloud port). */
|
|
236
|
+
onSave: (blob: Blob) => void;
|
|
237
|
+
}
|
|
238
|
+
declare function ImageEditSheet({ open, src, onClose, onSave, }: ImageEditSheetProps): React__default.JSX.Element | null;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* ModeSelector — the iPhone mode row: uppercase, letter-spaced labels in a
|
|
242
|
+
* horizontal band; the ACTIVE mode sits in a dark pill with the iOS camera
|
|
243
|
+
* yellow. VIDEO and PHOTO are persistent modes; UPLOAD is an immediate
|
|
244
|
+
* action (opens the host's picker) and never takes the active state — it is
|
|
245
|
+
* our third lane in the slot the iPhone layout leaves open next to PHOTO.
|
|
246
|
+
*
|
|
247
|
+
* Package source (`@ai-matrx/capture`) — presentational only.
|
|
248
|
+
*/
|
|
249
|
+
|
|
250
|
+
interface ModeSelectorProps {
|
|
251
|
+
mode: CaptureCameraMode;
|
|
252
|
+
onModeChange: (mode: CaptureCameraMode) => void;
|
|
253
|
+
onUpload: () => void;
|
|
254
|
+
/** Locks mode switching (while recording). */
|
|
255
|
+
modeDisabled?: boolean;
|
|
256
|
+
uploadDisabled?: boolean;
|
|
257
|
+
/** Host-injected extra entries after UPLOAD (e.g. SCAN) — immediate
|
|
258
|
+
* actions, never the active mode. */
|
|
259
|
+
extraModes?: {
|
|
260
|
+
id: string;
|
|
261
|
+
label: string;
|
|
262
|
+
onSelect: () => void;
|
|
263
|
+
}[];
|
|
264
|
+
}
|
|
265
|
+
declare function ModeSelector({ mode, onModeChange, onUpload, modeDisabled, uploadDisabled, extraModes, }: ModeSelectorProps): React__default.JSX.Element;
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* OptionsGridPanel — the iPhone two-tap options surface: tapping the grid
|
|
269
|
+
* button dims the viewfinder and reveals a rounded dark panel pinned to the
|
|
270
|
+
* bottom holding a grid of circular toggle buttons with uppercase labels
|
|
271
|
+
* (one tap to reveal, one tap to act). This is NOT a drawer — no drag
|
|
272
|
+
* handle, no route; tapping the scrim or the grid button again closes it.
|
|
273
|
+
*
|
|
274
|
+
* Tiles are injected (`CaptureOptionTile[]`) so hosts and domain extensions
|
|
275
|
+
* add their own toggles without touching the panel.
|
|
276
|
+
*
|
|
277
|
+
* Package source (`@ai-matrx/capture`) — presentational only.
|
|
278
|
+
*/
|
|
279
|
+
|
|
280
|
+
interface OptionsGridPanelProps {
|
|
281
|
+
open: boolean;
|
|
282
|
+
onClose: () => void;
|
|
283
|
+
tiles: CaptureOptionTile[];
|
|
284
|
+
}
|
|
285
|
+
declare function OptionsGridPanel({ open, onClose, tiles, }: OptionsGridPanelProps): React__default.JSX.Element | null;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* ShutterButton — the iPhone shutter: a thin white ring with a filled inner
|
|
289
|
+
* circle. Photo = white fill; video idle = red circle; video recording = the
|
|
290
|
+
* inner shape morphs to a small red rounded square (the iOS stop affordance).
|
|
291
|
+
* Press feedback is a scale-down of the INNER fill only, like iOS.
|
|
292
|
+
*
|
|
293
|
+
* Package source (`@ai-matrx/capture`) — presentational only.
|
|
294
|
+
*/
|
|
295
|
+
|
|
296
|
+
interface ShutterButtonProps {
|
|
297
|
+
mode: CaptureCameraMode;
|
|
298
|
+
recording: boolean;
|
|
299
|
+
disabled?: boolean;
|
|
300
|
+
onPress: () => void;
|
|
301
|
+
}
|
|
302
|
+
declare function ShutterButton({ mode, recording, disabled, onPress, }: ShutterButtonProps): React__default.JSX.Element;
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* ZoomRow — the iPhone zoom pills floating over the bottom of the feed:
|
|
306
|
+
* small translucent circles, the active factor in a slightly larger circle
|
|
307
|
+
* with yellow text and an "×" suffix. Rendered ONLY when the host reports a
|
|
308
|
+
* real zoom range (track capabilities) — we never fake unsupported zoom.
|
|
309
|
+
*
|
|
310
|
+
* Package source (`@ai-matrx/capture`) — presentational only.
|
|
311
|
+
*/
|
|
312
|
+
|
|
313
|
+
interface ZoomRowProps {
|
|
314
|
+
/** Available zoom factors in ascending order (e.g. [1, 2, 4]). */
|
|
315
|
+
options: number[];
|
|
316
|
+
/** The currently applied factor (nearest option is highlighted). */
|
|
317
|
+
value: number;
|
|
318
|
+
onSelect: (factor: number) => void;
|
|
319
|
+
}
|
|
320
|
+
declare function ZoomRow({ options, value, onSelect }: ZoomRowProps): React__default.JSX.Element | null;
|
|
321
|
+
|
|
322
|
+
interface TrackControls {
|
|
323
|
+
torchSupported: boolean;
|
|
324
|
+
torchOn: boolean;
|
|
325
|
+
toggleTorch: () => void;
|
|
326
|
+
/** ≥2 entries when the track reports a usable zoom range, else []. */
|
|
327
|
+
zoomOptions: number[];
|
|
328
|
+
zoom: number;
|
|
329
|
+
setZoom: (factor: number) => void;
|
|
330
|
+
/** Exposure compensation — only when the hardware reports a range. */
|
|
331
|
+
exposureSupported: boolean;
|
|
332
|
+
exposure: number;
|
|
333
|
+
exposureRange: {
|
|
334
|
+
min: number;
|
|
335
|
+
max: number;
|
|
336
|
+
step: number;
|
|
337
|
+
} | null;
|
|
338
|
+
setExposure: (value: number) => void;
|
|
339
|
+
}
|
|
340
|
+
declare function useTrackControls(stream: MediaStream | null): TrackControls;
|
|
341
|
+
|
|
342
|
+
export { CameraCapture, type CameraCaptureProps, type CaptureAspect, type CaptureCameraEngine, type CaptureCameraMode, type CaptureCameraSlots, type CaptureCloudPort, type CaptureOptionTile, CaptureSheet, type CaptureSheetAction, type CaptureSheetProps, type CaptureTimerSetting, CountdownOverlay, GridOverlay, ImageEditSheet, type ImageEditSheetProps, ModeSelector, type ModeSelectorProps, OptionsGridPanel, type OptionsGridPanelProps, ShutterButton, type ShutterButtonProps, type TrackControls, ZoomRow, type ZoomRowProps, useTrackControls };
|