@ng-native/expo 0.0.1 → 0.1.1

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 (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +413 -1
  3. package/dist/app-info.d.ts +58 -0
  4. package/dist/app-info.js +71 -0
  5. package/dist/app-info.js.map +1 -0
  6. package/dist/apple-sign-in-button.d.ts +16 -0
  7. package/dist/apple-sign-in-button.js +55 -0
  8. package/dist/apple-sign-in-button.js.map +1 -0
  9. package/dist/apple-sign-in.d.ts +68 -0
  10. package/dist/apple-sign-in.js +120 -0
  11. package/dist/apple-sign-in.js.map +1 -0
  12. package/dist/assets.d.ts +24 -0
  13. package/dist/assets.js +47 -0
  14. package/dist/assets.js.map +1 -0
  15. package/dist/background-task.d.ts +66 -0
  16. package/dist/background-task.js +82 -0
  17. package/dist/background-task.js.map +1 -0
  18. package/dist/battery.d.ts +46 -0
  19. package/dist/battery.js +76 -0
  20. package/dist/battery.js.map +1 -0
  21. package/dist/biometrics.d.ts +45 -0
  22. package/dist/biometrics.js +53 -0
  23. package/dist/biometrics.js.map +1 -0
  24. package/dist/brightness.d.ts +38 -0
  25. package/dist/brightness.js +81 -0
  26. package/dist/brightness.js.map +1 -0
  27. package/dist/browser.d.ts +42 -0
  28. package/dist/browser.js +42 -0
  29. package/dist/browser.js.map +1 -0
  30. package/dist/camera.d.ts +48 -0
  31. package/dist/camera.js +59 -0
  32. package/dist/camera.js.map +1 -0
  33. package/dist/clipboard.d.ts +43 -0
  34. package/dist/clipboard.js +60 -0
  35. package/dist/clipboard.js.map +1 -0
  36. package/dist/community-views.d.ts +14 -0
  37. package/dist/community-views.js +76 -0
  38. package/dist/community-views.js.map +1 -0
  39. package/dist/crypto.d.ts +56 -0
  40. package/dist/crypto.js +84 -0
  41. package/dist/crypto.js.map +1 -0
  42. package/dist/database.d.ts +47 -0
  43. package/dist/database.js +108 -0
  44. package/dist/database.js.map +1 -0
  45. package/dist/document-picker.d.ts +34 -0
  46. package/dist/document-picker.js +40 -0
  47. package/dist/document-picker.js.map +1 -0
  48. package/dist/dom-component.d.ts +87 -0
  49. package/dist/dom-component.js +139 -0
  50. package/dist/dom-component.js.map +1 -0
  51. package/dist/expo-image.d.ts +33 -0
  52. package/dist/expo-image.js +57 -0
  53. package/dist/expo-image.js.map +1 -0
  54. package/dist/expo-ui-components.d.ts +327 -0
  55. package/dist/expo-ui-components.js +707 -0
  56. package/dist/expo-ui-components.js.map +1 -0
  57. package/dist/expo-ui.d.ts +46 -0
  58. package/dist/expo-ui.js +128 -0
  59. package/dist/expo-ui.js.map +1 -0
  60. package/dist/file-system.d.ts +63 -0
  61. package/dist/file-system.js +67 -0
  62. package/dist/file-system.js.map +1 -0
  63. package/dist/fonts.d.ts +90 -0
  64. package/dist/fonts.js +118 -0
  65. package/dist/fonts.js.map +1 -0
  66. package/dist/glass.d.ts +33 -0
  67. package/dist/glass.js +72 -0
  68. package/dist/glass.js.map +1 -0
  69. package/dist/haptics.d.ts +49 -0
  70. package/dist/haptics.js +64 -0
  71. package/dist/haptics.js.map +1 -0
  72. package/dist/image-editor.d.ts +62 -0
  73. package/dist/image-editor.js +101 -0
  74. package/dist/image-editor.js.map +1 -0
  75. package/dist/image-picker.d.ts +49 -0
  76. package/dist/image-picker.js +58 -0
  77. package/dist/image-picker.js.map +1 -0
  78. package/dist/index.d.ts +20 -0
  79. package/dist/index.js +21 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/keep-awake.d.ts +39 -0
  82. package/dist/keep-awake.js +80 -0
  83. package/dist/keep-awake.js.map +1 -0
  84. package/dist/language-model.d.ts +129 -0
  85. package/dist/language-model.js +225 -0
  86. package/dist/language-model.js.map +1 -0
  87. package/dist/locale.d.ts +51 -0
  88. package/dist/locale.js +78 -0
  89. package/dist/locale.js.map +1 -0
  90. package/dist/location.d.ts +68 -0
  91. package/dist/location.js +83 -0
  92. package/dist/location.js.map +1 -0
  93. package/dist/map-view.d.ts +203 -0
  94. package/dist/map-view.js +184 -0
  95. package/dist/map-view.js.map +1 -0
  96. package/dist/media-library.d.ts +103 -0
  97. package/dist/media-library.js +160 -0
  98. package/dist/media-library.js.map +1 -0
  99. package/dist/native-state.d.ts +22 -0
  100. package/dist/native-state.js +43 -0
  101. package/dist/native-state.js.map +1 -0
  102. package/dist/native.d.ts +42 -0
  103. package/dist/native.js +73 -0
  104. package/dist/native.js.map +1 -0
  105. package/dist/network.d.ts +35 -0
  106. package/dist/network.js +60 -0
  107. package/dist/network.js.map +1 -0
  108. package/dist/notifications.d.ts +175 -0
  109. package/dist/notifications.js +296 -0
  110. package/dist/notifications.js.map +1 -0
  111. package/dist/observed.d.ts +37 -0
  112. package/dist/observed.js +55 -0
  113. package/dist/observed.js.map +1 -0
  114. package/dist/orientation.d.ts +35 -0
  115. package/dist/orientation.js +78 -0
  116. package/dist/orientation.js.map +1 -0
  117. package/dist/permissions.d.ts +54 -0
  118. package/dist/permissions.js +72 -0
  119. package/dist/permissions.js.map +1 -0
  120. package/dist/player.d.ts +92 -0
  121. package/dist/player.js +141 -0
  122. package/dist/player.js.map +1 -0
  123. package/dist/register-expo-view.d.ts +55 -0
  124. package/dist/register-expo-view.js +110 -0
  125. package/dist/register-expo-view.js.map +1 -0
  126. package/dist/screen-capture.d.ts +58 -0
  127. package/dist/screen-capture.js +78 -0
  128. package/dist/screen-capture.js.map +1 -0
  129. package/dist/segmented-control.d.ts +32 -0
  130. package/dist/segmented-control.js +55 -0
  131. package/dist/segmented-control.js.map +1 -0
  132. package/dist/sensors.d.ts +85 -0
  133. package/dist/sensors.js +115 -0
  134. package/dist/sensors.js.map +1 -0
  135. package/dist/splash-screen.d.ts +73 -0
  136. package/dist/splash-screen.js +115 -0
  137. package/dist/splash-screen.js.map +1 -0
  138. package/dist/store-review.d.ts +43 -0
  139. package/dist/store-review.js +52 -0
  140. package/dist/store-review.js.map +1 -0
  141. package/dist/store.d.ts +108 -0
  142. package/dist/store.js +247 -0
  143. package/dist/store.js.map +1 -0
  144. package/dist/symbol.d.ts +36 -0
  145. package/dist/symbol.js +69 -0
  146. package/dist/symbol.js.map +1 -0
  147. package/dist/tracking.d.ts +45 -0
  148. package/dist/tracking.js +54 -0
  149. package/dist/tracking.js.map +1 -0
  150. package/dist/transforms.d.ts +2 -0
  151. package/dist/transforms.js +13 -0
  152. package/dist/transforms.js.map +1 -0
  153. package/dist/updates.d.ts +61 -0
  154. package/dist/updates.js +97 -0
  155. package/dist/updates.js.map +1 -0
  156. package/package.json +397 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ashley Hunter
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,415 @@
1
1
  # @ng-native/expo
2
2
 
3
- A placeholder: this version has no code. See https://ng-native.com.
3
+ Expo's native modules as Angular services, and Expo's native views as elements.
4
+
5
+ Alpha: APIs may change before 1.0.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @ng-native/expo
11
+ npm install @angular/core expo
12
+ ```
13
+
14
+ Every Expo module (`expo-haptics`, `expo-clipboard`, `expo-file-system`, and the rest) is an
15
+ optional peer dependency: install only the ones the app actually uses.
16
+
17
+ ## Services
18
+
19
+ One entry point per module, so importing haptics does not bundle the file system. Every source
20
+ file lives in `src/`, as in every other package here; the entry points an app writes do not say so,
21
+ because the `exports` map takes `@ng-native/expo/haptics` to `src/haptics.ts`. Each is an
22
+ `InjectionToken` carrying its own factory, so there is nothing to provide and nothing to register -
23
+ injecting it is the whole setup, and a service nobody injects is never constructed. Each name is a
24
+ type as well as a token, so `inject(Clipboard)` and `private clipboard: Clipboard` both work.
25
+
26
+ ```ts
27
+ import { Clipboard } from '@ng-native/expo/clipboard';
28
+ import { FileSystem } from '@ng-native/expo/file-system';
29
+ import { Fonts } from '@ng-native/expo/fonts';
30
+ import { Haptics } from '@ng-native/expo/haptics';
31
+ import { SplashScreen } from '@ng-native/expo/splash-screen';
32
+
33
+ export class Notes {
34
+ private readonly clipboard = inject(Clipboard);
35
+ private readonly files = inject(FileSystem);
36
+ private readonly haptics = inject(Haptics);
37
+
38
+ /** A signal: how many times the pasteboard has changed. */
39
+ protected readonly changes = this.clipboard.changes;
40
+
41
+ protected async save(text: string): Promise<void> {
42
+ this.files.write(this.files.document('notes.txt'), text);
43
+ await this.clipboard.write(text);
44
+ this.haptics.notify('success');
45
+ }
46
+ }
47
+ ```
48
+
49
+ The names say what the thing is rather than who ships it, so app code asks for a clipboard rather
50
+ than for a package. Two shapes are worth knowing about:
51
+
52
+ - `Clipboard.changes` counts pasteboard changes; it does not hold the contents. On iOS 16 and
53
+ later, _reading_ the clipboard is what prompts the user for permission, so a signal that held
54
+ the text would prompt on every change - including changes made by other apps. The notification
55
+ is free and the read is explicit.
56
+ - `Fonts` is the odd one out: the method that matters is called _before_ the injector exists.
57
+ See below.
58
+ - `Haptics` returns nothing and swallows failures. Every Expo equivalent is a promise, and nobody
59
+ awaits a vibration; a device with no Taptic Engine would otherwise produce an unhandled
60
+ rejection for a feature that is by definition optional.
61
+
62
+ ## What this package costs to install
63
+
64
+ One package. Every Expo module is an **optional peer dependency**, so `pnpm add
65
+ @ng-native/expo` adds exactly itself - an app installs `expo-haptics` because it wants
66
+ haptics, not because this asked for it. There is one entry point per module and each imports only
67
+ its own, so reaching for haptics does not pull in the video player.
68
+
69
+ The version ranges track the SDK rather than each package, because since SDK 57 Expo does too:
70
+ `expo-battery` and `expo-video` are both `57.x` and ship together. That is also why this is one
71
+ package and not twenty: twenty would have to be version-bumped in lockstep anyway, and would need
72
+ a twenty-first to share `Permission`, `observed` and the rest.
73
+
74
+ Each service is one file: a `@Service()` class that reaches its module through an injected source
75
+ token. Nothing in the package statically imports an Expo module, because a file that does cannot be
76
+ loaded by Node at all - Expo's build output uses extensionless relative imports, and what it pulls
77
+ in reaches `react-native`, which is Flow. A `require` inside the token's factory has neither
78
+ problem: Metro still resolves the string literal and bundles the module exactly as before, and in
79
+ Node the call throws and the service goes inert. On a device, a module the app should have and does
80
+ not - never installed, or installed without the app being rebuilt since - throws a
81
+ `MissingModuleError` naming it and the commands that fix it.
82
+
83
+ That token is also the test seam, and it hangs off the service rather than sitting beside it -
84
+ `Clipboard.SOURCE`, not `CLIPBOARD_SOURCE`. One export per capability, and a token that cannot
85
+ drift away from the thing it belongs to. A fake is _provided_ rather than passed, so a test drives
86
+ the real service:
87
+
88
+ ```ts
89
+ const clipboard = serviceWith(Clipboard.SOURCE, fake, () => new Clipboard());
90
+ ```
91
+
92
+ Four are not services and say so: `Sensor` and `Store` are one class behind several tokens
93
+ (`Accelerometer` and `Barometer` are the same class; so are `Storage` and `SecureStorage`), and
94
+ `Fonts` and `SplashScreen` are called before an injector exists - `splashScreen.hold()` is the
95
+ first thing an entry file does. Those four take their platform as a constructor argument.
96
+
97
+ The app still installs `expo-haptics`, `expo-clipboard` and `expo-file-system` itself. That is
98
+ what links the native side; whether we import their JavaScript is a separate question, and
99
+ `Haptics` does not.
100
+
101
+ ## Fonts
102
+
103
+ A font on a phone is not fetched when the text engine first needs it: it has to be registered
104
+ with the platform before anything is laid out, or the first paint is in the fallback face and
105
+ reflows when the real one lands. So a face is declared in CSS, collected at build time, and
106
+ registered before the app mounts:
107
+
108
+ ```css
109
+ @font-face {
110
+ font-family: Inter;
111
+ src: url('./fonts/Inter-Regular.ttf');
112
+ }
113
+ @font-face {
114
+ font-family: Inter;
115
+ src: url('./fonts/Inter-Bold.ttf');
116
+ font-weight: 700;
117
+ }
118
+ ```
119
+
120
+ ```ts
121
+ import { loadFonts } from '@ng-native/expo/fonts';
122
+
123
+ await loadFonts(styleSheetOf(GlobalStyles));
124
+ mount(rootTag, App, getFabricUIManager(), { globalStyles: styleSheetOf(GlobalStyles) });
125
+ ```
126
+
127
+ `font-family: Inter` then means what it says. The `url()` becomes a `require` at build time, so
128
+ the bundler ships the file - a plain path would be a font that is simply missing on the device
129
+ with nothing anywhere to say why.
130
+
131
+ **There is no font matching on a device.** Native looks a family up by name and that is all, so a
132
+ bold cut is a family of its own: the second face above is registered as `Inter-700` as well, and
133
+ a rule that wants it asks for `font-family: Inter-700`. Writing `font-weight: 700` against a
134
+ family with one registered face gets whatever the platform synthesizes, exactly as it would in a
135
+ React Native app.
136
+
137
+ `loadFonts` takes any number of sheets and does nothing at all when none of them declare a face,
138
+ so bootstrap can call it unconditionally. Injecting `Fonts` afterwards answers what is loaded.
139
+
140
+ ## Device state
141
+
142
+ Every module that reports something changing has the same three parts: a getter, a listener, and
143
+ a `useX()` hook that is those two plus React state. The hook is the only surface some of them
144
+ offer for reading a value _over time_, so it is what is rebuilt here - once, as a signal - and
145
+ each module is a thin binding onto it.
146
+
147
+ ```ts
148
+ private readonly network = inject(Network);
149
+ private readonly battery = inject(Battery);
150
+
151
+ protected readonly offline = computed(() => this.network.reachable() === false);
152
+ protected readonly thrifty = computed(() => this.battery.saving() || this.battery.low());
153
+ ```
154
+
155
+ - `Network.reachable()` is `null` until the platform establishes it, which is **not** the same as
156
+ offline: a captive-portal wifi is connected and reachable by nothing, and an offline banner that
157
+ treats `null` as false flashes on every cold start.
158
+ - `Battery.low()` is under a fifth _and not charging_; plugged in at 15% is not a reason to do
159
+ less. Both signals start at their optimistic value, so an app never opens in its degraded mode.
160
+ - `DeviceOrientation` is the device, not the window. A layout asking which way _it_ is laid out
161
+ wants the `orientation` media feature and needs none of this; a camera preview needs this,
162
+ because a screen pinned to portrait still has a phone that is sideways.
163
+ - `Brightness.set()` and `DeviceOrientation.lock()` both return the function that undoes them,
164
+ ready for `DestroyRef.onDestroy`. An app that leaves the screen at full brightness after showing
165
+ a boarding pass is one the user experiences as a battery fault.
166
+
167
+ ### Sensors and locale
168
+
169
+ The sensors are one class parameterized by the reading, not one per sensor - they are all the same
170
+ object underneath. Nothing subscribes until `start`, and the interval is explicit:
171
+
172
+ ```ts
173
+ inject(DestroyRef).onDestroy(inject(Accelerometer).start(50));
174
+ ```
175
+
176
+ The sensible interval is a property of what the app is doing with it, a compass wants a tenth of a
177
+ second and a shake detector less, and every event is a change-detection pass - so a sensor left at
178
+ its default is a phone that never idles, and a sensor nobody stops is a battery nobody gets back.
179
+
180
+ `Locale` is the odd one: both getters are synchronous, so there is no default to sit at. It is a
181
+ service because the answers _change_ - a user can switch language in Settings and come back, and a
182
+ date that was formatted correctly is then wrong. The list is ordered by preference and always has
183
+ at least one entry, which is the reason to prefer it over a single locale string: an app that
184
+ supports the user's second language should use it rather than fall back to English. `rtl()` is a
185
+ layout decision rather than a translation one, which is why it is a signal.
186
+
187
+ ## Storage
188
+
189
+ Both stores are already plain promises, so what is worth having is not a wrapper but a binding: a
190
+ persisted value as a signal that writes through when set.
191
+
192
+ ```ts
193
+ private readonly store = inject(Storage);
194
+ protected readonly theme = this.store.signal<'light' | 'dark'>('theme', 'light');
195
+ ```
196
+
197
+ Reading it is reading the preference; `theme.set('dark')` persists. The same key always hands back
198
+ the same signal, so two components binding one preference stay in step, and a value written before
199
+ the read comes back is not undone by it.
200
+
201
+ `SecureStorage` is the keychain and the Android keystore - separate from `Storage` because the
202
+ difference should be visible at the injection site. It can also answer synchronously, so a token
203
+ never flashes its default.
204
+
205
+ ## Permissions
206
+
207
+ Every Expo module that needs one spells it the same way - `getXPermissionsAsync`,
208
+ `requestXPermissionsAsync`, and a `useXPermissions()` hook that is those two plus React state. So
209
+ there is one class here rather than one facade per module, and the module stays the app's own
210
+ dependency:
211
+
212
+ ```ts
213
+ import { requestCameraPermissionsAsync, getCameraPermissionsAsync } from 'expo-camera';
214
+ import { Permission } from '@ng-native/expo';
215
+
216
+ readonly camera = Permission.of(getCameraPermissionsAsync, requestCameraPermissionsAsync);
217
+
218
+ protected async open(): Promise<void> {
219
+ if (await this.camera.ensure()) this.scanning.set(true);
220
+ }
221
+ ```
222
+
223
+ `ensure()` is the method most call sites want: it checks first, so a permission the user granted
224
+ months ago shows no dialog, and it does not ask when the platform has stopped asking - which
225
+ would resolve to the same no while reading as though the user had been consulted. `blocked()` is
226
+ how an app knows to offer Settings instead.
227
+
228
+ `status()` distinguishes `unknown` from `undetermined`: nobody has asked the platform yet, versus
229
+ the platform saying the user has not decided.
230
+
231
+ ## Splash screen
232
+
233
+ The ordering is the whole feature, and it is easy to get subtly wrong. The native splash hides
234
+ itself as soon as the first frame is drawn, so an app that loads fonts _before_ mounting shows a
235
+ blank window for as long as that takes:
236
+
237
+ ```ts
238
+ import { splashScreen } from '@ng-native/expo/splash-screen';
239
+ import { loadFonts } from '@ng-native/expo/fonts';
240
+
241
+ splashScreen.hold(); // module scope, before anything renders
242
+
243
+ AppRegistry.registerRunnable('main', ({ rootTag }) => {
244
+ const fonts = loadFonts(styleSheetOf(GlobalStyles));
245
+ mount(Number(rootTag), App, getFabricUIManager(), { globalStyles: styleSheetOf(GlobalStyles) });
246
+ void splashScreen.hideWhenReady(fonts);
247
+ });
248
+ ```
249
+
250
+ Mounting does not wait for the fonts; the splash screen does. Text laid out before they arrive is
251
+ behind the splash, so nothing is ever seen in the fallback face and nothing reflows.
252
+ `hideWhenReady` waits one frame after the work, because hiding the instant it resolves uncovers
253
+ the frame that was on screen while it ran - and it uncovers even when the work fails, rather than
254
+ leaving a splash screen up forever.
255
+
256
+ ## Media
257
+
258
+ `useVideoPlayer` and `useAudioPlayer` are not where the player comes from - `createVideoPlayer`
259
+ gives the same object. What the hooks add is the two things a component needs and cannot get
260
+ otherwise: the player is _released_ when the component goes, and its changing state is _readable_,
261
+ which its own mutable properties are not.
262
+
263
+ ```ts
264
+ protected readonly player = videoPlayer(source, { timeUpdate: 0.5 });
265
+ ```
266
+
267
+ ```html
268
+ <expo-video [player]="player.native" /> <text>{{ player.state().currentTime }}</text>
269
+ ```
270
+
271
+ The player itself is passed straight through: it already has `play()`, `seekBy()` and the rest,
272
+ and wrapping them would be a second place for each to be wrong. `timeUpdate` is off unless asked
273
+ for, because it is the most frequent event either player emits and a screen with no progress bar
274
+ should not pay for one.
275
+
276
+ ## Notifications
277
+
278
+ Only the part React was holding. Scheduling, channels, categories, badges and tokens are already
279
+ plain promises, and an app calls those on the module directly.
280
+
281
+ What is here is the difference between a notification _arriving_ and a user _tapping_ one - the
282
+ second is a navigation instruction - and the response that **launched** the app, which happened
283
+ before any listener existed. Missing that is the single most common way notification routing is
284
+ got wrong.
285
+
286
+ ```ts
287
+ const tapped = inject(Notifications).take();
288
+ if (tapped) this.router.navigateByUrl(routeFor(tapped));
289
+ ```
290
+
291
+ `take()` rather than the signal, because routing on a tap is a one-off and a signal is not: an
292
+ effect on one fires again whenever its component is recreated, sending the user back to a screen
293
+ they had navigated away from. A second tap on the same notification is a new instruction and is
294
+ handed over again.
295
+
296
+ Pair it with `Permission.of(getPermissionsAsync, requestPermissionsAsync)` from the module.
297
+
298
+ ## Photos, files, location and privacy
299
+
300
+ - **`ImagePicker`** (`image-picker.ts`): `pick()` and `capture()`, each resolving to the picked
301
+ assets, empty if they canceled. `capture()` asks for the camera itself.
302
+ - **`Location`** (`location.ts`): a `position` signal, filled by `current(accuracy)` once or by
303
+ `start({ accuracy, distance })` until the function it returns is called.
304
+ - **`Biometrics`** (`biometrics.ts`): `available()`, `kinds()` and `authenticate(message)`, which
305
+ fails rather than passes when the module is missing.
306
+ - **`Browser`** (`browser.ts`): `open(url)`, and `signIn(url, redirectUrl)`, which resolves to the
307
+ URL the sign-in page redirected back to, or null.
308
+ - **`AppInfo`** (`app-info.ts`): the version, build, identifier and device, as plain values.
309
+ - **`Camera`** (`camera.ts`): a directive on `<expo-camera>` whose `takePicture()` takes a picture
310
+ from the view on screen, without a React ref.
311
+ - **`StoreReview`** (`store-review.ts`): `available()`, `hasAction()`, `request()` and
312
+ `storeUrl()`. Whether the prompt appears is the platform's decision, and a call that resolves is
313
+ not a prompt that was shown.
314
+ - **`Tracking`** (`tracking.ts`): App Tracking Transparency's `permission`, `available()` and
315
+ `advertisingId()`, which is null until tracking is allowed.
316
+ - **`DocumentPicker`** (`document-picker.ts`): `pick(options)`, resolving to the files picked,
317
+ empty if they canceled.
318
+ - **`Crypto`** (`crypto.ts`): `randomUUID()`, `digestString()`, `digest()`, `randomBytes()` and
319
+ `randomValues()`. The one service that throws without its module, since an empty identifier or
320
+ hash is a wrong answer that looks right.
321
+ - **`BackgroundTask`** (`background-task.ts`): `status()`, `register(name, options)`,
322
+ `unregister(name)` and `triggerForTesting()`. The task itself is defined with
323
+ `expo-task-manager` at the top level of `main.ts`, since the platform runs it without
324
+ bootstrapping Angular.
325
+ - **`ScreenCapture`** (`screen-capture.ts`): `prevent(key)` and `allow(key)`, which stay
326
+ prevented while any key is held, and a `screenshots` signal counting the screenshots taken.
327
+ - **`ImageEditor`** (`image-editor.ts`): `edit(uri, actions, options)` over
328
+ `expo-image-manipulator`, resolving to the saved file and releasing the native context and
329
+ image it made, and `manipulate(uri)` for the module's own context.
330
+ - **`MediaLibrary`** (`media-library.ts`): `save(uri, album)`, which asks for write-only access
331
+ itself, `assets(query)` and `metadata(query)` over the module's own `Query`, albums, the read
332
+ and write permissions, and `watch()` for changes, which starts listening only when called.
333
+
334
+ ## The rest
335
+
336
+ Four more modules whose only entry point was a hook, each the same story: the work underneath is a
337
+ plain promise, and what the hook adds is a _lifecycle_.
338
+
339
+ - **`database(name, migrations)`** replaces `SQLiteProvider` and `useSQLiteContext`. Opened on
340
+ first use rather than at startup - a database opened eagerly is a file handle and a journal for
341
+ an app that may never read from it - and opened _once_ however many callers arrive while it is
342
+ opening, because two connections to one file is a lock waiting to happen. Migrations run in
343
+ order, each in a transaction, with the version recorded in SQLite's own `user_version`.
344
+ - **`Updates`** checks and downloads in one call, because an app that checks without downloading
345
+ has learned something it cannot act on. `apply()` **restarts the app**, which is why nothing here
346
+ does it automatically: the moment is one the app knows and this does not. In Expo Go it reports
347
+ itself disabled rather than offering a banner that can never resolve.
348
+ - **`Assets`** preloads the images a screen should not pop in with, and resolves even when one
349
+ fails - a picture that will not appear is not a reason for the screen behind it to fail too.
350
+ - **`KeepAwake.hold()`** returns the release, and is never a bare activate: a screen that holds the
351
+ display on and never lets go is a phone that never sleeps, which the user experiences as a
352
+ battery fault and never attributes to the app that caused it.
353
+
354
+ ## Views
355
+
356
+ Most Expo modules need nothing from this package. `requireNativeModule`, `EventEmitter`,
357
+ `SharedObject` and `SharedRef` have no React in them, so a module that only calls into native is
358
+ imported and used as its own documentation says - the services above are a nicer surface, not a
359
+ shim. Autolinking is unaffected too: it is driven by the `expo` package and the
360
+ `expo-module.config.json` in each module, neither of which knows what renderer is above it.
361
+
362
+ What does need something is a module that renders. `requireNativeViewManager` returns a React
363
+ class, and the Fabric component underneath it is registered under a name derived from the module
364
+ name and, in Expo Go, from a per-project identifier. `registerExpoView` derives the same name and
365
+ hands it to the engine:
366
+
367
+ ```ts
368
+ import {
369
+ registerExpoView,
370
+ registerExpoViews,
371
+ registerExpoUiViews,
372
+ registerNativeViews,
373
+ } from '@ng-native/expo';
374
+
375
+ registerExpoViews('expo-image', 'expo-blur'); // Expo's own
376
+ registerNativeViews('web-view', 'slider'); // the community libraries in Expo's bundled list
377
+ registerExpoUiViews(Platform.OS); // every @expo/ui control the platform has
378
+ registerExpoView('my-module-view', 'MyModule'); // anything else
379
+ ```
380
+
381
+ ### @expo/ui
382
+
383
+ The closest thing in the ecosystem to what this project is for: every one of these is a real
384
+ platform control - a real `Picker`, a real `BottomSheet`, a real `Gauge` - rather than something
385
+ drawn to look like one. `@expo/ui` reaches them through `requireNativeView('ExpoUI', ...)`, which
386
+ is the derivation `registerExpoView` already mirrors, so the whole surface is a table of names.
387
+
388
+ Element names are platform-neutral where both platforms have the control, so an app writes
389
+ `<ui-slider>` once and `<ui-vstack>` gets Compose's `Column` on Android. Where only one platform
390
+ has it - a `Gauge` is SwiftUI's, a `SearchBar` is Compose's - the element exists only there, since
391
+ registering for the wrong platform is an element that commits as nothing.
392
+
393
+ **A `<ui-host>` is required around any of them.** SwiftUI and Compose lay out their own subtrees,
394
+ and the host view is what bridges Yoga's layout to theirs; without one the control has no size and
395
+ does not appear - which looks exactly like a module that failed to install.
396
+
397
+ `<expo-image>` is then an element like any other, and its props are the ones the module's native
398
+ view declares - which is to say the ones the React component would have passed down, after
399
+ whatever resolving it does in JavaScript:
400
+
401
+ ```html
402
+ <expo-image [source]="[{ uri }]" contentFit="cover" [transition]="{ duration: 400 }" />
403
+ ```
404
+
405
+ Most of that is deliberately not wrapped. An Angular component per Expo view, prop for prop, is
406
+ a maintenance burden with no end; a name plus the module's own documentation covers the common
407
+ case, and an app that wants a nicer surface can write the component it actually needs.
408
+
409
+ The exception is strict templates, where an unknown element and every prop on it is a type error.
410
+ The views apps reach for most (`ui-host`, `ui-menu`, `ui-button`, `ui-divider`, `ui-slot`,
411
+ `ui-image`, `ui-text`, `ui-date-picker`) and `segmented-control` have thin typed components:
412
+ import `UiHost`, `SegmentedControl` and the rest, and the element is typed while committing exactly
413
+ as before. Keep registering the names too. The component supplies the types and the registration
414
+ makes the element commit as the native view. Their events are outputs so `$event` is typed. The
415
+ element's own event is what arrives, so bind them in a template.
@@ -0,0 +1,58 @@
1
+ /**
2
+ * `AppInfo`, bound to `expo-application` and `expo-device`: the app's version and build, and the
3
+ * device it is running on.
4
+ *
5
+ * ```ts
6
+ * protected readonly info = inject(AppInfo);
7
+ * // {{ info.version }} ({{ info.build }}) on {{ info.device.model }}
8
+ * ```
9
+ *
10
+ * Constants, read once, rather than signals: none of them changes while the app runs. Anything the
11
+ * platform does not say is null, and so is everything from a module that is not installed.
12
+ */
13
+ import { InjectionToken } from '@angular/core';
14
+ import * as i0 from "@angular/core";
15
+ export type DeviceKind = 'phone' | 'tablet' | 'desktop' | 'tv' | 'unknown';
16
+ /** The constants this reads, from each module. */
17
+ export interface NativeAppInfo {
18
+ readonly application: {
19
+ readonly nativeApplicationVersion: string | null;
20
+ readonly nativeBuildVersion: string | null;
21
+ readonly applicationId: string | null;
22
+ readonly applicationName: string | null;
23
+ } | null;
24
+ readonly device: {
25
+ readonly modelName: string | null;
26
+ readonly brand: string | null;
27
+ readonly osName: string | null;
28
+ readonly osVersion: string | null;
29
+ readonly isDevice: boolean;
30
+ readonly deviceType: number | null;
31
+ } | null;
32
+ }
33
+ export declare class AppInfo {
34
+ /** Overridden in a test to be any app on any phone. */
35
+ static readonly SOURCE: InjectionToken<NativeAppInfo>;
36
+ private readonly native;
37
+ /** The version people see: `CFBundleShortVersionString`, or Android's `versionName`. */
38
+ readonly version: string | null;
39
+ /** The build number: `CFBundleVersion`, or Android's `versionCode`. */
40
+ readonly build: string | null;
41
+ /** The bundle identifier on iOS, the package name on Android. */
42
+ readonly id: string | null;
43
+ /** The name under the icon. */
44
+ readonly name: string | null;
45
+ readonly device: {
46
+ /** `iPhone 17 Pro`, `Pixel 9`. */
47
+ readonly model: string | null;
48
+ readonly brand: string | null;
49
+ /** `iOS`, `iPadOS`, `Android`. */
50
+ readonly os: string | null;
51
+ readonly osVersion: string | null;
52
+ /** False in a simulator or emulator. */
53
+ readonly physical: boolean | null;
54
+ readonly type: DeviceKind | null;
55
+ };
56
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppInfo, never>;
57
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
58
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * `AppInfo`, bound to `expo-application` and `expo-device`: the app's version and build, and the
3
+ * device it is running on.
4
+ *
5
+ * ```ts
6
+ * protected readonly info = inject(AppInfo);
7
+ * // {{ info.version }} ({{ info.build }}) on {{ info.device.model }}
8
+ * ```
9
+ *
10
+ * Constants, read once, rather than signals: none of them changes while the app runs. Anything the
11
+ * platform does not say is null, and so is everything from a module that is not installed.
12
+ */
13
+ import { InjectionToken, Service, inject } from '@angular/core';
14
+ import { expoModule } from "./native.js";
15
+ import * as i0 from "@angular/core";
16
+ /** Expo's `DeviceType` enum, whose values are these numbers. */
17
+ const KINDS = {
18
+ 0: 'unknown',
19
+ 1: 'phone',
20
+ 2: 'tablet',
21
+ 3: 'desktop',
22
+ 4: 'tv',
23
+ };
24
+ export class AppInfo {
25
+ /** Overridden in a test to be any app on any phone. */
26
+ static SOURCE = new InjectionToken('angular-native.appInfoSource', {
27
+ factory: () => ({
28
+ application: expoModule('expo-application', () => require('expo-application')),
29
+ device: expoModule('expo-device', () => require('expo-device')),
30
+ }),
31
+ });
32
+ native = inject(AppInfo.SOURCE);
33
+ /** The version people see: `CFBundleShortVersionString`, or Android's `versionName`. */
34
+ version = this.native.application?.nativeApplicationVersion ?? null;
35
+ /** The build number: `CFBundleVersion`, or Android's `versionCode`. */
36
+ build = this.native.application?.nativeBuildVersion ?? null;
37
+ /** The bundle identifier on iOS, the package name on Android. */
38
+ id = this.native.application?.applicationId ?? null;
39
+ /** The name under the icon. */
40
+ name = this.native.application?.applicationName ?? null;
41
+ device = deviceOf(this.native.device);
42
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: AppInfo, deps: [], target: i0.ɵɵFactoryTarget.Service });
43
+ static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.2.0", ngImport: i0, type: AppInfo });
44
+ }
45
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: AppInfo, decorators: [{
46
+ type: Service
47
+ }] });
48
+ /** What a device reads as without `expo-device`: nothing known. */
49
+ const UNKNOWN_DEVICE = {
50
+ modelName: null,
51
+ brand: null,
52
+ osName: null,
53
+ osVersion: null,
54
+ isDevice: null,
55
+ deviceType: null,
56
+ };
57
+ function deviceOf(native) {
58
+ const device = native ?? UNKNOWN_DEVICE;
59
+ return {
60
+ /** `iPhone 17 Pro`, `Pixel 9`. */
61
+ model: device.modelName,
62
+ brand: device.brand,
63
+ /** `iOS`, `iPadOS`, `Android`. */
64
+ os: device.osName,
65
+ osVersion: device.osVersion,
66
+ /** False in a simulator or emulator. */
67
+ physical: device.isDevice,
68
+ type: device.deviceType === null ? null : (KINDS[device.deviceType] ?? 'unknown'),
69
+ };
70
+ }
71
+ //# sourceMappingURL=app-info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-info.js","sourceRoot":"","sources":["../src/app-info.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;;AAIzC,gEAAgE;AAChE,MAAM,KAAK,GAA+B;IACxC,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,OAAO;IACV,CAAC,EAAE,QAAQ;IACX,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,IAAI;CACR,CAAC;AAqBF,MAAM,OAAO,OAAO;IAClB,uDAAuD;IACvD,MAAM,CAAU,MAAM,GAAG,IAAI,cAAc,CAAgB,8BAA8B,EAAE;QACzF,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;YACd,WAAW,EAAE,UAAU,CACrB,kBAAkB,EAClB,GAAG,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAA8C,CAC/E;YACD,MAAM,EAAE,UAAU,CAChB,aAAa,EACb,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,CAAyC,CACrE;SACF,CAAC;KACH,CAAC,CAAC;IAEc,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEjD,wFAAwF;IAC/E,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,wBAAwB,IAAI,IAAI,CAAC;IAC7E,uEAAuE;IAC9D,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,kBAAkB,IAAI,IAAI,CAAC;IACrE,iEAAiE;IACxD,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,IAAI,IAAI,CAAC;IAC7D,+BAA+B;IACtB,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,eAAe,IAAI,IAAI,CAAC;IAExD,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;uGA1BpC,OAAO;wGAAP,OAAO;;2FAAP,OAAO;kBADnB,OAAO;;AA8BR,mEAAmE;AACnE,MAAM,cAAc,GAAG;IACrB,SAAS,EAAE,IAAI;IACf,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,SAAS,EAAE,IAAI;IACf,QAAQ,EAAE,IAAI;IACd,UAAU,EAAE,IAAI;CACjB,CAAC;AAEF,SAAS,QAAQ,CAAC,MAA+B;IAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,cAAc,CAAC;IACxC,OAAO;QACL,kCAAkC;QAClC,KAAK,EAAE,MAAM,CAAC,SAAS;QACvB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,kCAAkC;QAClC,EAAE,EAAE,MAAM,CAAC,MAAM;QACjB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,wCAAwC;QACxC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,MAAM,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC;KACzE,CAAC;AACb,CAAC","sourcesContent":["/**\n * `AppInfo`, bound to `expo-application` and `expo-device`: the app's version and build, and the\n * device it is running on.\n *\n * ```ts\n * protected readonly info = inject(AppInfo);\n * // {{ info.version }} ({{ info.build }}) on {{ info.device.model }}\n * ```\n *\n * Constants, read once, rather than signals: none of them changes while the app runs. Anything the\n * platform does not say is null, and so is everything from a module that is not installed.\n */\nimport { InjectionToken, Service, inject } from '@angular/core';\nimport { expoModule } from './native.ts';\n\nexport type DeviceKind = 'phone' | 'tablet' | 'desktop' | 'tv' | 'unknown';\n\n/** Expo's `DeviceType` enum, whose values are these numbers. */\nconst KINDS: Record<number, DeviceKind> = {\n 0: 'unknown',\n 1: 'phone',\n 2: 'tablet',\n 3: 'desktop',\n 4: 'tv',\n};\n\n/** The constants this reads, from each module. */\nexport interface NativeAppInfo {\n readonly application: {\n readonly nativeApplicationVersion: string | null;\n readonly nativeBuildVersion: string | null;\n readonly applicationId: string | null;\n readonly applicationName: string | null;\n } | null;\n readonly device: {\n readonly modelName: string | null;\n readonly brand: string | null;\n readonly osName: string | null;\n readonly osVersion: string | null;\n readonly isDevice: boolean;\n readonly deviceType: number | null;\n } | null;\n}\n\n@Service()\nexport class AppInfo {\n /** Overridden in a test to be any app on any phone. */\n static readonly SOURCE = new InjectionToken<NativeAppInfo>('angular-native.appInfoSource', {\n factory: () => ({\n application: expoModule(\n 'expo-application',\n () => require('expo-application') as NonNullable<NativeAppInfo['application']>,\n ),\n device: expoModule(\n 'expo-device',\n () => require('expo-device') as NonNullable<NativeAppInfo['device']>,\n ),\n }),\n });\n\n private readonly native = inject(AppInfo.SOURCE);\n\n /** The version people see: `CFBundleShortVersionString`, or Android's `versionName`. */\n readonly version = this.native.application?.nativeApplicationVersion ?? null;\n /** The build number: `CFBundleVersion`, or Android's `versionCode`. */\n readonly build = this.native.application?.nativeBuildVersion ?? null;\n /** The bundle identifier on iOS, the package name on Android. */\n readonly id = this.native.application?.applicationId ?? null;\n /** The name under the icon. */\n readonly name = this.native.application?.applicationName ?? null;\n\n readonly device = deviceOf(this.native.device);\n}\n\n/** What a device reads as without `expo-device`: nothing known. */\nconst UNKNOWN_DEVICE = {\n modelName: null,\n brand: null,\n osName: null,\n osVersion: null,\n isDevice: null,\n deviceType: null,\n};\n\nfunction deviceOf(native: NativeAppInfo['device']) {\n const device = native ?? UNKNOWN_DEVICE;\n return {\n /** `iPhone 17 Pro`, `Pixel 9`. */\n model: device.modelName,\n brand: device.brand,\n /** `iOS`, `iPadOS`, `Android`. */\n os: device.osName,\n osVersion: device.osVersion,\n /** False in a simulator or emulator. */\n physical: device.isDevice,\n type: device.deviceType === null ? null : (KINDS[device.deviceType] ?? 'unknown'),\n } as const;\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import * as i0 from "@angular/core";
2
+ export type AppleButtonType = 'sign-in' | 'continue' | 'sign-up';
3
+ export type AppleButtonStyle = 'white' | 'white-outline' | 'black';
4
+ export declare class AppleSignInButton {
5
+ /** The button's wording: "Sign in with Apple", "Continue with Apple", "Sign up with Apple". */
6
+ readonly buttonType: import("@angular/core").InputSignal<AppleButtonType>;
7
+ /** Black on a light background, white or white with an outline on a dark one. */
8
+ readonly buttonStyle: import("@angular/core").InputSignal<AppleButtonStyle>;
9
+ readonly cornerRadius: import("@angular/core").InputSignalWithTransform<number | undefined, unknown>;
10
+ /** The button was tapped: start `AppleSignIn.signIn()` here. */
11
+ readonly buttonPress: import("@angular/core").OutputEmitterRef<void>;
12
+ protected readonly nativeType: import("@angular/core").Signal<number>;
13
+ protected readonly nativeStyle: import("@angular/core").Signal<number>;
14
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppleSignInButton, never>;
15
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppleSignInButton, "apple-sign-in-button", never, { "buttonType": { "alias": "buttonType"; "required": false; "isSignal": true; }; "buttonStyle": { "alias": "buttonStyle"; "required": false; "isSignal": true; }; "cornerRadius": { "alias": "cornerRadius"; "required": false; "isSignal": true; }; }, { "buttonPress": "buttonPress"; }, never, never, true, never>;
16
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * `<apple-sign-in-button>`: Apple's own Sign in with Apple button, `ASAuthorizationAppleIDButton`,
3
+ * from `expo-apple-authentication`. Apple's guidelines allow a custom button only if it follows
4
+ * their branding rules; this one is approved, localised and accessible as it is.
5
+ *
6
+ * Registered with `registerExpoViews('apple-sign-in-button')`, like the other Expo views. It needs
7
+ * a width and a height to show, and its colour and corners come from `buttonStyle` and
8
+ * `cornerRadius`, not from CSS. Show it only where `AppleSignIn.available()` is true: iOS only.
9
+ *
10
+ * ```html
11
+ * <apple-sign-in-button
12
+ * class="h-12 w-full"
13
+ * buttonType="continue"
14
+ * buttonStyle="black"
15
+ * cornerRadius="12"
16
+ * (buttonPress)="signIn()"
17
+ * />
18
+ * ```
19
+ */
20
+ import { Component, computed, input, output } from '@angular/core';
21
+ import { optionalNumber } from "./transforms.js";
22
+ import * as i0 from "@angular/core";
23
+ /** Native takes both as the module's enum values. */
24
+ const TYPES = { 'sign-in': 0, continue: 1, 'sign-up': 2 };
25
+ const STYLES = { white: 0, 'white-outline': 1, black: 2 };
26
+ export class AppleSignInButton {
27
+ /** The button's wording: "Sign in with Apple", "Continue with Apple", "Sign up with Apple". */
28
+ buttonType = input('sign-in', /* @ts-ignore */
29
+ ...(ngDevMode ? [{ debugName: "buttonType" }] : /* istanbul ignore next */ []));
30
+ /** Black on a light background, white or white with an outline on a dark one. */
31
+ buttonStyle = input('black', /* @ts-ignore */
32
+ ...(ngDevMode ? [{ debugName: "buttonStyle" }] : /* istanbul ignore next */ []));
33
+ cornerRadius = input(undefined, { ...(ngDevMode ? { debugName: "cornerRadius" } : /* istanbul ignore next */ {}), transform: optionalNumber });
34
+ /** The button was tapped: start `AppleSignIn.signIn()` here. */
35
+ buttonPress = output();
36
+ nativeType = computed(() => TYPES[this.buttonType()], /* @ts-ignore */
37
+ ...(ngDevMode ? [{ debugName: "nativeType" }] : /* istanbul ignore next */ []));
38
+ nativeStyle = computed(() => STYLES[this.buttonStyle()], /* @ts-ignore */
39
+ ...(ngDevMode ? [{ debugName: "nativeStyle" }] : /* istanbul ignore next */ []));
40
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: AppleSignInButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
41
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.2.0", type: AppleSignInButton, isStandalone: true, selector: "apple-sign-in-button", inputs: { buttonType: { classPropertyName: "buttonType", publicName: "buttonType", isSignal: true, isRequired: false, transformFunction: null }, buttonStyle: { classPropertyName: "buttonStyle", publicName: "buttonStyle", isSignal: true, isRequired: false, transformFunction: null }, cornerRadius: { classPropertyName: "cornerRadius", publicName: "cornerRadius", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { buttonPress: "buttonPress" }, host: { properties: { "buttonType": "nativeType()", "buttonStyle": "nativeStyle()", "cornerRadius": "cornerRadius()" } }, ngImport: i0, template: '', isInline: true });
42
+ }
43
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: AppleSignInButton, decorators: [{
44
+ type: Component,
45
+ args: [{
46
+ selector: 'apple-sign-in-button',
47
+ template: '',
48
+ host: {
49
+ '[buttonType]': 'nativeType()',
50
+ '[buttonStyle]': 'nativeStyle()',
51
+ '[cornerRadius]': 'cornerRadius()',
52
+ },
53
+ }]
54
+ }], propDecorators: { buttonType: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonType", required: false }] }], buttonStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonStyle", required: false }] }], cornerRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "cornerRadius", required: false }] }], buttonPress: [{ type: i0.Output, args: ["buttonPress"] }] } });
55
+ //# sourceMappingURL=apple-sign-in-button.js.map