@stacksjs/mobile 0.75.96 → 0.75.98

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Bundled TypeScript declarations
3
- * Generated from 8 source files
3
+ * Generated from 16 source files
4
4
  */
5
5
 
6
6
  import { NativeTab } from 'craft-native/mobile';
@@ -11,17 +11,6 @@ declare function host(): CraftHost | undefined;
11
11
  /** Reads the current host, including a bridge injected after this module loaded. */
12
12
  declare function getNativeMobileBridge(): CraftMobileBridge | null;
13
13
  declare function isNativeMobile(): boolean;
14
- /**
15
- * Whether this page runs inside Craft's phone shell, before the bridge exists.
16
- *
17
- * Craft installs `window.craft` once the page has finished loading — images
18
- * and all — so `isNativeMobile()` answers `false` during setup on a phone, and
19
- * a layout that decides then renders the website's chrome in the app. The
20
- * transports are there from the start: Android's `CraftAndroid` interface, and
21
- * on iOS the `craft` message handler. Craft's macOS windows carry that handler
22
- * too, so on iOS an iPhone or iPad user agent is what makes it the phone app.
23
- */
24
- declare function hasNativeMobileHost(): boolean;
25
14
  /**
26
15
  * Resolves `true` inside the phone shell and `false` in a browser, at a moment
27
16
  * when the answer is right.
@@ -32,21 +21,14 @@ declare function hasNativeMobileHost(): boolean;
32
21
  * decide something to render anything.
33
22
  */
34
23
  declare function whenNativeMobile(timeoutMs?: number): Promise<boolean>;
35
- /**
36
- * Resolves once the bridge object (`window.craft`) is installed: `true` then,
37
- * `false` in a browser at once, or after `timeoutMs` in a host that never
38
- * installs it.
39
- *
40
- * Not whenNativeMobile(), which answers `true` as soon as the phone shell is
41
- * recognisable, before the bridge exists and before anything can be asked of it.
42
- */
43
- declare function whenBridgeReady(timeoutMs?: unknown): Promise<boolean>;
44
24
  declare function onMobileReady(callback: (event: CraftReadyEvent) => void): () => void;
45
25
  declare function withNativeFeedback<T>(action: () => T | Promise<T>): Promise<T>;
26
+ // Each service's async methods wait for a native host's bridge (afterBridge):
27
+ // asked during an older shell's launch, they reached the web fallback, and a
28
+ // secure-storage read answered from localStorage.
46
29
  declare const biometrics: BiometricsApi;
47
30
  declare const camera: CameraApi;
48
31
  declare const device: DeviceApi;
49
- declare const haptics: HapticsApi;
50
32
  declare const lifecycle: LifecycleApi;
51
33
  declare const location: LocationApi;
52
34
  declare const notifications: NotificationsApi;
@@ -54,6 +36,16 @@ declare const permissions: PermissionsApi;
54
36
  declare const secureStorage: SecureStorageApi;
55
37
  declare const share: ShareApi;
56
38
  declare const appReview: AppReviewApi;
39
+ /**
40
+ * Haptic feedback: UIImpactFeedbackGenerator, UINotificationFeedbackGenerator
41
+ * and UISelectionFeedbackGenerator on iOS, a short vibration elsewhere.
42
+ *
43
+ * Never held for a bridge still loading, and never rejects: a tap played late
44
+ * is a wrong tap, and feedback failing must not stop the flow it decorates.
45
+ * `prepare()` wakes the Taptic Engine ahead of a likely tap (a finger landing
46
+ * on a pressable), so the tap that follows plays without latency.
47
+ */
48
+ declare const haptics: HapticsApi;
57
49
  /**
58
50
  * Deep links, asked of the bridge once there is one.
59
51
  *
@@ -72,6 +64,11 @@ declare const keepAwake: KeepAwakeApi;
72
64
  * to the Web Speech API.
73
65
  */
74
66
  declare const speech: SpeechApi;
67
+ /**
68
+ * Connectivity. A change subscription made before the bridge arrived listened
69
+ * to the browser's online/offline events only, and never heard the native
70
+ * monitor; it is made once the bridge is there.
71
+ */
75
72
  declare const network: NetworkApi;
76
73
  declare const pushNotifications: PushNotificationsApi;
77
74
  declare const health: HealthApi;
@@ -84,8 +81,170 @@ declare const watchConnectivity: WatchConnectivityApi;
84
81
  */
85
82
  declare const splash: { hide: () => boolean };
86
83
  declare const mobile: MobileApi;
84
+
85
+ // From: src/bridge.ts
86
+ /** The page's window, when there is one. */
87
+ declare function craftHost(): CraftHost | undefined;
88
+ /** `window.craft`, the bridge object, once installed. */
89
+ declare function craftRoot(): Record<string, any> | undefined;
90
+ /**
91
+ * Whether this page runs inside Craft's phone shell, before the bridge exists.
92
+ *
93
+ * Craft installs `window.craft` once the page has finished loading on an older
94
+ * shell — images and all — so a bridge check answers `false` during setup on
95
+ * a phone, and a layout that decides then renders the website's chrome in the
96
+ * app. The transports are there from the start: Android's `CraftAndroid`
97
+ * interface, and on iOS the `craft` message handler. Craft's macOS windows
98
+ * carry that handler too, so on iOS an iPhone or iPad user agent is what makes
99
+ * it the phone app.
100
+ */
101
+ declare function hasNativeMobileHost(): boolean;
102
+ /** A native host whose bridge object is not installed yet: worth waiting for. */
103
+ declare function bridgePending(): boolean;
104
+ /**
105
+ * Resolves once the bridge object (`window.craft`) is installed: `true` then,
106
+ * `false` in a browser at once, or after `timeoutMs` in a host that never
107
+ * installs it.
108
+ *
109
+ * Not whenNativeMobile(), which answers `true` as soon as the phone shell is
110
+ * recognisable, before the bridge exists and before anything can be asked of it.
111
+ */
112
+ declare function whenBridgeReady(timeoutMs?: unknown): Promise<boolean>;
113
+ /**
114
+ * The bridge function at `path` (`'dialog.confirm'`), or null when this host
115
+ * has none. Synchronous: no waiting for a bridge still on its way.
116
+ */
117
+ declare function nativeFunctionNow(path: string): ((...args: any[]) => unknown) | null;
118
+ /**
119
+ * The bridge function at `path`, waiting for a native host's bridge to arrive
120
+ * first. Null in a browser, on a shell that predates the API, or when the
121
+ * bridge did not come within `timeoutMs`.
122
+ */
123
+ declare function nativeFunction(path: string, timeoutMs?: unknown): Promise<((...args: any[]) => unknown) | null>;
124
+ /**
125
+ * Calls the bridge function at `path`, or `fallback` where there is none.
126
+ *
127
+ * Inside a native host whose bridge is still loading, the call is held until
128
+ * it arrives, so an early call reaches the native implementation rather than
129
+ * the web one.
130
+ */
131
+ declare function callNative<T>(path: string, args: unknown[], fallback: () => T | Promise<T>, options?: CallNativeOptions): Promise<T>;
132
+ /**
133
+ * Runs `run` once a native host's bridge is installed: at once when it is
134
+ * there or in a browser, after it arrives (or `BRIDGE_WAIT_MS` passes) in a
135
+ * host still loading it.
136
+ *
137
+ * craft-native's services read `window.craft` at call time and take their web
138
+ * path when it is missing, which during an older shell's launch it is. The
139
+ * services this package exports call through here, as plain object literals
140
+ * rather than wrapped at import: a bundler drops an object literal nobody
141
+ * imports, and could not drop a call made at module scope once minified.
142
+ */
143
+ declare function afterBridge<T>(run: () => T | Promise<T>, timeoutMs?: unknown): Promise<T>;
144
+ /**
145
+ * Subscribes once the bridge can take the subscription: at once when it is
146
+ * there or in a browser, otherwise when it arrives. The returned function
147
+ * unsubscribes either way, including before the subscription was made.
148
+ */
149
+ declare function subscribeWhenReady(subscribe: () => (() => void) | void, timeoutMs?: unknown): () => void;
150
+ /** Listens for a Craft DOM event on the window; the detail is passed through. */
151
+ declare function onCraftEvent<T = Record<string, unknown>>(name: string, callback: (detail: T) => void): () => void;
152
+ /**
153
+ * Reaching Craft's bridge at the right moment.
154
+ *
155
+ * Craft's iOS shell injects `window.craft` at document start, but an older
156
+ * shell installs it once the page has finished loading. A call made before
157
+ * then used to find no bridge and quietly take the web path: a secure-storage
158
+ * read answered from localStorage, a confirm drew the browser's own dialog.
159
+ * Inside a native host, a call now waits for the bridge (briefly: a host that
160
+ * never installs one gets the web fallback after `BRIDGE_WAIT_MS`), and only a
161
+ * browser takes the fallback at once.
162
+ */
163
+ /** How long a call waits for a native host's bridge before using the web fallback. */
164
+ declare const BRIDGE_WAIT_MS: 2500;
87
165
  declare interface CraftHost extends EventTarget {
88
166
  craft?: unknown
167
+ CraftAndroid?: unknown
168
+ webkit?: { messageHandlers?: Record<string, unknown> }
169
+ document?: Document
170
+ navigator?: Navigator
171
+ }
172
+ declare interface CallNativeOptions {
173
+ fallbackOnError?: boolean
174
+ timeoutMs?: number
175
+ }
176
+
177
+ // From: src/controls.ts
178
+ /**
179
+ * Calls `onLongPress` when a finger (or mouse) stays on `element` for
180
+ * `delay`. The click that follows a long press is swallowed, so a long press
181
+ * on a link opens its menu without also following it, and the browser's own
182
+ * callout menu is kept out of the way.
183
+ */
184
+ declare function observeLongPress(element: HTMLElement, options: LongPressOptions): () => void;
185
+ /** Which of `count` equal segments across `rect` the x coordinate is over, clamped to the ends. */
186
+ declare function segmentAt(x: number, rect: { left: number, width: number }, count: number): number;
187
+ /**
188
+ * Scrubbing a segmented control: a finger that lands on the chosen segment and
189
+ * slides drags the thumb across, and lifting chooses where it stopped. A tap
190
+ * elsewhere stays the button's own click.
191
+ */
192
+ declare function observeSegmentScrub(track: HTMLElement, options: SegmentScrubOptions): () => void;
193
+ /** The segment an arrow, Home or End key moves to from `index`, or null for any other key. */
194
+ declare function segmentForKey(key: string, index: number, count: number): number | null;
195
+ /** Moves focus to the `index`th tab of a segmented control, as arrow keys do in a tab list. */
196
+ declare function focusSegment(track: HTMLElement, index: number): void;
197
+ /**
198
+ * Wakes the Taptic Engine as a finger lands on anything marked
199
+ * `data-native-pressable`, so the tap that follows its press plays at once.
200
+ *
201
+ * Listening for touchstart at all is also what makes iOS apply `:active`, the
202
+ * pressed state the shell's stylesheet draws.
203
+ */
204
+ declare function installPressables(root: EventTarget): () => void;
205
+ declare interface LongPressOptions {
206
+ delay?: number
207
+ tolerance?: number
208
+ onPressStart?: () => void
209
+ onPressEnd?: () => void
210
+ onLongPress: (event: { x: number, y: number }) => void
211
+ }
212
+ declare interface SegmentScrubOptions {
213
+ count: () => number
214
+ selected: () => number
215
+ onPress?: (pressed: boolean) => void
216
+ onScrub: (index: number) => void
217
+ onCommit: (index: number) => void
218
+ }
219
+
220
+ // From: src/events.ts
221
+ /**
222
+ * The appearance as it stands. The shell writes `--craft-font-scale` and
223
+ * `data-craft-reduce-*` on the root element before the page runs, so this is
224
+ * right at setup too; elsewhere it reads the media queries.
225
+ */
226
+ declare function currentAppearance(): NativeAppearance;
227
+ /** A `craftAppearance` detail, made whole. */
228
+ declare function normalizeAppearance(detail: Partial<NativeAppearance> | null | undefined): NativeAppearance;
229
+ /**
230
+ * Calls `callback` with the appearance now and whenever the phone's settings
231
+ * change (Dynamic Type, Reduce Motion, Reduce Transparency, Light/Dark).
232
+ */
233
+ declare function onAppearance(callback: (appearance: NativeAppearance) => void, options?: { immediate?: boolean }): () => void;
234
+ /** The app came back to the front after `backgroundedMs` away. */
235
+ declare function onResume(callback: (detail: { backgroundedMs: number }) => void): () => void;
236
+ /** iOS is short of memory: drop caches that can be rebuilt. */
237
+ declare function onMemoryWarning(callback: () => void): () => void;
238
+ /** A content-available push arrived. The handler's settling completes it. */
239
+ declare function onSilentPush(handler: (payload: Record<string, unknown>) => unknown): () => void;
240
+ /** iOS woke the app to refresh (BGAppRefreshTask). The handler's settling completes it. */
241
+ declare function onBackgroundRefresh(handler: () => unknown): () => void;
242
+ declare interface NativeAppearance {
243
+ contentSizeCategory?: string
244
+ fontScale: number
245
+ reduceMotion: boolean
246
+ reduceTransparency: boolean
247
+ colorScheme: 'light' | 'dark'
89
248
  }
90
249
 
91
250
  // From: src/gestures.ts
@@ -116,17 +275,53 @@ declare function pullDistance(scrollTop: number, fingerTravel: number): number;
116
275
  * it disarms. Letting go while armed runs `onRefresh`.
117
276
  */
118
277
  declare function observePullToRefresh(options: PullToRefreshOptions): () => void;
119
- /** Where a page scrolls: the window, or a stand-in with the same shape. */
278
+ /**
279
+ * Where a large-title navigation bar is for a scroll offset.
280
+ *
281
+ * The title collapses over its own height. Pulled past the top (iOS's rubber
282
+ * band, a negative offset) it grows a little, at most 10%, anchored at its
283
+ * leading edge.
284
+ */
285
+ declare function largeTitleMetrics(offset: number, height?: number): LargeTitleMetrics;
286
+ /**
287
+ * Links a navigation bar to the page's scroll, a frame at a time.
288
+ *
289
+ * Writes `--native-nav-progress` (0 to 1) and `--native-nav-stretch` on
290
+ * `element`, so its CSS can fade the material in, move the small title into
291
+ * the bar and stretch the large one, all on the compositor. Nothing re-renders.
292
+ */
293
+ declare function observeLargeTitle(element: HTMLElement, options?: LargeTitleOptions): () => void;
294
+ /**
295
+ * The element a selector names, as a scroll host: for a screen whose content
296
+ * scrolls inside a container rather than the page. Undefined (the window)
297
+ * when nothing matches.
298
+ */
299
+ declare function resolveScrollHost(selector: string | null | undefined): ScrollHost | undefined;
300
+ /**
301
+ * Where a page scrolls: the window, a scrolling element (a screen that scrolls
302
+ * inside its own container), or a stand-in with the same shape.
303
+ */
120
304
  declare interface ScrollHost extends EventTarget {
121
305
  scrollY?: number
306
+ scrollTop?: number
122
307
  document?: { scrollingElement?: { scrollTop: number } | null }
123
308
  }
124
309
  declare interface PullToRefreshOptions {
125
310
  threshold?: number
126
- onPull?: (distance: number, armed: boolean) => void
311
+ onPull?: (distance: number, armed: boolean, pull: { bounce: number }) => void
127
312
  onRefresh: () => unknown | Promise<unknown>
128
313
  host?: ScrollHost
129
314
  }
315
+ declare interface LargeTitleMetrics {
316
+ progress: number
317
+ stretch: number
318
+ }
319
+ declare interface LargeTitleOptions {
320
+ height?: number
321
+ title?: HTMLElement | null
322
+ host?: ScrollHost
323
+ onChange?: (metrics: LargeTitleMetrics) => void
324
+ }
130
325
 
131
326
  // From: src/navigation.ts
132
327
  /** Whether going back stays inside this app. */
@@ -281,6 +476,402 @@ declare interface IndoorFix {
281
476
  }
282
477
  type IndoorVerdict = 'indoors' | 'outside' | 'unsure';
283
478
 
479
+ // From: src/native.ts
480
+ declare function hostNavigator(): Navigator | undefined;
481
+ /** A rectangle the bridge can serialise: getBoundingClientRect() returns a DOMRect, which it cannot. */
482
+ declare function toNativeRect(rect: { x?: number, y?: number, left?: number, top?: number, width: number, height: number }): NativeRect;
483
+ /** Shows an action sheet: `useActionSheet()(options)`, for a page that keeps the function. */
484
+ declare function useActionSheet(): (options: ActionSheetOptions) => Promise<string | null>;
485
+ /**
486
+ * Asks before doing something. `await confirmAction({ title: 'Delete this
487
+ * workout?', confirmLabel: 'Delete', destructive: true })` raises the iOS
488
+ * destructive-action sheet and resolves `true` when the action was chosen.
489
+ */
490
+ declare function confirmAction(options: ConfirmActionOptions): Promise<boolean>;
491
+ /**
492
+ * Shows a context menu beside `element`, the one that was long-pressed.
493
+ * Resolves with the chosen item's id, or null.
494
+ */
495
+ declare function showContextMenuFor(element: Element, options: Omit<ContextMenuOptions, 'anchor'>): Promise<string | null>;
496
+ declare function openOnTheWeb(url: string, options: BrowserOpenOptions): BrowserResult;
497
+ declare function symbolKey(name: string, options: SymbolOptions): string;
498
+ declare function downloadOnTheWeb(href: string, filename: string): string | null;
499
+ declare function pickOnTheWeb(types: string[]): Promise<PickedFile | null>;
500
+ declare function screenOrientation(): LockableOrientation | undefined;
501
+ declare const done: () => true;
502
+ declare const no: () => false;
503
+ declare const nothing: () => null;
504
+ declare const dialog: DialogApi;
505
+ declare const contextMenu: ContextMenuApi;
506
+ declare const browser: BrowserApi;
507
+ declare const symbolRequests: Map<string, Promise<string | null>>;
508
+ declare const symbolImages: Map<string, string | null>;
509
+ declare const symbols: SymbolsApi;
510
+ declare const statusBar: StatusBarApi;
511
+ declare const chrome: ChromeApi;
512
+ declare const refresh: RefreshApi;
513
+ declare const background: BackgroundApi;
514
+ declare const clipboard: ClipboardApi;
515
+ declare const db: DatabaseApi;
516
+ declare const files: FilesApi;
517
+ declare const shortcuts: ShortcutsApi;
518
+ declare const widgets: WidgetsApi;
519
+ /**
520
+ * @defaultValue
521
+ * ```ts
522
+ * {
523
+ * portrait: 'portrait-primary',
524
+ * portraitUpsideDown: 'portrait-secondary',
525
+ * landscape: 'landscape',
526
+ * landscapeLeft: 'landscape-primary',
527
+ * landscapeRight: 'landscape-secondary'
528
+ * }
529
+ * ```
530
+ */
531
+ declare const WEB_ORIENTATIONS: Record<OrientationLock, string>;
532
+ declare const orientation: OrientationApi;
533
+ declare const auth: AuthApi;
534
+ declare const storeKit: StoreKitApi;
535
+ // ---------------------------------------------------------------------------
536
+ // Dialogs
537
+ declare interface DialogApi {
538
+ alert: (options: AlertOptions) => Promise<void>
539
+ confirm: (options: ConfirmOptions) => Promise<boolean>
540
+ actionSheet: (options: ActionSheetOptions) => Promise<string | null>
541
+ }
542
+ declare interface ConfirmActionOptions extends ConfirmOptions {
543
+ style?: 'sheet' | 'alert'
544
+ anchor?: NativeRect
545
+ }
546
+ // ---------------------------------------------------------------------------
547
+ // Context menus
548
+ declare interface ContextMenuApi {
549
+ show: (options: ContextMenuOptions) => Promise<string | null>
550
+ }
551
+ // ---------------------------------------------------------------------------
552
+ // In-app browser
553
+ declare interface BrowserOpenOptions {
554
+ mode?: 'safari' | 'auth'
555
+ callbackScheme?: string
556
+ }
557
+ declare interface BrowserResult {
558
+ url?: string
559
+ cancelled: boolean
560
+ }
561
+ declare interface BrowserApi {
562
+ open: (url: string, options?: BrowserOpenOptions) => Promise<BrowserResult>
563
+ }
564
+ // ---------------------------------------------------------------------------
565
+ // SF Symbols
566
+ declare interface SymbolOptions {
567
+ pointSize?: number
568
+ weight?: 'ultralight' | 'thin' | 'light' | 'regular' | 'medium' | 'semibold' | 'bold' | 'heavy' | 'black'
569
+ color?: string
570
+ scale?: 'small' | 'medium' | 'large'
571
+ }
572
+ declare interface SymbolsApi {
573
+ isAvailable: () => boolean
574
+ image: (name: string, options?: SymbolOptions) => Promise<string | null>
575
+ cached: (name: string, options?: SymbolOptions) => string | null | undefined
576
+ clearCache: () => void
577
+ }
578
+ declare interface StatusBarApi {
579
+ setStyle: (style: StatusBarStyle) => Promise<boolean>
580
+ }
581
+ declare interface ChromeApi {
582
+ setUnderPageColor: (color: string) => Promise<boolean>
583
+ setKeyboardAccessory: (visible: boolean) => Promise<boolean>
584
+ }
585
+ // ---------------------------------------------------------------------------
586
+ // Native pull-to-refresh
587
+ declare interface RefreshApi {
588
+ isAvailable: () => boolean
589
+ enable: (options?: { tintColor?: string }) => Promise<boolean>
590
+ disable: () => Promise<boolean>
591
+ end: () => Promise<boolean>
592
+ onRefresh: (callback: () => void) => () => void
593
+ }
594
+ declare interface BackgroundApi {
595
+ complete: (ok: boolean) => Promise<boolean>
596
+ }
597
+ // ---------------------------------------------------------------------------
598
+ // Clipboard
599
+ declare interface ClipboardApi {
600
+ write: (text: string) => Promise<boolean>
601
+ read: () => Promise<string | null>
602
+ }
603
+ // ---------------------------------------------------------------------------
604
+ // The app's own SQLite database (Documents/craft.db)
605
+ declare interface DatabaseExecuteResult {
606
+ rowsAffected: number
607
+ lastInsertId: number
608
+ }
609
+ declare interface DatabaseApi {
610
+ isAvailable: () => boolean
611
+ query: <T = Record<string, unknown>>(sql: string, params?: unknown[]) => Promise<T[] | null>
612
+ execute: (sql: string, params?: unknown[]) => Promise<DatabaseExecuteResult | null>
613
+ }
614
+ // ---------------------------------------------------------------------------
615
+ // Files, documents and the camera's scanner
616
+ declare interface PickedFile {
617
+ name: string
618
+ path?: string
619
+ data?: string
620
+ mimeType?: string
621
+ }
622
+ declare interface ScannedCode {
623
+ type: string
624
+ data: string
625
+ }
626
+ declare interface FilesApi {
627
+ openPDF: (source: string, page?: number) => Promise<boolean>
628
+ takeScreenshot: () => Promise<string | null>
629
+ scanQRCode: () => Promise<ScannedCode | null>
630
+ pickFile: (types?: string[]) => Promise<PickedFile | null>
631
+ saveFile: (data: string, filename: string, mimeType?: string) => Promise<string | null>
632
+ downloadFile: (url: string, filename: string) => Promise<string | null>
633
+ }
634
+ // ---------------------------------------------------------------------------
635
+ // Home screen quick actions
636
+ declare interface HomeScreenShortcut {
637
+ type: string
638
+ title: string
639
+ subtitle?: string
640
+ symbol?: string
641
+ userInfo?: Record<string, string>
642
+ }
643
+ declare interface ShortcutsApi {
644
+ set: (shortcuts: HomeScreenShortcut[]) => Promise<boolean>
645
+ clear: () => Promise<boolean>
646
+ onShortcut: (callback: (type: string) => void) => () => void
647
+ }
648
+ // ---------------------------------------------------------------------------
649
+ // Home screen widgets (WidgetKit)
650
+ declare interface WidgetsApi {
651
+ update: (data: Record<string, unknown>) => Promise<boolean>
652
+ reload: () => Promise<boolean>
653
+ }
654
+ declare interface OrientationApi {
655
+ lock: (orientation: OrientationLock) => Promise<boolean>
656
+ unlock: () => Promise<boolean>
657
+ }
658
+ declare interface LockableOrientation { lock?: (orientation: string) => Promise<void>, unlock?: () => void }
659
+ // ---------------------------------------------------------------------------
660
+ // Sign in with Apple
661
+ declare interface AppleSignInResult {
662
+ userId: string
663
+ email?: string
664
+ name?: string
665
+ identityToken?: string
666
+ authorizationCode?: string
667
+ }
668
+ declare interface AuthApi {
669
+ signInWithApple: () => Promise<AppleSignInResult | null>
670
+ }
671
+ // ---------------------------------------------------------------------------
672
+ // In-app purchase (StoreKit 2)
673
+ declare interface StoreProduct {
674
+ id: string
675
+ displayName: string
676
+ description: string
677
+ price: string
678
+ displayPrice: string
679
+ }
680
+ declare interface StoreTransaction {
681
+ transactionId: string
682
+ productId: string
683
+ }
684
+ declare interface StoreKitApi {
685
+ isAvailable: () => boolean
686
+ products: (ids: string[]) => Promise<StoreProduct[]>
687
+ purchase: (id: string) => Promise<StoreTransaction | null>
688
+ restore: () => Promise<StoreTransaction[]>
689
+ }
690
+ // ---------------------------------------------------------------------------
691
+ // System chrome
692
+ type StatusBarStyle = 'default' | 'light' | 'dark';
693
+ // ---------------------------------------------------------------------------
694
+ // Orientation
695
+ type OrientationLock = 'portrait' | 'portraitUpsideDown' | 'landscape' | 'landscapeLeft' | 'landscapeRight';
696
+
697
+ // From: src/refresh-control.ts
698
+ /** Whether an element is laid out in view: connected, and not inside something hidden. */
699
+ declare function isShown(element: HTMLElement): boolean;
700
+ /**
701
+ * Refreshes the screen `element` belongs to with the native control, for as
702
+ * long as the returned function is not called. Check `refresh.isAvailable()`
703
+ * first: a shell without the control needs the web gesture instead.
704
+ */
705
+ declare function observeNativeRefresh(element: HTMLElement, options: NativeRefreshOptions): () => void;
706
+ declare interface NativeRefreshOptions {
707
+ tintColor?: string
708
+ onRefresh: () => unknown
709
+ }
710
+
711
+ // From: src/sheet-gesture.ts
712
+ /**
713
+ * Where each detent leaves a panel `height` tall on a `viewport` tall screen:
714
+ * large shows all of it, medium the bottom half of the screen, and dismissed
715
+ * none.
716
+ */
717
+ declare function sheetStops(height: number, viewport: number, detents: readonly SheetDetent[]): SheetStop[];
718
+ /**
719
+ * Where a released sheet goes.
720
+ *
721
+ * A flick (faster than 0.5px/ms) goes on to the next stop in its direction,
722
+ * past the lowest detent meaning dismissed. A slow release dismisses once the
723
+ * sheet is more than half way down from its lowest detent, and otherwise
724
+ * springs back to the nearest detent.
725
+ */
726
+ declare function settleSheet(state: { y: number, velocity: number, stops: SheetStop[] }): SheetSettle;
727
+ /** iOS's resistance past the top: the further it is pulled, the less it gives. */
728
+ declare function rubberBand(overshoot: number, dimension?: number): number;
729
+ /**
730
+ * Lets a sheet be dragged by its handles. While dragging, the panel follows
731
+ * the finger with `is-dragging` set (the stylesheet turns its transition off)
732
+ * and its parent's `--native-sheet-presence` (1 open, 0 gone) dims the
733
+ * backdrop to match; on release both are handed back to the stylesheet, which
734
+ * animates to wherever `onSettle` puts it.
735
+ */
736
+ declare function observeSheetDrag(options: SheetDragOptions): () => void;
737
+ /**
738
+ * Holds the page still and out of reach behind `keep`: everything outside it
739
+ * becomes inert (no taps, no focus, hidden from VoiceOver) and the document
740
+ * stops scrolling. Returns the release. Nested sheets count, so the page
741
+ * scrolls again only once the last has closed.
742
+ */
743
+ declare function lockBackground(keep: HTMLElement): () => void;
744
+ /**
745
+ * Moves `element` to the end of the body, out of every stacking context and
746
+ * transform on the way, and returns the way back: to where it was, or out of
747
+ * the document when that place has gone (the page navigated away).
748
+ */
749
+ declare function liftToBody(element: HTMLElement): () => void;
750
+ /**
751
+ * The iOS card presentation: while a large sheet is up, the page behind it
752
+ * shrinks back from the screen's edges, centred on what was in view. Undone by
753
+ * calling it with `false`.
754
+ */
755
+ declare function presentPageAsCard(doc: Document, on: boolean): void;
756
+ /** A flick faster than this (CSS pixels a millisecond) moves on to the next stop. */
757
+ declare const SHEET_FLICK_VELOCITY: 0.5;
758
+ /** A resting place, as the panel's downward offset from its fully open position. */
759
+ declare interface SheetStop {
760
+ name: SheetSettle
761
+ y: number
762
+ }
763
+ declare interface SheetDragOptions {
764
+ panel: HTMLElement
765
+ handles: HTMLElement[]
766
+ detents: () => SheetDetent[]
767
+ detent: () => SheetDetent
768
+ viewport?: () => number
769
+ onSettle: (to: SheetSettle) => void
770
+ }
771
+ /**
772
+ * What makes a bottom sheet behave like a UISheetPresentationController:
773
+ * dragged by its grabber or header, flicked away, resting at a medium or a
774
+ * large detent, and holding the page behind it still and out of reach.
775
+ */
776
+ type SheetDetent = 'medium' | 'large';
777
+ type SheetSettle = SheetDetent | 'dismiss';
778
+
779
+ // From: src/sheets.ts
780
+ /**
781
+ * Keeps Tab and Shift+Tab inside `container`: called from a keydown listener,
782
+ * it moves focus from one end to the other instead of out of it.
783
+ */
784
+ declare function trapFocus(container: HTMLElement, event: KeyboardEvent): void;
785
+ /**
786
+ * An alert or action sheet drawn in HTML. Resolves with the chosen action's
787
+ * id, or null when it is dismissed or Cancel is chosen.
788
+ */
789
+ declare function presentChoice(options: ChoiceOptions): Promise<string | null>;
790
+ declare function presentAlert(options: AlertOptions): Promise<void>;
791
+ declare function presentConfirm(options: ConfirmOptions): Promise<boolean>;
792
+ declare function presentActionSheet(options: ActionSheetOptions): Promise<string | null>;
793
+ /** Where a menu of `size` opens beside `anchor` within a `viewport`, 12px clear of its edges. */
794
+ declare function placeMenu(anchor: NativeRect, size: { width: number, height: number }, viewport: { width: number, height: number }): { top: number, left: number, origin: string };
795
+ /**
796
+ * A context menu drawn in HTML over a blurred page, beside the element that
797
+ * was pressed. Resolves with the chosen item's id, or null when dismissed.
798
+ */
799
+ declare function presentContextMenu(options: ContextMenuOptions): Promise<string | null>;
800
+ declare interface DialogAction {
801
+ id: string
802
+ title: string
803
+ style?: DialogActionStyle
804
+ }
805
+ /** A rectangle in CSS pixels relative to the viewport, as getBoundingClientRect() reports. */
806
+ declare interface NativeRect {
807
+ x: number
808
+ y: number
809
+ width: number
810
+ height: number
811
+ }
812
+ declare interface ChoiceOptions {
813
+ variant: 'alert' | 'sheet'
814
+ title?: string
815
+ message?: string
816
+ actions: DialogAction[]
817
+ cancelLabel?: string
818
+ }
819
+ declare interface ContextMenuItem {
820
+ id: string
821
+ title: string
822
+ symbol?: string
823
+ icon?: string
824
+ destructive?: boolean
825
+ disabled?: boolean
826
+ }
827
+ declare interface ContextMenuOptions {
828
+ items: ContextMenuItem[]
829
+ anchor: NativeRect
830
+ title?: string
831
+ }
832
+ declare interface AlertOptions {
833
+ title: string
834
+ message?: string
835
+ okLabel?: string
836
+ }
837
+ declare interface ConfirmOptions {
838
+ title: string
839
+ message?: string
840
+ confirmLabel?: string
841
+ cancelLabel?: string
842
+ destructive?: boolean
843
+ }
844
+ declare interface ActionSheetOptions {
845
+ title?: string
846
+ message?: string
847
+ actions: DialogAction[]
848
+ anchor?: NativeRect
849
+ cancelLabel?: string
850
+ }
851
+ type DialogActionStyle = 'default' | 'destructive' | 'cancel';
852
+
853
+ // From: src/shell.ts
854
+ /** Writes an appearance where CSS can read it: `--native-font-scale` and `data-native-reduce-*`. */
855
+ declare function applyAppearance(root: HTMLElement, appearance: NativeAppearance): void;
856
+ /**
857
+ * The colour behind the page: the first opaque background of the body or the
858
+ * root element. The under-page area should read as more of the page when it
859
+ * is pulled past its top or bottom, not as a white or black band.
860
+ */
861
+ declare function pageBackground(doc: Document): string | null;
862
+ /** Whether the page draws dark: the `.dark` class, or the system's preference where the app follows it. */
863
+ declare function pageIsDark(doc: Document): boolean;
864
+ /**
865
+ * Keeps the native chrome in step with the page until the returned function
866
+ * is called: on install, whenever the colour scheme flips (the `.dark` class
867
+ * or the system's), after each navigation, and on every appearance change.
868
+ */
869
+ declare function installNativeChrome(doc: Document, options?: NativeChromeOptions): () => void;
870
+ declare interface NativeChromeOptions {
871
+ root?: HTMLElement
872
+ keyboardAccessory?: boolean
873
+ }
874
+
284
875
  // From: src/spotlight.ts
285
876
  /**
286
877
  * Read configured kinds, leaving out any that could not work.
@@ -484,6 +1075,18 @@ declare interface SpotlightIndex {
484
1075
  declare function readTabLinks(nav: ParentNode): TabLink[];
485
1076
  /** The native bar's description of those links: the tabs, and which is current. */
486
1077
  declare function nativeTabs(links: TabLink[]): { tabs: NativeTab[], selected?: string };
1078
+ /** Whether the stx router runs the tabs itself (`data-stx-nav="tab"`, re-select included). */
1079
+ declare function routerHandlesTabs(): boolean;
1080
+ /**
1081
+ * Choosing the tab already current scrolls its screen back to the top, as on
1082
+ * iOS, and announces `stx:tabreselect` { href } for a screen that wants to do
1083
+ * more (a list that resets its filter).
1084
+ *
1085
+ * The stx router does this itself for `data-stx-nav="tab"` links, popping to
1086
+ * the tab's root on a second choice; this covers a router that predates tabs,
1087
+ * and stands aside wherever the router has them.
1088
+ */
1089
+ declare function handleTabReselect(nav: HTMLElement, options?: TabReselectOptions): () => void;
487
1090
  /**
488
1091
  * Mirror `nav`'s tabs into the native tab bar, for as long as the returned
489
1092
  * function is not called. Answers null when there is no native bar, and the
@@ -506,6 +1109,9 @@ declare interface TabLink {
506
1109
  badge: string
507
1110
  current: boolean
508
1111
  }
1112
+ declare interface TabReselectOptions {
1113
+ scrollToTop?: () => void
1114
+ }
509
1115
  declare interface MirrorTabBarOptions {
510
1116
  hidden?: () => boolean
511
1117
  api?: TabBarApi
@@ -587,6 +1193,22 @@ declare interface MobileApi {
587
1193
  health: HealthApi
588
1194
  liveActivities: LiveActivitiesApi
589
1195
  watchConnectivity: WatchConnectivityApi
1196
+ dialog: import('./native').DialogApi
1197
+ contextMenu: import('./native').ContextMenuApi
1198
+ browser: import('./native').BrowserApi
1199
+ symbols: import('./native').SymbolsApi
1200
+ statusBar: import('./native').StatusBarApi
1201
+ chrome: import('./native').ChromeApi
1202
+ refresh: import('./native').RefreshApi
1203
+ background: import('./native').BackgroundApi
1204
+ clipboard: import('./native').ClipboardApi
1205
+ db: import('./native').DatabaseApi
1206
+ files: import('./native').FilesApi
1207
+ shortcuts: import('./native').ShortcutsApi
1208
+ widgets: import('./native').WidgetsApi
1209
+ orientation: import('./native').OrientationApi
1210
+ auth: import('./native').AuthApi
1211
+ storeKit: import('./native').StoreKitApi
590
1212
  isNativeMobile: () => boolean
591
1213
  whenNative: (timeoutMs?: number) => Promise<boolean>
592
1214
  onReady: (callback: (event: CraftReadyEvent) => void) => () => void
@@ -683,6 +1305,7 @@ declare interface HapticsApi {
683
1305
  notification: (type?: HapticNotificationType) => Promise<void>
684
1306
  selection: () => Promise<void>
685
1307
  vibrate: (pattern: number[]) => Promise<void>
1308
+ prepare: (kind?: HapticKind) => Promise<void>
686
1309
  }
687
1310
  declare interface PermissionsApi {
688
1311
  check: (permission: PermissionType) => Promise<PermissionStatus>
@@ -872,6 +1495,7 @@ type PermissionStatus = 'granted' | 'denied' | 'undetermined' | 'restricted';
872
1495
  */
873
1496
  type BiometricType = 'faceId' | 'touchId' | 'fingerprint' | 'face' | 'iris' | 'none';
874
1497
  type AppState = 'active' | 'inactive' | 'background';
1498
+ type HapticKind = 'impact' | 'notification' | 'selection';
875
1499
  type HealthDataType = | 'steps'
876
1500
  | 'heartRate'
877
1501
  | 'activeEnergy'
@@ -889,6 +1513,6 @@ type HealthWorkoutActivity = | 'running' | 'cycling' | 'walking' | 'hiking' | 's
889
1513
  | 'stairClimbing' | 'yoga' | 'pilates' | 'strength' | 'hiit' | 'crossTraining'
890
1514
  | 'crossCountrySkiing' | 'skiing' | 'paddling' | 'climbing' | 'dance' | 'mobility' | 'other';
891
1515
 
892
- export { normalizeDeepLinkURL, getNativeMobileBridge, isNativeMobile, hasNativeMobileHost, whenNativeMobile, whenBridgeReady, onMobileReady, withNativeFeedback, biometrics, camera, device, haptics, lifecycle, location, notifications, permissions, secureStorage, share, appReview, deepLinks, keepAwake, speech, network, pushNotifications, health, liveActivities, watchConnectivity, splash, mobile, pageScrollTop, observePageScroll, pullDistance, observePullToRefresh, ScrollHost, PullToRefreshOptions, canGoBack, goBack, enterNavTrail, backLabelFor, navTrail, deepLinkPath, followDeepLinks, HistoryHost, NavTrailEntry, fixDistance, usableFixes, routeStats, paceLabel, speedLabel, createRouteRecorder, ROUTE_GAP_S, RouteFix, RouteStats, RouteStatsOptions, RouteRecorderOptions, RouteRecorder, indoorVerdict, typedDistanceKm, INDOOR_CHECK_AFTER_S, IndoorFix, IndoorVerdict, readSpotlightKinds, spotlightKind, spotlightAction, spotlightSlot, spotlightActions, spotlightActivityTypes, spotlightTitle, placeSpotlightItem, removeSpotlightItem, spotlightRoute, readSpotlightEntries, spotlightBridge, createSpotlightIndex, onSpotlightTap, MAX_SPOTLIGHT_SLOTS_PER_KIND, SpotlightKind, SpotlightKindInput, SpotlightItem, SpotlightEntry, SpotlightKindsResult, SpotlightPlacement, SpotlightBridge, SpotlightIndexOptions, SpotlightIndex, readTabLinks, nativeTabs, mirrorTabBar, tabBar, TabBarApi, TabLink, MirrorTabBarOptions, CraftMobileCapabilities, CraftMobileBridge, CraftReadyEvent, MobileApi, DeviceInfo, DeviceCapabilities, CameraOptions, PhotoResult, Location, LocationOptions, LocationRecordingState, LocationRecordingResult, ShareOptions, NotificationOptions, DeviceApi, HapticsApi, PermissionsApi, CameraApi, BiometricsApi, SecureStorageApi, LocationApi, ShareApi, LifecycleApi, NotificationsApi, KeepAwakeApi, SpeechOptions, SpeechApi, DeepLinksApi, NetworkStatus, NetworkApi, AppReviewApi, PushNotificationsApi, HealthDataOptions, HealthDataResult, HealthWorkoutLocation, HealthWorkout, HealthWorkoutResult, HealthWorkoutQuery, HealthWorkoutSample, HealthDailyValue, HealthAuthorizationOptions, HealthApi, LiveActivityState, LiveActivityOptions, LiveActivitiesApi, WatchConnectivityApi, HapticStyle, HapticNotificationType, PermissionType, PermissionStatus, BiometricType, AppState, HealthDataType, HealthDailyType, HealthWorkoutType, HealthWorkoutActivity };
1516
+ export { normalizeDeepLinkURL, getNativeMobileBridge, isNativeMobile, whenNativeMobile, onMobileReady, withNativeFeedback, biometrics, camera, device, lifecycle, location, notifications, permissions, secureStorage, share, appReview, haptics, deepLinks, keepAwake, speech, network, pushNotifications, health, liveActivities, watchConnectivity, splash, mobile, craftHost, craftRoot, hasNativeMobileHost, bridgePending, whenBridgeReady, nativeFunctionNow, nativeFunction, callNative, afterBridge, subscribeWhenReady, onCraftEvent, BRIDGE_WAIT_MS, CraftHost, CallNativeOptions, observeLongPress, segmentAt, observeSegmentScrub, segmentForKey, focusSegment, installPressables, LongPressOptions, SegmentScrubOptions, currentAppearance, normalizeAppearance, onAppearance, onResume, onMemoryWarning, onSilentPush, onBackgroundRefresh, NativeAppearance, pageScrollTop, observePageScroll, pullDistance, observePullToRefresh, largeTitleMetrics, observeLargeTitle, resolveScrollHost, ScrollHost, PullToRefreshOptions, LargeTitleMetrics, LargeTitleOptions, canGoBack, goBack, enterNavTrail, backLabelFor, navTrail, deepLinkPath, followDeepLinks, HistoryHost, NavTrailEntry, fixDistance, usableFixes, routeStats, paceLabel, speedLabel, createRouteRecorder, ROUTE_GAP_S, RouteFix, RouteStats, RouteStatsOptions, RouteRecorderOptions, RouteRecorder, indoorVerdict, typedDistanceKm, INDOOR_CHECK_AFTER_S, IndoorFix, IndoorVerdict, toNativeRect, useActionSheet, confirmAction, showContextMenuFor, dialog, contextMenu, browser, symbols, statusBar, chrome, refresh, background, clipboard, db, files, shortcuts, widgets, orientation, auth, storeKit, DialogApi, ConfirmActionOptions, ContextMenuApi, BrowserOpenOptions, BrowserResult, BrowserApi, SymbolOptions, SymbolsApi, StatusBarApi, ChromeApi, RefreshApi, BackgroundApi, ClipboardApi, DatabaseExecuteResult, DatabaseApi, PickedFile, ScannedCode, FilesApi, HomeScreenShortcut, ShortcutsApi, WidgetsApi, OrientationApi, AppleSignInResult, AuthApi, StoreProduct, StoreTransaction, StoreKitApi, StatusBarStyle, OrientationLock, ActionSheetOptions, AlertOptions, ChoiceOptions, ConfirmOptions, ContextMenuItem, ContextMenuOptions, DialogAction, DialogActionStyle, NativeRect, isShown, observeNativeRefresh, NativeRefreshOptions, sheetStops, settleSheet, rubberBand, observeSheetDrag, lockBackground, liftToBody, presentPageAsCard, SHEET_FLICK_VELOCITY, SheetStop, SheetDragOptions, SheetDetent, SheetSettle, trapFocus, presentChoice, presentAlert, presentConfirm, presentActionSheet, placeMenu, presentContextMenu, applyAppearance, pageBackground, pageIsDark, installNativeChrome, NativeChromeOptions, readSpotlightKinds, spotlightKind, spotlightAction, spotlightSlot, spotlightActions, spotlightActivityTypes, spotlightTitle, placeSpotlightItem, removeSpotlightItem, spotlightRoute, readSpotlightEntries, spotlightBridge, createSpotlightIndex, onSpotlightTap, MAX_SPOTLIGHT_SLOTS_PER_KIND, SpotlightKind, SpotlightKindInput, SpotlightItem, SpotlightEntry, SpotlightKindsResult, SpotlightPlacement, SpotlightBridge, SpotlightIndexOptions, SpotlightIndex, readTabLinks, nativeTabs, routerHandlesTabs, handleTabReselect, mirrorTabBar, tabBar, TabBarApi, TabLink, TabReselectOptions, MirrorTabBarOptions, CraftMobileCapabilities, CraftMobileBridge, CraftReadyEvent, MobileApi, DeviceInfo, DeviceCapabilities, CameraOptions, PhotoResult, Location, LocationOptions, LocationRecordingState, LocationRecordingResult, ShareOptions, NotificationOptions, DeviceApi, HapticsApi, PermissionsApi, CameraApi, BiometricsApi, SecureStorageApi, LocationApi, ShareApi, LifecycleApi, NotificationsApi, KeepAwakeApi, SpeechOptions, SpeechApi, DeepLinksApi, NetworkStatus, NetworkApi, AppReviewApi, PushNotificationsApi, HealthDataOptions, HealthDataResult, HealthWorkoutLocation, HealthWorkout, HealthWorkoutResult, HealthWorkoutQuery, HealthWorkoutSample, HealthDailyValue, HealthAuthorizationOptions, HealthApi, LiveActivityState, LiveActivityOptions, LiveActivitiesApi, WatchConnectivityApi, HapticStyle, HapticNotificationType, PermissionType, PermissionStatus, BiometricType, AppState, HapticKind, HealthDataType, HealthDailyType, HealthWorkoutType, HealthWorkoutActivity };
893
1517
  export { NativeTab } from 'craft-native/mobile';
894
1518
  export { NativeTabBarOptions } from 'craft-native/mobile';