@symbiote-native/camera 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/README.md CHANGED
@@ -4,54 +4,252 @@
4
4
  [SymbioteNative](../../README.md) adapter: React, Vue, Svelte, Solid and Angular. The camera
5
5
  preview, pictures, video recording and barcode scanning.
6
6
 
7
+ Built the same way as [`@symbiote-native/clipboard`](../clipboard)'s `ClipboardPasteButton`, an
8
+ `expo-modules-core` native view reached through `requireNativeViewManager` (see the
9
+ `symbiote-expo-native-module` project skill: why `expo-modules-core` is depended on directly and never
10
+ the `expo` meta-package, why the upstream JS is hand-ported into `core/`, and how autolinking finds the
11
+ native module). One render function in `core/` returns a descriptor and every adapter only turns it into
12
+ its own element.
13
+
7
14
  ## Install
8
15
 
16
+ **New app:**
17
+
18
+ ```bash
19
+ npx @symbiote-native/cli new my-app --camera
20
+ ```
21
+
22
+ **Existing SymbioteNative app:**
23
+
9
24
  ```bash
10
- npx @symbiote-native/cli new my-app --camera # new app
11
- npx @symbiote-native/cli add --camera # existing app
25
+ npx @symbiote-native/cli add --camera
12
26
  ```
13
27
 
14
- Manual: `npm install @symbiote-native/camera`, then wire `expo-modules-autolinking` once per app.
15
- Never install `expo-camera` or the `expo` meta-package yourself.
28
+ Either way: installs `@symbiote-native/camera` and wires the native autolinking automatically,
29
+ see [`@symbiote-native/cli`](../cli).
30
+
31
+ <details>
32
+ <summary>Manual install (no CLI - installing and wiring native autolinking by hand)</summary>
33
+
34
+ ```bash
35
+ npm install @symbiote-native/camera
36
+ ```
16
37
 
17
- ## Usage
38
+ Depends on `expo-camera` and `expo-modules-core` directly (regular dependencies, pinned to exact
39
+ versions, since this package's `core/` is hand-ported against one specific native API shape).
40
+ Never install `expo-camera` yourself, and never add the `expo` package to this project: it bundles
41
+ its own Metro/Babel pipeline that conflicts with this project's own.
42
+
43
+ ### Required one-time step: native autolinking wiring
44
+
45
+ `expo-camera`'s native code is discovered by `expo-modules-autolinking`, not by RN's own
46
+ `react-native.config.cjs` mechanism. Wire it into the native host app **once**, it covers this package
47
+ and every other `expo-modules-core` package with zero further changes. The steps and the
48
+ mechanics behind them are in the `symbiote-expo-native-module` skill and in
49
+ [`@symbiote-native/network`](../network)'s README; the reference app is `examples/expo-react`.
50
+
51
+ ### Permissions
52
+
53
+ The package declares what `expo-camera`'s config plugin adds, and the `expo-modules-link` postinstall
54
+ writes it into the app:
55
+
56
+ | File | Entry |
57
+ | --------------------- | ---------------------------------------------------------- |
58
+ | `Info.plist` | `NSCameraUsageDescription`, `NSMicrophoneUsageDescription` |
59
+ | `AndroidManifest.xml` | `CAMERA`, `RECORD_AUDIO` |
60
+
61
+ iOS wants the microphone text even if you only take pictures, because the same view can record. Reword
62
+ both texts to fit your app.
63
+
64
+ </details>
65
+
66
+ ## Shape
67
+
68
+ ```
69
+ src/core/ camera-view.ts - createCameraView(getNode): render, the handle (camera-view-handle.ts)
70
+ and the barcode throttle. camera-api.ts - the statics of upstream's class and the
71
+ permission calls. props.ts, picture-options.ts, picture-ref.ts, types.ts.
72
+ src/react/ @symbiote-native/camera/react - CameraView, useCameraPermissions, useMicrophonePermissions
73
+ src/vue/ @symbiote-native/camera/vue - the same names
74
+ src/svelte/ @symbiote-native/camera/svelte - the same names ({ status, requestPermission, getPermission })
75
+ src/solid/ @symbiote-native/camera/solid - the same names
76
+ src/angular/ @symbiote-native/camera/angular - CameraView, CameraPermissionsService, MicrophonePermissionsService
77
+ ```
78
+
79
+ ## Use it
80
+
81
+ ### React
18
82
 
19
83
  ```tsx
84
+ import { useRef } from 'react';
20
85
  import { CameraView, useCameraPermissions, type ICameraViewHandle } from '@symbiote-native/camera/react';
21
86
 
22
87
  const [permission, requestPermission] = useCameraPermissions();
23
- const ref = useRef<ICameraViewHandle>(null);
88
+ const camera = useRef<ICameraViewHandle>(null);
89
+
90
+ return permission?.granted === true ? (
91
+ <>
92
+ <CameraView ref={camera} style={{ flex: 1 }} facing="back" />
93
+ <button title="Take picture" onPress={() => camera.current?.takePictureAsync({ quality: 0.8 })} />
94
+ </>
95
+ ) : (
96
+ <button title="Allow the camera" onPress={() => requestPermission()} />
97
+ );
98
+ ```
99
+
100
+ ### Vue
101
+
102
+ ```vue
103
+ <script setup lang="ts">
104
+ import { ref } from 'vue';
105
+ import { CameraView, useCameraPermissions, type ICameraViewHandle } from '@symbiote-native/camera/vue';
106
+
107
+ const [permission, requestPermission] = useCameraPermissions();
108
+ const camera = ref<ICameraViewHandle | null>(null);
109
+ </script>
110
+
111
+ <template>
112
+ <template v-if="permission?.granted === true">
113
+ <CameraView ref="camera" :style="{ flex: 1 }" facing="back" />
114
+ <button title="Take picture" @press="camera?.takePictureAsync({ quality: 0.8 })" />
115
+ </template>
116
+ <button v-else title="Allow the camera" @press="requestPermission()" />
117
+ </template>
118
+ ```
119
+
120
+ ### Angular
121
+
122
+ ```ts
123
+ import { Component, inject } from '@angular/core';
124
+ import { SYMBIOTE_ELEMENTS } from '@symbiote-native/angular';
125
+ import { CameraPermissionsService, CameraView } from '@symbiote-native/camera/angular';
126
+
127
+ @Component({
128
+ standalone: true,
129
+ imports: [CameraView, SYMBIOTE_ELEMENTS],
130
+ template: `
131
+ @if (permission()?.granted === true) {
132
+ <CameraView #camera [style]="{ flex: 1 }" facing="back" />
133
+ <button title="Take picture" (press)="camera.takePictureAsync({ quality: 0.8 })" />
134
+ } @else {
135
+ <button title="Allow the camera" (press)="request()" />
136
+ }
137
+ `,
138
+ })
139
+ export class CameraCard {
140
+ private readonly service = inject(CameraPermissionsService);
141
+ readonly permission = this.service.connect();
142
+
143
+ request(): void {
144
+ void this.service.request();
145
+ }
146
+ }
147
+ ```
148
+
149
+ ### Svelte
150
+
151
+ ```svelte
152
+ <script lang="ts">
153
+ import { CameraView, useCameraPermissions, type ICameraViewHandle } from '@symbiote-native/camera/svelte';
24
154
 
25
- <CameraView ref={ref} style={{ flex: 1 }} facing="back" onBarcodeScanned={scan => console.log(scan.data)} />;
155
+ const permission = useCameraPermissions();
156
+ let camera = $state<ICameraViewHandle | undefined>();
157
+ </script>
26
158
 
27
- const picture = await ref.current?.takePictureAsync({ quality: 0.8 });
159
+ {#if permission.status?.granted === true}
160
+ <CameraView bind:this={camera} style={{ flex: 1 }} facing="back" />
161
+ <button title="Take picture" onPress={() => camera?.takePictureAsync({ quality: 0.8 })} />
162
+ {:else}
163
+ <button title="Allow the camera" onPress={() => permission.requestPermission()} />
164
+ {/if}
28
165
  ```
29
166
 
30
- The view takes the props of upstream's `CameraView` plus the View surface. The handle has
31
- `takePictureAsync`, `recordAsync`, `toggleRecordingAsync`, `stopRecording`, `pausePreview`,
32
- `resumePreview`, `getAvailablePictureSizesAsync`, `getAvailableLensesAsync` and
33
- `getSupportedFeatures`. A `ref` carries it in React and Solid (`ref={fn}`), the exposed members of
34
- a template ref in Vue, `bind:this` in Svelte and `@ViewChild` in Angular.
167
+ ### Solid
35
168
 
36
- The static members of upstream's `CameraView` are functions of the package: `isCameraAvailableAsync`
37
- (was `CameraView.isAvailableAsync`), `getAvailableVideoCodecsAsync`, `launchScanner`,
38
- `dismissScanner`, `onModernBarcodeScanned` and `isModernBarcodeScannerAvailable()`. `Camera`,
39
- `scanFromURLAsync` and `PictureRef` keep their names. The permission hooks are
40
- `useCameraPermissions` and `useMicrophonePermissions`, in Angular `CameraPermissionsService` and
41
- `MicrophonePermissionsService`.
169
+ ```tsx
170
+ import { Show, createSignal } from 'solid-js';
171
+ import { CameraView, useCameraPermissions, type ICameraViewHandle } from '@symbiote-native/camera/solid';
42
172
 
43
- ## App setup
173
+ const [permission, requestPermission] = useCameraPermissions();
174
+ const [camera, setCamera] = createSignal<ICameraViewHandle>();
175
+
176
+ <Show
177
+ when={permission()?.granted === true}
178
+ fallback={<button title="Allow the camera" onPress={() => requestPermission()} />}
179
+ >
180
+ <CameraView ref={setCamera} style={{ flex: 1 }} facing="back" />
181
+ <button title="Take picture" onPress={() => camera()?.takePictureAsync({ quality: 0.8 })} />
182
+ </Show>;
183
+ ```
44
184
 
45
- The package declares what `expo-camera`'s config plugin adds, and the `expo-modules-link`
46
- postinstall writes it into the app:
185
+ ## API
47
186
 
48
- | File | Entry |
49
- | -------------------- | -------------------------------------------------------------- |
50
- | `Info.plist` | `NSCameraUsageDescription`, `NSMicrophoneUsageDescription` |
51
- | `AndroidManifest.xml`| `CAMERA`, `RECORD_AUDIO` |
187
+ ```ts
188
+ <CameraView facing? flash? mode? zoom? mute? enableTorch? active? // active is iOS only
189
+ barcodeScannerSettings? onBarcodeScanned? onCameraReady? onMountError? ... />
190
+ // handle: takePictureAsync, recordAsync, toggleRecordingAsync, stopRecording, pausePreview,
191
+ // resumePreview, getAvailablePictureSizesAsync, getAvailableLensesAsync, getSupportedFeatures
52
192
 
53
- ## Not ported
193
+ isCameraAvailableAsync(): Promise<boolean> // was CameraView.isAvailableAsync
194
+ getAvailableVideoCodecsAsync(): Promise<ICameraVideoCodec[]> // iOS
195
+ launchScanner(options?): Promise<void> dismissScanner(): Promise<void>
196
+ onModernBarcodeScanned(listener): EventSubscription isModernBarcodeScannerAvailable(): boolean
197
+ scanFromURLAsync(url, barcodeTypes = ['qr']): Promise<ICameraBarcodeScanningResult[]>
198
+ Camera.getCameraPermissionsAsync() and the three twins // request and microphone variants
199
+ ```
54
200
 
55
- The web build (`.web` files, the browser barcode detector) and the plugin's
56
- `barcodeScannerEnabled: false` switch, which only trims the native binary size. The only upstream
57
- test covers the web manager, the suites here are written against the native behavior.
201
+ `PictureRef` keeps its name. Ported from upstream's `CameraView.tsx`, `Camera.ts` and `Camera.types.ts`.
202
+
203
+ ## Notes
204
+
205
+ - **The postinstall asks for both permissions.** It writes `NSCameraUsageDescription` and
206
+ `NSMicrophoneUsageDescription` into `Info.plist` and `CAMERA` and `RECORD_AUDIO` into the Android
207
+ manifest. iOS needs the microphone text even if you only take pictures, because the same view can
208
+ record. Reword both texts to fit your app.
209
+ - **Ask first, then render.** Show `CameraView` only once `useCameraPermissions` reports `granted`.
210
+ - **`onBarcodeScanned` turns scanning on.** The scanner is enabled exactly when you pass the prop,
211
+ and `barcodeScannerSettings={{ barcodeTypes: [...] }}` narrows what it looks for.
212
+ - **`CameraView` takes no children.** The native view does not host them, so draw controls and
213
+ frames as siblings, absolutely positioned over it.
214
+ - **The handle works after `onCameraReady`.** `takePictureAsync` and `recordAsync` before that can
215
+ fail or return nothing.
216
+ - **`active={false}` stops the camera session without unmounting the view.** iOS only, it is on by
217
+ default.
218
+ - **Not ported.** The web build (`.web` files, the browser barcode detector) and the plugin's `barcodeScannerEnabled: false` switch, which only trims the native binary size. The only upstream test covers the web manager, the suites here are written against the native behavior.
219
+
220
+ ## Common questions
221
+
222
+ - **iOS crash when the camera opens.** A missing usage description. The postinstall writes
223
+ `NSCameraUsageDescription` and `NSMicrophoneUsageDescription`, iOS wants both for the camera view.
224
+ - **Black preview.** Render the view only when permission is `granted`, test on a device (the iOS
225
+ Simulator has no camera) and wait for `onCameraReady` before calling the handle.
226
+ - **The barcode callback.** Passing `onBarcodeScanned` turns the scanner on. To scan once, pass
227
+ `undefined` after the first result.
228
+ - **Children.** `CameraView` takes none, upstream says to overlay a sibling with absolute
229
+ positioning.
230
+ - **Mounting and unmounting freezes or crashes iOS.** Keep the view mounted and set `active={false}`
231
+ (iOS) to stop the session.
232
+ - **Torch turns off at once.** Set `enableTorch` after `onCameraReady`.
233
+ - **System scanner.** `launchScanner()`, iOS 16+ and Google's code scanner on Android.
234
+
235
+ Sources: [Expo docs: Camera](https://docs.expo.dev/versions/latest/sdk/camera/),
236
+ [expo/expo#11736](https://github.com/expo/expo/issues/11736),
237
+ [expo/expo#16126](https://github.com/expo/expo/issues/16126),
238
+ [expo/expo#37150](https://github.com/expo/expo/issues/37150),
239
+ [expo/expo#34957](https://github.com/expo/expo/issues/34957),
240
+ [expo/expo#48780](https://github.com/expo/expo/issues/48780),
241
+ [expo/expo#36352](https://github.com/expo/expo/issues/36352).
242
+
243
+ ## Test it
244
+
245
+ No device is needed for the logic. The core tests (`src/core/*.test.ts`) replace `expo-modules-core`
246
+ (`requireNativeViewManager`, `Platform`) and assert the descriptor a render function returns. The
247
+ adapter tests (`src/{react,vue,solid,angular}/**/*.test.*`, `vitest`) render the real component over the
248
+ recording Fabric with an injected view config and assert the committed payload, and Svelte's
249
+ `*.smoke.test.ts` compile the `.svelte` files and mount them. Painting itself is verified on a device in
250
+ the six `examples/expo-*` canary apps (`examples/expo-react`, `examples/expo-vue-sfc`,
251
+ `examples/expo-vue-tsx`, `examples/expo-svelte`, `examples/expo-solid`, `examples/expo-angular`), see the
252
+ parent [README](../../README.md).
253
+
254
+ The permission hooks are tested with a fake native module (`use-camera-permissions.test.*`, the Angular
255
+ service test), the same pattern as every permission package.
@@ -2,7 +2,7 @@ import { Platform, requireNativeModule } from 'expo-modules-core';
2
2
  import { defineExpoViewMethods, getNativeTag } from '@symbiote-native/engine';
3
3
  import { CAMERA_MODULE_NAME } from './constants.js';
4
4
  import { expoCamera } from './native-module.js';
5
- import { ensurePictureOptions, ensureRecordingOptions } from './picture-options.js';
5
+ import { ensurePictureOptions, ensureRecordingOptions, } from './picture-options.js';
6
6
  const callViewFunction = defineExpoViewMethods(requireNativeModule, CAMERA_MODULE_NAME);
7
7
  export function createCameraViewHandle(getNode) {
8
8
  // Like upstream's `ref.current?.`, a view that has not committed yet answers nothing
@@ -16,13 +16,19 @@ export function createCameraViewHandle(getNode) {
16
16
  const pictureOptions = ensurePictureOptions(options);
17
17
  // The picture ref is an iOS feature, Android answers a plain picture
18
18
  if (Platform.select({ ios: Boolean(options?.pictureRef), default: false })) {
19
- return call('takePictureRef', [pictureOptions]);
19
+ return call('takePictureRef', [
20
+ pictureOptions,
21
+ ]);
20
22
  }
21
- return call('takePicture', [pictureOptions]);
23
+ return call('takePicture', [
24
+ pictureOptions,
25
+ ]);
22
26
  }
23
27
  return {
24
28
  takePictureAsync,
25
- recordAsync: async (options) => call('record', [ensureRecordingOptions(options)]),
29
+ recordAsync: async (options) => call('record', [
30
+ ensureRecordingOptions(options),
31
+ ]),
26
32
  toggleRecordingAsync: async () => call('toggleRecording'),
27
33
  stopRecording: () => {
28
34
  call('stopRecording');
@@ -1,5 +1,5 @@
1
1
  export { CameraView } from './camera-view';
2
2
  export type { ICameraViewReactProps } from './camera-view';
3
- export { useCameraPermissions, useMicrophonePermissions } from './use-camera-permissions';
3
+ export { useCameraPermissions, useMicrophonePermissions, } from './use-camera-permissions';
4
4
  export type { IUseCameraPermissionsHook } from './use-camera-permissions';
5
5
  export * from '../core';
@@ -1,4 +1,4 @@
1
1
  // @symbiote-native/camera/react: камера, съёмка, запись видео и сканирование кодов на общем ядре
2
2
  export { CameraView } from './camera-view.js';
3
- export { useCameraPermissions, useMicrophonePermissions } from './use-camera-permissions.js';
3
+ export { useCameraPermissions, useMicrophonePermissions, } from './use-camera-permissions.js';
4
4
  export * from '../core/index.js';
@@ -1,4 +1,4 @@
1
1
  export { CameraView } from './camera-view';
2
- export { useCameraPermissions, useMicrophonePermissions } from './use-camera-permissions';
2
+ export { useCameraPermissions, useMicrophonePermissions, } from './use-camera-permissions';
3
3
  export type { IUseCameraPermissionsHook } from './use-camera-permissions';
4
4
  export * from '../core';
@@ -1,4 +1,4 @@
1
1
  // @symbiote-native/camera/solid: камера, съёмка, запись видео и сканирование кодов на общем ядре
2
2
  export { CameraView } from './camera-view.js';
3
- export { useCameraPermissions, useMicrophonePermissions } from './use-camera-permissions.js';
3
+ export { useCameraPermissions, useMicrophonePermissions, } from './use-camera-permissions.js';
4
4
  export * from '../core/index.js';
@@ -1,4 +1,4 @@
1
1
  export { CameraView } from './camera-view';
2
- export { useCameraPermissions, useMicrophonePermissions } from './use-camera-permissions';
2
+ export { useCameraPermissions, useMicrophonePermissions, } from './use-camera-permissions';
3
3
  export type { IUseCameraPermissionsHook } from './use-camera-permissions';
4
4
  export * from '../core';
@@ -1,4 +1,4 @@
1
1
  // @symbiote-native/camera/vue: камера, съёмка, запись видео и сканирование кодов на общем ядре
2
2
  export { CameraView } from './camera-view.js';
3
- export { useCameraPermissions, useMicrophonePermissions } from './use-camera-permissions.js';
3
+ export { useCameraPermissions, useMicrophonePermissions, } from './use-camera-permissions.js';
4
4
  export * from '../core/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"camera-view-events.js","sourceRoot":"","sources":["../../src/core/camera-view-events.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"camera-view-events.js","sourceRoot":"","sources":["../../src/core/camera-view-events.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import { Platform, requireNativeModule } from 'expo-modules-core';
2
2
  import { defineExpoViewMethods, getNativeTag } from '@symbiote-native/engine';
3
3
  import { CAMERA_MODULE_NAME } from './constants';
4
4
  import { expoCamera } from './native-module';
5
- import { ensurePictureOptions, ensureRecordingOptions } from './picture-options';
5
+ import { ensurePictureOptions, ensureRecordingOptions, } from './picture-options';
6
6
  const callViewFunction = defineExpoViewMethods(requireNativeModule, CAMERA_MODULE_NAME);
7
7
  export function createCameraViewHandle(getNode) {
8
8
  // Like upstream's `ref.current?.`, a view that has not committed yet answers nothing
@@ -16,13 +16,19 @@ export function createCameraViewHandle(getNode) {
16
16
  const pictureOptions = ensurePictureOptions(options);
17
17
  // The picture ref is an iOS feature, Android answers a plain picture
18
18
  if (Platform.select({ ios: Boolean(options?.pictureRef), default: false })) {
19
- return call('takePictureRef', [pictureOptions]);
19
+ return call('takePictureRef', [
20
+ pictureOptions,
21
+ ]);
20
22
  }
21
- return call('takePicture', [pictureOptions]);
23
+ return call('takePicture', [
24
+ pictureOptions,
25
+ ]);
22
26
  }
23
27
  return {
24
28
  takePictureAsync,
25
- recordAsync: async (options) => call('record', [ensureRecordingOptions(options)]),
29
+ recordAsync: async (options) => call('record', [
30
+ ensureRecordingOptions(options),
31
+ ]),
26
32
  toggleRecordingAsync: async () => call('toggleRecording'),
27
33
  stopRecording: () => {
28
34
  call('stopRecording');
@@ -1 +1 @@
1
- {"version":3,"file":"camera-view-handle.js","sourceRoot":"","sources":["../../src/core/camera-view-handle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAiCjF,MAAM,gBAAgB,GAAG,qBAAqB,CAC5C,mBAAmB,EACnB,kBAAkB,CACnB,CAAC;AAEF,MAAM,UAAU,sBAAsB,CACpC,OAA+C;IAE/C,qFAAqF;IACrF,SAAS,IAAI,CACX,MAAc,EACd,OAA2B,EAAE;QAE7B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAChE,OAAO,gBAAgB,CAAU,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;IAQD,KAAK,UAAU,gBAAgB,CAAC,OAA+B;QAC7D,MAAM,cAAc,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACrD,qEAAqE;QACrE,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YAC3E,OAAO,IAAI,CAA6B,gBAAgB,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;QAC9E,CAAC;QACD,OAAO,IAAI,CAAkC,aAAa,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,OAAO;QACL,gBAAgB;QAChB,WAAW,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAC3B,IAAI,CAA2B,QAAQ,EAAE,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7E,oBAAoB,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAgB,iBAAiB,CAAC;QACxE,aAAa,EAAE,GAAG,EAAE;YAClB,IAAI,CAAC,eAAe,CAAC,CAAC;QACxB,CAAC;QACD,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAgB,cAAc,CAAC;QAC7D,aAAa,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAgB,eAAe,CAAC;QAC/D,6BAA6B,EAAE,KAAK,IAAI,EAAE,CACxC,CAAC,MAAM,IAAI,CAAoB,0BAA0B,CAAC,CAAC,IAAI,EAAE;QACnE,uBAAuB,EAAE,KAAK,IAAI,EAAE,CAClC,CAAC,MAAM,IAAI,CAAoB,oBAAoB,CAAC,CAAC,IAAI,EAAE;QAC7D,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC;YAC3B,+BAA+B,EAAE,UAAU,CAAC,+BAA+B;YAC3E,6BAA6B,EAAE,UAAU,CAAC,6BAA6B;SACxE,CAAC;QACF,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,IAAI,IAAI;KACrC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"camera-view-handle.js","sourceRoot":"","sources":["../../src/core/camera-view-handle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAiC3B,MAAM,gBAAgB,GAAG,qBAAqB,CAC5C,mBAAmB,EACnB,kBAAkB,CACnB,CAAC;AAEF,MAAM,UAAU,sBAAsB,CACpC,OAA+C;IAE/C,qFAAqF;IACrF,SAAS,IAAI,CACX,MAAc,EACd,OAA2B,EAAE;QAE7B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAChE,OAAO,gBAAgB,CAAU,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;IAQD,KAAK,UAAU,gBAAgB,CAAC,OAA+B;QAC7D,MAAM,cAAc,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACrD,qEAAqE;QACrE,IACE,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EACtE,CAAC;YACD,OAAO,IAAI,CAA6B,gBAAgB,EAAE;gBACxD,cAAc;aACf,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAkC,aAAa,EAAE;YAC1D,cAAc;SACf,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,gBAAgB;QAChB,WAAW,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAC3B,IAAI,CAA2B,QAAQ,EAAE;YACvC,sBAAsB,CAAC,OAAO,CAAC;SAChC,CAAC;QACJ,oBAAoB,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAgB,iBAAiB,CAAC;QACxE,aAAa,EAAE,GAAG,EAAE;YAClB,IAAI,CAAC,eAAe,CAAC,CAAC;QACxB,CAAC;QACD,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAgB,cAAc,CAAC;QAC7D,aAAa,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAgB,eAAe,CAAC;QAC/D,6BAA6B,EAAE,KAAK,IAAI,EAAE,CACxC,CAAC,MAAM,IAAI,CAAoB,0BAA0B,CAAC,CAAC,IAAI,EAAE;QACnE,uBAAuB,EAAE,KAAK,IAAI,EAAE,CAClC,CAAC,MAAM,IAAI,CAAoB,oBAAoB,CAAC,CAAC,IAAI,EAAE;QAC7D,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC;YAC3B,+BAA+B,EAC7B,UAAU,CAAC,+BAA+B;YAC5C,6BAA6B,EAAE,UAAU,CAAC,6BAA6B;SACxE,CAAC;QACF,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,IAAI,IAAI;KACrC,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAMxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAgDjD,MAAM,CAAC,MAAM,UAAU,GAAG,mBAAmB,CAC3C,kBAAkB,CACnB,CAAC"}
1
+ {"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAMxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAkDjD,MAAM,CAAC,MAAM,UAAU,GACrB,mBAAmB,CAAsB,kBAAkB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbiote-native/camera",
3
- "version": "0.0.0",
3
+ "version": "0.1.0",
4
4
  "description": "expo-camera wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. The camera preview, pictures, video recording and barcode scanning.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -67,7 +67,7 @@
67
67
  "dependencies": {
68
68
  "expo-camera": "57.0.6",
69
69
  "expo-modules-core": "57.0.20",
70
- "@symbiote-native/components": "3.1.4"
70
+ "@symbiote-native/components": "3.2.0"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "@angular/core": ">=20",
@@ -77,12 +77,12 @@
77
77
  "solid-js": ">=1.9.0",
78
78
  "svelte": ">=5.56.0",
79
79
  "vue": ">=3.5.0",
80
- "@symbiote-native/angular": "^3.2.0",
81
- "@symbiote-native/engine": "^1.5.0",
82
- "@symbiote-native/react": "^3.2.0",
83
- "@symbiote-native/svelte": "^3.1.0",
84
- "@symbiote-native/solid": "^3.1.0",
85
- "@symbiote-native/vue": "^3.2.0"
80
+ "@symbiote-native/angular": "^3.3.0",
81
+ "@symbiote-native/engine": "^1.6.0",
82
+ "@symbiote-native/react": "^3.3.0",
83
+ "@symbiote-native/solid": "^3.2.0",
84
+ "@symbiote-native/svelte": "^3.2.0",
85
+ "@symbiote-native/vue": "^3.3.0"
86
86
  },
87
87
  "peerDependenciesMeta": {
88
88
  "@symbiote-native/angular": {
@@ -130,13 +130,13 @@
130
130
  "solid-js": "^1.9.14",
131
131
  "svelte": "^5.56.0",
132
132
  "typescript": "~6.0.0",
133
- "@symbiote-native/angular": "3.2.0",
134
- "@symbiote-native/engine": "1.5.0",
135
- "@symbiote-native/solid": "3.1.0",
136
- "@symbiote-native/react": "3.2.0",
137
- "@symbiote-native/vue": "3.2.0",
138
- "@symbiote-native/test-utils": "0.4.6",
139
- "@symbiote-native/svelte": "3.1.0"
133
+ "@symbiote-native/angular": "3.3.0",
134
+ "@symbiote-native/engine": "1.6.0",
135
+ "@symbiote-native/react": "3.3.0",
136
+ "@symbiote-native/solid": "3.2.0",
137
+ "@symbiote-native/svelte": "3.2.0",
138
+ "@symbiote-native/test-utils": "0.4.7",
139
+ "@symbiote-native/vue": "3.3.0"
140
140
  },
141
141
  "scripts": {
142
142
  "typecheck": "tsc --build",
@@ -40,7 +40,10 @@ export type IAndroidBarcode =
40
40
  subject?: string;
41
41
  body?: string;
42
42
  })
43
- | (IAndroidBarcodeKind<'phone'> & { number?: string; phoneNumberType?: string })
43
+ | (IAndroidBarcodeKind<'phone'> & {
44
+ number?: string;
45
+ phoneNumberType?: string;
46
+ })
44
47
  | (IAndroidBarcodeKind<'wifi'> & {
45
48
  ssid?: string;
46
49
  password?: string;
@@ -15,8 +15,9 @@ function hasField(value: unknown, key: string, kind: string): boolean {
15
15
  return typeof Reflect.get(Object(value), key) === kind;
16
16
  }
17
17
 
18
- const isMountError: IGuard<ICameraMountError> = (value): value is ICameraMountError =>
19
- hasField(value, 'message', 'string');
18
+ const isMountError: IGuard<ICameraMountError> = (
19
+ value,
20
+ ): value is ICameraMountError => hasField(value, 'message', 'string');
20
21
 
21
22
  const isOrientation: IGuard<ICameraResponsiveOrientation> = (
22
23
  value,
@@ -87,7 +88,11 @@ export function createCameraViewEvents(): ICameraViewEvents {
87
88
  typeof onBarcodeScanned === 'function'
88
89
  ? throttledScan(result => onBarcodeScanned(result))
89
90
  : undefined,
90
- onAvailableLensesChanged: forward(props, 'onAvailableLensesChanged', isLenses),
91
+ onAvailableLensesChanged: forward(
92
+ props,
93
+ 'onAvailableLensesChanged',
94
+ isLenses,
95
+ ),
91
96
  onResponsiveOrientationChanged: forward(
92
97
  props,
93
98
  'onResponsiveOrientationChanged',
@@ -4,7 +4,10 @@ import type { ISymbioteNode } from '@symbiote-native/engine';
4
4
  import { CAMERA_MODULE_NAME } from './constants';
5
5
  import { expoCamera } from './native-module';
6
6
  import type { ICameraPictureRef } from './native-module';
7
- import { ensurePictureOptions, ensureRecordingOptions } from './picture-options';
7
+ import {
8
+ ensurePictureOptions,
9
+ ensureRecordingOptions,
10
+ } from './picture-options';
8
11
  import type {
9
12
  ICameraCapturedPicture,
10
13
  ICameraPictureOptions,
@@ -64,16 +67,24 @@ export function createCameraViewHandle(
64
67
  async function takePictureAsync(options?: ICameraPictureOptions) {
65
68
  const pictureOptions = ensurePictureOptions(options);
66
69
  // The picture ref is an iOS feature, Android answers a plain picture
67
- if (Platform.select({ ios: Boolean(options?.pictureRef), default: false })) {
68
- return call<Promise<ICameraPictureRef>>('takePictureRef', [pictureOptions]);
70
+ if (
71
+ Platform.select({ ios: Boolean(options?.pictureRef), default: false })
72
+ ) {
73
+ return call<Promise<ICameraPictureRef>>('takePictureRef', [
74
+ pictureOptions,
75
+ ]);
69
76
  }
70
- return call<Promise<ICameraCapturedPicture>>('takePicture', [pictureOptions]);
77
+ return call<Promise<ICameraCapturedPicture>>('takePicture', [
78
+ pictureOptions,
79
+ ]);
71
80
  }
72
81
 
73
82
  return {
74
83
  takePictureAsync,
75
84
  recordAsync: async options =>
76
- call<Promise<{ uri: string }>>('record', [ensureRecordingOptions(options)]),
85
+ call<Promise<{ uri: string }>>('record', [
86
+ ensureRecordingOptions(options),
87
+ ]),
77
88
  toggleRecordingAsync: async () => call<Promise<void>>('toggleRecording'),
78
89
  stopRecording: () => {
79
90
  call('stopRecording');
@@ -85,7 +96,8 @@ export function createCameraViewHandle(
85
96
  getAvailableLensesAsync: async () =>
86
97
  (await call<Promise<string[]>>('getAvailableLenses')) ?? [],
87
98
  getSupportedFeatures: () => ({
88
- isModernBarcodeScannerAvailable: expoCamera.isModernBarcodeScannerAvailable,
99
+ isModernBarcodeScannerAvailable:
100
+ expoCamera.isModernBarcodeScannerAvailable,
89
101
  toggleRecordingAsyncAvailable: expoCamera.toggleRecordingAsyncAvailable,
90
102
  }),
91
103
  getHostNode: () => getNode() ?? null,
@@ -20,7 +20,9 @@ export type ICameraPictureRef = SharedRef<'image'> & {
20
20
  width: number;
21
21
  height: number;
22
22
  /** Saves the image into the cache directory */
23
- savePictureAsync(options?: ICameraSavePictureOptions): Promise<ICameraPhotoResult>;
23
+ savePictureAsync(
24
+ options?: ICameraSavePictureOptions,
25
+ ): Promise<ICameraPhotoResult>;
24
26
  };
25
27
 
26
28
  export type ICameraPictureRefClass = abstract new (
@@ -52,6 +54,5 @@ export type ICameraNativeModule = {
52
54
  ): EventSubscription;
53
55
  };
54
56
 
55
- export const expoCamera = requireNativeModule<ICameraNativeModule>(
56
- CAMERA_MODULE_NAME,
57
- );
57
+ export const expoCamera =
58
+ requireNativeModule<ICameraNativeModule>(CAMERA_MODULE_NAME);
package/src/core/types.ts CHANGED
@@ -30,23 +30,12 @@ export type ICameraVideoCodec = 'avc1' | 'hvc1' | 'jpeg' | 'apcn' | 'ap4h';
30
30
 
31
31
  /** On Android all but `off` turn the stabilization on, the device picks the method */
32
32
  export type ICameraVideoStabilization =
33
- | 'off'
34
- | 'standard'
35
- | 'cinematic'
36
- | 'auto';
37
-
38
- export type ICameraVideoQuality =
39
- | '2160p'
40
- | '1080p'
41
- | '720p'
42
- | '480p'
43
- | '4:3';
33
+ 'off' | 'standard' | 'cinematic' | 'auto';
34
+
35
+ export type ICameraVideoQuality = '2160p' | '1080p' | '720p' | '480p' | '4:3';
44
36
 
45
37
  export type ICameraOrientation =
46
- | 'portrait'
47
- | 'portraitUpsideDown'
48
- | 'landscapeLeft'
49
- | 'landscapeRight';
38
+ 'portrait' | 'portraitUpsideDown' | 'landscapeLeft' | 'landscapeRight';
50
39
 
51
40
  export type ICameraBarcodeType =
52
41
  | 'aztec'
@@ -2,6 +2,9 @@
2
2
 
3
3
  export { CameraView } from './camera-view';
4
4
  export type { ICameraViewReactProps } from './camera-view';
5
- export { useCameraPermissions, useMicrophonePermissions } from './use-camera-permissions';
5
+ export {
6
+ useCameraPermissions,
7
+ useMicrophonePermissions,
8
+ } from './use-camera-permissions';
6
9
  export type { IUseCameraPermissionsHook } from './use-camera-permissions';
7
10
  export * from '../core';
@@ -1,6 +1,9 @@
1
1
  // @symbiote-native/camera/solid: камера, съёмка, запись видео и сканирование кодов на общем ядре
2
2
 
3
3
  export { CameraView } from './camera-view';
4
- export { useCameraPermissions, useMicrophonePermissions } from './use-camera-permissions';
4
+ export {
5
+ useCameraPermissions,
6
+ useMicrophonePermissions,
7
+ } from './use-camera-permissions';
5
8
  export type { IUseCameraPermissionsHook } from './use-camera-permissions';
6
9
  export * from '../core';
@@ -6,9 +6,7 @@ import {
6
6
  import type { IPermissionHookBehavior } from '@symbiote-native/engine';
7
7
  import type { PermissionResponse } from 'expo-modules-core';
8
8
 
9
- export type IUseCameraPermissionsHook = (
10
- options?: IPermissionHookBehavior,
11
- ) => {
9
+ export type IUseCameraPermissionsHook = (options?: IPermissionHookBehavior) => {
12
10
  readonly status: PermissionResponse | null;
13
11
  requestPermission: () => Promise<PermissionResponse>;
14
12
  getPermission: () => Promise<PermissionResponse>;
@@ -2,4 +2,7 @@ import { defineNativeViewComponent } from '@symbiote-native/vue';
2
2
  import { createCameraView } from '../core';
3
3
 
4
4
  /** Vue twin of `expo-camera`'s `CameraView` */
5
- export const CameraView = defineNativeViewComponent('CameraView', createCameraView);
5
+ export const CameraView = defineNativeViewComponent(
6
+ 'CameraView',
7
+ createCameraView,
8
+ );
package/src/vue/index.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  // @symbiote-native/camera/vue: камера, съёмка, запись видео и сканирование кодов на общем ядре
2
2
 
3
3
  export { CameraView } from './camera-view';
4
- export { useCameraPermissions, useMicrophonePermissions } from './use-camera-permissions';
4
+ export {
5
+ useCameraPermissions,
6
+ useMicrophonePermissions,
7
+ } from './use-camera-permissions';
5
8
  export type { IUseCameraPermissionsHook } from './use-camera-permissions';
6
9
  export * from '../core';