@symbiote-native/camera 0.0.0-stage → 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.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +254 -2
  3. package/build/angular/camera-view/index.d.ts +43 -0
  4. package/build/angular/camera-view/index.js +101 -0
  5. package/build/angular/index.d.ts +3 -0
  6. package/build/angular/index.js +4 -0
  7. package/build/angular/services/camera-permissions.service.d.ts +8 -0
  8. package/build/angular/services/camera-permissions.service.js +82 -0
  9. package/build/core/android-barcode.d.ts +50 -0
  10. package/build/core/android-barcode.js +2 -0
  11. package/build/core/camera-api.d.ts +35 -0
  12. package/build/core/camera-api.js +68 -0
  13. package/build/core/camera-view-events.d.ts +3 -0
  14. package/build/core/camera-view-events.js +60 -0
  15. package/build/core/camera-view-handle.d.ts +26 -0
  16. package/build/core/camera-view-handle.js +46 -0
  17. package/build/core/camera-view.d.ts +12 -0
  18. package/build/core/camera-view.js +38 -0
  19. package/build/core/constants.d.ts +6 -0
  20. package/build/core/constants.js +7 -0
  21. package/build/core/index.d.ts +9 -0
  22. package/build/core/index.js +5 -0
  23. package/build/core/native-module.d.ts +28 -0
  24. package/build/core/native-module.js +3 -0
  25. package/build/core/picture-options.d.ts +9 -0
  26. package/build/core/picture-options.js +29 -0
  27. package/build/core/picture-ref.d.ts +2 -0
  28. package/build/core/picture-ref.js +3 -0
  29. package/build/core/props.d.ts +4 -0
  30. package/build/core/props.js +26 -0
  31. package/build/core/types.d.ts +170 -0
  32. package/build/core/types.js +1 -0
  33. package/build/react/camera-view.d.ts +8 -0
  34. package/build/react/camera-view.js +6 -0
  35. package/build/react/index.d.ts +5 -0
  36. package/build/react/index.js +4 -0
  37. package/build/react/use-camera-permissions.d.ts +9 -0
  38. package/build/react/use-camera-permissions.js +5 -0
  39. package/build/solid/camera-view.d.ts +33 -0
  40. package/build/solid/camera-view.js +4 -0
  41. package/build/solid/index.d.ts +4 -0
  42. package/build/solid/index.js +4 -0
  43. package/build/solid/use-camera-permissions.d.ts +10 -0
  44. package/build/solid/use-camera-permissions.js +5 -0
  45. package/build/svelte/camera-view.svelte +32 -0
  46. package/build/svelte/camera-view.svelte.d.ts +22 -0
  47. package/build/svelte/index.d.ts +4 -0
  48. package/build/svelte/index.js +4 -0
  49. package/build/svelte/use-camera-permissions.svelte.d.ts +9 -0
  50. package/build/svelte/use-camera-permissions.svelte.js +5 -0
  51. package/build/vue/camera-view.d.ts +2 -0
  52. package/build/vue/camera-view.js +4 -0
  53. package/build/vue/index.d.ts +4 -0
  54. package/build/vue/index.js +4 -0
  55. package/build/vue/use-camera-permissions.d.ts +10 -0
  56. package/build/vue/use-camera-permissions.js +5 -0
  57. package/build-ngc/angular/camera-view/index.d.ts +46 -0
  58. package/build-ngc/angular/camera-view/index.js +60 -0
  59. package/build-ngc/angular/camera-view/index.js.map +1 -0
  60. package/build-ngc/angular/index.d.ts +3 -0
  61. package/build-ngc/angular/index.js +5 -0
  62. package/build-ngc/angular/index.js.map +1 -0
  63. package/build-ngc/angular/services/camera-permissions.service.d.ts +13 -0
  64. package/build-ngc/angular/services/camera-permissions.service.js +28 -0
  65. package/build-ngc/angular/services/camera-permissions.service.js.map +1 -0
  66. package/build-ngc/core/android-barcode.d.ts +50 -0
  67. package/build-ngc/core/android-barcode.js +3 -0
  68. package/build-ngc/core/android-barcode.js.map +1 -0
  69. package/build-ngc/core/camera-api.d.ts +35 -0
  70. package/build-ngc/core/camera-api.js +69 -0
  71. package/build-ngc/core/camera-api.js.map +1 -0
  72. package/build-ngc/core/camera-view-events.d.ts +3 -0
  73. package/build-ngc/core/camera-view-events.js +61 -0
  74. package/build-ngc/core/camera-view-events.js.map +1 -0
  75. package/build-ngc/core/camera-view-handle.d.ts +26 -0
  76. package/build-ngc/core/camera-view-handle.js +47 -0
  77. package/build-ngc/core/camera-view-handle.js.map +1 -0
  78. package/build-ngc/core/camera-view.d.ts +12 -0
  79. package/build-ngc/core/camera-view.js +39 -0
  80. package/build-ngc/core/camera-view.js.map +1 -0
  81. package/build-ngc/core/constants.d.ts +6 -0
  82. package/build-ngc/core/constants.js +8 -0
  83. package/build-ngc/core/constants.js.map +1 -0
  84. package/build-ngc/core/index.d.ts +9 -0
  85. package/build-ngc/core/index.js +6 -0
  86. package/build-ngc/core/index.js.map +1 -0
  87. package/build-ngc/core/native-module.d.ts +28 -0
  88. package/build-ngc/core/native-module.js +4 -0
  89. package/build-ngc/core/native-module.js.map +1 -0
  90. package/build-ngc/core/picture-options.d.ts +9 -0
  91. package/build-ngc/core/picture-options.js +30 -0
  92. package/build-ngc/core/picture-options.js.map +1 -0
  93. package/build-ngc/core/picture-ref.d.ts +2 -0
  94. package/build-ngc/core/picture-ref.js +4 -0
  95. package/build-ngc/core/picture-ref.js.map +1 -0
  96. package/build-ngc/core/props.d.ts +4 -0
  97. package/build-ngc/core/props.js +27 -0
  98. package/build-ngc/core/props.js.map +1 -0
  99. package/build-ngc/core/types.d.ts +170 -0
  100. package/build-ngc/core/types.js +2 -0
  101. package/build-ngc/core/types.js.map +1 -0
  102. package/native-link.json +22 -0
  103. package/package.json +144 -3
  104. package/src/angular/camera-view/index.ts +95 -0
  105. package/src/angular/index.ts +8 -0
  106. package/src/angular/services/camera-permissions.service.ts +28 -0
  107. package/src/core/android-barcode.ts +51 -0
  108. package/src/core/camera-api.ts +99 -0
  109. package/src/core/camera-view-events.ts +108 -0
  110. package/src/core/camera-view-handle.ts +105 -0
  111. package/src/core/camera-view.ts +56 -0
  112. package/src/core/constants.ts +11 -0
  113. package/src/core/index.ts +57 -0
  114. package/src/core/native-module.ts +58 -0
  115. package/src/core/picture-options.ts +46 -0
  116. package/src/core/picture-ref.ts +4 -0
  117. package/src/core/props.ts +31 -0
  118. package/src/core/types.ts +212 -0
  119. package/src/react/camera-view.ts +17 -0
  120. package/src/react/index.ts +10 -0
  121. package/src/react/use-camera-permissions.ts +21 -0
  122. package/src/solid/camera-view.ts +9 -0
  123. package/src/solid/index.ts +9 -0
  124. package/src/solid/use-camera-permissions.ts +22 -0
  125. package/src/svelte/camera-view.svelte +32 -0
  126. package/src/svelte/index.ts +9 -0
  127. package/src/svelte/svelte-ambient.d.ts +3 -0
  128. package/src/svelte/svelte-compile.test-helper.ts +6 -0
  129. package/src/svelte/use-camera-permissions.svelte.ts +19 -0
  130. package/src/vue/camera-view.ts +8 -0
  131. package/src/vue/index.ts +9 -0
  132. package/src/vue/use-camera-permissions.ts +22 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 A. Prokopenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,255 @@
1
- # Temporary Holding Version
1
+ # @symbiote-native/camera
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [`expo-camera`](https://docs.expo.dev/versions/latest/sdk/camera/) for **every**
4
+ [SymbioteNative](../../README.md) adapter: React, Vue, Svelte, Solid and Angular. The camera
5
+ preview, pictures, video recording and barcode scanning.
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
+
14
+ ## Install
15
+
16
+ **New app:**
17
+
18
+ ```bash
19
+ npx @symbiote-native/cli new my-app --camera
20
+ ```
21
+
22
+ **Existing SymbioteNative app:**
23
+
24
+ ```bash
25
+ npx @symbiote-native/cli add --camera
26
+ ```
27
+
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
+ ```
37
+
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
82
+
83
+ ```tsx
84
+ import { useRef } from 'react';
85
+ import { CameraView, useCameraPermissions, type ICameraViewHandle } from '@symbiote-native/camera/react';
86
+
87
+ const [permission, requestPermission] = useCameraPermissions();
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';
154
+
155
+ const permission = useCameraPermissions();
156
+ let camera = $state<ICameraViewHandle | undefined>();
157
+ </script>
158
+
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}
165
+ ```
166
+
167
+ ### Solid
168
+
169
+ ```tsx
170
+ import { Show, createSignal } from 'solid-js';
171
+ import { CameraView, useCameraPermissions, type ICameraViewHandle } from '@symbiote-native/camera/solid';
172
+
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
+ ```
184
+
185
+ ## API
186
+
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
192
+
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
+ ```
200
+
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.
@@ -0,0 +1,43 @@
1
+ import { NativeViewBase } from '@symbiote-native/angular';
2
+ import type { IDescriptor } from '@symbiote-native/components';
3
+ import type { ICameraViewHandle, ICameraViewProps } from '../../core';
4
+ /** Angular twin of `expo-camera`'s `CameraView` */
5
+ export declare class CameraView extends NativeViewBase {
6
+ facing?: ICameraViewProps['facing'];
7
+ flash?: ICameraViewProps['flash'];
8
+ zoom?: ICameraViewProps['zoom'];
9
+ mode?: ICameraViewProps['mode'];
10
+ mute?: ICameraViewProps['mute'];
11
+ mirror?: ICameraViewProps['mirror'];
12
+ autofocus?: ICameraViewProps['autofocus'];
13
+ active?: ICameraViewProps['active'];
14
+ videoQuality?: ICameraViewProps['videoQuality'];
15
+ videoBitrate?: ICameraViewProps['videoBitrate'];
16
+ animateShutter?: ICameraViewProps['animateShutter'];
17
+ pictureSize?: ICameraViewProps['pictureSize'];
18
+ selectedLens?: ICameraViewProps['selectedLens'];
19
+ enableTorch?: ICameraViewProps['enableTorch'];
20
+ videoStabilizationMode?: ICameraViewProps['videoStabilizationMode'];
21
+ barcodeScannerSettings?: ICameraViewProps['barcodeScannerSettings'];
22
+ responsiveOrientationWhenOrientationLocked?: ICameraViewProps['responsiveOrientationWhenOrientationLocked'];
23
+ ratio?: ICameraViewProps['ratio'];
24
+ onCameraReady?: ICameraViewProps['onCameraReady'];
25
+ onMountError?: ICameraViewProps['onMountError'];
26
+ onBarcodeScanned?: ICameraViewProps['onBarcodeScanned'];
27
+ onResponsiveOrientationChanged?: ICameraViewProps['onResponsiveOrientationChanged'];
28
+ onAvailableLensesChanged?: ICameraViewProps['onAvailableLensesChanged'];
29
+ private readonly view;
30
+ readonly takePictureAsync: ICameraViewHandle['takePictureAsync'];
31
+ readonly recordAsync: ICameraViewHandle['recordAsync'];
32
+ readonly toggleRecordingAsync: ICameraViewHandle['toggleRecordingAsync'];
33
+ readonly stopRecording: ICameraViewHandle['stopRecording'];
34
+ readonly pausePreview: ICameraViewHandle['pausePreview'];
35
+ readonly resumePreview: ICameraViewHandle['resumePreview'];
36
+ readonly getAvailablePictureSizesAsync: ICameraViewHandle['getAvailablePictureSizesAsync'];
37
+ readonly getAvailableLensesAsync: ICameraViewHandle['getAvailableLensesAsync'];
38
+ readonly getSupportedFeatures: ICameraViewHandle['getSupportedFeatures'];
39
+ readonly getHostNode: ICameraViewHandle['getHostNode'];
40
+ constructor();
41
+ protected readonly propNames: readonly ["facing", "flash", "zoom", "mode", "mute", "mirror", "autofocus", "active", "videoQuality", "videoBitrate", "animateShutter", "pictureSize", "selectedLens", "enableTorch", "videoStabilizationMode", "barcodeScannerSettings", "responsiveOrientationWhenOrientationLocked", "ratio", "onCameraReady", "onMountError", "onBarcodeScanned", "onResponsiveOrientationChanged", "onAvailableLensesChanged"];
42
+ protected renderView(props: object): IDescriptor | null;
43
+ }
@@ -0,0 +1,101 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { ChangeDetectionStrategy, Component } from '@angular/core';
36
+ import { DescriptorOutlet, NativeViewBase } from '@symbiote-native/angular';
37
+ import { createCameraView } from '../../core/index.js';
38
+ // One list is the inputs of the component and the props it hands to the native view
39
+ const CAMERA_VIEW_INPUTS = [
40
+ 'facing',
41
+ 'flash',
42
+ 'zoom',
43
+ 'mode',
44
+ 'mute',
45
+ 'mirror',
46
+ 'autofocus',
47
+ 'active',
48
+ 'videoQuality',
49
+ 'videoBitrate',
50
+ 'animateShutter',
51
+ 'pictureSize',
52
+ 'selectedLens',
53
+ 'enableTorch',
54
+ 'videoStabilizationMode',
55
+ 'barcodeScannerSettings',
56
+ 'responsiveOrientationWhenOrientationLocked',
57
+ 'ratio',
58
+ 'onCameraReady',
59
+ 'onMountError',
60
+ 'onBarcodeScanned',
61
+ 'onResponsiveOrientationChanged',
62
+ 'onAvailableLensesChanged',
63
+ ];
64
+ /** Angular twin of `expo-camera`'s `CameraView` */
65
+ let CameraView = (() => {
66
+ let _classDecorators = [Component({
67
+ selector: 'CameraView',
68
+ standalone: true,
69
+ imports: [DescriptorOutlet],
70
+ inputs: [...CAMERA_VIEW_INPUTS],
71
+ changeDetection: ChangeDetectionStrategy.OnPush,
72
+ template: `@if (descriptor; as node) {
73
+ <symbiote-descriptor-outlet [node]="node" />
74
+ }`,
75
+ })];
76
+ let _classDescriptor;
77
+ let _classExtraInitializers = [];
78
+ let _classThis;
79
+ let _classSuper = NativeViewBase;
80
+ var CameraView = class extends _classSuper {
81
+ static { _classThis = this; }
82
+ static {
83
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
84
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
85
+ CameraView = _classThis = _classDescriptor.value;
86
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
87
+ __runInitializers(_classThis, _classExtraInitializers);
88
+ }
89
+ view = createCameraView(() => this.hostNode());
90
+ constructor() {
91
+ super();
92
+ Object.assign(this, this.view.handle);
93
+ }
94
+ propNames = CAMERA_VIEW_INPUTS;
95
+ renderView(props) {
96
+ return this.view.render(props);
97
+ }
98
+ };
99
+ return CameraView = _classThis;
100
+ })();
101
+ export { CameraView };
@@ -0,0 +1,3 @@
1
+ export { CameraView } from './camera-view';
2
+ export { CameraPermissionsService, MicrophonePermissionsService, } from './services/camera-permissions.service';
3
+ export * from '../core';
@@ -0,0 +1,4 @@
1
+ // @symbiote-native/camera/angular: камера, съёмка, запись видео и сканирование кодов на общем ядре
2
+ export { CameraView } from './camera-view/index.js';
3
+ export { CameraPermissionsService, MicrophonePermissionsService, } from './services/camera-permissions.service.js';
4
+ export * from '../core/index.js';
@@ -0,0 +1,8 @@
1
+ import { PermissionsServiceBase } from '@symbiote-native/angular';
2
+ import type { PermissionResponse } from 'expo-modules-core';
3
+ export declare class CameraPermissionsService extends PermissionsServiceBase<PermissionResponse> {
4
+ constructor();
5
+ }
6
+ export declare class MicrophonePermissionsService extends PermissionsServiceBase<PermissionResponse> {
7
+ constructor();
8
+ }
@@ -0,0 +1,82 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { Injectable } from '@angular/core';
36
+ import { PermissionsServiceBase } from '@symbiote-native/angular';
37
+ import { cameraPermissionMethods, microphonePermissionMethods, } from '../../core/camera-api.js';
38
+ // Angular twin of `../../react`'s camera permission hooks
39
+ let CameraPermissionsService = (() => {
40
+ let _classDecorators = [Injectable({ providedIn: 'root' })];
41
+ let _classDescriptor;
42
+ let _classExtraInitializers = [];
43
+ let _classThis;
44
+ let _classSuper = PermissionsServiceBase;
45
+ var CameraPermissionsService = class extends _classSuper {
46
+ static { _classThis = this; }
47
+ static {
48
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
49
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
50
+ CameraPermissionsService = _classThis = _classDescriptor.value;
51
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
52
+ __runInitializers(_classThis, _classExtraInitializers);
53
+ }
54
+ constructor() {
55
+ super(cameraPermissionMethods.getMethod, cameraPermissionMethods.requestMethod);
56
+ }
57
+ };
58
+ return CameraPermissionsService = _classThis;
59
+ })();
60
+ export { CameraPermissionsService };
61
+ let MicrophonePermissionsService = (() => {
62
+ let _classDecorators = [Injectable({ providedIn: 'root' })];
63
+ let _classDescriptor;
64
+ let _classExtraInitializers = [];
65
+ let _classThis;
66
+ let _classSuper = PermissionsServiceBase;
67
+ var MicrophonePermissionsService = class extends _classSuper {
68
+ static { _classThis = this; }
69
+ static {
70
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
71
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
72
+ MicrophonePermissionsService = _classThis = _classDescriptor.value;
73
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
74
+ __runInitializers(_classThis, _classExtraInitializers);
75
+ }
76
+ constructor() {
77
+ super(microphonePermissionMethods.getMethod, microphonePermissionMethods.requestMethod);
78
+ }
79
+ };
80
+ return MicrophonePermissionsService = _classThis;
81
+ })();
82
+ export { MicrophonePermissionsService };
@@ -0,0 +1,50 @@
1
+ type IAndroidBarcodeKind<TType extends string> = {
2
+ type: TType;
3
+ };
4
+ export type IAndroidBarcode = (IAndroidBarcodeKind<'contactInfo'> & {
5
+ firstName?: string;
6
+ middleName?: string;
7
+ lastName?: string;
8
+ title?: string;
9
+ organization?: string;
10
+ email?: string;
11
+ phone?: string;
12
+ url?: string;
13
+ address?: string;
14
+ }) | (IAndroidBarcodeKind<'geoPoint'> & {
15
+ lat: string;
16
+ lng: string;
17
+ }) | (IAndroidBarcodeKind<'sms'> & {
18
+ phoneNumber?: string;
19
+ message?: string;
20
+ }) | (IAndroidBarcodeKind<'url'> & {
21
+ url?: string;
22
+ }) | (IAndroidBarcodeKind<'calendarEvent'> & {
23
+ summary?: string;
24
+ description?: string;
25
+ location?: string;
26
+ start?: string;
27
+ end?: string;
28
+ }) | (IAndroidBarcodeKind<'driverLicense'> & {
29
+ firstName?: string;
30
+ middleName?: string;
31
+ lastName?: string;
32
+ licenseNumber?: string;
33
+ expiryDate?: string;
34
+ issueDate?: string;
35
+ addressStreet?: string;
36
+ addressCity?: string;
37
+ addressState?: string;
38
+ }) | (IAndroidBarcodeKind<'email'> & {
39
+ address?: string;
40
+ subject?: string;
41
+ body?: string;
42
+ }) | (IAndroidBarcodeKind<'phone'> & {
43
+ number?: string;
44
+ phoneNumberType?: string;
45
+ }) | (IAndroidBarcodeKind<'wifi'> & {
46
+ ssid?: string;
47
+ password?: string;
48
+ encryptionType?: string;
49
+ });
50
+ export {};
@@ -0,0 +1,2 @@
1
+ // What Google's code scanner adds to a result, Android only
2
+ export {};
@@ -0,0 +1,35 @@
1
+ import type { EventSubscription, PermissionResponse } from 'expo-modules-core';
2
+ import type { ICameraBarcodeScanningResult, ICameraBarcodeType, ICameraScanningOptions, ICameraScanningResult, ICameraVideoCodec } from './types';
3
+ /** Whether the device has a camera, the permissions are a separate question */
4
+ export declare function isCameraAvailableAsync(): Promise<boolean>;
5
+ /** iOS only */
6
+ export declare function getAvailableVideoCodecsAsync(): Promise<ICameraVideoCodec[]>;
7
+ /** Whether the device has `DataScannerViewController` (iOS 16+) or Google's code scanner */
8
+ export declare function isModernBarcodeScannerAvailable(): boolean;
9
+ /** A device without the modern scanner does nothing here */
10
+ export declare function launchScanner(options?: ICameraScanningOptions): Promise<void>;
11
+ /** Dismisses the scanner on iOS, on Android it closes itself after a scan */
12
+ export declare function dismissScanner(): Promise<void>;
13
+ export declare function onModernBarcodeScanned(listener: (event: ICameraScanningResult) => void): EventSubscription;
14
+ /** Only QR codes are scanned on iOS */
15
+ export declare function scanFromURLAsync(url: string, barcodeTypes?: ICameraBarcodeType[]): Promise<ICameraBarcodeScanningResult[]>;
16
+ declare function getCameraPermissionsAsync(): Promise<PermissionResponse>;
17
+ declare function requestCameraPermissionsAsync(): Promise<PermissionResponse>;
18
+ declare function getMicrophonePermissionsAsync(): Promise<PermissionResponse>;
19
+ declare function requestMicrophonePermissionsAsync(): Promise<PermissionResponse>;
20
+ export declare const Camera: {
21
+ getCameraPermissionsAsync: typeof getCameraPermissionsAsync;
22
+ requestCameraPermissionsAsync: typeof requestCameraPermissionsAsync;
23
+ getMicrophonePermissionsAsync: typeof getMicrophonePermissionsAsync;
24
+ requestMicrophonePermissionsAsync: typeof requestMicrophonePermissionsAsync;
25
+ scanFromURLAsync: typeof scanFromURLAsync;
26
+ };
27
+ export declare const cameraPermissionMethods: {
28
+ getMethod: typeof getCameraPermissionsAsync;
29
+ requestMethod: typeof requestCameraPermissionsAsync;
30
+ };
31
+ export declare const microphonePermissionMethods: {
32
+ getMethod: typeof getMicrophonePermissionsAsync;
33
+ requestMethod: typeof requestMicrophonePermissionsAsync;
34
+ };
35
+ export {};