@ng-native/expo 0.14.0 → 0.16.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.
@@ -19,4 +19,6 @@ dependencies {
19
19
  implementation 'androidx.core:core:1.17.0'
20
20
  // `<search-field>`'s SearchView. React Native depends on AppCompat already.
21
21
  implementation 'androidx.appcompat:appcompat:1.7.0'
22
+ // ReactTypefaceUtils, which finds a face expo-font registered for `<search-field>` as a text's.
23
+ implementation 'com.facebook.react:react-android'
22
24
  }
@@ -1,11 +1,15 @@
1
1
  package dev.ngnative.expo
2
2
 
3
3
  import android.content.Context
4
+ import android.util.TypedValue
4
5
  import android.view.inputmethod.InputMethodManager
6
+ import android.widget.TextView
5
7
  import androidx.appcompat.widget.SearchView
8
+ import com.facebook.react.views.text.ReactTypefaceUtils
6
9
  import expo.modules.kotlin.AppContext
7
10
  import expo.modules.kotlin.modules.Module
8
11
  import expo.modules.kotlin.modules.ModuleDefinition
12
+ import expo.modules.kotlin.types.Either
9
13
  import expo.modules.kotlin.viewevent.EventDispatcher
10
14
  import expo.modules.kotlin.views.ExpoView
11
15
 
@@ -29,6 +33,19 @@ class SearchFieldModule : Module() {
29
33
  Prop("placeholder") { view: SearchFieldView, placeholder: String? ->
30
34
  view.search.queryHint = placeholder
31
35
  }
36
+ // The face and size the field's CSS resolves to, as a text's: the face by the name expo-font
37
+ // registers it under.
38
+ Prop("fontFamily") { view: SearchFieldView, family: String? -> view.fontFamily = family }
39
+ Prop("fontSize") { view: SearchFieldView, size: Double? -> view.fontSize = size?.toFloat() }
40
+ // A weight and a slant no matched face already draws: a number, or `normal` and `bold`.
41
+ Prop("fontWeight") { view: SearchFieldView, weight: Either<Double, String>? ->
42
+ view.fontWeight = when {
43
+ weight == null -> null
44
+ weight.`is`(Double::class) -> weight.get(Double::class).toInt().toString()
45
+ else -> weight.get(String::class)
46
+ }
47
+ }
48
+ Prop("fontStyle") { view: SearchFieldView, style: String? -> view.fontStyle = style }
32
49
 
33
50
  AsyncFunction("focus") { view: SearchFieldView -> view.focus() }.runOnQueue(expo.modules.kotlin.functions.Queues.MAIN)
34
51
  AsyncFunction("blur") { view: SearchFieldView -> view.search.clearFocus() }.runOnQueue(expo.modules.kotlin.functions.Queues.MAIN)
@@ -85,6 +102,50 @@ class SearchFieldView(context: Context, appContext: AppContext) : ExpoView(conte
85
102
  addView(search, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
86
103
  }
87
104
 
105
+ /** The text box, and the face and size it starts with, put back when the CSS names none. */
106
+ private val input = search.findViewById<TextView>(androidx.appcompat.R.id.search_src_text)
107
+ private val systemTypeface = input?.typeface
108
+ private val systemTextSize = input?.textSize
109
+
110
+ var fontFamily: String? = null
111
+ set(value) {
112
+ field = value
113
+ applyFont()
114
+ }
115
+ var fontSize: Float? = null
116
+ set(value) {
117
+ field = value
118
+ applyFont()
119
+ }
120
+ var fontWeight: String? = null
121
+ set(value) {
122
+ field = value
123
+ applyFont()
124
+ }
125
+ var fontStyle: String? = null
126
+ set(value) {
127
+ field = value
128
+ applyFont()
129
+ }
130
+
131
+ /**
132
+ * The CSS's face, weight and slant, found as a text's is, at its size in sp, so it scales with the
133
+ * font size setting.
134
+ */
135
+ private fun applyFont() {
136
+ val input = input ?: return
137
+ input.typeface = ReactTypefaceUtils.applyStyles(
138
+ systemTypeface,
139
+ ReactTypefaceUtils.parseFontStyle(fontStyle),
140
+ ReactTypefaceUtils.parseFontWeight(fontWeight),
141
+ fontFamily,
142
+ context.assets,
143
+ )
144
+ val size = fontSize
145
+ if (size != null) input.setTextSize(TypedValue.COMPLEX_UNIT_SP, size)
146
+ else if (systemTextSize != null) input.setTextSize(TypedValue.COMPLEX_UNIT_PX, systemTextSize)
147
+ }
148
+
88
149
  /** Puts JavaScript's text in the field, unless it answers a keystroke older than the last one. */
89
150
  private fun applyText() {
90
151
  if (mostRecentEventCount < eventCount || search.query.toString() == text) return
package/dist/camera.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `Camera`: a picture taken from the `<expo-camera>` view on screen.
2
+ * `Camera`: a picture taken, or a video recorded, from the `<expo-camera>` view on screen.
3
3
  *
4
4
  * ```ts
5
5
  * registerExpoViews('expo-camera'); // once, at startup
@@ -14,11 +14,15 @@
14
14
  * }
15
15
  * ```
16
16
  *
17
+ * A video is `record()`, which resolves once it stops - `stopRecording()`, or a `maxDuration` or
18
+ * `maxFileSize` reached - on a view with `mode="video"`.
19
+ *
17
20
  * Importing it is all it takes: it applies to every `<expo-camera>` in the template. The view is
18
21
  * what takes the picture, so this is a directive on the view rather than a service.
19
22
  *
20
23
  * In React, `takePictureAsync` is a method on the component's ref. Underneath, it is one of the
21
- * functions Expo defines on the view (`AsyncFunction("takePicture")` in the module), which native
24
+ * functions Expo defines on the view (`AsyncFunction("takePicture")` in the module, and `record`
25
+ * and `stopRecording` beside it), which native
22
26
  * finds by reading `nativeTag` off whatever it is called on. So this calls the same function with
23
27
  * the tag the engine committed the view under, and no ref is needed.
24
28
  */
@@ -26,11 +30,23 @@ import { InjectionToken } from '@angular/core';
26
30
  import * as i0 from "@angular/core";
27
31
  export type PictureOptions = Omit<import('expo-camera').CameraPictureOptions, 'onPictureSaved' | 'pictureRef'>;
28
32
  export type CameraPicture = import('expo-camera').CameraCapturedPicture;
33
+ /** `expo-camera`'s own, less `mirror`, which it has deprecated for the view's `mirror` prop. */
34
+ export type RecordingOptions = Omit<import('expo-camera').CameraRecordingOptions, 'mirror'>;
35
+ /** A recorded video: a file in the cache directory. */
36
+ export interface CameraRecording {
37
+ readonly uri: string;
38
+ }
29
39
  /** The functions `expo-camera` defines on its view, called with the view's tag as `this`. */
30
40
  export interface CameraViewFunctions {
31
41
  takePicture(this: {
32
42
  nativeTag: number;
33
43
  }, options: PictureOptions): Promise<CameraPicture>;
44
+ record(this: {
45
+ nativeTag: number;
46
+ }, options: RecordingOptions): Promise<CameraRecording>;
47
+ stopRecording(this: {
48
+ nativeTag: number;
49
+ }): Promise<void> | void;
34
50
  }
35
51
  export declare class Camera {
36
52
  /** Overridden in a test to take pictures without a camera. */
@@ -43,6 +59,16 @@ export declare class Camera {
43
59
  * no camera to take it with yet.
44
60
  */
45
61
  takePicture(options?: PictureOptions): Promise<CameraPicture | null>;
62
+ /**
63
+ * Record a video, resolving once the recording stops: `stopRecording()`, a `maxDuration` (in
64
+ * seconds) or `maxFileSize` (in bytes) reached, or the preview stopping. The view needs
65
+ * `mode="video"`, and the microphone permission unless it has `mute`: without it, Android rejects
66
+ * and iOS records without sound. Null without the module, or before the view has reached the
67
+ * screen.
68
+ */
69
+ record(options?: RecordingOptions): Promise<CameraRecording | null>;
70
+ /** Stop the recording in progress, if there is one: `record()` then resolves with the video. */
71
+ stopRecording(): Promise<void>;
46
72
  static ɵfac: i0.ɵɵFactoryDeclaration<Camera, never>;
47
73
  static ɵdir: i0.ɵɵDirectiveDeclaration<Camera, "expo-camera", ["camera"], {}, {}, never, never, true, never>;
48
74
  }
package/dist/camera.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `Camera`: a picture taken from the `<expo-camera>` view on screen.
2
+ * `Camera`: a picture taken, or a video recorded, from the `<expo-camera>` view on screen.
3
3
  *
4
4
  * ```ts
5
5
  * registerExpoViews('expo-camera'); // once, at startup
@@ -14,11 +14,15 @@
14
14
  * }
15
15
  * ```
16
16
  *
17
+ * A video is `record()`, which resolves once it stops - `stopRecording()`, or a `maxDuration` or
18
+ * `maxFileSize` reached - on a view with `mode="video"`.
19
+ *
17
20
  * Importing it is all it takes: it applies to every `<expo-camera>` in the template. The view is
18
21
  * what takes the picture, so this is a directive on the view rather than a service.
19
22
  *
20
23
  * In React, `takePictureAsync` is a method on the component's ref. Underneath, it is one of the
21
- * functions Expo defines on the view (`AsyncFunction("takePicture")` in the module), which native
24
+ * functions Expo defines on the view (`AsyncFunction("takePicture")` in the module, and `record`
25
+ * and `stopRecording` beside it), which native
22
26
  * finds by reading `nativeTag` off whatever it is called on. So this calls the same function with
23
27
  * the tag the engine committed the view under, and no ref is needed.
24
28
  */
@@ -52,6 +56,26 @@ export class Camera {
52
56
  return null;
53
57
  return this.functions.takePicture.call({ nativeTag }, options);
54
58
  }
59
+ /**
60
+ * Record a video, resolving once the recording stops: `stopRecording()`, a `maxDuration` (in
61
+ * seconds) or `maxFileSize` (in bytes) reached, or the preview stopping. The view needs
62
+ * `mode="video"`, and the microphone permission unless it has `mute`: without it, Android rejects
63
+ * and iOS records without sound. Null without the module, or before the view has reached the
64
+ * screen.
65
+ */
66
+ async record(options = {}) {
67
+ const nativeTag = this.engine.tagOf(this.node);
68
+ if (!this.functions || nativeTag === null)
69
+ return null;
70
+ return this.functions.record.call({ nativeTag }, options);
71
+ }
72
+ /** Stop the recording in progress, if there is one: `record()` then resolves with the video. */
73
+ async stopRecording() {
74
+ const nativeTag = this.engine.tagOf(this.node);
75
+ if (!this.functions || nativeTag === null)
76
+ return;
77
+ await this.functions.stopRecording.call({ nativeTag });
78
+ }
55
79
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: Camera, deps: [], target: i0.ɵɵFactoryTarget.Directive });
56
80
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.2.0", type: Camera, isStandalone: true, selector: "expo-camera", exportAs: ["camera"], ngImport: i0 });
57
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"camera.js","sourceRoot":"","sources":["../src/camera.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAmB,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;;AAc5D,MAAM,OAAO,MAAM;IACjB,8DAA8D;IAC9D,MAAM,CAAU,MAAM,GAAG,IAAI,cAAc,CACzC,6BAA6B,EAC7B;QACE,OAAO,EAAE,GAAG,EAAE;YACZ,MAAM,IAAI,GAAG,QAAQ,CACnB,GAAG,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAuC,CACzE,CAAC;YACF,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,EAAE,GAAG,EAAE,CAC5C,IAAI,EAAE,2BAA2B,CAE9B,YAAY,CAAC,CACjB,CAAC;YACF,iFAAiF;YACjF,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,OAAO,MAAwC,CAAC;YAChF,uFAAuF;YACvF,OAAO,MAAM,EAAE,cAAc,EAAE,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC;QACxD,CAAC;KACF,CACF,CAAC;IAEe,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACxB,IAAI,GAAG,MAAM,CAAyB,UAAU,CAAC,CAAC,aAAa,CAAC;IAEjF;;;OAGG;IACH,KAAK,CAAC,WAAW,CAAC,UAA0B,EAAE;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACvD,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC;uGAlCU,MAAM;2FAAN,MAAM;;2FAAN,MAAM;kBADlB,SAAS;mBAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE","sourcesContent":["/**\n * `Camera`: a picture taken from the `<expo-camera>` view on screen.\n *\n * ```ts\n * registerExpoViews('expo-camera'); // once, at startup\n *\n * @Component({\n * imports: [Camera],\n * template: `<expo-camera facing=\"back\" class=\"flex-1\" />`,\n * })\n * export class Scanner {\n * private readonly camera = viewChild.required(Camera);\n * async shoot() { const picture = await this.camera().takePicture({ quality: 0.8 }); }\n * }\n * ```\n *\n * Importing it is all it takes: it applies to every `<expo-camera>` in the template. The view is\n * what takes the picture, so this is a directive on the view rather than a service.\n *\n * In React, `takePictureAsync` is a method on the component's ref. Underneath, it is one of the\n * functions Expo defines on the view (`AsyncFunction(\"takePicture\")` in the module), which native\n * finds by reading `nativeTag` off whatever it is called on. So this calls the same function with\n * the tag the engine committed the view under, and no ref is needed.\n */\nimport { Directive, ElementRef, InjectionToken, inject } from '@angular/core';\nimport { Engine, type EngineNode } from '@ng-native/fabric';\nimport { expoModule, optional, present } from './native.ts';\n\nexport type PictureOptions = Omit<\n import('expo-camera').CameraPictureOptions,\n 'onPictureSaved' | 'pictureRef'\n>;\nexport type CameraPicture = import('expo-camera').CameraCapturedPicture;\n\n/** The functions `expo-camera` defines on its view, called with the view's tag as `this`. */\nexport interface CameraViewFunctions {\n takePicture(this: { nativeTag: number }, options: PictureOptions): Promise<CameraPicture>;\n}\n\n@Directive({ selector: 'expo-camera', exportAs: 'camera' })\nexport class Camera {\n /** Overridden in a test to take pictures without a camera. */\n static readonly SOURCE = new InjectionToken<CameraViewFunctions | null>(\n 'angular-native.cameraSource',\n {\n factory: () => {\n const core = optional(\n () => require('expo-modules-core') as typeof import('expo-modules-core'),\n );\n const module = expoModule('expo-camera', () =>\n core?.requireOptionalNativeModule<{\n ViewPrototypes?: Record<string, CameraViewFunctions>;\n }>('ExpoCamera'),\n );\n // Missing, the stand-in is the functions: taking a picture says what to install.\n if (module && !present(module)) return module as unknown as CameraViewFunctions;\n // The camera is the module's first view, so its functions are under the module's name.\n return module?.ViewPrototypes?.['ExpoCamera'] ?? null;\n },\n },\n );\n\n private readonly functions = inject(Camera.SOURCE);\n private readonly engine = inject(Engine);\n private readonly node = inject<ElementRef<EngineNode>>(ElementRef).nativeElement;\n\n /**\n * Take a picture. Null without the module, or before the view has reached the screen - there is\n * no camera to take it with yet.\n */\n async takePicture(options: PictureOptions = {}): Promise<CameraPicture | null> {\n const nativeTag = this.engine.tagOf(this.node);\n if (!this.functions || nativeTag === null) return null;\n return this.functions.takePicture.call({ nativeTag }, options);\n }\n}\n"]}
1
+ {"version":3,"file":"camera.js","sourceRoot":"","sources":["../src/camera.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAmB,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;;AAsB5D,MAAM,OAAO,MAAM;IACjB,8DAA8D;IAC9D,MAAM,CAAU,MAAM,GAAG,IAAI,cAAc,CACzC,6BAA6B,EAC7B;QACE,OAAO,EAAE,GAAG,EAAE;YACZ,MAAM,IAAI,GAAG,QAAQ,CACnB,GAAG,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAuC,CACzE,CAAC;YACF,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,EAAE,GAAG,EAAE,CAC5C,IAAI,EAAE,2BAA2B,CAE9B,YAAY,CAAC,CACjB,CAAC;YACF,iFAAiF;YACjF,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,OAAO,MAAwC,CAAC;YAChF,uFAAuF;YACvF,OAAO,MAAM,EAAE,cAAc,EAAE,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC;QACxD,CAAC;KACF,CACF,CAAC;IAEe,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACxB,IAAI,GAAG,MAAM,CAAyB,UAAU,CAAC,CAAC,aAAa,CAAC;IAEjF;;;OAGG;IACH,KAAK,CAAC,WAAW,CAAC,UAA0B,EAAE;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACvD,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,UAA4B,EAAE;QACzC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACvD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;IAED,gGAAgG;IAChG,KAAK,CAAC,aAAa;QACjB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI;YAAE,OAAO;QAClD,MAAM,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;IACzD,CAAC;uGAtDU,MAAM;2FAAN,MAAM;;2FAAN,MAAM;kBADlB,SAAS;mBAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE","sourcesContent":["/**\n * `Camera`: a picture taken, or a video recorded, from the `<expo-camera>` view on screen.\n *\n * ```ts\n * registerExpoViews('expo-camera'); // once, at startup\n *\n * @Component({\n * imports: [Camera],\n * template: `<expo-camera facing=\"back\" class=\"flex-1\" />`,\n * })\n * export class Scanner {\n * private readonly camera = viewChild.required(Camera);\n * async shoot() { const picture = await this.camera().takePicture({ quality: 0.8 }); }\n * }\n * ```\n *\n * A video is `record()`, which resolves once it stops - `stopRecording()`, or a `maxDuration` or\n * `maxFileSize` reached - on a view with `mode=\"video\"`.\n *\n * Importing it is all it takes: it applies to every `<expo-camera>` in the template. The view is\n * what takes the picture, so this is a directive on the view rather than a service.\n *\n * In React, `takePictureAsync` is a method on the component's ref. Underneath, it is one of the\n * functions Expo defines on the view (`AsyncFunction(\"takePicture\")` in the module, and `record`\n * and `stopRecording` beside it), which native\n * finds by reading `nativeTag` off whatever it is called on. So this calls the same function with\n * the tag the engine committed the view under, and no ref is needed.\n */\nimport { Directive, ElementRef, InjectionToken, inject } from '@angular/core';\nimport { Engine, type EngineNode } from '@ng-native/fabric';\nimport { expoModule, optional, present } from './native.ts';\n\nexport type PictureOptions = Omit<\n import('expo-camera').CameraPictureOptions,\n 'onPictureSaved' | 'pictureRef'\n>;\nexport type CameraPicture = import('expo-camera').CameraCapturedPicture;\n/** `expo-camera`'s own, less `mirror`, which it has deprecated for the view's `mirror` prop. */\nexport type RecordingOptions = Omit<import('expo-camera').CameraRecordingOptions, 'mirror'>;\n/** A recorded video: a file in the cache directory. */\nexport interface CameraRecording {\n readonly uri: string;\n}\n\n/** The functions `expo-camera` defines on its view, called with the view's tag as `this`. */\nexport interface CameraViewFunctions {\n takePicture(this: { nativeTag: number }, options: PictureOptions): Promise<CameraPicture>;\n record(this: { nativeTag: number }, options: RecordingOptions): Promise<CameraRecording>;\n stopRecording(this: { nativeTag: number }): Promise<void> | void;\n}\n\n@Directive({ selector: 'expo-camera', exportAs: 'camera' })\nexport class Camera {\n /** Overridden in a test to take pictures without a camera. */\n static readonly SOURCE = new InjectionToken<CameraViewFunctions | null>(\n 'angular-native.cameraSource',\n {\n factory: () => {\n const core = optional(\n () => require('expo-modules-core') as typeof import('expo-modules-core'),\n );\n const module = expoModule('expo-camera', () =>\n core?.requireOptionalNativeModule<{\n ViewPrototypes?: Record<string, CameraViewFunctions>;\n }>('ExpoCamera'),\n );\n // Missing, the stand-in is the functions: taking a picture says what to install.\n if (module && !present(module)) return module as unknown as CameraViewFunctions;\n // The camera is the module's first view, so its functions are under the module's name.\n return module?.ViewPrototypes?.['ExpoCamera'] ?? null;\n },\n },\n );\n\n private readonly functions = inject(Camera.SOURCE);\n private readonly engine = inject(Engine);\n private readonly node = inject<ElementRef<EngineNode>>(ElementRef).nativeElement;\n\n /**\n * Take a picture. Null without the module, or before the view has reached the screen - there is\n * no camera to take it with yet.\n */\n async takePicture(options: PictureOptions = {}): Promise<CameraPicture | null> {\n const nativeTag = this.engine.tagOf(this.node);\n if (!this.functions || nativeTag === null) return null;\n return this.functions.takePicture.call({ nativeTag }, options);\n }\n\n /**\n * Record a video, resolving once the recording stops: `stopRecording()`, a `maxDuration` (in\n * seconds) or `maxFileSize` (in bytes) reached, or the preview stopping. The view needs\n * `mode=\"video\"`, and the microphone permission unless it has `mute`: without it, Android rejects\n * and iOS records without sound. Null without the module, or before the view has reached the\n * screen.\n */\n async record(options: RecordingOptions = {}): Promise<CameraRecording | null> {\n const nativeTag = this.engine.tagOf(this.node);\n if (!this.functions || nativeTag === null) return null;\n return this.functions.record.call({ nativeTag }, options);\n }\n\n /** Stop the recording in progress, if there is one: `record()` then resolves with the video. */\n async stopRecording(): Promise<void> {\n const nativeTag = this.engine.tagOf(this.node);\n if (!this.functions || nativeTag === null) return;\n await this.functions.stopRecording.call({ nativeTag });\n }\n}\n"]}
@@ -42,12 +42,14 @@ export interface UiModifier {
42
42
  */
43
43
  export declare class UiHost {
44
44
  protected readonly nativeView: true;
45
+ protected readonly android: boolean;
45
46
  readonly matchContents: import("@angular/core").InputSignal<boolean | {
46
47
  readonly vertical?: boolean;
47
48
  readonly horizontal?: boolean;
48
49
  } | undefined>;
49
50
  protected readonly matchVertical: Signal<boolean | undefined>;
50
51
  protected readonly matchHorizontal: Signal<boolean | undefined>;
52
+ /** The safe area SwiftUI's host ignores, iOS only: Compose's host has no such prop. */
51
53
  readonly ignoreSafeArea: import("@angular/core").InputSignal<"all" | "keyboard" | "container" | undefined>;
52
54
  readonly useViewportSizeMeasurement: import("@angular/core").InputSignalWithTransform<boolean | undefined, unknown>;
53
55
  static ɵfac: i0.ɵɵFactoryDeclaration<UiHost, never>;
@@ -56,11 +58,14 @@ export declare class UiHost {
56
58
  /** A SwiftUI `Menu`. Its trigger is the `label` or a `<ui-slot name="label">`; its items are children. */
57
59
  export declare class UiMenu {
58
60
  protected readonly nativeView: true;
61
+ protected readonly android: boolean;
59
62
  readonly label: import("@angular/core").InputSignal<string | undefined>;
60
63
  /** An SF Symbol name. */
61
64
  readonly systemImage: import("@angular/core").InputSignal<string | undefined>;
65
+ /** What VoiceOver reads for the menu's trigger: SwiftUI's `accessibilityLabel` modifier. */
62
66
  readonly accessibilityLabel: import("@angular/core").InputSignal<string | undefined>;
63
67
  readonly modifiers: import("@angular/core").InputSignal<readonly UiModifier[] | undefined>;
68
+ protected readonly resolvedModifiers: Signal<readonly UiModifier[] | undefined>;
64
69
  static ɵfac: i0.ɵɵFactoryDeclaration<UiMenu, never>;
65
70
  static ɵcmp: i0.ɵɵComponentDeclaration<UiMenu, "ui-menu", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "systemImage": { "alias": "systemImage"; "required": false; "isSignal": true; }; "accessibilityLabel": { "alias": "accessibilityLabel"; "required": false; "isSignal": true; }; "modifiers": { "alias": "modifiers"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
66
71
  }
@@ -75,6 +80,7 @@ export declare class UiMenu {
75
80
  * and no height.
76
81
  */
77
82
  export declare class UiViewHost {
83
+ protected readonly android: boolean;
78
84
  protected readonly nativeView: true;
79
85
  readonly matchContents: import("@angular/core").InputSignalWithTransform<boolean | undefined, unknown>;
80
86
  /**
@@ -82,6 +88,7 @@ export declare class UiViewHost {
82
88
  * delivers its touches: it then takes them itself, and is measured from itself.
83
89
  */
84
90
  readonly layoutRoot: import("@angular/core").InputSignalWithTransform<boolean | undefined, unknown>;
91
+ /** Compose's modifiers for the view host, Android only: SwiftUI's view host takes none. */
85
92
  readonly modifiers: import("@angular/core").InputSignal<readonly UiModifier[] | undefined>;
86
93
  static ɵfac: i0.ɵɵFactoryDeclaration<UiViewHost, never>;
87
94
  static ɵcmp: i0.ɵɵComponentDeclaration<UiViewHost, "ui-view-host", never, { "matchContents": { "alias": "matchContents"; "required": false; "isSignal": true; }; "layoutRoot": { "alias": "layoutRoot"; "required": false; "isSignal": true; }; "modifiers": { "alias": "modifiers"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
@@ -115,7 +122,8 @@ export declare class UiButton {
115
122
  readonly role: import("@angular/core").InputSignal<"default" | "cancel" | "destructive" | "close" | undefined>;
116
123
  /**
117
124
  * In a home-screen widget's or a Live Activity's layout, what a tap on it hands the app: see
118
- * `@ng-native/expo/widget` and `@ng-native/expo/live-activity`.
125
+ * `@ng-native/expo/widget` and `@ng-native/expo/live-activity`. The layout's build reads it, so
126
+ * an app's own button is not sent it: `@expo/ui`'s button there has no target.
119
127
  */
120
128
  readonly target: import("@angular/core").InputSignal<string | undefined>;
121
129
  readonly modifiers: import("@angular/core").InputSignal<readonly UiModifier[] | undefined>;
@@ -139,6 +147,7 @@ export declare class UiSlot {
139
147
  protected readonly nativeView: true;
140
148
  protected readonly android: boolean;
141
149
  readonly name: import("@angular/core").InputSignal<string>;
150
+ /** What the slot tells its SwiftUI parent about itself, iOS only. */
142
151
  readonly extraProps: import("@angular/core").InputSignal<Readonly<Record<string, unknown>> | undefined>;
143
152
  static ɵfac: i0.ɵɵFactoryDeclaration<UiSlot, never>;
144
153
  static ɵcmp: i0.ɵɵComponentDeclaration<UiSlot, "ui-slot", never, { "name": { "alias": "name"; "required": true; "isSignal": true; }; "extraProps": { "alias": "extraProps"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
@@ -213,12 +222,22 @@ export declare class UiVStack {
213
222
  */
214
223
  export declare class UiImage {
215
224
  protected readonly nativeView: true;
225
+ /** Compose's image is another control, which takes a `source`: none of these are its. */
226
+ protected readonly android: boolean;
216
227
  readonly systemName: import("@angular/core").InputSignal<string | undefined>;
217
228
  readonly assetName: import("@angular/core").InputSignal<string | undefined>;
218
229
  readonly uiImage: import("@angular/core").InputSignal<string | undefined>;
230
+ /**
231
+ * A symbol's size in points, as a `font` modifier of that size, which does not scale with
232
+ * Dynamic Type. A `font` modifier in `modifiers` wins over it. Without either, the symbol is
233
+ * SwiftUI's default size, where `@expo/ui`'s own `Image` and a widget layout draw it at 24.
234
+ */
219
235
  readonly size: import("@angular/core").InputSignalWithTransform<number | undefined, unknown>;
236
+ /** A symbol's colour, as a `foregroundStyle` modifier. */
220
237
  readonly color: import("@angular/core").InputSignal<string | undefined>;
221
238
  readonly modifiers: import("@angular/core").InputSignal<readonly UiModifier[] | undefined>;
239
+ /** SwiftUI's image reads neither `size` nor `color`: `@expo/ui`'s `Image` makes them modifiers. */
240
+ protected readonly resolvedModifiers: Signal<readonly UiModifier[] | undefined>;
222
241
  static ɵfac: i0.ɵɵFactoryDeclaration<UiImage, never>;
223
242
  static ɵcmp: i0.ɵɵComponentDeclaration<UiImage, "ui-image", never, { "systemName": { "alias": "systemName"; "required": false; "isSignal": true; }; "assetName": { "alias": "assetName"; "required": false; "isSignal": true; }; "uiImage": { "alias": "uiImage"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "modifiers": { "alias": "modifiers"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
224
243
  }
@@ -299,7 +318,16 @@ export declare class UiDatePicker {
299
318
  protected readonly resolvedSelection: Signal<string | undefined>;
300
319
  /** SwiftUI takes a list of what to show, and Compose one word for it. */
301
320
  protected readonly resolvedComponents: Signal<"date" | "hourAndMinute" | readonly ("date" | "hourAndMinute")[] | "dateAndTime" | undefined>;
302
- protected readonly initialDate: Signal<number | null | undefined>;
321
+ protected readonly initialDate: Signal<number | null>;
322
+ /** Compose takes `range` as `selectableDates`, each end in milliseconds. */
323
+ protected readonly selectableDates: Signal<{
324
+ start: number | null;
325
+ end: number | null;
326
+ } | undefined>;
327
+ /**
328
+ * SwiftUI's picker reads `disabled` and `accessibilityLabel` as modifiers, and Compose's reads
329
+ * `accessibilityLabel` as the `semantics` modifier's `contentDescription`.
330
+ */
303
331
  protected readonly resolvedModifiers: Signal<readonly UiModifier[] | undefined>;
304
332
  /**
305
333
  * SwiftUI's picker cannot be empty: it shows today, and reports that as a change the moment it
@@ -397,6 +425,8 @@ export declare class UiPicker {
397
425
  /** Each option's `tag`, one array per value, so a pass hands native the same objects. */
398
426
  protected readonly tags: Signal<Map<string | number, readonly UiModifier[]>>;
399
427
  protected readonly android: boolean;
428
+ /** SwiftUI's picker view draws nothing without a label, and a segmented one never shows it. */
429
+ protected readonly shownLabel: Signal<string>;
400
430
  /** Whether Android's dropdown is open. */
401
431
  protected readonly open: import("@angular/core").WritableSignal<boolean>;
402
432
  /**
@@ -488,17 +518,25 @@ export declare class UiColorPicker {
488
518
  static ɵfac: i0.ɵɵFactoryDeclaration<UiColorPicker, never>;
489
519
  static ɵcmp: i0.ɵɵComponentDeclaration<UiColorPicker, "ui-color-picker", never, { "selection": { "alias": "selection"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "supportsOpacity": { "alias": "supportsOpacity"; "required": false; "isSignal": true; }; "modifiers": { "alias": "modifiers"; "required": false; "isSignal": true; }; }, { "selectionChange": "selectionChange"; }, never, never, true, never>;
490
520
  }
491
- /** A SwiftUI `Gauge`: `value` between `min` and `max`, drawn as `type` says. */
521
+ /**
522
+ * A SwiftUI `Gauge`: `value` between `min` and `max`, drawn as `type` says, with its labels drawn as
523
+ * text in the slots SwiftUI reads them from, as `@expo/ui`'s `Gauge` draws them.
524
+ */
492
525
  export declare class UiGauge {
493
526
  protected readonly nativeView: true;
494
527
  readonly value: import("@angular/core").InputSignalWithTransform<number | undefined, unknown>;
495
528
  readonly min: import("@angular/core").InputSignalWithTransform<number | undefined, unknown>;
496
529
  readonly max: import("@angular/core").InputSignalWithTransform<number | undefined, unknown>;
530
+ /**
531
+ * How it is drawn, as the `gaugeStyle` modifier: `'automatic'`, `'circular'`,
532
+ * `'circularCapacity'`, `'linear'` or `'linearCapacity'`.
533
+ */
497
534
  readonly type: import("@angular/core").InputSignal<string | undefined>;
498
535
  readonly currentValueLabel: import("@angular/core").InputSignal<string | undefined>;
499
536
  readonly minimumValueLabel: import("@angular/core").InputSignal<string | undefined>;
500
537
  readonly maximumValueLabel: import("@angular/core").InputSignal<string | undefined>;
501
538
  readonly modifiers: import("@angular/core").InputSignal<readonly UiModifier[] | undefined>;
539
+ protected readonly resolvedModifiers: Signal<readonly UiModifier[] | undefined>;
502
540
  static ɵfac: i0.ɵɵFactoryDeclaration<UiGauge, never>;
503
541
  static ɵcmp: i0.ɵɵComponentDeclaration<UiGauge, "ui-gauge", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "currentValueLabel": { "alias": "currentValueLabel"; "required": false; "isSignal": true; }; "minimumValueLabel": { "alias": "minimumValueLabel"; "required": false; "isSignal": true; }; "maximumValueLabel": { "alias": "maximumValueLabel"; "required": false; "isSignal": true; }; "modifiers": { "alias": "modifiers"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
504
542
  }
@@ -698,8 +736,14 @@ export declare class UiLabel {
698
736
  readonly title: import("@angular/core").InputSignal<string | undefined>;
699
737
  /** An SF Symbol name. */
700
738
  readonly systemImage: import("@angular/core").InputSignal<string | undefined>;
739
+ /**
740
+ * The colour of the symbol alone, drawn as the label's icon in that colour, since SwiftUI's
741
+ * label takes no colour. The `foregroundStyle` modifier colours the title too.
742
+ */
701
743
  readonly color: import("@angular/core").InputSignal<string | undefined>;
702
744
  readonly modifiers: import("@angular/core").InputSignal<readonly UiModifier[] | undefined>;
745
+ /** The icon's colour, when there is a symbol to draw in it. */
746
+ protected readonly iconColor: Signal<UiModifier | undefined>;
703
747
  static ɵfac: i0.ɵɵFactoryDeclaration<UiLabel, never>;
704
748
  static ɵcmp: i0.ɵɵComponentDeclaration<UiLabel, "ui-label", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "systemImage": { "alias": "systemImage"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "modifiers": { "alias": "modifiers"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
705
749
  }
@@ -730,13 +774,19 @@ export declare class UiForm {
730
774
  static ɵfac: i0.ɵɵFactoryDeclaration<UiForm, never>;
731
775
  static ɵcmp: i0.ɵɵComponentDeclaration<UiForm, "ui-form", never, { "modifiers": { "alias": "modifiers"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
732
776
  }
733
- /** A SwiftUI `Section` of a form or a list, under `title`. */
777
+ /**
778
+ * A SwiftUI `Section` of a form or a list, under `title`, iOS only. A `<ui-slot name="header">`
779
+ * is its header in place of a `title`, and a `<ui-slot name="footer">` is the note under its rows.
780
+ * When both a non-empty `title` and a header slot are set, `@expo/ui`'s `SectionView` draws the
781
+ * `title` and drops the slot; an empty `title` counts as unset. The slot's `name` is written as it is,
782
+ * not bound, as that is what picks it out of the rows.
783
+ */
734
784
  export declare class UiSection {
735
785
  protected readonly nativeView: true;
736
786
  readonly title: import("@angular/core").InputSignal<string | undefined>;
737
787
  readonly modifiers: import("@angular/core").InputSignal<readonly UiModifier[] | undefined>;
738
788
  static ɵfac: i0.ɵɵFactoryDeclaration<UiSection, never>;
739
- static ɵcmp: i0.ɵɵComponentDeclaration<UiSection, "ui-section", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "modifiers": { "alias": "modifiers"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
789
+ static ɵcmp: i0.ɵɵComponentDeclaration<UiSection, "ui-section", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "modifiers": { "alias": "modifiers"; "required": false; "isSignal": true; }; }, {}, never, ["ui-slot[name=header]", "*", "ui-slot[name=footer]"], true, never>;
740
790
  }
741
791
  /**
742
792
  * A SwiftUI `Group`, iOS only: its children as they are, with no layout of its own. What it is for
@@ -882,6 +932,13 @@ export declare class UiBottomSheet {
882
932
  readonly detents: import("@angular/core").InputSignal<readonly UiPresentationDetent[] | undefined>;
883
933
  /** Whether the grabber shows at the top of the sheet. */
884
934
  readonly showDragIndicator: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
935
+ /**
936
+ * The colour of the sheet behind its content: SwiftUI's `presentationBackground` on iOS, where
937
+ * a sheet below its full height is otherwise drawn as glass, and Compose's `containerColor` on
938
+ * Android. Over a `background-color` the element has from CSS, which colours the sheet the same
939
+ * way. Neither is the sheet as the system draws it.
940
+ */
941
+ readonly backgroundColor: import("@angular/core").InputSignal<string | undefined>;
885
942
  /**
886
943
  * The sheet has finished closing, whether the user dismissed it or `open` was set false: the
887
944
  * moment another sheet or a dialog can be presented.
@@ -928,6 +985,16 @@ export declare class UiBottomSheet {
928
985
  * detents of a sheet not sized to its content are followed while it is open.
929
986
  */
930
987
  protected readonly presentation: Signal<readonly UiModifier[]>;
988
+ /** The `background-color` the element has from CSS, which the sheet draws rather than it. */
989
+ private readonly painted;
990
+ /** The sheet's colour: the input's, or else the element's from CSS. */
991
+ protected readonly color: Signal<{} | undefined>;
992
+ /**
993
+ * The sheet's own background, a colour converted as any colour is, where one is given. As a
994
+ * shape style for `@expo/ui` 57.0.17 and later, and as the plain colour the versions before it
995
+ * read, Expo Go's among them. Each ignores the other's field.
996
+ */
997
+ private readonly background;
931
998
  /**
932
999
  * The one view a view host holds. Sized to its content it needs a width of its own, the
933
1000
  * window's; otherwise it fills the height the sheet gives it.
@@ -969,6 +1036,6 @@ export declare class UiBottomSheet {
969
1036
  /** The sheet has gone: its content leaves the tree. */
970
1037
  private finish;
971
1038
  static ɵfac: i0.ɵɵFactoryDeclaration<UiBottomSheet, never>;
972
- static ɵcmp: i0.ɵɵComponentDeclaration<UiBottomSheet, "ui-bottom-sheet", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "fitToContents": { "alias": "fitToContents"; "required": false; "isSignal": true; }; "detents": { "alias": "detents"; "required": false; "isSignal": true; }; "showDragIndicator": { "alias": "showDragIndicator"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "dismissed": "dismissed"; }, ["toolbarItems"], ["*", "ui-toolbar-item"], true, never>;
1039
+ static ɵcmp: i0.ɵɵComponentDeclaration<UiBottomSheet, "ui-bottom-sheet", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "fitToContents": { "alias": "fitToContents"; "required": false; "isSignal": true; }; "detents": { "alias": "detents"; "required": false; "isSignal": true; }; "showDragIndicator": { "alias": "showDragIndicator"; "required": false; "isSignal": true; }; "backgroundColor": { "alias": "backgroundColor"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "dismissed": "dismissed"; }, ["toolbarItems"], ["*", "ui-toolbar-item"], true, never>;
973
1040
  }
974
1041
  export {};