@ai-matrx/capture 0.2.1 → 0.3.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 CHANGED
@@ -49,3 +49,16 @@ The package-completeness release: the whole capture loop now lives in the box (A
49
49
  ## 0.2.1 — 2026-08-29
50
50
 
51
51
  - `CameraCapture.onReviewOpenChange` — hosts pause feed-watchers (QR scanning) while the package viewer/editor covers the camera.
52
+
53
+ ## 0.3.0 — 2026-08-30
54
+
55
+ **v3 — the vertical-rail chrome.** `CameraCaptureV3` is a SECOND chrome over the same engine, cloud port and package-owned review loop, not a replacement; `CameraCapture` is unchanged and still exported. Every difference answers something v2 got wrong on a real phone (Arman):
56
+
57
+ - **`HoldShutter` — one button.** Tap = photo, press-and-hold = video. v2 spent a row on a mode selector, so the user paid bar height AND a decision before the moment they were trying to catch. A hold that passes ~1.2s LATCHES, so a slipped finger does not lose the take; the next tap stops it. Pointer capture + cancel/lost-capture handling means a drag off the button can never leave the camera recording with nothing to stop.
58
+ - **`CaptureRail` — options on the right edge.** A rail over the feed instead of a two-tap grid behind a button: no layout cost, one tap to anything, viewfinder intact. Actions marked `primary` (flip, flash) stay; the rest collapse behind a chevron, and the chevron only renders when there is genuinely something to hide.
59
+ - **`CaptureExpandingField` — text is a button until you need it.** A pill that expands into a field on press (the pattern Apple uses for search). v2 pinned a live `<input>` in the bottom bar: a permanent row for occasional use, keyboard-bait over the viewfinder, and an idle camera that looked like a form. Commits on Enter, blur AND unmount — the v2 input's evaporating-value bug, kept fixed.
60
+ - **ONE media door.** v3 has no UPLOAD mode. The library button is the only way to existing media and `engine.onUpload` is called from INSIDE the host's drawer. New law 5 fails the build if the v3 chrome ever grows its own upload button.
61
+ - **`onRecordIntent`** — fires on pointer-DOWN, before the hold threshold decides. Hosts warm the mic on it; with a hold shutter there is no "user chose VIDEO" moment, and warming after recording starts costs the first second of audio on iOS Safari or throws a permission prompt mid-take.
62
+ - Law 4 now scans EVERY `CameraCapture*.tsx` for the required cloud port, by filename pattern — a third chrome inherits THE CLOUD LAW by existing, not by someone remembering.
63
+
64
+ Deliberately not copied from the app this borrows its shape from: fixed duration choices (they belong to that product's format, not to a camera) and the oversized promo pill for a new feature (chrome is not a billboard).
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @ai-matrx/capture — root entry: TYPES ONLY, RSC-safe (no \"use client\").\n *\n * THE CLOUD LAW: cloud integration is WHAT this system does, not an option.\n * `CameraCapture` (from `@ai-matrx/capture/react`) requires a\n * `CaptureCloudPort`; the host injects HOW it is fulfilled, never WHETHER.\n */\n\nexport type {\n CaptureAspect,\n CaptureCameraEngine,\n CaptureCameraMode,\n CaptureCameraSlots,\n CaptureCloudPort,\n CaptureOptionTile,\n CaptureTimerSetting,\n} from \"./types\";\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @ai-matrx/capture — root entry: TYPES ONLY, RSC-safe (no \"use client\").\n *\n * THE CLOUD LAW: cloud integration is WHAT this system does, not an option.\n * `CameraCapture` (from `@ai-matrx/capture/react`) requires a\n * `CaptureCloudPort`; the host injects HOW it is fulfilled, never WHETHER.\n */\n\nexport type {\n CaptureAspect,\n CaptureCameraEngine,\n CaptureCameraMode,\n CaptureCameraSlots,\n CaptureCameraV3Slots,\n CaptureCloudPort,\n CaptureOptionTile,\n CaptureRailAction,\n CaptureTimerSetting,\n} from \"./types\";\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
package/dist/index.d.cts CHANGED
@@ -113,5 +113,53 @@ interface CaptureCameraSlots {
113
113
  /** Free overlays rendered above everything (sheets, pagers). */
114
114
  overlays?: React.ReactNode;
115
115
  }
116
+ /** One action on the v3 right-hand rail. */
117
+ interface CaptureRailAction {
118
+ id: string;
119
+ /** Accessible name; also the label shown when `showLabels` is on. */
120
+ label: string;
121
+ icon: React.ReactNode;
122
+ /** Engaged/on — rendered in the accent colour. */
123
+ active?: boolean;
124
+ /** A short read-out under the icon (e.g. "3s", "4:3", "Auto"). */
125
+ valueLabel?: string;
126
+ disabled?: boolean;
127
+ /**
128
+ * Primary actions stay visible when the rail is collapsed. Everything else
129
+ * hides behind the chevron. Keep this to the two or three a user reaches for
130
+ * without thinking — a rail where nothing collapses is just a long rail.
131
+ */
132
+ primary?: boolean;
133
+ onPress: () => void;
134
+ }
135
+ /**
136
+ * Slots for the v3 chrome. Deliberately fewer and differently shaped than
137
+ * `CaptureCameraSlots`: v3 has no mode row, so the slots that existed to sit
138
+ * around one are gone, and the rail replaces the options grid.
139
+ */
140
+ interface CaptureCameraV3Slots {
141
+ /** Centre of the top row — the item label / count. Keep it to one line. */
142
+ topCenter?: React.ReactNode;
143
+ /** Honesty chips under the top row (QR confirmation, upload progress). */
144
+ statusChips?: React.ReactNode;
145
+ /** Rendered OVER the feed just above the shutter row — the filmstrip home. */
146
+ aboveShutter?: React.ReactNode;
147
+ /**
148
+ * The one action to the RIGHT of the shutter (Next / Break / Process).
149
+ * Exactly one: the shutter row is a thumb-reach zone and a second control
150
+ * there turns a one-hand camera into a two-hand one.
151
+ */
152
+ shutterTrailing?: React.ReactNode;
153
+ /** Actions on the right rail, in order. */
154
+ railActions?: CaptureRailAction[];
155
+ /**
156
+ * The expanding text entry pinned to the top row (serial, tag, caption).
157
+ * Supply `<CaptureExpandingField/>` or any control — it is a slot so a host
158
+ * that needs none pays nothing for it.
159
+ */
160
+ topEntry?: React.ReactNode;
161
+ /** Free overlays above everything (sheets, pagers). */
162
+ overlays?: React.ReactNode;
163
+ }
116
164
 
117
- export type { CaptureAspect, CaptureCameraEngine, CaptureCameraMode, CaptureCameraSlots, CaptureCloudPort, CaptureOptionTile, CaptureTimerSetting };
165
+ export type { CaptureAspect, CaptureCameraEngine, CaptureCameraMode, CaptureCameraSlots, CaptureCameraV3Slots, CaptureCloudPort, CaptureOptionTile, CaptureRailAction, CaptureTimerSetting };
package/dist/index.d.ts CHANGED
@@ -113,5 +113,53 @@ interface CaptureCameraSlots {
113
113
  /** Free overlays rendered above everything (sheets, pagers). */
114
114
  overlays?: React.ReactNode;
115
115
  }
116
+ /** One action on the v3 right-hand rail. */
117
+ interface CaptureRailAction {
118
+ id: string;
119
+ /** Accessible name; also the label shown when `showLabels` is on. */
120
+ label: string;
121
+ icon: React.ReactNode;
122
+ /** Engaged/on — rendered in the accent colour. */
123
+ active?: boolean;
124
+ /** A short read-out under the icon (e.g. "3s", "4:3", "Auto"). */
125
+ valueLabel?: string;
126
+ disabled?: boolean;
127
+ /**
128
+ * Primary actions stay visible when the rail is collapsed. Everything else
129
+ * hides behind the chevron. Keep this to the two or three a user reaches for
130
+ * without thinking — a rail where nothing collapses is just a long rail.
131
+ */
132
+ primary?: boolean;
133
+ onPress: () => void;
134
+ }
135
+ /**
136
+ * Slots for the v3 chrome. Deliberately fewer and differently shaped than
137
+ * `CaptureCameraSlots`: v3 has no mode row, so the slots that existed to sit
138
+ * around one are gone, and the rail replaces the options grid.
139
+ */
140
+ interface CaptureCameraV3Slots {
141
+ /** Centre of the top row — the item label / count. Keep it to one line. */
142
+ topCenter?: React.ReactNode;
143
+ /** Honesty chips under the top row (QR confirmation, upload progress). */
144
+ statusChips?: React.ReactNode;
145
+ /** Rendered OVER the feed just above the shutter row — the filmstrip home. */
146
+ aboveShutter?: React.ReactNode;
147
+ /**
148
+ * The one action to the RIGHT of the shutter (Next / Break / Process).
149
+ * Exactly one: the shutter row is a thumb-reach zone and a second control
150
+ * there turns a one-hand camera into a two-hand one.
151
+ */
152
+ shutterTrailing?: React.ReactNode;
153
+ /** Actions on the right rail, in order. */
154
+ railActions?: CaptureRailAction[];
155
+ /**
156
+ * The expanding text entry pinned to the top row (serial, tag, caption).
157
+ * Supply `<CaptureExpandingField/>` or any control — it is a slot so a host
158
+ * that needs none pays nothing for it.
159
+ */
160
+ topEntry?: React.ReactNode;
161
+ /** Free overlays above everything (sheets, pagers). */
162
+ overlays?: React.ReactNode;
163
+ }
116
164
 
117
- export type { CaptureAspect, CaptureCameraEngine, CaptureCameraMode, CaptureCameraSlots, CaptureCloudPort, CaptureOptionTile, CaptureTimerSetting };
165
+ export type { CaptureAspect, CaptureCameraEngine, CaptureCameraMode, CaptureCameraSlots, CaptureCameraV3Slots, CaptureCloudPort, CaptureOptionTile, CaptureRailAction, CaptureTimerSetting };