@stacksjs/mobile 0.75.97 → 0.75.99

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. */
@@ -154,6 +349,17 @@ declare function enterNavTrail(trail: NavTrailEntry[], path: string, limit?: num
154
349
  declare function backLabelFor(previous: NavTrailEntry | null, fallback: string, max?: number): string;
155
350
  /** The trail for this window: it outlives each screen, not a full reload. */
156
351
  declare function navTrail(): NavTrailEntry[];
352
+ /**
353
+ * The path a back from the screen on show returns to, in its own tab's stack.
354
+ *
355
+ * The trail is one list for the window, but the stx router keeps a stack per
356
+ * tab, so a screen opened in Calendar after a visit to Today goes back to
357
+ * Calendar, not to whatever was entered last. Answers null at a tab's root,
358
+ * and undefined when there is no router that keeps tabs to ask.
359
+ */
360
+ declare function previousScreenPath(): string | null | undefined;
361
+ /** The latest trail entry for `path`, which carries that screen's name. */
362
+ declare function trailEntryFor(trail: NavTrailEntry[], path: string): NavTrailEntry | null;
157
363
  /**
158
364
  * The in-app path a deep link opens, or null when it is not this app's.
159
365
  *
@@ -281,6 +487,402 @@ declare interface IndoorFix {
281
487
  }
282
488
  type IndoorVerdict = 'indoors' | 'outside' | 'unsure';
283
489
 
490
+ // From: src/native.ts
491
+ declare function hostNavigator(): Navigator | undefined;
492
+ /** A rectangle the bridge can serialise: getBoundingClientRect() returns a DOMRect, which it cannot. */
493
+ declare function toNativeRect(rect: { x?: number, y?: number, left?: number, top?: number, width: number, height: number }): NativeRect;
494
+ /** Shows an action sheet: `useActionSheet()(options)`, for a page that keeps the function. */
495
+ declare function useActionSheet(): (options: ActionSheetOptions) => Promise<string | null>;
496
+ /**
497
+ * Asks before doing something. `await confirmAction({ title: 'Delete this
498
+ * workout?', confirmLabel: 'Delete', destructive: true })` raises the iOS
499
+ * destructive-action sheet and resolves `true` when the action was chosen.
500
+ */
501
+ declare function confirmAction(options: ConfirmActionOptions): Promise<boolean>;
502
+ /**
503
+ * Shows a context menu beside `element`, the one that was long-pressed.
504
+ * Resolves with the chosen item's id, or null.
505
+ */
506
+ declare function showContextMenuFor(element: Element, options: Omit<ContextMenuOptions, 'anchor'>): Promise<string | null>;
507
+ declare function openOnTheWeb(url: string, options: BrowserOpenOptions): BrowserResult;
508
+ declare function symbolKey(name: string, options: SymbolOptions): string;
509
+ declare function downloadOnTheWeb(href: string, filename: string): string | null;
510
+ declare function pickOnTheWeb(types: string[]): Promise<PickedFile | null>;
511
+ declare function screenOrientation(): LockableOrientation | undefined;
512
+ declare const done: () => true;
513
+ declare const no: () => false;
514
+ declare const nothing: () => null;
515
+ declare const dialog: DialogApi;
516
+ declare const contextMenu: ContextMenuApi;
517
+ declare const browser: BrowserApi;
518
+ declare const symbolRequests: Map<string, Promise<string | null>>;
519
+ declare const symbolImages: Map<string, string | null>;
520
+ declare const symbols: SymbolsApi;
521
+ declare const statusBar: StatusBarApi;
522
+ declare const chrome: ChromeApi;
523
+ declare const refresh: RefreshApi;
524
+ declare const background: BackgroundApi;
525
+ declare const clipboard: ClipboardApi;
526
+ declare const db: DatabaseApi;
527
+ declare const files: FilesApi;
528
+ declare const shortcuts: ShortcutsApi;
529
+ declare const widgets: WidgetsApi;
530
+ /**
531
+ * @defaultValue
532
+ * ```ts
533
+ * {
534
+ * portrait: 'portrait-primary',
535
+ * portraitUpsideDown: 'portrait-secondary',
536
+ * landscape: 'landscape',
537
+ * landscapeLeft: 'landscape-primary',
538
+ * landscapeRight: 'landscape-secondary'
539
+ * }
540
+ * ```
541
+ */
542
+ declare const WEB_ORIENTATIONS: Record<OrientationLock, string>;
543
+ declare const orientation: OrientationApi;
544
+ declare const auth: AuthApi;
545
+ declare const storeKit: StoreKitApi;
546
+ // ---------------------------------------------------------------------------
547
+ // Dialogs
548
+ declare interface DialogApi {
549
+ alert: (options: AlertOptions) => Promise<void>
550
+ confirm: (options: ConfirmOptions) => Promise<boolean>
551
+ actionSheet: (options: ActionSheetOptions) => Promise<string | null>
552
+ }
553
+ declare interface ConfirmActionOptions extends ConfirmOptions {
554
+ style?: 'sheet' | 'alert'
555
+ anchor?: NativeRect
556
+ }
557
+ // ---------------------------------------------------------------------------
558
+ // Context menus
559
+ declare interface ContextMenuApi {
560
+ show: (options: ContextMenuOptions) => Promise<string | null>
561
+ }
562
+ // ---------------------------------------------------------------------------
563
+ // In-app browser
564
+ declare interface BrowserOpenOptions {
565
+ mode?: 'safari' | 'auth'
566
+ callbackScheme?: string
567
+ }
568
+ declare interface BrowserResult {
569
+ url?: string
570
+ cancelled: boolean
571
+ }
572
+ declare interface BrowserApi {
573
+ open: (url: string, options?: BrowserOpenOptions) => Promise<BrowserResult>
574
+ }
575
+ // ---------------------------------------------------------------------------
576
+ // SF Symbols
577
+ declare interface SymbolOptions {
578
+ pointSize?: number
579
+ weight?: 'ultralight' | 'thin' | 'light' | 'regular' | 'medium' | 'semibold' | 'bold' | 'heavy' | 'black'
580
+ color?: string
581
+ scale?: 'small' | 'medium' | 'large'
582
+ }
583
+ declare interface SymbolsApi {
584
+ isAvailable: () => boolean
585
+ image: (name: string, options?: SymbolOptions) => Promise<string | null>
586
+ cached: (name: string, options?: SymbolOptions) => string | null | undefined
587
+ clearCache: () => void
588
+ }
589
+ declare interface StatusBarApi {
590
+ setStyle: (style: StatusBarStyle) => Promise<boolean>
591
+ }
592
+ declare interface ChromeApi {
593
+ setUnderPageColor: (color: string) => Promise<boolean>
594
+ setKeyboardAccessory: (visible: boolean) => Promise<boolean>
595
+ }
596
+ // ---------------------------------------------------------------------------
597
+ // Native pull-to-refresh
598
+ declare interface RefreshApi {
599
+ isAvailable: () => boolean
600
+ enable: (options?: { tintColor?: string }) => Promise<boolean>
601
+ disable: () => Promise<boolean>
602
+ end: () => Promise<boolean>
603
+ onRefresh: (callback: () => void) => () => void
604
+ }
605
+ declare interface BackgroundApi {
606
+ complete: (ok: boolean) => Promise<boolean>
607
+ }
608
+ // ---------------------------------------------------------------------------
609
+ // Clipboard
610
+ declare interface ClipboardApi {
611
+ write: (text: string) => Promise<boolean>
612
+ read: () => Promise<string | null>
613
+ }
614
+ // ---------------------------------------------------------------------------
615
+ // The app's own SQLite database (Documents/craft.db)
616
+ declare interface DatabaseExecuteResult {
617
+ rowsAffected: number
618
+ lastInsertId: number
619
+ }
620
+ declare interface DatabaseApi {
621
+ isAvailable: () => boolean
622
+ query: <T = Record<string, unknown>>(sql: string, params?: unknown[]) => Promise<T[] | null>
623
+ execute: (sql: string, params?: unknown[]) => Promise<DatabaseExecuteResult | null>
624
+ }
625
+ // ---------------------------------------------------------------------------
626
+ // Files, documents and the camera's scanner
627
+ declare interface PickedFile {
628
+ name: string
629
+ path?: string
630
+ data?: string
631
+ mimeType?: string
632
+ }
633
+ declare interface ScannedCode {
634
+ type: string
635
+ data: string
636
+ }
637
+ declare interface FilesApi {
638
+ openPDF: (source: string, page?: number) => Promise<boolean>
639
+ takeScreenshot: () => Promise<string | null>
640
+ scanQRCode: () => Promise<ScannedCode | null>
641
+ pickFile: (types?: string[]) => Promise<PickedFile | null>
642
+ saveFile: (data: string, filename: string, mimeType?: string) => Promise<string | null>
643
+ downloadFile: (url: string, filename: string) => Promise<string | null>
644
+ }
645
+ // ---------------------------------------------------------------------------
646
+ // Home screen quick actions
647
+ declare interface HomeScreenShortcut {
648
+ type: string
649
+ title: string
650
+ subtitle?: string
651
+ symbol?: string
652
+ userInfo?: Record<string, string>
653
+ }
654
+ declare interface ShortcutsApi {
655
+ set: (shortcuts: HomeScreenShortcut[]) => Promise<boolean>
656
+ clear: () => Promise<boolean>
657
+ onShortcut: (callback: (type: string) => void) => () => void
658
+ }
659
+ // ---------------------------------------------------------------------------
660
+ // Home screen widgets (WidgetKit)
661
+ declare interface WidgetsApi {
662
+ update: (data: Record<string, unknown>) => Promise<boolean>
663
+ reload: () => Promise<boolean>
664
+ }
665
+ declare interface OrientationApi {
666
+ lock: (orientation: OrientationLock) => Promise<boolean>
667
+ unlock: () => Promise<boolean>
668
+ }
669
+ declare interface LockableOrientation { lock?: (orientation: string) => Promise<void>, unlock?: () => void }
670
+ // ---------------------------------------------------------------------------
671
+ // Sign in with Apple
672
+ declare interface AppleSignInResult {
673
+ userId: string
674
+ email?: string
675
+ name?: string
676
+ identityToken?: string
677
+ authorizationCode?: string
678
+ }
679
+ declare interface AuthApi {
680
+ signInWithApple: () => Promise<AppleSignInResult | null>
681
+ }
682
+ // ---------------------------------------------------------------------------
683
+ // In-app purchase (StoreKit 2)
684
+ declare interface StoreProduct {
685
+ id: string
686
+ displayName: string
687
+ description: string
688
+ price: string
689
+ displayPrice: string
690
+ }
691
+ declare interface StoreTransaction {
692
+ transactionId: string
693
+ productId: string
694
+ }
695
+ declare interface StoreKitApi {
696
+ isAvailable: () => boolean
697
+ products: (ids: string[]) => Promise<StoreProduct[]>
698
+ purchase: (id: string) => Promise<StoreTransaction | null>
699
+ restore: () => Promise<StoreTransaction[]>
700
+ }
701
+ // ---------------------------------------------------------------------------
702
+ // System chrome
703
+ type StatusBarStyle = 'default' | 'light' | 'dark';
704
+ // ---------------------------------------------------------------------------
705
+ // Orientation
706
+ type OrientationLock = 'portrait' | 'portraitUpsideDown' | 'landscape' | 'landscapeLeft' | 'landscapeRight';
707
+
708
+ // From: src/refresh-control.ts
709
+ /** Whether an element is laid out in view: connected, and not inside something hidden. */
710
+ declare function isShown(element: HTMLElement): boolean;
711
+ /**
712
+ * Refreshes the screen `element` belongs to with the native control, for as
713
+ * long as the returned function is not called. Check `refresh.isAvailable()`
714
+ * first: a shell without the control needs the web gesture instead.
715
+ */
716
+ declare function observeNativeRefresh(element: HTMLElement, options: NativeRefreshOptions): () => void;
717
+ declare interface NativeRefreshOptions {
718
+ tintColor?: string
719
+ onRefresh: () => unknown
720
+ }
721
+
722
+ // From: src/sheet-gesture.ts
723
+ /**
724
+ * Where each detent leaves a panel `height` tall on a `viewport` tall screen:
725
+ * large shows all of it, medium the bottom half of the screen, and dismissed
726
+ * none.
727
+ */
728
+ declare function sheetStops(height: number, viewport: number, detents: readonly SheetDetent[]): SheetStop[];
729
+ /**
730
+ * Where a released sheet goes.
731
+ *
732
+ * A flick (faster than 0.5px/ms) goes on to the next stop in its direction,
733
+ * past the lowest detent meaning dismissed. A slow release dismisses once the
734
+ * sheet is more than half way down from its lowest detent, and otherwise
735
+ * springs back to the nearest detent.
736
+ */
737
+ declare function settleSheet(state: { y: number, velocity: number, stops: SheetStop[] }): SheetSettle;
738
+ /** iOS's resistance past the top: the further it is pulled, the less it gives. */
739
+ declare function rubberBand(overshoot: number, dimension?: number): number;
740
+ /**
741
+ * Lets a sheet be dragged by its handles. While dragging, the panel follows
742
+ * the finger with `is-dragging` set (the stylesheet turns its transition off)
743
+ * and its parent's `--native-sheet-presence` (1 open, 0 gone) dims the
744
+ * backdrop to match; on release both are handed back to the stylesheet, which
745
+ * animates to wherever `onSettle` puts it.
746
+ */
747
+ declare function observeSheetDrag(options: SheetDragOptions): () => void;
748
+ /**
749
+ * Holds the page still and out of reach behind `keep`: everything outside it
750
+ * becomes inert (no taps, no focus, hidden from VoiceOver) and the document
751
+ * stops scrolling. Returns the release. Nested sheets count, so the page
752
+ * scrolls again only once the last has closed.
753
+ */
754
+ declare function lockBackground(keep: HTMLElement): () => void;
755
+ /**
756
+ * Moves `element` to the end of the body, out of every stacking context and
757
+ * transform on the way, and returns the way back: to where it was, or out of
758
+ * the document when that place has gone (the page navigated away).
759
+ */
760
+ declare function liftToBody(element: HTMLElement): () => void;
761
+ /**
762
+ * The iOS card presentation: while a large sheet is up, the page behind it
763
+ * shrinks back from the screen's edges, centred on what was in view. Undone by
764
+ * calling it with `false`.
765
+ */
766
+ declare function presentPageAsCard(doc: Document, on: boolean): void;
767
+ /** A flick faster than this (CSS pixels a millisecond) moves on to the next stop. */
768
+ declare const SHEET_FLICK_VELOCITY: 0.5;
769
+ /** A resting place, as the panel's downward offset from its fully open position. */
770
+ declare interface SheetStop {
771
+ name: SheetSettle
772
+ y: number
773
+ }
774
+ declare interface SheetDragOptions {
775
+ panel: HTMLElement
776
+ handles: HTMLElement[]
777
+ detents: () => SheetDetent[]
778
+ detent: () => SheetDetent
779
+ viewport?: () => number
780
+ onSettle: (to: SheetSettle) => void
781
+ }
782
+ /**
783
+ * What makes a bottom sheet behave like a UISheetPresentationController:
784
+ * dragged by its grabber or header, flicked away, resting at a medium or a
785
+ * large detent, and holding the page behind it still and out of reach.
786
+ */
787
+ type SheetDetent = 'medium' | 'large';
788
+ type SheetSettle = SheetDetent | 'dismiss';
789
+
790
+ // From: src/sheets.ts
791
+ /**
792
+ * Keeps Tab and Shift+Tab inside `container`: called from a keydown listener,
793
+ * it moves focus from one end to the other instead of out of it.
794
+ */
795
+ declare function trapFocus(container: HTMLElement, event: KeyboardEvent): void;
796
+ /**
797
+ * An alert or action sheet drawn in HTML. Resolves with the chosen action's
798
+ * id, or null when it is dismissed or Cancel is chosen.
799
+ */
800
+ declare function presentChoice(options: ChoiceOptions): Promise<string | null>;
801
+ declare function presentAlert(options: AlertOptions): Promise<void>;
802
+ declare function presentConfirm(options: ConfirmOptions): Promise<boolean>;
803
+ declare function presentActionSheet(options: ActionSheetOptions): Promise<string | null>;
804
+ /** Where a menu of `size` opens beside `anchor` within a `viewport`, 12px clear of its edges. */
805
+ declare function placeMenu(anchor: NativeRect, size: { width: number, height: number }, viewport: { width: number, height: number }): { top: number, left: number, origin: string };
806
+ /**
807
+ * A context menu drawn in HTML over a blurred page, beside the element that
808
+ * was pressed. Resolves with the chosen item's id, or null when dismissed.
809
+ */
810
+ declare function presentContextMenu(options: ContextMenuOptions): Promise<string | null>;
811
+ declare interface DialogAction {
812
+ id: string
813
+ title: string
814
+ style?: DialogActionStyle
815
+ }
816
+ /** A rectangle in CSS pixels relative to the viewport, as getBoundingClientRect() reports. */
817
+ declare interface NativeRect {
818
+ x: number
819
+ y: number
820
+ width: number
821
+ height: number
822
+ }
823
+ declare interface ChoiceOptions {
824
+ variant: 'alert' | 'sheet'
825
+ title?: string
826
+ message?: string
827
+ actions: DialogAction[]
828
+ cancelLabel?: string
829
+ }
830
+ declare interface ContextMenuItem {
831
+ id: string
832
+ title: string
833
+ symbol?: string
834
+ icon?: string
835
+ destructive?: boolean
836
+ disabled?: boolean
837
+ }
838
+ declare interface ContextMenuOptions {
839
+ items: ContextMenuItem[]
840
+ anchor: NativeRect
841
+ title?: string
842
+ }
843
+ declare interface AlertOptions {
844
+ title: string
845
+ message?: string
846
+ okLabel?: string
847
+ }
848
+ declare interface ConfirmOptions {
849
+ title: string
850
+ message?: string
851
+ confirmLabel?: string
852
+ cancelLabel?: string
853
+ destructive?: boolean
854
+ }
855
+ declare interface ActionSheetOptions {
856
+ title?: string
857
+ message?: string
858
+ actions: DialogAction[]
859
+ anchor?: NativeRect
860
+ cancelLabel?: string
861
+ }
862
+ type DialogActionStyle = 'default' | 'destructive' | 'cancel';
863
+
864
+ // From: src/shell.ts
865
+ /** Writes an appearance where CSS can read it: `--native-font-scale` and `data-native-reduce-*`. */
866
+ declare function applyAppearance(root: HTMLElement, appearance: NativeAppearance): void;
867
+ /**
868
+ * The colour behind the page: the first opaque background of the body or the
869
+ * root element. The under-page area should read as more of the page when it
870
+ * is pulled past its top or bottom, not as a white or black band.
871
+ */
872
+ declare function pageBackground(doc: Document): string | null;
873
+ /** Whether the page draws dark: the `.dark` class, or the system's preference where the app follows it. */
874
+ declare function pageIsDark(doc: Document): boolean;
875
+ /**
876
+ * Keeps the native chrome in step with the page until the returned function
877
+ * is called: on install, whenever the colour scheme flips (the `.dark` class
878
+ * or the system's), after each navigation, and on every appearance change.
879
+ */
880
+ declare function installNativeChrome(doc: Document, options?: NativeChromeOptions): () => void;
881
+ declare interface NativeChromeOptions {
882
+ root?: HTMLElement
883
+ keyboardAccessory?: boolean
884
+ }
885
+
284
886
  // From: src/spotlight.ts
285
887
  /**
286
888
  * Read configured kinds, leaving out any that could not work.
@@ -484,6 +1086,20 @@ declare interface SpotlightIndex {
484
1086
  declare function readTabLinks(nav: ParentNode): TabLink[];
485
1087
  /** The native bar's description of those links: the tabs, and which is current. */
486
1088
  declare function nativeTabs(links: TabLink[]): { tabs: NativeTab[], selected?: string };
1089
+ /** Whether the stx router runs the tabs itself (`data-stx-nav="tab"`, re-select included). */
1090
+ declare function routerHandlesTabs(): boolean;
1091
+ /**
1092
+ * Choosing the tab already current scrolls its screen back to the top, as on
1093
+ * iOS, and announces `stx:tabreselect` { href } for a screen that wants to do
1094
+ * more (a list that resets its filter).
1095
+ *
1096
+ * The stx router does this itself for `data-stx-nav="tab"` links, popping to
1097
+ * the tab's root on a second choice; this covers a router that predates tabs,
1098
+ * and stands aside wherever the router has them.
1099
+ */
1100
+ declare function handleTabReselect(nav: HTMLElement, options?: TabReselectOptions): () => void;
1101
+ /** Marks `element` as covering the tab bar, or no longer, and says so. */
1102
+ declare function coverTabBar(element: Element, covering: boolean): void;
487
1103
  /**
488
1104
  * Mirror `nav`'s tabs into the native tab bar, for as long as the returned
489
1105
  * function is not called. Answers null when there is no native bar, and the
@@ -491,6 +1107,12 @@ declare function nativeTabs(links: TabLink[]): { tabs: NativeTab[], selected?: s
491
1107
  */
492
1108
  declare function mirrorTabBar(nav: HTMLElement, options?: MirrorTabBarOptions): (() => void) | null;
493
1109
  declare const tabBar: TabBarApi;
1110
+ /**
1111
+ * What an open sheet raises when it starts or stops covering the tab bar. A
1112
+ * sheet on iOS slides up over the tab bar; the native bar is drawn above the
1113
+ * page, so while one is up the bar steps aside instead.
1114
+ */
1115
+ declare const TAB_BAR_COVER_EVENT: 'stacks:tab-bar-cover';
494
1116
  declare interface TabBarApi {
495
1117
  isAvailable: () => boolean
496
1118
  set: (tabs: NativeTab[], options?: { selected?: string, tint?: string, tintDark?: string }) => boolean
@@ -506,6 +1128,9 @@ declare interface TabLink {
506
1128
  badge: string
507
1129
  current: boolean
508
1130
  }
1131
+ declare interface TabReselectOptions {
1132
+ scrollToTop?: () => void
1133
+ }
509
1134
  declare interface MirrorTabBarOptions {
510
1135
  hidden?: () => boolean
511
1136
  api?: TabBarApi
@@ -587,6 +1212,22 @@ declare interface MobileApi {
587
1212
  health: HealthApi
588
1213
  liveActivities: LiveActivitiesApi
589
1214
  watchConnectivity: WatchConnectivityApi
1215
+ dialog: import('./native').DialogApi
1216
+ contextMenu: import('./native').ContextMenuApi
1217
+ browser: import('./native').BrowserApi
1218
+ symbols: import('./native').SymbolsApi
1219
+ statusBar: import('./native').StatusBarApi
1220
+ chrome: import('./native').ChromeApi
1221
+ refresh: import('./native').RefreshApi
1222
+ background: import('./native').BackgroundApi
1223
+ clipboard: import('./native').ClipboardApi
1224
+ db: import('./native').DatabaseApi
1225
+ files: import('./native').FilesApi
1226
+ shortcuts: import('./native').ShortcutsApi
1227
+ widgets: import('./native').WidgetsApi
1228
+ orientation: import('./native').OrientationApi
1229
+ auth: import('./native').AuthApi
1230
+ storeKit: import('./native').StoreKitApi
590
1231
  isNativeMobile: () => boolean
591
1232
  whenNative: (timeoutMs?: number) => Promise<boolean>
592
1233
  onReady: (callback: (event: CraftReadyEvent) => void) => () => void
@@ -683,6 +1324,7 @@ declare interface HapticsApi {
683
1324
  notification: (type?: HapticNotificationType) => Promise<void>
684
1325
  selection: () => Promise<void>
685
1326
  vibrate: (pattern: number[]) => Promise<void>
1327
+ prepare: (kind?: HapticKind) => Promise<void>
686
1328
  }
687
1329
  declare interface PermissionsApi {
688
1330
  check: (permission: PermissionType) => Promise<PermissionStatus>
@@ -872,6 +1514,7 @@ type PermissionStatus = 'granted' | 'denied' | 'undetermined' | 'restricted';
872
1514
  */
873
1515
  type BiometricType = 'faceId' | 'touchId' | 'fingerprint' | 'face' | 'iris' | 'none';
874
1516
  type AppState = 'active' | 'inactive' | 'background';
1517
+ type HapticKind = 'impact' | 'notification' | 'selection';
875
1518
  type HealthDataType = | 'steps'
876
1519
  | 'heartRate'
877
1520
  | 'activeEnergy'
@@ -889,6 +1532,6 @@ type HealthWorkoutActivity = | 'running' | 'cycling' | 'walking' | 'hiking' | 's
889
1532
  | 'stairClimbing' | 'yoga' | 'pilates' | 'strength' | 'hiit' | 'crossTraining'
890
1533
  | 'crossCountrySkiing' | 'skiing' | 'paddling' | 'climbing' | 'dance' | 'mobility' | 'other';
891
1534
 
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 };
1535
+ 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, previousScreenPath, trailEntryFor, 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, coverTabBar, mirrorTabBar, tabBar, TAB_BAR_COVER_EVENT, 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
1536
  export { NativeTab } from 'craft-native/mobile';
894
1537
  export { NativeTabBarOptions } from 'craft-native/mobile';