@stacksjs/mobile 0.75.164 → 0.75.166
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/README.md +66 -0
- package/dist/index.d.ts +112 -6
- package/dist/index.js +2 -2
- package/dist/scheduled-workouts-fake.d.ts +20 -0
- package/dist/scheduled-workouts.d.ts +72 -0
- package/dist/testing.d.ts +189 -2
- package/dist/testing.js +138 -0
- package/dist/types.d.ts +36 -4
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -119,6 +119,21 @@ if (health.supports('getHeartRateSamples')) {
|
|
|
119
119
|
}
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
+
Mindful minutes: ask for `mindful` with writing allowed, then
|
|
123
|
+
`health.saveMindfulSession({ id, startDate, endDate })` records a meditation or
|
|
124
|
+
breathing session. The id is kept as the sample's external UUID, so saving it
|
|
125
|
+
again keeps the first sample (`existing: true`). `health.getMindfulSessions(range)`
|
|
126
|
+
reads every app's sessions back, oldest first, with `ownApp` set on the ones this
|
|
127
|
+
app wrote, so an import can skip its own. Both are iOS only for now and need
|
|
128
|
+
Craft 0.0.161; an older build resolves `null` and `[]`.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
await health.requestAuthorization(['mindful'], { write: true })
|
|
132
|
+
if (health.supports('saveMindfulSession'))
|
|
133
|
+
await health.saveMindfulSession({ id: session.id, startDate: started, endDate: Date.now() })
|
|
134
|
+
const others = (await health.getMindfulSessions({ startDate: Date.now() - 7 * 86400000 })).filter(row => !row.ownApp)
|
|
135
|
+
```
|
|
136
|
+
|
|
122
137
|
## Heart-rate strap
|
|
123
138
|
|
|
124
139
|
`heartRate` reads a Bluetooth heart-rate strap (Polar, Garmin, Wahoo), or a
|
|
@@ -131,6 +146,12 @@ every reading natively, screen locked or app closed, until `stopRecording()`
|
|
|
131
146
|
hands them back. iOS only, behind `capabilities.heartRate` (which adds the
|
|
132
147
|
`bluetooth-central` background mode); Bluetooth needs no network.
|
|
133
148
|
|
|
149
|
+
`capabilities.backgroundAudio` (iOS) adds the `audio` background mode, so a
|
|
150
|
+
soundscape played with Web Audio keeps going with the screen locked: a sleep
|
|
151
|
+
timer built on stx's `useAmbientSound().fadeOut(seconds, after)` then fades it
|
|
152
|
+
out on the audio clock. App Review expects audible content from an app that
|
|
153
|
+
asks for it.
|
|
154
|
+
|
|
134
155
|
```ts
|
|
135
156
|
import { createRouteRecorder, heartRate, location } from '@stacksjs/mobile'
|
|
136
157
|
|
|
@@ -152,6 +173,51 @@ with fixes recorded separately. In a browser and on Android `isAvailable()` is
|
|
|
152
173
|
false, the state says `available: false` and nothing fires. Word iOS's prompt
|
|
153
174
|
with `ios.usageDescriptions.NSBluetoothAlwaysUsageDescription`.
|
|
154
175
|
|
|
176
|
+
## Apple Watch scheduled workouts
|
|
177
|
+
|
|
178
|
+
`scheduledWorkouts` puts structured workouts on the paired Apple Watch through
|
|
179
|
+
WorkoutKit's scheduler (iOS 17+): each appears in the watch's Workout app on
|
|
180
|
+
its day, with its warmup, repeated blocks, cooldown, goals and alerts. iOS
|
|
181
|
+
only, behind `capabilities.scheduledWorkouts`; only an app with it compiles in
|
|
182
|
+
and links WorkoutKit. The calls work on the page and on native stx screens.
|
|
183
|
+
A plan is plain JSON in SI units, its `id` a UUID the app keeps for it.
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { scheduledWorkouts } from '@stacksjs/mobile'
|
|
187
|
+
|
|
188
|
+
if (await scheduledWorkouts.isSupported()) { // false off an iPhone, never rejects
|
|
189
|
+
await scheduledWorkouts.requestAuthorization() // iOS's prompt, once; call it from a tap
|
|
190
|
+
const kept = await scheduledWorkouts.list() // [{ id, date, hour, minute, complete }]
|
|
191
|
+
await scheduledWorkouts.schedule({
|
|
192
|
+
id: '6f1c2b8e-5a7d-4c3e-9b1a-2d4e6f8a0b1c',
|
|
193
|
+
date: '2026-10-20', hour: 6, minute: 30, // local; 07:00 without a time
|
|
194
|
+
workout: {
|
|
195
|
+
activity: 'running', location: 'outdoor', displayName: '4 x 1 km',
|
|
196
|
+
warmup: { goal: { type: 'time', seconds: 600 } },
|
|
197
|
+
blocks: [{ iterations: 4, steps: [
|
|
198
|
+
{ purpose: 'work', step: { goal: { type: 'distance', meters: 1000 }, alert: { type: 'speed', min: 4.1, max: 4.4 } } },
|
|
199
|
+
{ purpose: 'recovery', step: { goal: { type: 'time', seconds: 120 } } },
|
|
200
|
+
] }],
|
|
201
|
+
},
|
|
202
|
+
})
|
|
203
|
+
await scheduledWorkouts.remove(kept[0].id) // every day it is on
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Goals are `open`, `time` (seconds), `distance` (meters) and `energy`
|
|
208
|
+
(kilocalories); alerts `heartRate`, `power`, `speed` (m/s), `cadence` ranges and
|
|
209
|
+
`heartRateZone` / `powerZone`. An activity or goal WorkoutKit refuses rejects
|
|
210
|
+
the call with a message naming it; an alert it refuses is left out and named
|
|
211
|
+
in the result's `droppedAlerts`. `schedule` also rejects LIMIT_REACHED (the
|
|
212
|
+
watch holds 15) and NOT_SCHEDULED when nothing kept the plan, as without a
|
|
213
|
+
paired watch. In a browser and on Android `isSupported()` is false and every
|
|
214
|
+
other call rejects `unsupported`.
|
|
215
|
+
|
|
216
|
+
For tests, `createScheduledWorkoutsFake()` from `@stacksjs/mobile/testing` is a
|
|
217
|
+
`craft.scheduledWorkouts` that answers like the shell. On the iOS simulator,
|
|
218
|
+
which never has a watch, the app's `CraftFakeWorkoutScheduler` default makes
|
|
219
|
+
the shell keep plans itself (`xcrun simctl spawn <device> defaults write <bundle id> CraftFakeWorkoutScheduler -bool YES`).
|
|
220
|
+
|
|
155
221
|
## Apple Music
|
|
156
222
|
|
|
157
223
|
`music` shows what the Music app is playing (title, artist, album, a small
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bundled TypeScript declarations
|
|
3
|
-
* Generated from
|
|
3
|
+
* Generated from 18 source files
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { NativeTab } from 'craft-native/mobile';
|
|
@@ -522,6 +522,80 @@ declare interface RouteRecorder {
|
|
|
522
522
|
readonly heartRate: HeartRateSample[]
|
|
523
523
|
}
|
|
524
524
|
|
|
525
|
+
// From: src/scheduled-workouts.ts
|
|
526
|
+
declare function native(): Record<string, any> | undefined;
|
|
527
|
+
/** The rejection every call but `isSupported()` gets where nothing can schedule. */
|
|
528
|
+
declare function scheduledWorkoutsUnsupported(): Error;
|
|
529
|
+
declare function authorizationOf(value: unknown): ScheduledWorkoutsAuthorization;
|
|
530
|
+
/** A row of `list()`, or null for one that is not a scheduled plan. */
|
|
531
|
+
declare function normalizeScheduledWorkout(value: unknown): ScheduledWorkout | null;
|
|
532
|
+
declare function call<T>(method: ScheduledWorkoutsMethod, normalize: (value: unknown) => T, ...args: unknown[]): Promise<T>;
|
|
533
|
+
declare const scheduledWorkouts: ScheduledWorkoutsApi;
|
|
534
|
+
declare interface AppleWorkoutStep {
|
|
535
|
+
goal: AppleWorkoutGoal
|
|
536
|
+
alert?: AppleWorkoutAlert
|
|
537
|
+
displayName?: string
|
|
538
|
+
}
|
|
539
|
+
declare interface AppleIntervalBlock {
|
|
540
|
+
iterations: number
|
|
541
|
+
steps: Array<{ purpose: 'work' | 'recovery', step: AppleWorkoutStep }>
|
|
542
|
+
}
|
|
543
|
+
declare interface AppleCustomWorkout {
|
|
544
|
+
activity: string
|
|
545
|
+
location: 'indoor' | 'outdoor' | 'unknown'
|
|
546
|
+
swimmingLocation?: 'pool' | 'openWater'
|
|
547
|
+
poolLengthMeters?: number
|
|
548
|
+
displayName: string
|
|
549
|
+
warmup?: AppleWorkoutStep
|
|
550
|
+
cooldown?: AppleWorkoutStep
|
|
551
|
+
blocks: AppleIntervalBlock[]
|
|
552
|
+
}
|
|
553
|
+
declare interface AppleWorkoutPlan {
|
|
554
|
+
id: string
|
|
555
|
+
date: string
|
|
556
|
+
hour?: number
|
|
557
|
+
minute?: number
|
|
558
|
+
workout: AppleCustomWorkout
|
|
559
|
+
}
|
|
560
|
+
/** A plan on the watch's schedule. */
|
|
561
|
+
declare interface ScheduledWorkout {
|
|
562
|
+
id: string
|
|
563
|
+
date: string
|
|
564
|
+
hour?: number
|
|
565
|
+
minute?: number
|
|
566
|
+
complete: boolean
|
|
567
|
+
}
|
|
568
|
+
declare interface ScheduleWorkoutResult {
|
|
569
|
+
id: string
|
|
570
|
+
droppedAlerts?: string[]
|
|
571
|
+
}
|
|
572
|
+
declare interface ScheduledWorkoutsApi {
|
|
573
|
+
isAvailable: () => boolean
|
|
574
|
+
supports: (method: ScheduledWorkoutsMethod) => boolean
|
|
575
|
+
isSupported: () => Promise<boolean>
|
|
576
|
+
authorization: () => Promise<ScheduledWorkoutsAuthorization>
|
|
577
|
+
requestAuthorization: () => Promise<ScheduledWorkoutsAuthorization>
|
|
578
|
+
list: () => Promise<ScheduledWorkout[]>
|
|
579
|
+
schedule: (plan: AppleWorkoutPlan) => Promise<ScheduleWorkoutResult>
|
|
580
|
+
remove: (id: string) => Promise<boolean>
|
|
581
|
+
removeAll: () => Promise<number>
|
|
582
|
+
}
|
|
583
|
+
type ScheduledWorkoutsAuthorization = 'authorized' | 'denied' | 'notDetermined' | 'restricted' | 'unsupported';
|
|
584
|
+
type AppleWorkoutGoal = | { type: 'open' }
|
|
585
|
+
| { type: 'time', seconds: number }
|
|
586
|
+
| { type: 'distance', meters: number }
|
|
587
|
+
| { type: 'energy', kilocalories: number }
|
|
588
|
+
type AppleWorkoutAlert = | { type: 'heartRate', min: number, max: number }
|
|
589
|
+
| { type: 'heartRateZone', zone: number }
|
|
590
|
+
/** Watts (PowerRangeAlert). */
|
|
591
|
+
| { type: 'power', min: number, max: number }
|
|
592
|
+
| { type: 'powerZone', zone: number }
|
|
593
|
+
/** Metres per second, the current speed (SpeedRangeAlert); a pace range is sent as speed. */
|
|
594
|
+
| { type: 'speed', min: number, max: number }
|
|
595
|
+
/** Per minute (CadenceRangeAlert). */
|
|
596
|
+
| { type: 'cadence', min: number, max: number }
|
|
597
|
+
type ScheduledWorkoutsMethod = 'isSupported' | 'authorization' | 'requestAuthorization' | 'list' | 'schedule' | 'remove' | 'removeAll';
|
|
598
|
+
|
|
525
599
|
// From: src/session-clock.ts
|
|
526
600
|
declare function startSessionClock(now: number): SessionClock;
|
|
527
601
|
declare function pauseSessionClock(clock: SessionClock, now: number): SessionClock;
|
|
@@ -1251,6 +1325,7 @@ declare interface CraftMobileCapabilities {
|
|
|
1251
1325
|
deepLinks?: boolean
|
|
1252
1326
|
flashlight?: boolean
|
|
1253
1327
|
music?: boolean
|
|
1328
|
+
scheduledWorkouts?: boolean
|
|
1254
1329
|
network?: boolean
|
|
1255
1330
|
deviceInfo?: boolean
|
|
1256
1331
|
badge?: boolean
|
|
@@ -1299,6 +1374,7 @@ declare interface MobileApi {
|
|
|
1299
1374
|
brightness: BrightnessApi
|
|
1300
1375
|
music: MusicApi
|
|
1301
1376
|
heartRate: HeartRateApi
|
|
1377
|
+
scheduledWorkouts: import('./scheduled-workouts').ScheduledWorkoutsApi
|
|
1302
1378
|
speech: SpeechApi
|
|
1303
1379
|
network: NetworkApi
|
|
1304
1380
|
pushNotifications: PushNotificationsApi
|
|
@@ -1702,6 +1778,32 @@ declare interface HealthSleepInterval {
|
|
|
1702
1778
|
sourceName: string
|
|
1703
1779
|
deviceName?: string
|
|
1704
1780
|
}
|
|
1781
|
+
/** A meditation or breathing session to record as mindful minutes. */
|
|
1782
|
+
declare interface HealthMindfulSession {
|
|
1783
|
+
id: string
|
|
1784
|
+
startDate: number
|
|
1785
|
+
endDate: number
|
|
1786
|
+
}
|
|
1787
|
+
declare interface HealthMindfulSessionResult {
|
|
1788
|
+
id: string
|
|
1789
|
+
externalId: string
|
|
1790
|
+
existing: boolean
|
|
1791
|
+
}
|
|
1792
|
+
declare interface HealthMindfulSessionQuery extends HealthSampleQuery {
|
|
1793
|
+
limit?: number
|
|
1794
|
+
}
|
|
1795
|
+
/** A mindful session in Apple Health, written by any app (the Mindfulness app, Calm, this one). */
|
|
1796
|
+
declare interface HealthMindfulSample {
|
|
1797
|
+
id: string
|
|
1798
|
+
startDate: number
|
|
1799
|
+
endDate: number
|
|
1800
|
+
durationSeconds: number
|
|
1801
|
+
sourceName: string
|
|
1802
|
+
sourceBundleId: string
|
|
1803
|
+
ownApp: boolean
|
|
1804
|
+
externalId?: string
|
|
1805
|
+
deviceName?: string
|
|
1806
|
+
}
|
|
1705
1807
|
declare interface HealthAuthorizationOptions {
|
|
1706
1808
|
write?: boolean
|
|
1707
1809
|
}
|
|
@@ -1713,6 +1815,8 @@ declare interface HealthApi {
|
|
|
1713
1815
|
getDailyStatistics: (type: HealthDailyType, options?: HealthDataOptions) => Promise<HealthDailyValue[]>
|
|
1714
1816
|
getHeartRateSamples: (options?: HealthHeartRateQuery) => Promise<HealthHeartRateSample[]>
|
|
1715
1817
|
getSleepIntervals: (options?: HealthSampleQuery) => Promise<HealthSleepInterval[]>
|
|
1818
|
+
saveMindfulSession: (session: HealthMindfulSession) => Promise<HealthMindfulSessionResult | null>
|
|
1819
|
+
getMindfulSessions: (options?: HealthMindfulSessionQuery) => Promise<HealthMindfulSample[]>
|
|
1716
1820
|
supports: (method: HealthReadMethod) => boolean
|
|
1717
1821
|
}
|
|
1718
1822
|
declare interface LiveActivityState {
|
|
@@ -1784,9 +1888,11 @@ type HealthDataType = | 'steps'
|
|
|
1784
1888
|
| 'dietaryEnergy'
|
|
1785
1889
|
| 'dietaryProtein'
|
|
1786
1890
|
| 'dietaryCarbohydrates'
|
|
1787
|
-
| 'dietaryFat'
|
|
1891
|
+
| 'dietaryFat'
|
|
1892
|
+
/** Mindful minutes (meditation, breathing): `saveMindfulSession` writes, `getMindfulSessions` reads (Craft 0.0.161). */
|
|
1893
|
+
| 'mindful';
|
|
1788
1894
|
/** The types with one value per day. `sleep` is hours asleep, counted on the day you woke. */
|
|
1789
|
-
type HealthDailyType = Exclude<HealthDataType, 'workouts'>;
|
|
1895
|
+
type HealthDailyType = Exclude<HealthDataType, 'workouts' | 'mindful'>;
|
|
1790
1896
|
type HealthWorkoutType = 'running' | 'walking' | 'hiking' | 'cycling';
|
|
1791
1897
|
/** The activity of a workout read from Apple Health, named independently of the SDK. */
|
|
1792
1898
|
type HealthWorkoutActivity = | 'running' | 'cycling' | 'walking' | 'hiking' | 'swimming' | 'rowing' | 'elliptical'
|
|
@@ -1794,9 +1900,9 @@ type HealthWorkoutActivity = | 'running' | 'cycling' | 'walking' | 'hiking' | 's
|
|
|
1794
1900
|
| 'crossCountrySkiing' | 'skiing' | 'paddling' | 'climbing' | 'dance' | 'mobility' | 'other';
|
|
1795
1901
|
/** A sleep analysis stage: in bed, awake, or asleep (staged or not). */
|
|
1796
1902
|
type HealthSleepStage = 'inBed' | 'awake' | 'asleep' | 'core' | 'deep' | 'rem';
|
|
1797
|
-
/** The health reads an installed app build may or may not answer. */
|
|
1798
|
-
type HealthReadMethod = 'getWorkouts' | 'getDailyStatistics' | 'getHeartRateSamples' | 'getSleepIntervals';
|
|
1903
|
+
/** The health reads and writes an installed app build may or may not answer. */
|
|
1904
|
+
type HealthReadMethod = 'getWorkouts' | 'getDailyStatistics' | 'getHeartRateSamples' | 'getSleepIntervals' | 'saveMindfulSession' | 'getMindfulSessions';
|
|
1799
1905
|
|
|
1800
|
-
export { normalizeDeepLinkURL, getNativeMobileBridge, isNativeMobile, whenNativeMobile, onMobileReady, withNativeFeedback, biometrics, camera, device, lifecycle, location, notifications, permissions, secureStorage, share, appReview, haptics, deepLinks, snapshots, keepAwake, brightness, music, heartRate, 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, goBackToTabRoot, trailEntryFor, deepLinkPath, followDeepLinks, HistoryHost, NavTrailEntry, TabRootHost, attachHeartRate, fixDistance, usableFixes, routeStats, paceLabel, speedLabel, createRouteRecorder, HEART_RATE_MATCH_MS, ROUTE_GAP_S, RouteFix, RouteStats, RouteStatsOptions, RouteRecorderOptions, RouteRecorder, startSessionClock, pauseSessionClock, resumeSessionClock, sessionClockElapsed, SessionClock, 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, AppleSignInOptions, 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, BrightnessApi, SpeechOptions, SpeechApi, NowPlaying, MusicSkipOptions, HeartRateDevice, HeartRateRecordingState, HeartRateState, HeartRateReading, HeartRateSample, HeartRateRecordingApi, HeartRateApi, MusicApi, DeepLinksApi, SnapshotsApi, NetworkStatus, NetworkApi, AppReviewApi, PushNotificationsApi, HealthDataOptions, HealthDataResult, HealthWorkoutLocation, HealthWorkout, HealthWorkoutResult, HealthWorkoutQuery, HealthWorkoutSample, HealthDailyValue, HealthSampleQuery, HealthHeartRateQuery, HealthHeartRateSample, HealthSleepInterval, HealthAuthorizationOptions, HealthApi, LiveActivityState, LiveActivityOptions, LiveActivitiesApi, WatchConnectivityApi, HapticStyle, HapticNotificationType, PermissionType, PermissionStatus, BiometricType, AppState, HapticKind, MusicAuthorization, MusicPlaybackState, MusicMethod, HeartRateAuthorization, BluetoothState, HeartRateConnection, HeartRateMethod, HealthDataType, HealthDailyType, HealthWorkoutType, HealthWorkoutActivity, HealthSleepStage, HealthReadMethod };
|
|
1906
|
+
export { normalizeDeepLinkURL, getNativeMobileBridge, isNativeMobile, whenNativeMobile, onMobileReady, withNativeFeedback, biometrics, camera, device, lifecycle, location, notifications, permissions, secureStorage, share, appReview, haptics, deepLinks, snapshots, keepAwake, brightness, music, heartRate, 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, goBackToTabRoot, trailEntryFor, deepLinkPath, followDeepLinks, HistoryHost, NavTrailEntry, TabRootHost, attachHeartRate, fixDistance, usableFixes, routeStats, paceLabel, speedLabel, createRouteRecorder, HEART_RATE_MATCH_MS, ROUTE_GAP_S, RouteFix, RouteStats, RouteStatsOptions, RouteRecorderOptions, RouteRecorder, scheduledWorkoutsUnsupported, normalizeScheduledWorkout, scheduledWorkouts, AppleWorkoutStep, AppleIntervalBlock, AppleCustomWorkout, AppleWorkoutPlan, ScheduledWorkout, ScheduleWorkoutResult, ScheduledWorkoutsApi, ScheduledWorkoutsAuthorization, AppleWorkoutGoal, AppleWorkoutAlert, ScheduledWorkoutsMethod, startSessionClock, pauseSessionClock, resumeSessionClock, sessionClockElapsed, SessionClock, 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, AppleSignInOptions, 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, BrightnessApi, SpeechOptions, SpeechApi, NowPlaying, MusicSkipOptions, HeartRateDevice, HeartRateRecordingState, HeartRateState, HeartRateReading, HeartRateSample, HeartRateRecordingApi, HeartRateApi, MusicApi, DeepLinksApi, SnapshotsApi, NetworkStatus, NetworkApi, AppReviewApi, PushNotificationsApi, HealthDataOptions, HealthDataResult, HealthWorkoutLocation, HealthWorkout, HealthWorkoutResult, HealthWorkoutQuery, HealthWorkoutSample, HealthDailyValue, HealthSampleQuery, HealthHeartRateQuery, HealthHeartRateSample, HealthSleepInterval, HealthMindfulSession, HealthMindfulSessionResult, HealthMindfulSessionQuery, HealthMindfulSample, HealthAuthorizationOptions, HealthApi, LiveActivityState, LiveActivityOptions, LiveActivitiesApi, WatchConnectivityApi, HapticStyle, HapticNotificationType, PermissionType, PermissionStatus, BiometricType, AppState, HapticKind, MusicAuthorization, MusicPlaybackState, MusicMethod, HeartRateAuthorization, BluetoothState, HeartRateConnection, HeartRateMethod, HealthDataType, HealthDailyType, HealthWorkoutType, HealthWorkoutActivity, HealthSleepStage, HealthReadMethod };
|
|
1801
1907
|
export { NativeTab } from 'craft-native/mobile';
|
|
1802
1908
|
export { NativeTabBarOptions } from 'craft-native/mobile';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{appReview as
|
|
1
|
+
import{appReview as Cn,biometrics as Re,brightness as ie,camera as ae,deepLinks as St,device as _,haptics as se,health as V,heartRate as w,keepAwake as xt,lifecycle as On,liveActivities as Te,location as N,music as P,network as At,notifications as le,permissions as X,pushNotifications as Le,secureStorage as ce,share as wt,speech as Me,snapshots as ue,splash as Nn,watchConnectivity as J}from"craft-native/mobile";var or=2500;function S(){if(typeof window>"u")return;return window}function me(){let e=S()?.craft;return e&&typeof e==="object"?e:void 0}function Rt(){return typeof navigator>"u"?"":navigator.userAgent||""}function ge(){let e=S();if(!e)return!1;if(e.CraftAndroid)return!0;return Boolean(e.webkit?.messageHandlers?.craft)&&/iPhone|iPad|iPod/.test(Rt())}function Q(){let e=S();if(!e||e.craft)return!1;return ge()||Boolean(e.webkit?.messageHandlers?.craft)}function B(e=15000){let t=S();if(t?.craft)return Promise.resolve(!0);if(!t||!Q())return Promise.resolve(!1);return new Promise((n)=>{let r=()=>{clearTimeout(o),t.removeEventListener("craftReady",r),n(Boolean(t.craft))},o=setTimeout(r,e);t.addEventListener("craftReady",r)})}function Tt(e,t){if(!e)return null;let n=t.split("."),r=e;for(let i of n.slice(0,-1))if(r=r?.[i],!r||typeof r!=="object"&&typeof r!=="function")return null;let o=r?.[n[n.length-1]];return typeof o==="function"?o.bind(r):null}function L(e){return Tt(me(),e)}async function Lt(e,t=2500){let n=L(e);if(n||!Q())return n;return await B(t),L(e)}async function v(e,t,n,r={}){let o=await Lt(e,r.timeoutMs);if(!o)return n();try{return await o(...t)}catch(i){if(r.fallbackOnError)return n();throw i}}async function c(e,t=2500){if(Q())await B(t);return e()}function D(e,t=2500){let n,r=!1;if(!Q())n=e();else B(t).then(()=>{if(!r)n=e()});return()=>{if(r=!0,typeof n==="function")n()}}function O(e,t){let n=S();if(!n)return()=>{};let r=(o)=>t(o.detail??{});return n.addEventListener(e,r),()=>n.removeEventListener(e,r)}var Ce="native-dialog-styles",Mt=`
|
|
2
2
|
.native-dialog { position: fixed; inset: 0; z-index: 2147483000; font-size: var(--native-font-size, 17px); font-family: var(--native-font-family, -apple-system, system-ui, sans-serif); -webkit-tap-highlight-color: transparent; }
|
|
3
3
|
.native-dialog-backdrop { position: absolute; inset: 0; background: rgb(0 0 0 / 0.3); opacity: 0; transition: opacity 220ms ease; }
|
|
4
4
|
.native-dialog--menu .native-dialog-backdrop { background: rgb(0 0 0 / 0.12); -webkit-backdrop-filter: blur(14px) saturate(140%); backdrop-filter: blur(14px) saturate(140%); }
|
|
@@ -52,4 +52,4 @@ import{appReview as kn,biometrics as Ae,brightness as re,camera as oe,deepLinks
|
|
|
52
52
|
.native-dialog-group, .native-menu { -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--native-dialog-solid, rgb(242 242 247)); }
|
|
53
53
|
.dark .native-dialog-group, .dark .native-menu { background: var(--native-dialog-solid-dark, rgb(44 44 46)); }
|
|
54
54
|
}
|
|
55
|
-
`;function Me(){return S()?.document}function Tt(e){if(e.getElementById(Le))return;let t=e.createElement("style");t.id=Le,t.textContent=Et,(e.head??e.documentElement).appendChild(t)}var Rt=0;function E(e,t,n,r){let o=e.createElement(t);if(o.className=n,r!==void 0)o.textContent=r;return o}var Pe='button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function Lt(e,t){if(t.key!=="Tab")return;let n=Array.from(e.querySelectorAll(Pe));if(n.length===0){t.preventDefault();return}let r=n[0],o=n[n.length-1],i=e.ownerDocument.activeElement;if(t.shiftKey&&(i===r||!e.contains(i)))t.preventDefault(),o.focus();else if(!t.shiftKey&&(i===o||!e.contains(i)))t.preventDefault(),r.focus()}function Ce(e,t,n,r){Tt(e);let o=S(),i=e.activeElement,a=E(e,"div",`native-dialog native-dialog--${t}`);return a.setAttribute("data-native-dialog",t),a.appendChild(E(e,"div","native-dialog-backdrop")),new Promise((s)=>{let l=!1,g=(h)=>{if(l)return;l=!0,a.classList.remove("is-open"),e.removeEventListener("keydown",p,!0),setTimeout(()=>{if(a.remove(),i&&typeof i.focus==="function")i.focus()},260),s(h)},p=(h)=>{if(h.key==="Escape"){h.preventDefault(),g(r());return}Lt(u,h)},u=n({root:a,settle:g});a.appendChild(u),e.body.appendChild(a),e.addEventListener("keydown",p,!0);let f=o;(typeof f?.requestAnimationFrame==="function"?(h)=>f.requestAnimationFrame(()=>f.requestAnimationFrame(h)):(h)=>setTimeout(h,16))(()=>{if(!l)a.classList.add("is-open")}),(u.querySelector("[data-native-autofocus]")??u.querySelector(Pe))?.focus()})}function fe(e){let t=Me();if(!t?.body)return Promise.resolve(null);let n=`native-dialog-${++Rt}`,r=e.actions.find((a)=>a.style==="cancel"),o=e.variant==="sheet"?e.actions.filter((a)=>a.style!=="cancel"):e.actions,i=e.variant==="sheet"?r??{id:"__cancel",title:e.cancelLabel||"Cancel",style:"cancel"}:void 0;return Ce(t,e.variant,({root:a,settle:s})=>{let l=(d)=>d.style==="cancel"?null:d.id,g=E(t,"div","native-dialog-panel");g.setAttribute("role","alertdialog"),g.setAttribute("aria-modal","true"),g.tabIndex=-1;let p=E(t,"div","native-dialog-group");if(e.title||e.message){let d=E(t,"div","native-dialog-header");if(e.title){let m=E(t,"p","native-dialog-title",e.title);m.id=`${n}-title`,d.appendChild(m),g.setAttribute("aria-labelledby",m.id)}if(e.message){let m=E(t,"p","native-dialog-message",e.message);m.id=`${n}-message`,d.appendChild(m),g.setAttribute("aria-describedby",m.id)}p.appendChild(d)}let u=E(t,"div","native-dialog-actions");if(e.variant==="alert"&&o.length===2)u.classList.add("is-row");for(let d of o){let m=E(t,"button",`native-dialog-action${d.style==="destructive"?" is-destructive":""}${d.style==="cancel"?" is-cancel":""}`,d.title);m.type="button",m.setAttribute("data-action-id",d.id),m.addEventListener("click",()=>s(l(d))),u.appendChild(m)}if(p.appendChild(u),g.appendChild(p),i){let d=E(t,"div","native-dialog-group"),m=E(t,"button","native-dialog-action is-cancel",i.title);m.type="button",m.setAttribute("data-action-id",i.id),m.addEventListener("click",()=>s(null)),d.appendChild(m),g.appendChild(d)}let f=a.querySelector(".native-dialog-backdrop");if(e.variant==="sheet")f?.addEventListener("click",()=>s(null));return g},()=>{if(e.variant==="sheet")return null;if(r)return null;return o.length===1?o[0].id:null})}async function Oe(e){await fe({variant:"alert",title:e.title,message:e.message,actions:[{id:"ok",title:e.okLabel||"OK"}]})}async function Ne(e){return await fe({variant:"alert",title:e.title,message:e.message,actions:[{id:"cancel",title:e.cancelLabel||"Cancel",style:"cancel"},{id:"confirm",title:e.confirmLabel||"OK",style:e.destructive?"destructive":"default"}]})==="confirm"}function Ie(e){return fe({variant:"sheet",title:e.title,message:e.message,actions:e.actions,cancelLabel:e.cancelLabel})}function Mt(e,t,n){let i=Math.max(12,Math.min(e.x,n.width-t.width-12)),a=e.y+e.height+8,s=a+t.height<=n.height-12,l=e.y-8-t.height,g=s||l<12?Math.max(12,Math.min(a,n.height-t.height-12)):l,p=e.x+e.width/2>n.width/2?"right":"left";return{top:g,left:i,origin:`${s||l<12?"top":"bottom"} ${p}`}}function He(e){let t=Me();if(!t?.body)return Promise.resolve(null);let n=S();return Ce(t,"menu",({root:r,settle:o})=>{let i=E(t,"div","native-menu native-dialog-panel");if(i.setAttribute("role","menu"),e.title)i.appendChild(E(t,"p","native-menu-title",e.title)),i.setAttribute("aria-label",e.title);for(let a of e.items){let s=E(t,"button",`native-menu-item${a.destructive?" is-destructive":""}`);if(s.type="button",s.setAttribute("role","menuitem"),s.setAttribute("data-action-id",a.id),a.disabled)s.disabled=!0;if(s.appendChild(E(t,"span","native-menu-label",a.title)),a.icon){let l=E(t,"i",`native-menu-icon ${a.icon}`);l.setAttribute("aria-hidden","true"),s.appendChild(l)}s.addEventListener("click",()=>o(a.id)),i.appendChild(s)}return r.querySelector(".native-dialog-backdrop")?.addEventListener("click",()=>o(null)),queueMicrotask(()=>{let a=i.getBoundingClientRect?.(),s=Mt(e.anchor,{width:a?.width||248,height:a?.height||e.items.length*44},{width:n?.innerWidth||390,height:n?.innerHeight||844});i.style.top=`${s.top}px`,i.style.left=`${s.left}px`,i.style.setProperty("--native-menu-origin",s.origin)}),i},()=>null)}var Fe=()=>!0,R=()=>!1,M=()=>null;function _e(){return S()?.navigator??(typeof navigator>"u"?void 0:navigator)}function be(e){return{x:Math.round(e.x??e.left??0),y:Math.round(e.y??e.top??0),width:Math.round(e.width),height:Math.round(e.height)}}var q={alert:(e)=>v("dialog.alert",[e],()=>Oe(e),{fallbackOnError:!0}).then(()=>{}),confirm:(e)=>v("dialog.confirm",[e],()=>Ne(e),{fallbackOnError:!0}).then(Boolean),actionSheet:async(e)=>{let t={...e,anchor:e.anchor?be(e.anchor):void 0},n=await v("dialog.actionSheet",[t],()=>Ie(e),{fallbackOnError:!0});if(typeof n!=="string")return null;return e.actions.find((r)=>r.id===n)?.style==="cancel"?null:n}};function rr(){return(e)=>q.actionSheet(e)}async function or(e){if((e.style??(e.destructive?"sheet":"alert"))==="alert")return q.confirm(e);return await q.actionSheet({title:e.title,message:e.message,anchor:e.anchor,actions:[{id:"confirm",title:e.confirmLabel||"OK",style:e.destructive?"destructive":"default"},{id:"cancel",title:e.cancelLabel||"Cancel",style:"cancel"}]})==="confirm"}var ve={show:async(e)=>{let t={title:e.title,anchor:be(e.anchor),items:e.items.map(({id:r,title:o,symbol:i,destructive:a,disabled:s})=>({id:r,title:o,symbol:i,destructive:a,disabled:s}))},n=await v("contextMenu.show",[t],()=>He(e),{fallbackOnError:!0});return typeof n==="string"?n:null}};function ir(e,t){return ve.show({...t,anchor:be(e.getBoundingClientRect())})}function Pt(e,t){let n=S();if(!n)return{cancelled:!0};if(typeof n.craft?.openURL==="function")return Promise.resolve(n.craft.openURL(e)).catch(()=>{}),{cancelled:!1};if(t.mode==="auth")return n.location?.assign(e),{cancelled:!1};if(!(typeof n.open==="function"?n.open(e,"_blank","noopener"):null))n.location?.assign(e);return{cancelled:!1}}var Ke={open:async(e,t={})=>{let n=await v("browser.open",[e,t],()=>Pt(e,t),{fallbackOnError:!0});if(!n||typeof n!=="object")return{cancelled:!1};let{url:r,cancelled:o}=n;return typeof r==="string"?{url:r,cancelled:Boolean(o)}:{cancelled:Boolean(o)}}},me=new Map,ge=new Map;function De(e,t){return`${e}|${t.pointSize??""}|${t.weight??""}|${t.color??""}|${t.scale??""}`}var $e={isAvailable:()=>L("symbols.image")!==null,image:(e,t={})=>{let n=De(e,t),r=me.get(n);if(r)return r;let o=v("symbols.image",[e,t],M).then((i)=>typeof i==="string"&&i.startsWith("data:")?i:null,M).then((i)=>(ge.set(n,i),i));return me.set(n,o),o},cached:(e,t={})=>ge.get(De(e,t)),clearCache:()=>{me.clear(),ge.clear()}},Q={setStyle:(e)=>v("statusBar.setStyle",[e],R,{fallbackOnError:!0}).then((t)=>t!==!1)},U={setUnderPageColor:(e)=>v("chrome.setUnderPageColor",[e],R,{fallbackOnError:!0}).then((t)=>t!==!1),setKeyboardAccessory:(e)=>v("chrome.setKeyboardAccessory",[e],R,{fallbackOnError:!0}).then((t)=>t!==!1)},I={isAvailable:()=>L("refresh.enable")!==null,enable:(e)=>v("refresh.enable",[e??{}],R,{fallbackOnError:!0}).then((t)=>t!==!1),disable:()=>v("refresh.disable",[],R,{fallbackOnError:!0}).then((e)=>e!==!1),end:()=>v("refresh.end",[],R,{fallbackOnError:!0}).then((e)=>e!==!1),onRefresh:(e)=>O("craftRefresh",()=>e())},W={complete:(e)=>v("background.complete",[e],R,{fallbackOnError:!0}).then((t)=>t!==!1)},qe={write:(e)=>v("clipboard.write",[e],async()=>{let t=_e()?.clipboard;if(!t?.writeText)return!1;return t.writeText(e).then(Fe,R)},{fallbackOnError:!0}).then((t)=>t!==!1),read:()=>v("clipboard.read",[],async()=>{let e=_e()?.clipboard;if(!e?.readText)return null;return e.readText().catch(M)},{fallbackOnError:!0}).then((e)=>typeof e==="string"?e:null)},Ue={isAvailable:()=>L("db.query")!==null,query:(e,t=[])=>v("db.query",[e,t],M).then((n)=>Array.isArray(n)?n:null),execute:(e,t=[])=>v("db.execute",[e,t],M).then((n)=>{if(!n||typeof n!=="object")return null;let{rowsAffected:r,lastInsertId:o}=n;return{rowsAffected:Number(r)||0,lastInsertId:Number(o)||0}})};function he(e,t){let n=S()?.document;if(!n?.body)return null;let r=n.createElement("a");return r.href=e,r.download=t,r.rel="noopener",r.style.display="none",n.body.appendChild(r),r.click(),r.remove(),t}function Ct(e){let t=S()?.document;if(!t?.body)return Promise.resolve(null);return new Promise((n)=>{let r=t.createElement("input");if(r.type="file",r.style.display="none",e.length)r.accept=e.map((i)=>i.includes("/")||i.startsWith(".")?i:`.${i}`).join(",");let o=(i)=>{r.remove(),n(i)};r.addEventListener("cancel",()=>o(null)),r.addEventListener("change",()=>{let i=r.files?.[0];if(!i)return o(null);let a=new FileReader;a.onload=()=>o({name:i.name,mimeType:i.type||void 0,data:typeof a.result==="string"?a.result:void 0}),a.onerror=()=>o({name:i.name,mimeType:i.type||void 0}),a.readAsDataURL(i)}),t.body.appendChild(r),r.click()})}var We={openPDF:(e,t=0)=>v("openPDF",[e,t],()=>{let n=S();return Boolean(n?.open?.(e,"_blank","noopener"))}).then((n)=>n!==!1),takeScreenshot:()=>v("takeScreenshot",[],M,{fallbackOnError:!0}).then((e)=>typeof e==="string"?e:null),scanQRCode:()=>v("scanQRCode",[],M).then((e)=>{if(!e||typeof e!=="object")return null;let{type:t,data:n}=e;return typeof n==="string"?{type:String(t??""),data:n}:null},M),pickFile:(e=[])=>v("pickFile",[e],()=>Ct(e)).then((t)=>{if(!t||typeof t!=="object")return null;let n=t;if(typeof n.name!=="string")return null;return{name:n.name,path:typeof n.path==="string"?n.path:void 0,data:typeof n.data==="string"?n.data:void 0,mimeType:typeof n.mimeType==="string"?n.mimeType:void 0}},M),saveFile:(e,t,n)=>v("saveFile",[e,t,n],()=>{if(e.startsWith("data:"))return he(e,t);let r=new Blob([e],{type:n||"text/plain"}),o=URL.createObjectURL(r),i=he(o,t);return setTimeout(()=>URL.revokeObjectURL(o),1000),i}).then((r)=>typeof r==="string"?r:null),downloadFile:(e,t)=>v("downloadFile",[e,t],()=>he(e,t)).then((n)=>typeof n==="string"?n:null)},ze={set:(e)=>v("shortcuts.set",[e.map(({symbol:t,...n})=>t?{...n,iconName:t}:n)],R).then((t)=>t!==!1),clear:()=>v("shortcuts.clear",[],R).then((e)=>e!==!1),onShortcut:(e)=>O("craftShortcut",(t)=>{if(typeof t.type==="string")e(t.type)})},Ye={update:(e)=>v("widget.update",[e],R).then((t)=>t!==!1),reload:()=>v("widget.reload",[],R).then((e)=>e!==!1)},Ot={portrait:"portrait-primary",portraitUpsideDown:"portrait-secondary",landscape:"landscape",landscapeLeft:"landscape-primary",landscapeRight:"landscape-secondary"};function Be(){return S()?.screen?.orientation}var je={lock:(e)=>v("lockOrientation",[e],()=>{let t=Be();return t?.lock?t.lock(Ot[e]).then(Fe,R):!1}).then((t)=>t!==!1),unlock:()=>v("unlockOrientation",[],()=>(Be()?.unlock?.(),!0)).then((e)=>e!==!1)},Ve={signInWithApple:(e={})=>v("signInWithApple",e.nonce?[{nonce:e.nonce}]:[],M).then((t)=>{if(!t||typeof t!=="object"||typeof t.userId!=="string")return null;return t})},Ge={isAvailable:()=>L("iap.purchase")!==null,products:(e)=>v("iap.getProducts",[e],()=>[]).then((t)=>Array.isArray(t)?t:[]),purchase:(e)=>v("iap.purchase",[e],M).then((t)=>t&&typeof t==="object"?t:null,(t)=>{if(/cancel/i.test(String(t?.message??t)))return null;throw t}),restore:()=>v("iap.restore",[],()=>[]).then((e)=>Array.isArray(e)?e:[])};function lr(e,t){let n=t.delay??500,r=t.tolerance??10,o=null,i=null,a=!1,s=()=>{if(o)clearTimeout(o);if(o=null,i&&!a)t.onPressEnd?.();i=null},l=(f)=>{let d=f;if(d.button!==void 0&&d.button!==0)return;a=!1,i={x:d.clientX,y:d.clientY},t.onPressStart?.(),o=setTimeout(()=>{if(o=null,!i)return;a=!0,t.onLongPress({...i}),i=null},n)},g=(f)=>{if(!i)return;let d=f;if(Math.hypot(d.clientX-i.x,d.clientY-i.y)>r)s()},p=(f)=>{if(!a)return;a=!1,f.preventDefault(),f.stopPropagation()},u=(f)=>f.preventDefault();return e.addEventListener("pointerdown",l),e.addEventListener("pointermove",g),e.addEventListener("pointerup",s),e.addEventListener("pointercancel",s),e.addEventListener("pointerleave",s),e.addEventListener("click",p,!0),e.addEventListener("contextmenu",u),()=>{s(),e.removeEventListener("pointerdown",l),e.removeEventListener("pointermove",g),e.removeEventListener("pointerup",s),e.removeEventListener("pointercancel",s),e.removeEventListener("pointerleave",s),e.removeEventListener("click",p,!0),e.removeEventListener("contextmenu",u)}}function Nt(e,t,n){if(n<=1||t.width<=0)return 0;let r=Math.floor((e-t.left)/t.width*n);return Math.max(0,Math.min(n-1,r))}function cr(e,t){let n=null,r=null,o=!1,i=0,a=(d)=>{let m=e.getBoundingClientRect();return Nt(d,{left:m.left+2,width:m.width-4},t.count())},s=(d)=>{let m=d;if(m.button!==void 0&&m.button!==0)return;let h=a(m.clientX);if(h!==t.selected())return;n=h,i=h,o=!1,r=m.pointerId;try{e.setPointerCapture?.(m.pointerId)}catch{}t.onPress?.(!0)},l=(d)=>{if(n===null)return;let m=a(d.clientX);if(m===i)return;o=!0,i=m,t.onScrub(m)},g=(d)=>{if(n===null)return;if(r!==null)try{e.releasePointerCapture?.(r)}catch{}if(t.onPress?.(!1),d&&o)t.onCommit(i);else if(o)t.onScrub(n);n=null,r=null},p=(d)=>{if(!o)return;o=!1,d.preventDefault(),d.stopPropagation()},u=()=>g(!0),f=()=>g(!1);return e.addEventListener("pointerdown",s),e.addEventListener("pointermove",l),e.addEventListener("pointerup",u),e.addEventListener("pointercancel",f),e.addEventListener("click",p,!0),()=>{e.removeEventListener("pointerdown",s),e.removeEventListener("pointermove",l),e.removeEventListener("pointerup",u),e.removeEventListener("pointercancel",f),e.removeEventListener("click",p,!0)}}function ur(e,t,n){if(n<=0)return null;switch(e){case"ArrowRight":case"ArrowDown":return(t+1)%n;case"ArrowLeft":case"ArrowUp":return(t-1+n)%n;case"Home":return 0;case"End":return n-1;default:return null}}function dr(e,t){e.querySelectorAll('[role="tab"]')[t]?.focus()}function pr(e){let t=(n)=>{if(!n.target?.closest?.("[data-native-pressable]"))return;let o=L("haptics.prepare");if(o)Promise.resolve().then(()=>o("impact")).catch(()=>{})};return e.addEventListener("touchstart",t,{passive:!0,capture:!0}),()=>e.removeEventListener("touchstart",t,{capture:!0})}function ye(e){let t=S();try{return Boolean(t?.matchMedia?.(e).matches)}catch{return!1}}function Xe(e){return e!==null&&e!==void 0&&e!=="false"&&e!=="0"}function Je(){let e=S()?.document?.documentElement,t=Number.parseFloat(e?.style?.getPropertyValue("--craft-font-scale")||"");return{fontScale:Number.isFinite(t)&&t>0?t:1,reduceMotion:Xe(e?.getAttribute("data-craft-reduce-motion"))||ye("(prefers-reduced-motion: reduce)"),reduceTransparency:Xe(e?.getAttribute("data-craft-reduce-transparency"))||ye("(prefers-reduced-transparency: reduce)"),colorScheme:e?.classList?.contains("dark")||ye("(prefers-color-scheme: dark)")?"dark":"light"}}function It(e){let t=Je(),n=Number(e?.fontScale);return{contentSizeCategory:typeof e?.contentSizeCategory==="string"?e.contentSizeCategory:void 0,fontScale:Number.isFinite(n)&&n>0?n:t.fontScale,reduceMotion:typeof e?.reduceMotion==="boolean"?e.reduceMotion:t.reduceMotion,reduceTransparency:typeof e?.reduceTransparency==="boolean"?e.reduceTransparency:t.reduceTransparency,colorScheme:e?.colorScheme==="dark"||e?.colorScheme==="light"?e.colorScheme:t.colorScheme}}function Qe(e,t={}){if(t.immediate!==!1)e(Je());return O("craftAppearance",(n)=>e(It(n)))}function hr(e){return O("craftResume",(t)=>e({backgroundedMs:Number(t.backgroundedMs)||0}))}function br(e){return O("craftMemoryWarning",()=>e())}function Ze(e){return(t)=>{Promise.resolve().then(()=>e(t)).then(()=>W.complete(!0),()=>W.complete(!1))}}function vr(e){let t=Ze(e);return O("craftSilentPush",(n)=>t(n.payload??{}))}function yr(e){let t=Ze(()=>e());return O("craftBackgroundRefresh",()=>t(void 0))}import{haptics as Ht}from"craft-native/mobile";function Se(){if(typeof window>"u")return;return window}function z(e=Se()){if(!e)return 0;if(typeof e.scrollY==="number")return e.scrollY;if(typeof e.scrollTop==="number")return e.scrollTop;return e.document?.scrollingElement?.scrollTop??0}function _t(e,t=Se()){if(!t)return()=>{};let n=!1,r=typeof requestAnimationFrame==="function"?requestAnimationFrame:(i)=>setTimeout(i,16),o=()=>{if(n)return;n=!0,r(()=>{n=!1,e(z(t))})};return e(z(t)),t.addEventListener("scroll",o,{passive:!0}),()=>t.removeEventListener("scroll",o)}function Dt(e,t){let n=Math.max(0,-e),r=e<=0?Math.max(0,t)*0.5:0;return Math.round(Math.max(n,r))}function wr(e){let t=e.host??Se();if(!t)return()=>{};let n=e.threshold??72,r=null,o=!1,i=!1,a=typeof requestAnimationFrame==="function"?requestAnimationFrame:(h)=>setTimeout(h,16),s=null,l=(h)=>{s=null,e.onPull?.(h,o,{bounce:Math.min(h,Math.max(0,-z(t)))})},g=(h)=>{let k=s!==null;if(s=h,k)return;a(()=>{if(s!==null)l(s)})},p=(h)=>{let k=h.touches?.[0];return k?k.clientY:null},u=(h)=>{if(i||z(t)>0)return;r=p(h),o=!1},f=(h)=>{if(r===null)return;let k=p(h);if(k===null)return;let C=Dt(z(t),k-r);if(!o&&C>=n)o=!0,Promise.resolve(Ht.impact("medium")).catch(()=>{});else if(o&&C<n*0.8)o=!1;g(C)},d=async()=>{if(r===null)return;if(r=null,!o){l(0);return}o=!1,i=!0,l(n);try{await e.onRefresh()}finally{i=!1,l(0)}},m=()=>{if(r===null)return;r=null,o=!1,l(0)};return t.addEventListener("touchstart",u,{passive:!0}),t.addEventListener("touchmove",f,{passive:!0}),t.addEventListener("touchend",d),t.addEventListener("touchcancel",m),()=>{s=null,t.removeEventListener("touchstart",u),t.removeEventListener("touchmove",f),t.removeEventListener("touchend",d),t.removeEventListener("touchcancel",m)}}function Bt(e,t=52){let n=Math.max(1,t),r=Math.min(1,Math.max(0,e/n)),o=e<0?1+Math.min(0.1,-e/600):1;return{progress:Math.round(r*1000)/1000,stretch:Math.round(o*1000)/1000}}function Ar(e,t={}){let n="",r=()=>t.title?.offsetHeight||t.height||52;return _t((o)=>{let i=Bt(o,r()),a=`${i.progress}|${i.stretch}`;if(a===n)return;n=a,e.style.setProperty("--native-nav-progress",String(i.progress)),e.style.setProperty("--native-nav-stretch",String(i.stretch)),t.onChange?.(i)},t.host)}function kr(e){if(!e||typeof window>"u")return;let t=window.document?.querySelector(e);return t?t:void 0}function nt(){if(typeof window>"u")return;return window}var et="__stxPushed",Ft="__stxScroll";function Kt(e=nt()){let t=e?.history?.state;if(t===null||t===void 0)return!1;if(typeof t!=="object")return!0;let n=t;if(et in n)return n[et]===!0;return!(Ft in n)}function Tr(e=nt()){if(!Kt(e))return!1;return e.history.back(),!0}function Rr(e,t,n=50){let r=e[e.length-1];if(e.length>=2&&e[e.length-2].path===t)e.pop();else if(!r||r.path!==t)e.push({path:t,title:""});if(e.length>n)e.splice(0,e.length-n);return{current:e[e.length-1],previous:e[e.length-2]??null}}function Lr(e,t,n=12){let r=e?.title.trim()??"";return r&&r.length<=n?r:t}function Mr(){if(typeof window>"u")return[];let e=window;return e.__stacksNavTrail??=[]}function $t(e){try{let t=new URL(e,"http://local");return`${t.pathname}${t.search}`}catch{return e}}function Pr(){if(typeof window>"u")return;let e=window.stxRouter;if(typeof e?.screens!=="function")return;let t=e.screens(),n=t.find((o)=>o.active);if(!n)return;let r=t.filter((o)=>o.tab===n.tab&&o.depth<n.depth);if(!r.length)return null;return $t(r.reduce((o,i)=>i.depth>o.depth?i:o).url)}function Cr(e=typeof window>"u"?void 0:window){let t=e?.stxRouter;if(typeof t?.screens!=="function"||typeof e?.history?.go!=="function")return!1;let n=t.screens(),r=n.find((a)=>a.active);if(!r)return!1;let o=n.filter((a)=>a.tab===r.tab&&a.depth<r.depth);if(!o.length)return!1;let i=o.reduce((a,s)=>s.depth<a.depth?s:a);return e.history.go(i.depth-r.depth),!0}function Or(e,t){for(let n=e.length-1;n>=0;n--)if(e[n].path===t)return e[n];return null}function qt(e,t=Ut()){let n;try{n=new URL(e)}catch{return null}let r=`${n.search}${n.hash}`;if(n.protocol==="http:"||n.protocol==="https:"){if(!t||n.origin!==t)return null;return`${n.pathname||"/"}${r}`}return`${`/${[n.host,n.pathname.replace(/^\/+/,"")].filter(Boolean).join("/")}`}${r}`}function Ut(){if(typeof window>"u")return;return window.location?.origin}var tt="stacks-mobile-deep-link";function Nr(e,t){let n=(r)=>{let o=qt(r);if(o)e(o)};return t.getInitialURL().then((r)=>{if(!r)return;try{if(sessionStorage.getItem(tt)===r)return;sessionStorage.setItem(tt,r)}catch{}n(r)}).catch(()=>{}),t.onLink((r,o)=>{if(o?.initial)return;n(r)})}var Hr=5000;function Wt(e,t,n=5000){let r=t.filter((o)=>Number.isFinite(o.timestamp)&&Number.isFinite(o.bpm)&&o.bpm>0).slice().sort((o,i)=>o.timestamp-i.timestamp);if(!r.length)return e.slice();return e.map((o)=>{let i=0,a=r.length;while(i<a){let p=i+a>>1;if(r[p].timestamp<o.timestamp)i=p+1;else a=p}let s=r[i],l=r[i-1],g=!s?l:!l?s:o.timestamp-l.timestamp<=s.timestamp-o.timestamp?l:s;if(!g||Math.abs(g.timestamp-o.timestamp)>n)return o;return{...o,heartRate:Math.round(g.bpm)}})}var zt=6371008.8,Yt=30,jt=Yt;function Vt(e,t){let n=Math.PI/180,r=(t.latitude-e.latitude)*n,o=(t.longitude-e.longitude)*n,i=Math.sin(r/2)**2+Math.cos(e.latitude*n)*Math.cos(t.latitude*n)*Math.sin(o/2)**2;return 2*zt*Math.asin(Math.min(1,Math.sqrt(i)))}function Gt(e,t=25){let n=new Set;return e.filter((r)=>Number.isFinite(r.latitude)&&Number.isFinite(r.longitude)&&Number.isFinite(r.timestamp)&&Math.abs(r.latitude)<=90&&Math.abs(r.longitude)<=180&&Number.isFinite(r.accuracy)&&r.accuracy>=0&&r.accuracy<=t).sort((r,o)=>r.timestamp-o.timestamp).filter((r)=>{if(n.has(r.timestamp))return!1;return n.add(r.timestamp),!0})}function rt(e,t={}){let n=Gt(e,t.maxAccuracyM??25),r=t.paceWindowS??30,o=[],i=0,a=0,s=null;for(let u of n){let f=o[o.length-1],d=s?(u.timestamp-s.timestamp)/1000:0;if(s=u,!f){o.push({fix:u,cumM:0});continue}if(d>jt){o.push({fix:u,cumM:i});continue}let m=(u.timestamp-f.fix.timestamp)/1000,h=Vt(f.fix,u),k=Math.min(10,Math.max(3,f.fix.accuracy,u.accuracy));if(h<k)continue;if(i+=h,m>0&&h/m>=0.5)a+=m;o.push({fix:u,cumM:i})}let l=o[o.length-1],g=null,p=null;if(l&&n.at(-1).timestamp-l.fix.timestamp<=r*1000){let u=l.fix.timestamp-r*1000,f=o.find((h)=>h.fix.timestamp>=u)??l,d=l.cumM-f.cumM,m=(l.fix.timestamp-f.fix.timestamp)/1000;if(d>=20&&m>0)p=d/m,g=m/(d/1000)}return{distanceM:i,movingS:a,paceSPerKm:g,averagePaceSPerKm:i>=50&&a>0?a/(i/1000):null,speedMps:p,accuracyM:n.length?n[n.length-1].accuracy:e.length?e[e.length-1].accuracy??null:null,fixes:n.length}}function _r(e){if(e==null||e<=0||!Number.isFinite(e)||e>3600)return"–";let t=Math.round(e);return`${Math.floor(t/60)}:${String(t%60).padStart(2,"0")}`}function Dr(e){return e!=null&&e>0&&Number.isFinite(e)?(e*3.6).toFixed(1):"–"}var ot={distanceM:0,movingS:0,paceSPerKm:null,averagePaceSPerKm:null,speedMps:null,accuracyM:null,fixes:0};function Br(e){let t=e.location,n=e.intervalMs??3000,r=ot,o=null,i=e.heartRate,a=!1,s=[],l=()=>typeof document<"u"&&document.visibilityState==="hidden",g=0,p=null,u=Promise.resolve(),f=null,d=!1;function m(x){let b=u.then(x);return u=b.then(()=>{},()=>{}),b}function h(){if(p)return p;let x=g;return p=(async()=>{let b=await t.readRecording();if(x===g&&!d)r=rt(b,e),e.onUpdate?.(r);return r})().finally(()=>{p=null}),p}function k(){if(C(),d)return;o=setInterval(()=>{if(!l())h().catch(()=>{})},n)}function C(){if(o)clearInterval(o);o=null}async function F(x){if(!i||!a)return;await x(i).catch(()=>{})}return{get stats(){return r},get heartRate(){return s},start(){return f=null,m(async()=>{if(await t.startRecording({enableHighAccuracy:!0,...e.locationOptions}),s=[],a=!!i?.isAvailable(),await F((x)=>x.startRecording()),g++,r={...ot},!d)e.onUpdate?.(r);return k(),r})},attach(){return m(async()=>{let x=await t.getRecordingState();if(!x?.active)return null;if(i?.isAvailable())a=!!(await i.getRecordingState().catch(()=>null))?.active;if(await h().catch(()=>{}),!x.paused)k();return x})},pause(){return m(async()=>{await t.pauseRecording(),await F((x)=>x.pauseRecording()),C(),await h().catch(()=>{})})},resume(){return m(async()=>{await t.resumeRecording(),await F((x)=>x.resumeRecording()),k()})},stop(){if(f)return f;return f=m(async()=>{C(),g++;let b=(await t.stopRecording())?.locations??[];if(i&&a){let y=await i.stopRecording().catch(()=>null);a=!1,s=y?.samples??[],b=Wt(b,s)}if(r=rt(b,e),!d)e.onUpdate?.(r);return b}).catch((x)=>{throw f=null,x}),f},dispose(){d=!0,g++,C()},refresh:h}}function Kr(e){return{startedAt:Number.isFinite(e)?e:null,pausedAt:null,pausedMs:0}}function $r(e,t){return e.startedAt===null||e.pausedAt!==null||!Number.isFinite(t)?e:{...e,pausedAt:Math.max(e.startedAt,t)}}function qr(e,t){return e.pausedAt===null||!Number.isFinite(t)?e:{...e,pausedAt:null,pausedMs:e.pausedMs+Math.max(0,t-e.pausedAt)}}function Ur(e,t){if(e.startedAt===null)return 0;let n=((e.pausedAt??t)-e.startedAt-e.pausedMs)/1000;return Number.isFinite(n)?Math.max(0,n):0}var zr=150;function Xt(e,t){let n=Math.PI/180,r=(t.latitude-e.latitude)*n,o=(t.longitude-e.longitude)*n,i=Math.sin(r/2)**2+Math.cos(e.latitude*n)*Math.cos(t.latitude*n)*Math.sin(o/2)**2;return 12742017.6*Math.asin(Math.min(1,Math.sqrt(i)))}function Z(e,t){let n=[...e].sort((r,o)=>r-o);return n[Math.min(n.length-1,Math.floor(t*n.length))]}function Yr(e,t){let n=(e||[]).filter((a)=>Number.isFinite(a?.latitude)&&Number.isFinite(a?.longitude)&&Math.abs(a.latitude)<=90&&Math.abs(a.longitude)<=180),r=n.filter((a)=>a.accuracy!=null).map((a)=>Number(a.accuracy)).filter((a)=>Number.isFinite(a)&&a>=0),o=r.length?Z(r,0.5):Number.POSITIVE_INFINITY,i=0;if(n.length){let a={latitude:Z(n.map((s)=>s.latitude),0.5),longitude:Z(n.map((s)=>s.longitude),0.5)};i=Z(n.map((s)=>Xt(a,s)),0.8)}if(n.length>=10&&i>150&&o<=15)return"outside";if(t<150)return"unsure";if(n.length<3||o>30||i<25)return"indoors";if(i<50&&o>10)return"indoors";return"unsure"}function jr(e,t={}){let r=String(e||"").trim().toLowerCase().replace(",",".").match(/^(\d+(?:\.\d*)?|\.\d+)\s*(km|k|m|mi)?$/);if(!r)return null;let o=Number(r[1]),i=r[2]||t.defaultUnit||(o>100?"m":"km"),a=i==="m"?o/1000:i==="mi"?o*1.609344:o;return Number.isFinite(a)&&a>=0&&a<=2000?Math.round(a*1000)/1000:null}var ne=new Set,it=!1,ee=null;function Jt(e){return e.isConnected&&e.getClientRects().length>0}function at(){return[...ne].find((e)=>Jt(e.element))}function te(){let e=at(),t=Boolean(e);if(t===it)return;if(it=t,t)I.enable(e?.tintColor?{tintColor:e.tintColor}:{});else I.disable()}function Qt(){let e=at();if(!e){I.end();return}Promise.resolve().then(()=>e.run()).catch(()=>{}).finally(()=>I.end())}function Xr(e,t){let n={element:e,tintColor:t.tintColor,run:t.onRefresh};ne.add(n);let r=e.ownerDocument?.defaultView;if(!ee){let o=I.onRefresh(Qt),i=()=>te();r?.addEventListener("stx:load",i),ee=()=>{o(),r?.removeEventListener("stx:load",i)}}return te(),r?.requestAnimationFrame?.(()=>te()),()=>{if(ne.delete(n),ne.size===0)ee?.(),ee=null;te()}}var Qr=0.5;function Zt(e,t,n){let r=[];if(n.includes("large")||n.length===0)r.push({name:"large",y:0});if(n.includes("medium"))r.push({name:"medium",y:Math.max(0,Math.round(e-t*0.5))});return r.push({name:"dismiss",y:Math.max(1,e)}),r.sort((o,i)=>o.y-i.y)}function en(e){let{y:t,velocity:n,stops:r}=e,o=r.filter((s)=>s.name!=="dismiss"),i=r.find((s)=>s.name==="dismiss");if(o.length===0)return"dismiss";if(n>0.5)return(r.filter((l)=>l.y>t+1)[0]??i).name;if(n<-0.5){let s=o.filter((l)=>l.y<t-1);return(s[s.length-1]??o[0]).name}let a=o[o.length-1];if(t>a.y+(i.y-a.y)*0.5)return"dismiss";return o.reduce((s,l)=>Math.abs(l.y-t)<Math.abs(s.y-t)?l:s).name}function tn(e,t=400){if(e<=0)return 0;return e*t*0.55/(t+e*0.55)}function Zr(e){let{panel:t}=e,n=null,r=[],o=0,i=()=>e.viewport?.()??t.ownerDocument?.defaultView?.innerHeight??800,a=()=>Zt(t.offsetHeight||t.getBoundingClientRect().height,i(),e.detents()),s=(p)=>{let u=p;if(u.button!==void 0&&u.button!==0)return;if(u.target?.closest?.("button, a, input, select, textarea, [role=button]"))return;let f=a().find((d)=>d.name===e.detent())?.y??0;n={y:u.clientY,base:f,pointerId:u.pointerId},o=f,r=[{y:f,t:u.timeStamp}],t.classList.add("is-dragging");try{p.currentTarget?.setPointerCapture?.(u.pointerId)}catch{}},l=(p)=>{if(!n)return;let u=p,f=n.base+u.clientY-n.y;o=f<0?-tn(-f):f,r.push({y:o,t:u.timeStamp});while(r.length>2&&u.timeStamp-r[0].t>100)r.shift();t.style.transform=`translateY(${o}px)`;let d=t.offsetHeight||1;t.parentElement?.style.setProperty("--native-sheet-presence",String(Math.max(0,Math.min(1,1-o/d))))},g=(p)=>{if(!n)return;let u=p;n=null;let f=r[0],d=Math.max(1,u.timeStamp-f.t),m=(o-f.y)/d;t.classList.remove("is-dragging"),t.style.transform="",t.parentElement?.style.removeProperty("--native-sheet-presence"),e.onSettle(en({y:o,velocity:m,stops:a()}))};for(let p of e.handles)p.addEventListener("pointerdown",s),p.addEventListener("pointermove",l),p.addEventListener("pointerup",g),p.addEventListener("pointercancel",g);return()=>{for(let p of e.handles)p.removeEventListener("pointerdown",s),p.removeEventListener("pointermove",l),p.removeEventListener("pointerup",g),p.removeEventListener("pointercancel",g)}}var st=0,xe="";function eo(e){let t=e.ownerDocument,n=[],r=e;while(r.parentElement&&r!==t.body){for(let a of Array.from(r.parentElement.children)){if(a===r||a.hasAttribute("inert")||a.hasAttribute("data-native-dialog"))continue;if(["SCRIPT","STYLE","TEMPLATE","LINK"].includes(a.tagName))continue;if(a.hasAttribute("data-native-sheet")&&a.getAttribute("aria-hidden")==="true")continue;a.setAttribute("inert",""),n.push(a)}r=r.parentElement}let o=t.documentElement;if(st++===0)xe=o.style.overflow||"",o.style.overflow="hidden";let i=!1;return()=>{if(i)return;i=!0;for(let a of n)a.removeAttribute("inert");if(--st===0)if(xe)o.style.overflow=xe;else o.style.removeProperty("overflow")}}function to(e){let t=e.ownerDocument;if(e.parentElement===t.body)return()=>{};let n=t.createComment("native-sheet");return e.parentNode?.insertBefore(n,e),t.body.appendChild(e),()=>{if(n.parentNode)n.parentNode.insertBefore(e,n);else e.remove();n.remove()}}function no(e,t){let n=e.documentElement;if(!t){n.removeAttribute("data-native-sheet-card");return}let r=e.defaultView,o=(r?.scrollY??0)+(r?.innerHeight??800)/2;n.style.setProperty("--native-sheet-card-origin",`${Math.round(o)}px`),n.setAttribute("data-native-sheet-card","")}function nn(e,t){e.style.setProperty("--native-font-scale",String(t.fontScale)),e.toggleAttribute("data-native-reduce-motion",t.reduceMotion),e.toggleAttribute("data-native-reduce-transparency",t.reduceTransparency)}function rn(e){let t=e.replace(/\s+/g,"").toLowerCase();return!t||t==="transparent"||/^rgba\(\d+,\d+,\d+,0(\.0+)?\)$/.test(t)||/\/0(\.0+)?\)$/.test(t)}function on(e){let t=e.defaultView;if(!t?.getComputedStyle)return null;for(let n of[e.body,e.documentElement]){if(!n)continue;let r=t.getComputedStyle(n).backgroundColor;if(r&&!rn(r))return r}return null}function an(e){if(e.documentElement.classList.contains("dark"))return!0;if(e.documentElement.classList.contains("light"))return!1;return Boolean(e.defaultView?.matchMedia?.("(prefers-color-scheme: dark)").matches)}function ao(e,t={}){let n=t.root??e.documentElement;U.setKeyboardAccessory(t.keyboardAccessory===!0);let r="",o="",i=()=>{let p=on(e);if(p&&p!==r)r=p,U.setUnderPageColor(p);let u=an(e)?"light":"dark";if(u!==o)o=u,Q.setStyle(u)},a=Qe((p)=>{nn(n,p),i()}),s=e.defaultView,l=typeof s?.MutationObserver==="function"?new s.MutationObserver(i):null;l?.observe(e.documentElement,{attributes:!0,attributeFilter:["class","style","data-theme"]});let g=s?.matchMedia?.("(prefers-color-scheme: dark)");return g?.addEventListener?.("change",i),s?.addEventListener("stx:load",i),i(),()=>{a(),l?.disconnect(),g?.removeEventListener?.("change",i),s?.removeEventListener("stx:load",i)}}var lo=64;var sn=/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/,ln=/^(?:0|[1-9]\d*)$/;function ct(e){let t=[],n=[],r=e&&typeof e==="object"&&!Array.isArray(e)?e:{};for(let[o,i]of Object.entries(r)){let a=i&&typeof i==="object"?i:null;if(!a){n.push(`spotlight kind "${o}" is not an object`);continue}let{slots:s,route:l}=a,g=typeof a.noun==="string"&&a.noun.trim()?a.noun.trim():"Item";if(!sn.test(o)||o.includes("-slot-")){n.push(`spotlight kind "${o}" is not a usable name: lowercase letters, digits and single dashes, and never "-slot-"`);continue}if(typeof s!=="number"||!Number.isInteger(s)||s<=0||s>64){n.push(`spotlight kind "${o}" needs slots between 1 and 64, not ${String(s)}`);continue}if(typeof l!=="string"||!l.startsWith("/")||!l.includes(":id")){n.push(`spotlight kind "${o}" needs a route starting with "/" and carrying ":id", not ${String(l)}`);continue}t.push({name:o,slots:s,route:l,noun:g})}return{kinds:t,problems:n}}function j(e,t){return e.find((n)=>n.name===t)??null}function Y(e,t,n){let r=j(e,t);if(!r||!Number.isInteger(n)||n<0||n>=r.slots)return null;return`${t}-slot-${n}`}function cn(e,t){if(typeof t!=="string")return null;let n=t.lastIndexOf("-slot-");if(n<=0)return null;let r=t.slice(0,n),o=t.slice(n+6);if(!ln.test(o))return null;let i=Number(o);return Y(e,r,i)===t?{kind:r,slot:i}:null}function ut(e){return e.flatMap((t)=>Array.from({length:t.slots},(n,r)=>`${t.name}-slot-${r}`))}function co(e,t){let n=e&&typeof e==="object"?e:{};if(n.enabled===!1)return[];let o=[...(Array.isArray(n.activityTypes)?n.activityTypes.filter((i)=>typeof i==="string"&&i.trim().length>0):[]).map((i)=>i.trim()),...ut(ct(n.kinds).kinds)];return[...new Set(o)].map((i)=>`${t}.${i}`)}function dt(e,t,n){let r=typeof n.name==="string"?n.name.replace(/\s+/g," ").trim():"";if(!r)return`${j(e,t)?.noun??"Item"} #${n.id}`;return r.length>120?`${r.slice(0,119).trimEnd()}…`:r}function un(e,t,n,r,o=Date.now()){let i=j(e,n);if(!i||!Number.isInteger(r.id)||r.id<=0)return null;let a=t.filter((m)=>m.kind===n),s=dt(e,n,r),l=a.find((m)=>m.itemId===r.id)??null,g=l?null:mn(a,i.slots),p=l||g!==null?null:gn(a),u=l?.slot??g??p?.slot;if(u===void 0||u===null)return null;let f={kind:n,slot:u,itemId:r.id,title:s,donatedAt:o},d=t.filter((m)=>m.kind!==n||m.slot!==u&&m.itemId!==r.id);return{entries:pt(e,[...d,f]),entry:f,evicted:p,changed:!l||l.title!==s}}function dn(e,t,n){let r=e.find((o)=>o.kind===t&&o.itemId===n)??null;return{entries:r?e.filter((o)=>o!==r):[...e],removed:r}}function pn(e,t,n){let r=cn(e,n);if(!r)return null;let o=t.find((a)=>a.kind===r.kind&&a.slot===r.slot),i=j(e,r.kind)?.route;return o&&i?i.replace(":id",String(o.itemId)):null}function fn(e,t){if(!Array.isArray(t))return[];let n=new Map,r=new Set;for(let o of t){if(!o||typeof o!=="object")continue;let i=o,{kind:a,slot:s,itemId:l,title:g,donatedAt:p}=i;if(typeof a!=="string"||typeof s!=="number"||Y(e,a,s)===null)continue;if(typeof l!=="number"||!Number.isInteger(l)||l<=0)continue;let u=`${a}-slot-${s}`,f=`${a}#${l}`;if(n.has(u)||r.has(f))continue;n.set(u,{kind:a,slot:s,itemId:l,title:typeof g==="string"&&g.trim()?g:dt(e,a,{id:l}),donatedAt:typeof p==="number"&&Number.isFinite(p)&&p>0?p:0}),r.add(f)}return pt(e,[...n.values()])}function pt(e,t){let n=new Map(e.map((r,o)=>[r.name,o]));return[...t].sort((r,o)=>(n.get(r.kind)??0)-(n.get(o.kind)??0)||r.slot-o.slot)}function mn(e,t){let n=new Set(e.map((r)=>r.slot));for(let r=0;r<t;r++)if(!n.has(r))return r;return null}function gn(e){return e.reduce((t,n)=>!t||n.donatedAt<t.donatedAt?n:t,null)}function hn(){let e=globalThis.craft;return e&&typeof e==="object"?e.siri:void 0}var bn="stacks_spotlight_index",vn=3000;function uo(e){let t=e.onProblem??((b)=>console.warn(`[spotlight] ${b}`)),n=Array.isArray(e.kinds)?{kinds:[...e.kinds],problems:[]}:ct(e.kinds);for(let b of n.problems)t(b);let r=e.enabled===!1?[]:n.kinds,o=e.storageKey??bn,i=e.legacyStorageKeys??[],a=e.timeoutMs??vn,s=e.now??(()=>Date.now()),l=e.bridge??hn,g=null;function p(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function u(){if(g)return g;g=[];let b=p();if(!b)return g;try{let y=[o,...i].map((w)=>b.getItem(w)).find((w)=>w);g=y?fn(r,JSON.parse(y)):[]}catch{g=[]}return g}function f(b){g=b;let y=p();if(!y)return;try{y.setItem(o,JSON.stringify(b));for(let w of i)y.removeItem(w)}catch{}}async function d(b){if(!b)return null;let y;try{return await Promise.race([b,new Promise((w)=>{y=setTimeout(()=>w(null),a)})])}catch{return null}finally{if(y!==void 0)clearTimeout(y)}}let m=Promise.resolve();function h(b){let y=m.then(b,b);return m=y.catch(()=>{return}),y}async function k(b,y){let w=l()?.register;if(!w||r.length===0)return!1;return h(async()=>{let T=un(r,u(),b,y,s()),H=T&&Y(r,b,T.entry.slot);if(!T||!H)return!1;if(!T.changed)return f(T.entries),!0;let K=await d(w(T.entry.title,H))!==null;if(K)f(T.entries);return K})}async function C(b,y){let w=l()?.remove;if(!w)return!1;return h(async()=>{let{entries:T,removed:H}=dn(u(),b,y);if(!H)return!1;let K=Y(r,b,H.slot),St=K?await d(w(K))!==null:!1;return f(T),St})}async function F(b,y){let w=j(r,b)?.slots;if(!w||!l()?.register)return 0;let T=0;for(let H of[...y].slice(0,w).reverse())if(await k(b,H))T++;return T}async function x(){let b=l()?.remove;if(!b)return f([]),0;return h(async()=>{let y=0;for(let w of u()){let T=Y(r,w.kind,w.slot);if(T&&await d(b(T))!==null)y++}return f([]),y})}return{kinds:r,index:k,sync:F,remove:C,clear:x,routeFor:(b)=>pn(r,u(),b),entries:()=>u(),activityTypes:(b)=>ut(r).map((y)=>`${b}.${y}`),reset:()=>{g=null}}}var lt=["craftShortcut","craftSiriShortcut"];function po(e,t){let n=(r)=>{let o=r.detail,i=typeof o==="string"?o:o&&typeof o==="object"?o.action??o.type:null,a=typeof i==="string"?e.routeFor(i):null;if(a)t(a)};if(typeof globalThis.addEventListener!=="function")return()=>{};for(let r of lt)globalThis.addEventListener(r,n);return()=>{for(let r of lt)globalThis.removeEventListener(r,n)}}import{tabBar as yn}from"craft-native/mobile";var Sn=yn;function xn(e){return Array.from(e.querySelectorAll("a[data-native-tab]")).map((t)=>({id:t.getAttribute("href")||"",title:t.getAttribute("data-native-tab")||t.getAttribute("aria-label")||"",symbol:t.getAttribute("data-native-tab-symbol")||"circle",badge:(t.querySelector(".native-tab-badge")?.textContent||"").trim(),current:t.hasAttribute("data-stx-nav-current")||t.classList.contains("is-active")})).filter((t)=>t.id&&t.title)}function wn(e){return{tabs:e.map(({id:n,title:r,symbol:o,badge:i})=>i?{id:n,title:r,symbol:o,badge:i}:{id:n,title:r,symbol:o}),selected:e.find((n)=>n.current)?.id}}function mt(){if(typeof window>"u")return;let e=window.stxRouter;return e&&typeof e==="object"?e:void 0}function An(){return typeof mt()?.selectTab==="function"}function go(e,t={}){let n=(r)=>{if(An()||r.defaultPrevented)return;let o=r.target?.closest?.("a[data-native-tab]");if(!o||!e.contains(o))return;if(!o.hasAttribute("data-stx-nav-current")&&!o.classList.contains("is-active")&&o.getAttribute("aria-current")!=="page")return;r.preventDefault();let i=e.ownerDocument.defaultView;if(t.scrollToTop)t.scrollToTop();else i?.scrollTo?.({top:0,behavior:i.matchMedia?.("(prefers-reduced-motion: reduce)").matches?"auto":"smooth"});i?.dispatchEvent(new CustomEvent("stx:tabreselect",{detail:{href:o.getAttribute("href")||""}}))};return e.addEventListener("click",n),()=>e.removeEventListener("click",n)}function ft(e){let t=e.trim();return/^#[0-9a-f]{6}$/i.test(t)?t:void 0}var we="stacks:tab-bar-cover";function ho(e,t){if(t)e.setAttribute("data-native-covers-tab-bar","");else e.removeAttribute("data-native-covers-tab-bar");e.ownerDocument?.defaultView?.dispatchEvent(new Event(we))}function bo(e,t={}){let n=t.api??Sn;if(!n.isAvailable())return null;let r=t.hidden??(()=>Boolean(e.ownerDocument?.querySelector("[data-native-hide-tab-bar], [data-native-covers-tab-bar]"))),o=typeof getComputedStyle==="function"?getComputedStyle(e):null,i=ft(o?.getPropertyValue("--native-tab-active")||""),a=ft(o?.getPropertyValue("--native-tab-active-dark")||""),s="",l=()=>{if(r()){if(s!=="hidden")n.hide();s="hidden";return}let{tabs:f,selected:d}=wn(xn(e)),m=JSON.stringify({tabs:f,selected:d});if(m===s)return;let h=s&&s!=="hidden"?JSON.parse(s):null;if(h&&d&&JSON.stringify(h.tabs)===JSON.stringify(f))n.select(d);else n.set(f,{selected:d,tint:i,tintDark:a});s=m},g=typeof MutationObserver==="function"?new MutationObserver(l):null;g?.observe(e,{attributes:!0,attributeFilter:["data-stx-nav-current","class"],childList:!0,subtree:!0,characterData:!0});let p=n.onSelect((f)=>{let d=mt();if(d?.selectTab){d.selectTab(f);return}Array.from(e.querySelectorAll("a[data-native-tab]")).find((h)=>h.getAttribute("href")===f)?.click()}),u=()=>l();if(typeof window<"u")window.addEventListener("stx:load",u),window.addEventListener("stx:screen-shown",u),window.addEventListener(we,u);return l(),()=>{if(g?.disconnect(),p(),typeof window<"u")window.removeEventListener("stx:load",u),window.removeEventListener("stx:screen-shown",u),window.removeEventListener(we,u);n.hide()}}var Rn={isAvailable:()=>c(()=>Ae.isAvailable()),getBiometricType:()=>c(()=>Ae.getBiometricType()),authenticate:(e)=>c(()=>Ae.authenticate(e))},Ln={takePicture:(e)=>c(()=>oe.takePicture(e)),pickImage:()=>c(()=>oe.pickImage()),pickMultiple:(e)=>c(()=>oe.pickMultiple(e)),isAvailable:()=>c(()=>oe.isAvailable())},Mn={getInfo:()=>c(()=>D.getInfo()),getCapabilities:()=>c(()=>D.getCapabilities()),isMobile:()=>D.isMobile(),isIOS:()=>D.isIOS(),isAndroid:()=>D.isAndroid(),getLocale:()=>D.getLocale(),getTimezone:()=>D.getTimezone()},Pn=En,Cn={getCurrentPosition:(e)=>c(()=>N.getCurrentPosition(e)),watchPosition:(e,t)=>N.watchPosition(e,t),clearWatch:(e)=>N.clearWatch(e),startRecording:(e)=>c(()=>N.startRecording(e)),pauseRecording:()=>c(()=>N.pauseRecording()),resumeRecording:()=>c(()=>N.resumeRecording()),stopRecording:()=>c(()=>N.stopRecording()),getRecordingState:()=>c(()=>N.getRecordingState()),readRecording:()=>c(()=>N.readRecording())},On={show:(e)=>c(()=>ae.show(e)),schedule:(e)=>c(()=>ae.schedule(e)),cancelAll:()=>c(()=>ae.cancelAll()),setBadge:(e)=>c(()=>ae.setBadge(e))},Nn={check:(e)=>c(()=>G.check(e)),request:(e)=>c(()=>G.request(e)),checkMultiple:(e)=>c(()=>G.checkMultiple(e)),requestMultiple:(e)=>c(()=>G.requestMultiple(e)),openSettings:()=>c(()=>G.openSettings())},In={set:(e,t)=>c(()=>se.set(e,t)),get:(e)=>c(()=>se.get(e)),delete:(e)=>c(()=>se.delete(e)),clear:()=>c(()=>se.clear())},Hn={share:(e)=>c(()=>vt.share(e)),isAvailable:()=>vt.isAvailable()},_n={request:()=>c(()=>kn.request())},ce={impact:(e)=>Promise.resolve().then(()=>ie.impact(e)).catch(()=>{}),notification:(e)=>Promise.resolve().then(()=>ie.notification(e)).catch(()=>{}),selection:()=>Promise.resolve().then(()=>ie.selection()).catch(()=>{}),vibrate:(e)=>Promise.resolve().then(()=>ie.vibrate(e)).catch(()=>{}),prepare:(e)=>{let t=L("haptics.prepare");return t?Promise.resolve().then(()=>t(e)).then(()=>{},()=>{}):Promise.resolve()}};function yt(e){if(typeof e==="string")return e.trim()||null;if(!e||typeof e!=="object")return null;let t=e.url;return typeof t==="string"&&t.trim()?t:null}var Dn={async getInitialURL(){if(!await B())return null;return yt(await gt.getInitialURL?.())},onLink(e){let t=null,n=!1,r=()=>{if(n)return;t=gt.onLink?.((o,i)=>{let a=yt(o);if(a)e(a,{initial:i?.initial===!0})})??null};if(de()?.craft)r();else B().then(r);return()=>{n=!0,t?.()}}},wo={isAvailable:()=>le.isAvailable(),set:(e,t)=>le.set(e,t),remove:(e)=>le.remove(e),clear:()=>le.clear()},Bn={enable:()=>c(()=>ht.enable()),disable:()=>c(()=>ht.disable())},Fn={isAvailable:()=>re.isAvailable(),get:()=>c(()=>re.get()),set:(e)=>c(()=>re.set(e)),restore:()=>c(()=>re.restore())},Kn={isAvailable:()=>P.isAvailable(),supports:(e)=>P.supports(e),getAuthorizationStatus:()=>c(()=>P.getAuthorizationStatus()),requestAuthorization:()=>c(()=>P.requestAuthorization()),getNowPlaying:()=>c(()=>P.getNowPlaying()),play:()=>c(()=>P.play()),pause:()=>c(()=>P.pause()),togglePlayPause:()=>c(()=>P.togglePlayPause()),skipToNext:()=>c(()=>P.skipToNext()),skipToPrevious:(e)=>c(()=>P.skipToPrevious(e)),onChange:(e)=>_(()=>P.onChange(e))},$n={isAvailable:()=>A.isAvailable(),supports:(e)=>A.supports(e),getState:()=>c(()=>A.getState()),requestAuthorization:()=>c(()=>A.requestAuthorization()),scan:(e)=>c(()=>A.scan(e)),stopScan:()=>c(()=>A.stopScan()),getDevices:()=>c(()=>A.getDevices()),connect:(e)=>c(()=>A.connect(e)),reconnect:()=>c(()=>A.reconnect()),disconnect:(e)=>c(()=>A.disconnect(e)),startRecording:()=>c(()=>A.startRecording()),pauseRecording:()=>c(()=>A.pauseRecording()),resumeRecording:()=>c(()=>A.resumeRecording()),stopRecording:()=>c(()=>A.stopRecording()),getRecordingState:()=>c(()=>A.getRecordingState()),readRecording:(e)=>c(()=>A.readRecording(e)),onReading:(e)=>_(()=>A.onReading(e)),onDevice:(e)=>_(()=>A.onDevice(e)),onState:(e)=>_(()=>A.onState(e))},qn={isAvailable:()=>Te.isAvailable(),speak:(e,t)=>c(()=>Te.speak(e,t)),stop:()=>c(()=>Te.stop())},Un={getStatus:()=>c(()=>bt.getStatus()),onChange:(e)=>_(()=>bt.onChange(e))},Wn={register:()=>c(()=>Ee.register()),onToken:(e)=>Ee.onToken(e),onNotification:(e)=>_(()=>Ee.onNotification(e))},zn={requestAuthorization:(e,t)=>c(()=>V.requestAuthorization(e,t)),getData:(e,t)=>c(()=>V.getData(e,t)),saveWorkout:(e)=>c(()=>V.saveWorkout(e)),getWorkouts:(e)=>c(()=>V.getWorkouts(e)),getDailyStatistics:(e,t)=>c(()=>V.getDailyStatistics(e,t)),getHeartRateSamples:(e)=>v("health.getHeartRateSamples",[e??{}],()=>[]).then((t)=>Array.isArray(t)?t:[]),getSleepIntervals:(e)=>v("health.getSleepIntervals",[e??{}],()=>[]).then((t)=>Array.isArray(t)?t:[]),supports:(e)=>L(`health.${e}`)!==null},Yn={start:(e)=>c(()=>ke.start(e)),update:(e)=>c(()=>ke.update(e)),end:()=>c(()=>ke.end())},jn={send:(e)=>c(()=>X.send(e)),updateContext:(e)=>c(()=>X.updateContext(e)),isReachable:()=>c(()=>X.isReachable()),onMessage:(e)=>X.onMessage(e),onReachabilityChange:(e)=>X.onReachabilityChange(e)},Ao=Tn;function de(){return S()}function ue(){let e=de()?.craft;if(!e||typeof e!=="object")return null;if(!("platform"in e)||e.platform!=="ios"&&e.platform!=="android")return null;let t="capabilities"in e?e.capabilities:void 0,n=t&&typeof t==="object"&&!Array.isArray(t)?Object.fromEntries(Object.entries(t).filter(([,r])=>typeof r==="boolean")):{};return{platform:e.platform,capabilities:n}}function Re(){return ue()!==null}function Vn(e=2000){if(Re()||pe())return Promise.resolve(!0);let t=de();if(!t||!(t.craft||t.webkit?.messageHandlers?.craft))return Promise.resolve(!1);return new Promise((n)=>{let r=()=>{clearTimeout(o),t.removeEventListener("craftReady",r),n(Re())},o=setTimeout(r,e);t.addEventListener("craftReady",r,{once:!0})})}function Gn(e){let t=de();if(!t)return()=>{};if(ue()){let r=!1;return queueMicrotask(()=>{if(!r)e(new Event("craftReady"))}),()=>{r=!0}}let n=(r)=>{if(!ue())return;t.removeEventListener("craftReady",n),e(r)};return t.addEventListener("craftReady",n),()=>t.removeEventListener("craftReady",n)}async function Xn(e){await ce.impact("light");try{let t=await e();return await ce.notification("success"),t}catch(t){throw await ce.notification("error"),t}}var ko={get nativeBridge(){return ue()},biometrics:Rn,camera:Ln,device:Mn,haptics:ce,lifecycle:Pn,location:Cn,notifications:On,permissions:Nn,secureStorage:In,share:Hn,appReview:_n,deepLinks:Dn,keepAwake:Bn,brightness:Fn,music:Kn,heartRate:$n,speech:qn,network:Un,pushNotifications:Wn,health:zn,liveActivities:Yn,watchConnectivity:jn,dialog:q,contextMenu:ve,browser:Ke,symbols:$e,statusBar:Q,chrome:U,refresh:I,background:W,clipboard:qe,db:Ue,files:We,shortcuts:ze,widgets:Ye,orientation:je,auth:Ve,storeKit:Ge,isNativeMobile:Re,whenNative:Vn,onReady:Gn,withFeedback:Xn};export{Jn as BRIDGE_WAIT_MS,Hr as HEART_RATE_MATCH_MS,zr as INDOOR_CHECK_AFTER_S,lo as MAX_SPOTLIGHT_SLOTS_PER_KIND,Yt as ROUTE_GAP_S,Qr as SHEET_FLICK_VELOCITY,we as TAB_BAR_COVER_EVENT,c as afterBridge,_n as appReview,nn as applyAppearance,Wt as attachHeartRate,Ve as auth,Lr as backLabelFor,W as background,Rn as biometrics,J as bridgePending,Fn as brightness,Ke as browser,v as callNative,Ln as camera,Kt as canGoBack,U as chrome,qe as clipboard,or as confirmAction,ve as contextMenu,ho as coverTabBar,S as craftHost,xt as craftRoot,Br as createRouteRecorder,uo as createSpotlightIndex,Je as currentAppearance,Ue as db,qt as deepLinkPath,Dn as deepLinks,Mn as device,q as dialog,Rr as enterNavTrail,We as files,Vt as fixDistance,dr as focusSegment,Nr as followDeepLinks,ue as getNativeMobileBridge,Tr as goBack,Cr as goBackToTabRoot,go as handleTabReselect,ce as haptics,pe as hasNativeMobileHost,zn as health,$n as heartRate,Yr as indoorVerdict,ao as installNativeChrome,pr as installPressables,Re as isNativeMobile,Jt as isShown,Bn as keepAwake,Bt as largeTitleMetrics,Pn as lifecycle,to as liftToBody,Yn as liveActivities,Cn as location,eo as lockBackground,bo as mirrorTabBar,ko as mobile,Kn as music,kt as nativeFunction,L as nativeFunctionNow,wn as nativeTabs,Mr as navTrail,Un as network,It as normalizeAppearance,yt as normalizeDeepLinkURL,On as notifications,Ar as observeLargeTitle,lr as observeLongPress,Xr as observeNativeRefresh,_t as observePageScroll,wr as observePullToRefresh,cr as observeSegmentScrub,Zr as observeSheetDrag,Qe as onAppearance,yr as onBackgroundRefresh,O as onCraftEvent,br as onMemoryWarning,Gn as onMobileReady,hr as onResume,vr as onSilentPush,po as onSpotlightTap,je as orientation,_r as paceLabel,on as pageBackground,an as pageIsDark,z as pageScrollTop,$r as pauseSessionClock,Nn as permissions,Mt as placeMenu,un as placeSpotlightItem,Ie as presentActionSheet,Oe as presentAlert,fe as presentChoice,Ne as presentConfirm,He as presentContextMenu,no as presentPageAsCard,Pr as previousScreenPath,Dt as pullDistance,Wn as pushNotifications,fn as readSpotlightEntries,ct as readSpotlightKinds,xn as readTabLinks,I as refresh,dn as removeSpotlightItem,kr as resolveScrollHost,qr as resumeSessionClock,rt as routeStats,An as routerHandlesTabs,tn as rubberBand,In as secureStorage,Nt as segmentAt,ur as segmentForKey,Ur as sessionClockElapsed,en as settleSheet,Hn as share,Zt as sheetStops,ze as shortcuts,ir as showContextMenuFor,wo as snapshots,qn as speech,Dr as speedLabel,Ao as splash,Y as spotlightAction,ut as spotlightActions,co as spotlightActivityTypes,hn as spotlightBridge,j as spotlightKind,pn as spotlightRoute,cn as spotlightSlot,dt as spotlightTitle,Kr as startSessionClock,Q as statusBar,Ge as storeKit,_ as subscribeWhenReady,$e as symbols,Sn as tabBar,be as toNativeRect,Or as trailEntryFor,Lt as trapFocus,jr as typedDistanceKm,Gt as usableFixes,rr as useActionSheet,jn as watchConnectivity,B as whenBridgeReady,Vn as whenNativeMobile,Ye as widgets,Xn as withNativeFeedback};
|
|
55
|
+
`;function Oe(){return S()?.document}function Pt(e){if(e.getElementById(Ce))return;let t=e.createElement("style");t.id=Ce,t.textContent=Mt,(e.head??e.documentElement).appendChild(t)}var Ct=0;function E(e,t,n,r){let o=e.createElement(t);if(o.className=n,r!==void 0)o.textContent=r;return o}var Ne='button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function Ot(e,t){if(t.key!=="Tab")return;let n=Array.from(e.querySelectorAll(Ne));if(n.length===0){t.preventDefault();return}let r=n[0],o=n[n.length-1],i=e.ownerDocument.activeElement;if(t.shiftKey&&(i===r||!e.contains(i)))t.preventDefault(),o.focus();else if(!t.shiftKey&&(i===o||!e.contains(i)))t.preventDefault(),r.focus()}function Ie(e,t,n,r){Pt(e);let o=S(),i=e.activeElement,a=E(e,"div",`native-dialog native-dialog--${t}`);return a.setAttribute("data-native-dialog",t),a.appendChild(E(e,"div","native-dialog-backdrop")),new Promise((s)=>{let l=!1,g=(h)=>{if(l)return;l=!0,a.classList.remove("is-open"),e.removeEventListener("keydown",p,!0),setTimeout(()=>{if(a.remove(),i&&typeof i.focus==="function")i.focus()},260),s(h)},p=(h)=>{if(h.key==="Escape"){h.preventDefault(),g(r());return}Ot(u,h)},u=n({root:a,settle:g});a.appendChild(u),e.body.appendChild(a),e.addEventListener("keydown",p,!0);let f=o;(typeof f?.requestAnimationFrame==="function"?(h)=>f.requestAnimationFrame(()=>f.requestAnimationFrame(h)):(h)=>setTimeout(h,16))(()=>{if(!l)a.classList.add("is-open")}),(u.querySelector("[data-native-autofocus]")??u.querySelector(Ne))?.focus()})}function he(e){let t=Oe();if(!t?.body)return Promise.resolve(null);let n=`native-dialog-${++Ct}`,r=e.actions.find((a)=>a.style==="cancel"),o=e.variant==="sheet"?e.actions.filter((a)=>a.style!=="cancel"):e.actions,i=e.variant==="sheet"?r??{id:"__cancel",title:e.cancelLabel||"Cancel",style:"cancel"}:void 0;return Ie(t,e.variant,({root:a,settle:s})=>{let l=(d)=>d.style==="cancel"?null:d.id,g=E(t,"div","native-dialog-panel");g.setAttribute("role","alertdialog"),g.setAttribute("aria-modal","true"),g.tabIndex=-1;let p=E(t,"div","native-dialog-group");if(e.title||e.message){let d=E(t,"div","native-dialog-header");if(e.title){let m=E(t,"p","native-dialog-title",e.title);m.id=`${n}-title`,d.appendChild(m),g.setAttribute("aria-labelledby",m.id)}if(e.message){let m=E(t,"p","native-dialog-message",e.message);m.id=`${n}-message`,d.appendChild(m),g.setAttribute("aria-describedby",m.id)}p.appendChild(d)}let u=E(t,"div","native-dialog-actions");if(e.variant==="alert"&&o.length===2)u.classList.add("is-row");for(let d of o){let m=E(t,"button",`native-dialog-action${d.style==="destructive"?" is-destructive":""}${d.style==="cancel"?" is-cancel":""}`,d.title);m.type="button",m.setAttribute("data-action-id",d.id),m.addEventListener("click",()=>s(l(d))),u.appendChild(m)}if(p.appendChild(u),g.appendChild(p),i){let d=E(t,"div","native-dialog-group"),m=E(t,"button","native-dialog-action is-cancel",i.title);m.type="button",m.setAttribute("data-action-id",i.id),m.addEventListener("click",()=>s(null)),d.appendChild(m),g.appendChild(d)}let f=a.querySelector(".native-dialog-backdrop");if(e.variant==="sheet")f?.addEventListener("click",()=>s(null));return g},()=>{if(e.variant==="sheet")return null;if(r)return null;return o.length===1?o[0].id:null})}async function He(e){await he({variant:"alert",title:e.title,message:e.message,actions:[{id:"ok",title:e.okLabel||"OK"}]})}async function De(e){return await he({variant:"alert",title:e.title,message:e.message,actions:[{id:"cancel",title:e.cancelLabel||"Cancel",style:"cancel"},{id:"confirm",title:e.confirmLabel||"OK",style:e.destructive?"destructive":"default"}]})==="confirm"}function _e(e){return he({variant:"sheet",title:e.title,message:e.message,actions:e.actions,cancelLabel:e.cancelLabel})}function Nt(e,t,n){let i=Math.max(12,Math.min(e.x,n.width-t.width-12)),a=e.y+e.height+8,s=a+t.height<=n.height-12,l=e.y-8-t.height,g=s||l<12?Math.max(12,Math.min(a,n.height-t.height-12)):l,p=e.x+e.width/2>n.width/2?"right":"left";return{top:g,left:i,origin:`${s||l<12?"top":"bottom"} ${p}`}}function Be(e){let t=Oe();if(!t?.body)return Promise.resolve(null);let n=S();return Ie(t,"menu",({root:r,settle:o})=>{let i=E(t,"div","native-menu native-dialog-panel");if(i.setAttribute("role","menu"),e.title)i.appendChild(E(t,"p","native-menu-title",e.title)),i.setAttribute("aria-label",e.title);for(let a of e.items){let s=E(t,"button",`native-menu-item${a.destructive?" is-destructive":""}`);if(s.type="button",s.setAttribute("role","menuitem"),s.setAttribute("data-action-id",a.id),a.disabled)s.disabled=!0;if(s.appendChild(E(t,"span","native-menu-label",a.title)),a.icon){let l=E(t,"i",`native-menu-icon ${a.icon}`);l.setAttribute("aria-hidden","true"),s.appendChild(l)}s.addEventListener("click",()=>o(a.id)),i.appendChild(s)}return r.querySelector(".native-dialog-backdrop")?.addEventListener("click",()=>o(null)),queueMicrotask(()=>{let a=i.getBoundingClientRect?.(),s=Nt(e.anchor,{width:a?.width||248,height:a?.height||e.items.length*44},{width:n?.innerWidth||390,height:n?.innerHeight||844});i.style.top=`${s.top}px`,i.style.left=`${s.left}px`,i.style.setProperty("--native-menu-origin",s.origin)}),i},()=>null)}var $e=()=>!0,T=()=>!1,M=()=>null;function Fe(){return S()?.navigator??(typeof navigator>"u"?void 0:navigator)}function Se(e){return{x:Math.round(e.x??e.left??0),y:Math.round(e.y??e.top??0),width:Math.round(e.width),height:Math.round(e.height)}}var z={alert:(e)=>v("dialog.alert",[e],()=>He(e),{fallbackOnError:!0}).then(()=>{}),confirm:(e)=>v("dialog.confirm",[e],()=>De(e),{fallbackOnError:!0}).then(Boolean),actionSheet:async(e)=>{let t={...e,anchor:e.anchor?Se(e.anchor):void 0},n=await v("dialog.actionSheet",[t],()=>_e(e),{fallbackOnError:!0});if(typeof n!=="string")return null;return e.actions.find((r)=>r.id===n)?.style==="cancel"?null:n}};function ur(){return(e)=>z.actionSheet(e)}async function dr(e){if((e.style??(e.destructive?"sheet":"alert"))==="alert")return z.confirm(e);return await z.actionSheet({title:e.title,message:e.message,anchor:e.anchor,actions:[{id:"confirm",title:e.confirmLabel||"OK",style:e.destructive?"destructive":"default"},{id:"cancel",title:e.cancelLabel||"Cancel",style:"cancel"}]})==="confirm"}var xe={show:async(e)=>{let t={title:e.title,anchor:Se(e.anchor),items:e.items.map(({id:r,title:o,symbol:i,destructive:a,disabled:s})=>({id:r,title:o,symbol:i,destructive:a,disabled:s}))},n=await v("contextMenu.show",[t],()=>Be(e),{fallbackOnError:!0});return typeof n==="string"?n:null}};function pr(e,t){return xe.show({...t,anchor:Se(e.getBoundingClientRect())})}function It(e,t){let n=S();if(!n)return{cancelled:!0};if(typeof n.craft?.openURL==="function")return Promise.resolve(n.craft.openURL(e)).catch(()=>{}),{cancelled:!1};if(t.mode==="auth")return n.location?.assign(e),{cancelled:!1};if(!(typeof n.open==="function"?n.open(e,"_blank","noopener"):null))n.location?.assign(e);return{cancelled:!1}}var ze={open:async(e,t={})=>{let n=await v("browser.open",[e,t],()=>It(e,t),{fallbackOnError:!0});if(!n||typeof n!=="object")return{cancelled:!1};let{url:r,cancelled:o}=n;return typeof r==="string"?{url:r,cancelled:Boolean(o)}:{cancelled:Boolean(o)}}},be=new Map,ve=new Map;function We(e,t){return`${e}|${t.pointSize??""}|${t.weight??""}|${t.color??""}|${t.scale??""}`}var qe={isAvailable:()=>L("symbols.image")!==null,image:(e,t={})=>{let n=We(e,t),r=be.get(n);if(r)return r;let o=v("symbols.image",[e,t],M).then((i)=>typeof i==="string"&&i.startsWith("data:")?i:null,M).then((i)=>(ve.set(n,i),i));return be.set(n,o),o},cached:(e,t={})=>ve.get(We(e,t)),clearCache:()=>{be.clear(),ve.clear()}},Z={setStyle:(e)=>v("statusBar.setStyle",[e],T,{fallbackOnError:!0}).then((t)=>t!==!1)},q={setUnderPageColor:(e)=>v("chrome.setUnderPageColor",[e],T,{fallbackOnError:!0}).then((t)=>t!==!1),setKeyboardAccessory:(e)=>v("chrome.setKeyboardAccessory",[e],T,{fallbackOnError:!0}).then((t)=>t!==!1)},I={isAvailable:()=>L("refresh.enable")!==null,enable:(e)=>v("refresh.enable",[e??{}],T,{fallbackOnError:!0}).then((t)=>t!==!1),disable:()=>v("refresh.disable",[],T,{fallbackOnError:!0}).then((e)=>e!==!1),end:()=>v("refresh.end",[],T,{fallbackOnError:!0}).then((e)=>e!==!1),onRefresh:(e)=>O("craftRefresh",()=>e())},U={complete:(e)=>v("background.complete",[e],T,{fallbackOnError:!0}).then((t)=>t!==!1)},Ue={write:(e)=>v("clipboard.write",[e],async()=>{let t=Fe()?.clipboard;if(!t?.writeText)return!1;return t.writeText(e).then($e,T)},{fallbackOnError:!0}).then((t)=>t!==!1),read:()=>v("clipboard.read",[],async()=>{let e=Fe()?.clipboard;if(!e?.readText)return null;return e.readText().catch(M)},{fallbackOnError:!0}).then((e)=>typeof e==="string"?e:null)},je={isAvailable:()=>L("db.query")!==null,query:(e,t=[])=>v("db.query",[e,t],M).then((n)=>Array.isArray(n)?n:null),execute:(e,t=[])=>v("db.execute",[e,t],M).then((n)=>{if(!n||typeof n!=="object")return null;let{rowsAffected:r,lastInsertId:o}=n;return{rowsAffected:Number(r)||0,lastInsertId:Number(o)||0}})};function ye(e,t){let n=S()?.document;if(!n?.body)return null;let r=n.createElement("a");return r.href=e,r.download=t,r.rel="noopener",r.style.display="none",n.body.appendChild(r),r.click(),r.remove(),t}function Ht(e){let t=S()?.document;if(!t?.body)return Promise.resolve(null);return new Promise((n)=>{let r=t.createElement("input");if(r.type="file",r.style.display="none",e.length)r.accept=e.map((i)=>i.includes("/")||i.startsWith(".")?i:`.${i}`).join(",");let o=(i)=>{r.remove(),n(i)};r.addEventListener("cancel",()=>o(null)),r.addEventListener("change",()=>{let i=r.files?.[0];if(!i)return o(null);let a=new FileReader;a.onload=()=>o({name:i.name,mimeType:i.type||void 0,data:typeof a.result==="string"?a.result:void 0}),a.onerror=()=>o({name:i.name,mimeType:i.type||void 0}),a.readAsDataURL(i)}),t.body.appendChild(r),r.click()})}var Ye={openPDF:(e,t=0)=>v("openPDF",[e,t],()=>{let n=S();return Boolean(n?.open?.(e,"_blank","noopener"))}).then((n)=>n!==!1),takeScreenshot:()=>v("takeScreenshot",[],M,{fallbackOnError:!0}).then((e)=>typeof e==="string"?e:null),scanQRCode:()=>v("scanQRCode",[],M).then((e)=>{if(!e||typeof e!=="object")return null;let{type:t,data:n}=e;return typeof n==="string"?{type:String(t??""),data:n}:null},M),pickFile:(e=[])=>v("pickFile",[e],()=>Ht(e)).then((t)=>{if(!t||typeof t!=="object")return null;let n=t;if(typeof n.name!=="string")return null;return{name:n.name,path:typeof n.path==="string"?n.path:void 0,data:typeof n.data==="string"?n.data:void 0,mimeType:typeof n.mimeType==="string"?n.mimeType:void 0}},M),saveFile:(e,t,n)=>v("saveFile",[e,t,n],()=>{if(e.startsWith("data:"))return ye(e,t);let r=new Blob([e],{type:n||"text/plain"}),o=URL.createObjectURL(r),i=ye(o,t);return setTimeout(()=>URL.revokeObjectURL(o),1000),i}).then((r)=>typeof r==="string"?r:null),downloadFile:(e,t)=>v("downloadFile",[e,t],()=>ye(e,t)).then((n)=>typeof n==="string"?n:null)},Ge={set:(e)=>v("shortcuts.set",[e.map(({symbol:t,...n})=>t?{...n,iconName:t}:n)],T).then((t)=>t!==!1),clear:()=>v("shortcuts.clear",[],T).then((e)=>e!==!1),onShortcut:(e)=>O("craftShortcut",(t)=>{if(typeof t.type==="string")e(t.type)})},Ve={update:(e)=>v("widget.update",[e],T).then((t)=>t!==!1),reload:()=>v("widget.reload",[],T).then((e)=>e!==!1)},Dt={portrait:"portrait-primary",portraitUpsideDown:"portrait-secondary",landscape:"landscape",landscapeLeft:"landscape-primary",landscapeRight:"landscape-secondary"};function Ke(){return S()?.screen?.orientation}var Xe={lock:(e)=>v("lockOrientation",[e],()=>{let t=Ke();return t?.lock?t.lock(Dt[e]).then($e,T):!1}).then((t)=>t!==!1),unlock:()=>v("unlockOrientation",[],()=>(Ke()?.unlock?.(),!0)).then((e)=>e!==!1)},Je={signInWithApple:(e={})=>v("signInWithApple",e.nonce?[{nonce:e.nonce}]:[],M).then((t)=>{if(!t||typeof t!=="object"||typeof t.userId!=="string")return null;return t})},Qe={isAvailable:()=>L("iap.purchase")!==null,products:(e)=>v("iap.getProducts",[e],()=>[]).then((t)=>Array.isArray(t)?t:[]),purchase:(e)=>v("iap.purchase",[e],M).then((t)=>t&&typeof t==="object"?t:null,(t)=>{if(/cancel/i.test(String(t?.message??t)))return null;throw t}),restore:()=>v("iap.restore",[],()=>[]).then((e)=>Array.isArray(e)?e:[])};var _t=["authorized","denied","notDetermined","restricted","unsupported"];function ee(){let e=me(),t=e?.scheduledWorkouts;if(!t||typeof t!=="object"||e?.capabilities?.scheduledWorkouts!==!0)return;return t}function Bt(){return Object.assign(Error("unsupported"),{code:"UNSUPPORTED"})}function Ze(e){return _t.includes(e)?e:"unsupported"}function Ft(e){if(!e||typeof e!=="object")return null;let t=e;if(typeof t.id!=="string"||!t.id||typeof t.date!=="string"||!/^\d{4}-\d{2}-\d{2}$/.test(t.date))return null;let n={id:t.id.toLowerCase(),date:t.date,complete:t.complete===!0};if(typeof t.hour==="number"&&Number.isFinite(t.hour))n.hour=t.hour;if(typeof t.minute==="number"&&Number.isFinite(t.minute))n.minute=t.minute;return n}function F(e,t,...n){return c(async()=>{let r=ee();if(typeof r?.[e]!=="function")throw Bt();return t(await r[e](...n))})}var et={isAvailable:()=>typeof ee()?.isSupported==="function",supports:(e)=>typeof ee()?.[e]==="function",isSupported:()=>c(async()=>{let e=ee();if(typeof e?.isSupported!=="function")return!1;try{return await e.isSupported()===!0}catch{return!1}}),authorization:()=>F("authorization",Ze),requestAuthorization:()=>F("requestAuthorization",Ze),list:()=>F("list",(e)=>Array.isArray(e)?e.map(Ft).filter((t)=>t!==null):[]),schedule:(e)=>{if(!e||typeof e!=="object"||typeof e.id!=="string")return Promise.reject(Object.assign(Error("schedule needs a plan with an id"),{code:"INVALID_ARGUMENT"}));return F("schedule",(t)=>{let n=t&&typeof t==="object"?t:{},r={id:(typeof n.id==="string"?n.id:e.id).toLowerCase()};if(Array.isArray(n.droppedAlerts)&&n.droppedAlerts.length)r.droppedAlerts=n.droppedAlerts.filter((o)=>typeof o==="string");return r},e)},remove:(e)=>F("remove",(t)=>t===!0,e),removeAll:()=>F("removeAll",(e)=>typeof e==="number"&&Number.isFinite(e)?e:0)};function br(e,t){let n=t.delay??500,r=t.tolerance??10,o=null,i=null,a=!1,s=()=>{if(o)clearTimeout(o);if(o=null,i&&!a)t.onPressEnd?.();i=null},l=(f)=>{let d=f;if(d.button!==void 0&&d.button!==0)return;a=!1,i={x:d.clientX,y:d.clientY},t.onPressStart?.(),o=setTimeout(()=>{if(o=null,!i)return;a=!0,t.onLongPress({...i}),i=null},n)},g=(f)=>{if(!i)return;let d=f;if(Math.hypot(d.clientX-i.x,d.clientY-i.y)>r)s()},p=(f)=>{if(!a)return;a=!1,f.preventDefault(),f.stopPropagation()},u=(f)=>f.preventDefault();return e.addEventListener("pointerdown",l),e.addEventListener("pointermove",g),e.addEventListener("pointerup",s),e.addEventListener("pointercancel",s),e.addEventListener("pointerleave",s),e.addEventListener("click",p,!0),e.addEventListener("contextmenu",u),()=>{s(),e.removeEventListener("pointerdown",l),e.removeEventListener("pointermove",g),e.removeEventListener("pointerup",s),e.removeEventListener("pointercancel",s),e.removeEventListener("pointerleave",s),e.removeEventListener("click",p,!0),e.removeEventListener("contextmenu",u)}}function Wt(e,t,n){if(n<=1||t.width<=0)return 0;let r=Math.floor((e-t.left)/t.width*n);return Math.max(0,Math.min(n-1,r))}function vr(e,t){let n=null,r=null,o=!1,i=0,a=(d)=>{let m=e.getBoundingClientRect();return Wt(d,{left:m.left+2,width:m.width-4},t.count())},s=(d)=>{let m=d;if(m.button!==void 0&&m.button!==0)return;let h=a(m.clientX);if(h!==t.selected())return;n=h,i=h,o=!1,r=m.pointerId;try{e.setPointerCapture?.(m.pointerId)}catch{}t.onPress?.(!0)},l=(d)=>{if(n===null)return;let m=a(d.clientX);if(m===i)return;o=!0,i=m,t.onScrub(m)},g=(d)=>{if(n===null)return;if(r!==null)try{e.releasePointerCapture?.(r)}catch{}if(t.onPress?.(!1),d&&o)t.onCommit(i);else if(o)t.onScrub(n);n=null,r=null},p=(d)=>{if(!o)return;o=!1,d.preventDefault(),d.stopPropagation()},u=()=>g(!0),f=()=>g(!1);return e.addEventListener("pointerdown",s),e.addEventListener("pointermove",l),e.addEventListener("pointerup",u),e.addEventListener("pointercancel",f),e.addEventListener("click",p,!0),()=>{e.removeEventListener("pointerdown",s),e.removeEventListener("pointermove",l),e.removeEventListener("pointerup",u),e.removeEventListener("pointercancel",f),e.removeEventListener("click",p,!0)}}function yr(e,t,n){if(n<=0)return null;switch(e){case"ArrowRight":case"ArrowDown":return(t+1)%n;case"ArrowLeft":case"ArrowUp":return(t-1+n)%n;case"Home":return 0;case"End":return n-1;default:return null}}function Sr(e,t){e.querySelectorAll('[role="tab"]')[t]?.focus()}function xr(e){let t=(n)=>{if(!n.target?.closest?.("[data-native-pressable]"))return;let o=L("haptics.prepare");if(o)Promise.resolve().then(()=>o("impact")).catch(()=>{})};return e.addEventListener("touchstart",t,{passive:!0,capture:!0}),()=>e.removeEventListener("touchstart",t,{capture:!0})}function Ae(e){let t=S();try{return Boolean(t?.matchMedia?.(e).matches)}catch{return!1}}function tt(e){return e!==null&&e!==void 0&&e!=="false"&&e!=="0"}function nt(){let e=S()?.document?.documentElement,t=Number.parseFloat(e?.style?.getPropertyValue("--craft-font-scale")||"");return{fontScale:Number.isFinite(t)&&t>0?t:1,reduceMotion:tt(e?.getAttribute("data-craft-reduce-motion"))||Ae("(prefers-reduced-motion: reduce)"),reduceTransparency:tt(e?.getAttribute("data-craft-reduce-transparency"))||Ae("(prefers-reduced-transparency: reduce)"),colorScheme:e?.classList?.contains("dark")||Ae("(prefers-color-scheme: dark)")?"dark":"light"}}function Kt(e){let t=nt(),n=Number(e?.fontScale);return{contentSizeCategory:typeof e?.contentSizeCategory==="string"?e.contentSizeCategory:void 0,fontScale:Number.isFinite(n)&&n>0?n:t.fontScale,reduceMotion:typeof e?.reduceMotion==="boolean"?e.reduceMotion:t.reduceMotion,reduceTransparency:typeof e?.reduceTransparency==="boolean"?e.reduceTransparency:t.reduceTransparency,colorScheme:e?.colorScheme==="dark"||e?.colorScheme==="light"?e.colorScheme:t.colorScheme}}function rt(e,t={}){if(t.immediate!==!1)e(nt());return O("craftAppearance",(n)=>e(Kt(n)))}function Er(e){return O("craftResume",(t)=>e({backgroundedMs:Number(t.backgroundedMs)||0}))}function Rr(e){return O("craftMemoryWarning",()=>e())}function ot(e){return(t)=>{Promise.resolve().then(()=>e(t)).then(()=>U.complete(!0),()=>U.complete(!1))}}function Tr(e){let t=ot(e);return O("craftSilentPush",(n)=>t(n.payload??{}))}function Lr(e){let t=ot(()=>e());return O("craftBackgroundRefresh",()=>t(void 0))}import{haptics as $t}from"craft-native/mobile";function we(){if(typeof window>"u")return;return window}function j(e=we()){if(!e)return 0;if(typeof e.scrollY==="number")return e.scrollY;if(typeof e.scrollTop==="number")return e.scrollTop;return e.document?.scrollingElement?.scrollTop??0}function zt(e,t=we()){if(!t)return()=>{};let n=!1,r=typeof requestAnimationFrame==="function"?requestAnimationFrame:(i)=>setTimeout(i,16),o=()=>{if(n)return;n=!0,r(()=>{n=!1,e(j(t))})};return e(j(t)),t.addEventListener("scroll",o,{passive:!0}),()=>t.removeEventListener("scroll",o)}function qt(e,t){let n=Math.max(0,-e),r=e<=0?Math.max(0,t)*0.5:0;return Math.round(Math.max(n,r))}function Cr(e){let t=e.host??we();if(!t)return()=>{};let n=e.threshold??72,r=null,o=!1,i=!1,a=typeof requestAnimationFrame==="function"?requestAnimationFrame:(h)=>setTimeout(h,16),s=null,l=(h)=>{s=null,e.onPull?.(h,o,{bounce:Math.min(h,Math.max(0,-j(t)))})},g=(h)=>{let k=s!==null;if(s=h,k)return;a(()=>{if(s!==null)l(s)})},p=(h)=>{let k=h.touches?.[0];return k?k.clientY:null},u=(h)=>{if(i||j(t)>0)return;r=p(h),o=!1},f=(h)=>{if(r===null)return;let k=p(h);if(k===null)return;let C=qt(j(t),k-r);if(!o&&C>=n)o=!0,Promise.resolve($t.impact("medium")).catch(()=>{});else if(o&&C<n*0.8)o=!1;g(C)},d=async()=>{if(r===null)return;if(r=null,!o){l(0);return}o=!1,i=!0,l(n);try{await e.onRefresh()}finally{i=!1,l(0)}},m=()=>{if(r===null)return;r=null,o=!1,l(0)};return t.addEventListener("touchstart",u,{passive:!0}),t.addEventListener("touchmove",f,{passive:!0}),t.addEventListener("touchend",d),t.addEventListener("touchcancel",m),()=>{s=null,t.removeEventListener("touchstart",u),t.removeEventListener("touchmove",f),t.removeEventListener("touchend",d),t.removeEventListener("touchcancel",m)}}function Ut(e,t=52){let n=Math.max(1,t),r=Math.min(1,Math.max(0,e/n)),o=e<0?1+Math.min(0.1,-e/600):1;return{progress:Math.round(r*1000)/1000,stretch:Math.round(o*1000)/1000}}function Or(e,t={}){let n="",r=()=>t.title?.offsetHeight||t.height||52;return zt((o)=>{let i=Ut(o,r()),a=`${i.progress}|${i.stretch}`;if(a===n)return;n=a,e.style.setProperty("--native-nav-progress",String(i.progress)),e.style.setProperty("--native-nav-stretch",String(i.stretch)),t.onChange?.(i)},t.host)}function Nr(e){if(!e||typeof window>"u")return;let t=window.document?.querySelector(e);return t?t:void 0}function st(){if(typeof window>"u")return;return window}var it="__stxPushed",jt="__stxScroll";function Yt(e=st()){let t=e?.history?.state;if(t===null||t===void 0)return!1;if(typeof t!=="object")return!0;let n=t;if(it in n)return n[it]===!0;return!(jt in n)}function Hr(e=st()){if(!Yt(e))return!1;return e.history.back(),!0}function Dr(e,t,n=50){let r=e[e.length-1];if(e.length>=2&&e[e.length-2].path===t)e.pop();else if(!r||r.path!==t)e.push({path:t,title:""});if(e.length>n)e.splice(0,e.length-n);return{current:e[e.length-1],previous:e[e.length-2]??null}}function _r(e,t,n=12){let r=e?.title.trim()??"";return r&&r.length<=n?r:t}function Br(){if(typeof window>"u")return[];let e=window;return e.__stacksNavTrail??=[]}function Gt(e){try{let t=new URL(e,"http://local");return`${t.pathname}${t.search}`}catch{return e}}function Fr(){if(typeof window>"u")return;let e=window.stxRouter;if(typeof e?.screens!=="function")return;let t=e.screens(),n=t.find((o)=>o.active);if(!n)return;let r=t.filter((o)=>o.tab===n.tab&&o.depth<n.depth);if(!r.length)return null;return Gt(r.reduce((o,i)=>i.depth>o.depth?i:o).url)}function Wr(e=typeof window>"u"?void 0:window){let t=e?.stxRouter;if(typeof t?.screens!=="function"||typeof e?.history?.go!=="function")return!1;let n=t.screens(),r=n.find((a)=>a.active);if(!r)return!1;let o=n.filter((a)=>a.tab===r.tab&&a.depth<r.depth);if(!o.length)return!1;let i=o.reduce((a,s)=>s.depth<a.depth?s:a);return e.history.go(i.depth-r.depth),!0}function Kr(e,t){for(let n=e.length-1;n>=0;n--)if(e[n].path===t)return e[n];return null}function Vt(e,t=Xt()){let n;try{n=new URL(e)}catch{return null}let r=`${n.search}${n.hash}`;if(n.protocol==="http:"||n.protocol==="https:"){if(!t||n.origin!==t)return null;return`${n.pathname||"/"}${r}`}return`${`/${[n.host,n.pathname.replace(/^\/+/,"")].filter(Boolean).join("/")}`}${r}`}function Xt(){if(typeof window>"u")return;return window.location?.origin}var at="stacks-mobile-deep-link";function $r(e,t){let n=(r)=>{let o=Vt(r);if(o)e(o)};return t.getInitialURL().then((r)=>{if(!r)return;try{if(sessionStorage.getItem(at)===r)return;sessionStorage.setItem(at,r)}catch{}n(r)}).catch(()=>{}),t.onLink((r,o)=>{if(o?.initial)return;n(r)})}var qr=5000;function Jt(e,t,n=5000){let r=t.filter((o)=>Number.isFinite(o.timestamp)&&Number.isFinite(o.bpm)&&o.bpm>0).slice().sort((o,i)=>o.timestamp-i.timestamp);if(!r.length)return e.slice();return e.map((o)=>{let i=0,a=r.length;while(i<a){let p=i+a>>1;if(r[p].timestamp<o.timestamp)i=p+1;else a=p}let s=r[i],l=r[i-1],g=!s?l:!l?s:o.timestamp-l.timestamp<=s.timestamp-o.timestamp?l:s;if(!g||Math.abs(g.timestamp-o.timestamp)>n)return o;return{...o,heartRate:Math.round(g.bpm)}})}var Qt=6371008.8,Zt=30,en=Zt;function tn(e,t){let n=Math.PI/180,r=(t.latitude-e.latitude)*n,o=(t.longitude-e.longitude)*n,i=Math.sin(r/2)**2+Math.cos(e.latitude*n)*Math.cos(t.latitude*n)*Math.sin(o/2)**2;return 2*Qt*Math.asin(Math.min(1,Math.sqrt(i)))}function nn(e,t=25){let n=new Set;return e.filter((r)=>Number.isFinite(r.latitude)&&Number.isFinite(r.longitude)&&Number.isFinite(r.timestamp)&&Math.abs(r.latitude)<=90&&Math.abs(r.longitude)<=180&&Number.isFinite(r.accuracy)&&r.accuracy>=0&&r.accuracy<=t).sort((r,o)=>r.timestamp-o.timestamp).filter((r)=>{if(n.has(r.timestamp))return!1;return n.add(r.timestamp),!0})}function lt(e,t={}){let n=nn(e,t.maxAccuracyM??25),r=t.paceWindowS??30,o=[],i=0,a=0,s=null;for(let u of n){let f=o[o.length-1],d=s?(u.timestamp-s.timestamp)/1000:0;if(s=u,!f){o.push({fix:u,cumM:0});continue}if(d>en){o.push({fix:u,cumM:i});continue}let m=(u.timestamp-f.fix.timestamp)/1000,h=tn(f.fix,u),k=Math.min(10,Math.max(3,f.fix.accuracy,u.accuracy));if(h<k)continue;if(i+=h,m>0&&h/m>=0.5)a+=m;o.push({fix:u,cumM:i})}let l=o[o.length-1],g=null,p=null;if(l&&n.at(-1).timestamp-l.fix.timestamp<=r*1000){let u=l.fix.timestamp-r*1000,f=o.find((h)=>h.fix.timestamp>=u)??l,d=l.cumM-f.cumM,m=(l.fix.timestamp-f.fix.timestamp)/1000;if(d>=20&&m>0)p=d/m,g=m/(d/1000)}return{distanceM:i,movingS:a,paceSPerKm:g,averagePaceSPerKm:i>=50&&a>0?a/(i/1000):null,speedMps:p,accuracyM:n.length?n[n.length-1].accuracy:e.length?e[e.length-1].accuracy??null:null,fixes:n.length}}function Ur(e){if(e==null||e<=0||!Number.isFinite(e)||e>3600)return"–";let t=Math.round(e);return`${Math.floor(t/60)}:${String(t%60).padStart(2,"0")}`}function jr(e){return e!=null&&e>0&&Number.isFinite(e)?(e*3.6).toFixed(1):"–"}var ct={distanceM:0,movingS:0,paceSPerKm:null,averagePaceSPerKm:null,speedMps:null,accuracyM:null,fixes:0};function Yr(e){let t=e.location,n=e.intervalMs??3000,r=ct,o=null,i=e.heartRate,a=!1,s=[],l=()=>typeof document<"u"&&document.visibilityState==="hidden",g=0,p=null,u=Promise.resolve(),f=null,d=!1;function m(x){let b=u.then(x);return u=b.then(()=>{},()=>{}),b}function h(){if(p)return p;let x=g;return p=(async()=>{let b=await t.readRecording();if(x===g&&!d)r=lt(b,e),e.onUpdate?.(r);return r})().finally(()=>{p=null}),p}function k(){if(C(),d)return;o=setInterval(()=>{if(!l())h().catch(()=>{})},n)}function C(){if(o)clearInterval(o);o=null}async function W(x){if(!i||!a)return;await x(i).catch(()=>{})}return{get stats(){return r},get heartRate(){return s},start(){return f=null,m(async()=>{if(await t.startRecording({enableHighAccuracy:!0,...e.locationOptions}),s=[],a=!!i?.isAvailable(),await W((x)=>x.startRecording()),g++,r={...ct},!d)e.onUpdate?.(r);return k(),r})},attach(){return m(async()=>{let x=await t.getRecordingState();if(!x?.active)return null;if(i?.isAvailable())a=!!(await i.getRecordingState().catch(()=>null))?.active;if(await h().catch(()=>{}),!x.paused)k();return x})},pause(){return m(async()=>{await t.pauseRecording(),await W((x)=>x.pauseRecording()),C(),await h().catch(()=>{})})},resume(){return m(async()=>{await t.resumeRecording(),await W((x)=>x.resumeRecording()),k()})},stop(){if(f)return f;return f=m(async()=>{C(),g++;let b=(await t.stopRecording())?.locations??[];if(i&&a){let y=await i.stopRecording().catch(()=>null);a=!1,s=y?.samples??[],b=Jt(b,s)}if(r=lt(b,e),!d)e.onUpdate?.(r);return b}).catch((x)=>{throw f=null,x}),f},dispose(){d=!0,g++,C()},refresh:h}}function Vr(e){return{startedAt:Number.isFinite(e)?e:null,pausedAt:null,pausedMs:0}}function Xr(e,t){return e.startedAt===null||e.pausedAt!==null||!Number.isFinite(t)?e:{...e,pausedAt:Math.max(e.startedAt,t)}}function Jr(e,t){return e.pausedAt===null||!Number.isFinite(t)?e:{...e,pausedAt:null,pausedMs:e.pausedMs+Math.max(0,t-e.pausedAt)}}function Qr(e,t){if(e.startedAt===null)return 0;let n=((e.pausedAt??t)-e.startedAt-e.pausedMs)/1000;return Number.isFinite(n)?Math.max(0,n):0}var eo=150;function rn(e,t){let n=Math.PI/180,r=(t.latitude-e.latitude)*n,o=(t.longitude-e.longitude)*n,i=Math.sin(r/2)**2+Math.cos(e.latitude*n)*Math.cos(t.latitude*n)*Math.sin(o/2)**2;return 12742017.6*Math.asin(Math.min(1,Math.sqrt(i)))}function te(e,t){let n=[...e].sort((r,o)=>r-o);return n[Math.min(n.length-1,Math.floor(t*n.length))]}function to(e,t){let n=(e||[]).filter((a)=>Number.isFinite(a?.latitude)&&Number.isFinite(a?.longitude)&&Math.abs(a.latitude)<=90&&Math.abs(a.longitude)<=180),r=n.filter((a)=>a.accuracy!=null).map((a)=>Number(a.accuracy)).filter((a)=>Number.isFinite(a)&&a>=0),o=r.length?te(r,0.5):Number.POSITIVE_INFINITY,i=0;if(n.length){let a={latitude:te(n.map((s)=>s.latitude),0.5),longitude:te(n.map((s)=>s.longitude),0.5)};i=te(n.map((s)=>rn(a,s)),0.8)}if(n.length>=10&&i>150&&o<=15)return"outside";if(t<150)return"unsure";if(n.length<3||o>30||i<25)return"indoors";if(i<50&&o>10)return"indoors";return"unsure"}function no(e,t={}){let r=String(e||"").trim().toLowerCase().replace(",",".").match(/^(\d+(?:\.\d*)?|\.\d+)\s*(km|k|m|mi)?$/);if(!r)return null;let o=Number(r[1]),i=r[2]||t.defaultUnit||(o>100?"m":"km"),a=i==="m"?o/1000:i==="mi"?o*1.609344:o;return Number.isFinite(a)&&a>=0&&a<=2000?Math.round(a*1000)/1000:null}var oe=new Set,ut=!1,ne=null;function on(e){return e.isConnected&&e.getClientRects().length>0}function dt(){return[...oe].find((e)=>on(e.element))}function re(){let e=dt(),t=Boolean(e);if(t===ut)return;if(ut=t,t)I.enable(e?.tintColor?{tintColor:e.tintColor}:{});else I.disable()}function an(){let e=dt();if(!e){I.end();return}Promise.resolve().then(()=>e.run()).catch(()=>{}).finally(()=>I.end())}function io(e,t){let n={element:e,tintColor:t.tintColor,run:t.onRefresh};oe.add(n);let r=e.ownerDocument?.defaultView;if(!ne){let o=I.onRefresh(an),i=()=>re();r?.addEventListener("stx:load",i),ne=()=>{o(),r?.removeEventListener("stx:load",i)}}return re(),r?.requestAnimationFrame?.(()=>re()),()=>{if(oe.delete(n),oe.size===0)ne?.(),ne=null;re()}}var so=0.5;function sn(e,t,n){let r=[];if(n.includes("large")||n.length===0)r.push({name:"large",y:0});if(n.includes("medium"))r.push({name:"medium",y:Math.max(0,Math.round(e-t*0.5))});return r.push({name:"dismiss",y:Math.max(1,e)}),r.sort((o,i)=>o.y-i.y)}function ln(e){let{y:t,velocity:n,stops:r}=e,o=r.filter((s)=>s.name!=="dismiss"),i=r.find((s)=>s.name==="dismiss");if(o.length===0)return"dismiss";if(n>0.5)return(r.filter((l)=>l.y>t+1)[0]??i).name;if(n<-0.5){let s=o.filter((l)=>l.y<t-1);return(s[s.length-1]??o[0]).name}let a=o[o.length-1];if(t>a.y+(i.y-a.y)*0.5)return"dismiss";return o.reduce((s,l)=>Math.abs(l.y-t)<Math.abs(s.y-t)?l:s).name}function cn(e,t=400){if(e<=0)return 0;return e*t*0.55/(t+e*0.55)}function lo(e){let{panel:t}=e,n=null,r=[],o=0,i=()=>e.viewport?.()??t.ownerDocument?.defaultView?.innerHeight??800,a=()=>sn(t.offsetHeight||t.getBoundingClientRect().height,i(),e.detents()),s=(p)=>{let u=p;if(u.button!==void 0&&u.button!==0)return;if(u.target?.closest?.("button, a, input, select, textarea, [role=button]"))return;let f=a().find((d)=>d.name===e.detent())?.y??0;n={y:u.clientY,base:f,pointerId:u.pointerId},o=f,r=[{y:f,t:u.timeStamp}],t.classList.add("is-dragging");try{p.currentTarget?.setPointerCapture?.(u.pointerId)}catch{}},l=(p)=>{if(!n)return;let u=p,f=n.base+u.clientY-n.y;o=f<0?-cn(-f):f,r.push({y:o,t:u.timeStamp});while(r.length>2&&u.timeStamp-r[0].t>100)r.shift();t.style.transform=`translateY(${o}px)`;let d=t.offsetHeight||1;t.parentElement?.style.setProperty("--native-sheet-presence",String(Math.max(0,Math.min(1,1-o/d))))},g=(p)=>{if(!n)return;let u=p;n=null;let f=r[0],d=Math.max(1,u.timeStamp-f.t),m=(o-f.y)/d;t.classList.remove("is-dragging"),t.style.transform="",t.parentElement?.style.removeProperty("--native-sheet-presence"),e.onSettle(ln({y:o,velocity:m,stops:a()}))};for(let p of e.handles)p.addEventListener("pointerdown",s),p.addEventListener("pointermove",l),p.addEventListener("pointerup",g),p.addEventListener("pointercancel",g);return()=>{for(let p of e.handles)p.removeEventListener("pointerdown",s),p.removeEventListener("pointermove",l),p.removeEventListener("pointerup",g),p.removeEventListener("pointercancel",g)}}var pt=0,ke="";function co(e){let t=e.ownerDocument,n=[],r=e;while(r.parentElement&&r!==t.body){for(let a of Array.from(r.parentElement.children)){if(a===r||a.hasAttribute("inert")||a.hasAttribute("data-native-dialog"))continue;if(["SCRIPT","STYLE","TEMPLATE","LINK"].includes(a.tagName))continue;if(a.hasAttribute("data-native-sheet")&&a.getAttribute("aria-hidden")==="true")continue;a.setAttribute("inert",""),n.push(a)}r=r.parentElement}let o=t.documentElement;if(pt++===0)ke=o.style.overflow||"",o.style.overflow="hidden";let i=!1;return()=>{if(i)return;i=!0;for(let a of n)a.removeAttribute("inert");if(--pt===0)if(ke)o.style.overflow=ke;else o.style.removeProperty("overflow")}}function uo(e){let t=e.ownerDocument;if(e.parentElement===t.body)return()=>{};let n=t.createComment("native-sheet");return e.parentNode?.insertBefore(n,e),t.body.appendChild(e),()=>{if(n.parentNode)n.parentNode.insertBefore(e,n);else e.remove();n.remove()}}function po(e,t){let n=e.documentElement;if(!t){n.removeAttribute("data-native-sheet-card");return}let r=e.defaultView,o=(r?.scrollY??0)+(r?.innerHeight??800)/2;n.style.setProperty("--native-sheet-card-origin",`${Math.round(o)}px`),n.setAttribute("data-native-sheet-card","")}function un(e,t){e.style.setProperty("--native-font-scale",String(t.fontScale)),e.toggleAttribute("data-native-reduce-motion",t.reduceMotion),e.toggleAttribute("data-native-reduce-transparency",t.reduceTransparency)}function dn(e){let t=e.replace(/\s+/g,"").toLowerCase();return!t||t==="transparent"||/^rgba\(\d+,\d+,\d+,0(\.0+)?\)$/.test(t)||/\/0(\.0+)?\)$/.test(t)}function pn(e){let t=e.defaultView;if(!t?.getComputedStyle)return null;for(let n of[e.body,e.documentElement]){if(!n)continue;let r=t.getComputedStyle(n).backgroundColor;if(r&&!dn(r))return r}return null}function fn(e){if(e.documentElement.classList.contains("dark"))return!0;if(e.documentElement.classList.contains("light"))return!1;return Boolean(e.defaultView?.matchMedia?.("(prefers-color-scheme: dark)").matches)}function ho(e,t={}){let n=t.root??e.documentElement;q.setKeyboardAccessory(t.keyboardAccessory===!0);let r="",o="",i=()=>{let p=pn(e);if(p&&p!==r)r=p,q.setUnderPageColor(p);let u=fn(e)?"light":"dark";if(u!==o)o=u,Z.setStyle(u)},a=rt((p)=>{un(n,p),i()}),s=e.defaultView,l=typeof s?.MutationObserver==="function"?new s.MutationObserver(i):null;l?.observe(e.documentElement,{attributes:!0,attributeFilter:["class","style","data-theme"]});let g=s?.matchMedia?.("(prefers-color-scheme: dark)");return g?.addEventListener?.("change",i),s?.addEventListener("stx:load",i),i(),()=>{a(),l?.disconnect(),g?.removeEventListener?.("change",i),s?.removeEventListener("stx:load",i)}}var vo=64;var mn=/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/,gn=/^(?:0|[1-9]\d*)$/;function mt(e){let t=[],n=[],r=e&&typeof e==="object"&&!Array.isArray(e)?e:{};for(let[o,i]of Object.entries(r)){let a=i&&typeof i==="object"?i:null;if(!a){n.push(`spotlight kind "${o}" is not an object`);continue}let{slots:s,route:l}=a,g=typeof a.noun==="string"&&a.noun.trim()?a.noun.trim():"Item";if(!mn.test(o)||o.includes("-slot-")){n.push(`spotlight kind "${o}" is not a usable name: lowercase letters, digits and single dashes, and never "-slot-"`);continue}if(typeof s!=="number"||!Number.isInteger(s)||s<=0||s>64){n.push(`spotlight kind "${o}" needs slots between 1 and 64, not ${String(s)}`);continue}if(typeof l!=="string"||!l.startsWith("/")||!l.includes(":id")){n.push(`spotlight kind "${o}" needs a route starting with "/" and carrying ":id", not ${String(l)}`);continue}t.push({name:o,slots:s,route:l,noun:g})}return{kinds:t,problems:n}}function G(e,t){return e.find((n)=>n.name===t)??null}function Y(e,t,n){let r=G(e,t);if(!r||!Number.isInteger(n)||n<0||n>=r.slots)return null;return`${t}-slot-${n}`}function hn(e,t){if(typeof t!=="string")return null;let n=t.lastIndexOf("-slot-");if(n<=0)return null;let r=t.slice(0,n),o=t.slice(n+6);if(!gn.test(o))return null;let i=Number(o);return Y(e,r,i)===t?{kind:r,slot:i}:null}function gt(e){return e.flatMap((t)=>Array.from({length:t.slots},(n,r)=>`${t.name}-slot-${r}`))}function yo(e,t){let n=e&&typeof e==="object"?e:{};if(n.enabled===!1)return[];let o=[...(Array.isArray(n.activityTypes)?n.activityTypes.filter((i)=>typeof i==="string"&&i.trim().length>0):[]).map((i)=>i.trim()),...gt(mt(n.kinds).kinds)];return[...new Set(o)].map((i)=>`${t}.${i}`)}function ht(e,t,n){let r=typeof n.name==="string"?n.name.replace(/\s+/g," ").trim():"";if(!r)return`${G(e,t)?.noun??"Item"} #${n.id}`;return r.length>120?`${r.slice(0,119).trimEnd()}…`:r}function bn(e,t,n,r,o=Date.now()){let i=G(e,n);if(!i||!Number.isInteger(r.id)||r.id<=0)return null;let a=t.filter((m)=>m.kind===n),s=ht(e,n,r),l=a.find((m)=>m.itemId===r.id)??null,g=l?null:xn(a,i.slots),p=l||g!==null?null:An(a),u=l?.slot??g??p?.slot;if(u===void 0||u===null)return null;let f={kind:n,slot:u,itemId:r.id,title:s,donatedAt:o},d=t.filter((m)=>m.kind!==n||m.slot!==u&&m.itemId!==r.id);return{entries:bt(e,[...d,f]),entry:f,evicted:p,changed:!l||l.title!==s}}function vn(e,t,n){let r=e.find((o)=>o.kind===t&&o.itemId===n)??null;return{entries:r?e.filter((o)=>o!==r):[...e],removed:r}}function yn(e,t,n){let r=hn(e,n);if(!r)return null;let o=t.find((a)=>a.kind===r.kind&&a.slot===r.slot),i=G(e,r.kind)?.route;return o&&i?i.replace(":id",String(o.itemId)):null}function Sn(e,t){if(!Array.isArray(t))return[];let n=new Map,r=new Set;for(let o of t){if(!o||typeof o!=="object")continue;let i=o,{kind:a,slot:s,itemId:l,title:g,donatedAt:p}=i;if(typeof a!=="string"||typeof s!=="number"||Y(e,a,s)===null)continue;if(typeof l!=="number"||!Number.isInteger(l)||l<=0)continue;let u=`${a}-slot-${s}`,f=`${a}#${l}`;if(n.has(u)||r.has(f))continue;n.set(u,{kind:a,slot:s,itemId:l,title:typeof g==="string"&&g.trim()?g:ht(e,a,{id:l}),donatedAt:typeof p==="number"&&Number.isFinite(p)&&p>0?p:0}),r.add(f)}return bt(e,[...n.values()])}function bt(e,t){let n=new Map(e.map((r,o)=>[r.name,o]));return[...t].sort((r,o)=>(n.get(r.kind)??0)-(n.get(o.kind)??0)||r.slot-o.slot)}function xn(e,t){let n=new Set(e.map((r)=>r.slot));for(let r=0;r<t;r++)if(!n.has(r))return r;return null}function An(e){return e.reduce((t,n)=>!t||n.donatedAt<t.donatedAt?n:t,null)}function wn(){let e=globalThis.craft;return e&&typeof e==="object"?e.siri:void 0}var kn="stacks_spotlight_index",En=3000;function So(e){let t=e.onProblem??((b)=>console.warn(`[spotlight] ${b}`)),n=Array.isArray(e.kinds)?{kinds:[...e.kinds],problems:[]}:mt(e.kinds);for(let b of n.problems)t(b);let r=e.enabled===!1?[]:n.kinds,o=e.storageKey??kn,i=e.legacyStorageKeys??[],a=e.timeoutMs??En,s=e.now??(()=>Date.now()),l=e.bridge??wn,g=null;function p(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function u(){if(g)return g;g=[];let b=p();if(!b)return g;try{let y=[o,...i].map((A)=>b.getItem(A)).find((A)=>A);g=y?Sn(r,JSON.parse(y)):[]}catch{g=[]}return g}function f(b){g=b;let y=p();if(!y)return;try{y.setItem(o,JSON.stringify(b));for(let A of i)y.removeItem(A)}catch{}}async function d(b){if(!b)return null;let y;try{return await Promise.race([b,new Promise((A)=>{y=setTimeout(()=>A(null),a)})])}catch{return null}finally{if(y!==void 0)clearTimeout(y)}}let m=Promise.resolve();function h(b){let y=m.then(b,b);return m=y.catch(()=>{return}),y}async function k(b,y){let A=l()?.register;if(!A||r.length===0)return!1;return h(async()=>{let R=bn(r,u(),b,y,s()),H=R&&Y(r,b,R.entry.slot);if(!R||!H)return!1;if(!R.changed)return f(R.entries),!0;let K=await d(A(R.entry.title,H))!==null;if(K)f(R.entries);return K})}async function C(b,y){let A=l()?.remove;if(!A)return!1;return h(async()=>{let{entries:R,removed:H}=vn(u(),b,y);if(!H)return!1;let K=Y(r,b,H.slot),Et=K?await d(A(K))!==null:!1;return f(R),Et})}async function W(b,y){let A=G(r,b)?.slots;if(!A||!l()?.register)return 0;let R=0;for(let H of[...y].slice(0,A).reverse())if(await k(b,H))R++;return R}async function x(){let b=l()?.remove;if(!b)return f([]),0;return h(async()=>{let y=0;for(let A of u()){let R=Y(r,A.kind,A.slot);if(R&&await d(b(R))!==null)y++}return f([]),y})}return{kinds:r,index:k,sync:W,remove:C,clear:x,routeFor:(b)=>yn(r,u(),b),entries:()=>u(),activityTypes:(b)=>gt(r).map((y)=>`${b}.${y}`),reset:()=>{g=null}}}var ft=["craftShortcut","craftSiriShortcut"];function xo(e,t){let n=(r)=>{let o=r.detail,i=typeof o==="string"?o:o&&typeof o==="object"?o.action??o.type:null,a=typeof i==="string"?e.routeFor(i):null;if(a)t(a)};if(typeof globalThis.addEventListener!=="function")return()=>{};for(let r of ft)globalThis.addEventListener(r,n);return()=>{for(let r of ft)globalThis.removeEventListener(r,n)}}import{tabBar as Rn}from"craft-native/mobile";var Tn=Rn;function Ln(e){return Array.from(e.querySelectorAll("a[data-native-tab]")).map((t)=>({id:t.getAttribute("href")||"",title:t.getAttribute("data-native-tab")||t.getAttribute("aria-label")||"",symbol:t.getAttribute("data-native-tab-symbol")||"circle",badge:(t.querySelector(".native-tab-badge")?.textContent||"").trim(),current:t.hasAttribute("data-stx-nav-current")||t.classList.contains("is-active")})).filter((t)=>t.id&&t.title)}function Mn(e){return{tabs:e.map(({id:n,title:r,symbol:o,badge:i})=>i?{id:n,title:r,symbol:o,badge:i}:{id:n,title:r,symbol:o}),selected:e.find((n)=>n.current)?.id}}function yt(){if(typeof window>"u")return;let e=window.stxRouter;return e&&typeof e==="object"?e:void 0}function Pn(){return typeof yt()?.selectTab==="function"}function ko(e,t={}){let n=(r)=>{if(Pn()||r.defaultPrevented)return;let o=r.target?.closest?.("a[data-native-tab]");if(!o||!e.contains(o))return;if(!o.hasAttribute("data-stx-nav-current")&&!o.classList.contains("is-active")&&o.getAttribute("aria-current")!=="page")return;r.preventDefault();let i=e.ownerDocument.defaultView;if(t.scrollToTop)t.scrollToTop();else i?.scrollTo?.({top:0,behavior:i.matchMedia?.("(prefers-reduced-motion: reduce)").matches?"auto":"smooth"});i?.dispatchEvent(new CustomEvent("stx:tabreselect",{detail:{href:o.getAttribute("href")||""}}))};return e.addEventListener("click",n),()=>e.removeEventListener("click",n)}function vt(e){let t=e.trim();return/^#[0-9a-f]{6}$/i.test(t)?t:void 0}var Ee="stacks:tab-bar-cover";function Eo(e,t){if(t)e.setAttribute("data-native-covers-tab-bar","");else e.removeAttribute("data-native-covers-tab-bar");e.ownerDocument?.defaultView?.dispatchEvent(new Event(Ee))}function Ro(e,t={}){let n=t.api??Tn;if(!n.isAvailable())return null;let r=t.hidden??(()=>Boolean(e.ownerDocument?.querySelector("[data-native-hide-tab-bar], [data-native-covers-tab-bar]"))),o=typeof getComputedStyle==="function"?getComputedStyle(e):null,i=vt(o?.getPropertyValue("--native-tab-active")||""),a=vt(o?.getPropertyValue("--native-tab-active-dark")||""),s="",l=()=>{if(r()){if(s!=="hidden")n.hide();s="hidden";return}let{tabs:f,selected:d}=Mn(Ln(e)),m=JSON.stringify({tabs:f,selected:d});if(m===s)return;let h=s&&s!=="hidden"?JSON.parse(s):null;if(h&&d&&JSON.stringify(h.tabs)===JSON.stringify(f))n.select(d);else n.set(f,{selected:d,tint:i,tintDark:a});s=m},g=typeof MutationObserver==="function"?new MutationObserver(l):null;g?.observe(e,{attributes:!0,attributeFilter:["data-stx-nav-current","class"],childList:!0,subtree:!0,characterData:!0});let p=n.onSelect((f)=>{let d=yt();if(d?.selectTab){d.selectTab(f);return}Array.from(e.querySelectorAll("a[data-native-tab]")).find((h)=>h.getAttribute("href")===f)?.click()}),u=()=>l();if(typeof window<"u")window.addEventListener("stx:load",u),window.addEventListener("stx:screen-shown",u),window.addEventListener(Ee,u);return l(),()=>{if(g?.disconnect(),p(),typeof window<"u")window.removeEventListener("stx:load",u),window.removeEventListener("stx:screen-shown",u),window.removeEventListener(Ee,u);n.hide()}}var In={isAvailable:()=>c(()=>Re.isAvailable()),getBiometricType:()=>c(()=>Re.getBiometricType()),authenticate:(e)=>c(()=>Re.authenticate(e))},Hn={takePicture:(e)=>c(()=>ae.takePicture(e)),pickImage:()=>c(()=>ae.pickImage()),pickMultiple:(e)=>c(()=>ae.pickMultiple(e)),isAvailable:()=>c(()=>ae.isAvailable())},Dn={getInfo:()=>c(()=>_.getInfo()),getCapabilities:()=>c(()=>_.getCapabilities()),isMobile:()=>_.isMobile(),isIOS:()=>_.isIOS(),isAndroid:()=>_.isAndroid(),getLocale:()=>_.getLocale(),getTimezone:()=>_.getTimezone()},_n=On,Bn={getCurrentPosition:(e)=>c(()=>N.getCurrentPosition(e)),watchPosition:(e,t)=>N.watchPosition(e,t),clearWatch:(e)=>N.clearWatch(e),startRecording:(e)=>c(()=>N.startRecording(e)),pauseRecording:()=>c(()=>N.pauseRecording()),resumeRecording:()=>c(()=>N.resumeRecording()),stopRecording:()=>c(()=>N.stopRecording()),getRecordingState:()=>c(()=>N.getRecordingState()),readRecording:()=>c(()=>N.readRecording())},Fn={show:(e)=>c(()=>le.show(e)),schedule:(e)=>c(()=>le.schedule(e)),cancelAll:()=>c(()=>le.cancelAll()),setBadge:(e)=>c(()=>le.setBadge(e))},Wn={check:(e)=>c(()=>X.check(e)),request:(e)=>c(()=>X.request(e)),checkMultiple:(e)=>c(()=>X.checkMultiple(e)),requestMultiple:(e)=>c(()=>X.requestMultiple(e)),openSettings:()=>c(()=>X.openSettings())},Kn={set:(e,t)=>c(()=>ce.set(e,t)),get:(e)=>c(()=>ce.get(e)),delete:(e)=>c(()=>ce.delete(e)),clear:()=>c(()=>ce.clear())},$n={share:(e)=>c(()=>wt.share(e)),isAvailable:()=>wt.isAvailable()},zn={request:()=>c(()=>Cn.request())},de={impact:(e)=>Promise.resolve().then(()=>se.impact(e)).catch(()=>{}),notification:(e)=>Promise.resolve().then(()=>se.notification(e)).catch(()=>{}),selection:()=>Promise.resolve().then(()=>se.selection()).catch(()=>{}),vibrate:(e)=>Promise.resolve().then(()=>se.vibrate(e)).catch(()=>{}),prepare:(e)=>{let t=L("haptics.prepare");return t?Promise.resolve().then(()=>t(e)).then(()=>{},()=>{}):Promise.resolve()}};function kt(e){if(typeof e==="string")return e.trim()||null;if(!e||typeof e!=="object")return null;let t=e.url;return typeof t==="string"&&t.trim()?t:null}var qn={async getInitialURL(){if(!await B())return null;return kt(await St.getInitialURL?.())},onLink(e){let t=null,n=!1,r=()=>{if(n)return;t=St.onLink?.((o,i)=>{let a=kt(o);if(a)e(a,{initial:i?.initial===!0})})??null};if(fe()?.craft)r();else B().then(r);return()=>{n=!0,t?.()}}},Oo={isAvailable:()=>ue.isAvailable(),set:(e,t)=>ue.set(e,t),remove:(e)=>ue.remove(e),clear:()=>ue.clear()},Un={enable:()=>c(()=>xt.enable()),disable:()=>c(()=>xt.disable())},jn={isAvailable:()=>ie.isAvailable(),get:()=>c(()=>ie.get()),set:(e)=>c(()=>ie.set(e)),restore:()=>c(()=>ie.restore())},Yn={isAvailable:()=>P.isAvailable(),supports:(e)=>P.supports(e),getAuthorizationStatus:()=>c(()=>P.getAuthorizationStatus()),requestAuthorization:()=>c(()=>P.requestAuthorization()),getNowPlaying:()=>c(()=>P.getNowPlaying()),play:()=>c(()=>P.play()),pause:()=>c(()=>P.pause()),togglePlayPause:()=>c(()=>P.togglePlayPause()),skipToNext:()=>c(()=>P.skipToNext()),skipToPrevious:(e)=>c(()=>P.skipToPrevious(e)),onChange:(e)=>D(()=>P.onChange(e))},Gn={isAvailable:()=>w.isAvailable(),supports:(e)=>w.supports(e),getState:()=>c(()=>w.getState()),requestAuthorization:()=>c(()=>w.requestAuthorization()),scan:(e)=>c(()=>w.scan(e)),stopScan:()=>c(()=>w.stopScan()),getDevices:()=>c(()=>w.getDevices()),connect:(e)=>c(()=>w.connect(e)),reconnect:()=>c(()=>w.reconnect()),disconnect:(e)=>c(()=>w.disconnect(e)),startRecording:()=>c(()=>w.startRecording()),pauseRecording:()=>c(()=>w.pauseRecording()),resumeRecording:()=>c(()=>w.resumeRecording()),stopRecording:()=>c(()=>w.stopRecording()),getRecordingState:()=>c(()=>w.getRecordingState()),readRecording:(e)=>c(()=>w.readRecording(e)),onReading:(e)=>D(()=>w.onReading(e)),onDevice:(e)=>D(()=>w.onDevice(e)),onState:(e)=>D(()=>w.onState(e))},Vn={isAvailable:()=>Me.isAvailable(),speak:(e,t)=>c(()=>Me.speak(e,t)),stop:()=>c(()=>Me.stop())},Xn={getStatus:()=>c(()=>At.getStatus()),onChange:(e)=>D(()=>At.onChange(e))},Jn={register:()=>c(()=>Le.register()),onToken:(e)=>Le.onToken(e),onNotification:(e)=>D(()=>Le.onNotification(e))},Qn={requestAuthorization:(e,t)=>c(()=>V.requestAuthorization(e,t)),getData:(e,t)=>c(()=>V.getData(e,t)),saveWorkout:(e)=>c(()=>V.saveWorkout(e)),getWorkouts:(e)=>c(()=>V.getWorkouts(e)),getDailyStatistics:(e,t)=>c(()=>V.getDailyStatistics(e,t)),getHeartRateSamples:(e)=>v("health.getHeartRateSamples",[e??{}],()=>[]).then((t)=>Array.isArray(t)?t:[]),getSleepIntervals:(e)=>v("health.getSleepIntervals",[e??{}],()=>[]).then((t)=>Array.isArray(t)?t:[]),saveMindfulSession:(e)=>v("health.saveMindfulSession",[e],()=>null).then((t)=>t??null),getMindfulSessions:(e)=>v("health.getMindfulSessions",[e??{}],()=>[]).then((t)=>Array.isArray(t)?t:[]),supports:(e)=>L(`health.${e}`)!==null},Zn={start:(e)=>c(()=>Te.start(e)),update:(e)=>c(()=>Te.update(e)),end:()=>c(()=>Te.end())},er={send:(e)=>c(()=>J.send(e)),updateContext:(e)=>c(()=>J.updateContext(e)),isReachable:()=>c(()=>J.isReachable()),onMessage:(e)=>J.onMessage(e),onReachabilityChange:(e)=>J.onReachabilityChange(e)},No=Nn;function fe(){return S()}function pe(){let e=fe()?.craft;if(!e||typeof e!=="object")return null;if(!("platform"in e)||e.platform!=="ios"&&e.platform!=="android")return null;let t="capabilities"in e?e.capabilities:void 0,n=t&&typeof t==="object"&&!Array.isArray(t)?Object.fromEntries(Object.entries(t).filter(([,r])=>typeof r==="boolean")):{};return{platform:e.platform,capabilities:n}}function Pe(){return pe()!==null}function tr(e=2000){if(Pe()||ge())return Promise.resolve(!0);let t=fe();if(!t||!(t.craft||t.webkit?.messageHandlers?.craft))return Promise.resolve(!1);return new Promise((n)=>{let r=()=>{clearTimeout(o),t.removeEventListener("craftReady",r),n(Pe())},o=setTimeout(r,e);t.addEventListener("craftReady",r,{once:!0})})}function nr(e){let t=fe();if(!t)return()=>{};if(pe()){let r=!1;return queueMicrotask(()=>{if(!r)e(new Event("craftReady"))}),()=>{r=!0}}let n=(r)=>{if(!pe())return;t.removeEventListener("craftReady",n),e(r)};return t.addEventListener("craftReady",n),()=>t.removeEventListener("craftReady",n)}async function rr(e){await de.impact("light");try{let t=await e();return await de.notification("success"),t}catch(t){throw await de.notification("error"),t}}var Io={get nativeBridge(){return pe()},biometrics:In,camera:Hn,device:Dn,haptics:de,lifecycle:_n,location:Bn,notifications:Fn,permissions:Wn,secureStorage:Kn,share:$n,appReview:zn,deepLinks:qn,keepAwake:Un,brightness:jn,music:Yn,heartRate:Gn,scheduledWorkouts:et,speech:Vn,network:Xn,pushNotifications:Jn,health:Qn,liveActivities:Zn,watchConnectivity:er,dialog:z,contextMenu:xe,browser:ze,symbols:qe,statusBar:Z,chrome:q,refresh:I,background:U,clipboard:Ue,db:je,files:Ye,shortcuts:Ge,widgets:Ve,orientation:Xe,auth:Je,storeKit:Qe,isNativeMobile:Pe,whenNative:tr,onReady:nr,withFeedback:rr};export{or as BRIDGE_WAIT_MS,qr as HEART_RATE_MATCH_MS,eo as INDOOR_CHECK_AFTER_S,vo as MAX_SPOTLIGHT_SLOTS_PER_KIND,Zt as ROUTE_GAP_S,so as SHEET_FLICK_VELOCITY,Ee as TAB_BAR_COVER_EVENT,c as afterBridge,zn as appReview,un as applyAppearance,Jt as attachHeartRate,Je as auth,_r as backLabelFor,U as background,In as biometrics,Q as bridgePending,jn as brightness,ze as browser,v as callNative,Hn as camera,Yt as canGoBack,q as chrome,Ue as clipboard,dr as confirmAction,xe as contextMenu,Eo as coverTabBar,S as craftHost,me as craftRoot,Yr as createRouteRecorder,So as createSpotlightIndex,nt as currentAppearance,je as db,Vt as deepLinkPath,qn as deepLinks,Dn as device,z as dialog,Dr as enterNavTrail,Ye as files,tn as fixDistance,Sr as focusSegment,$r as followDeepLinks,pe as getNativeMobileBridge,Hr as goBack,Wr as goBackToTabRoot,ko as handleTabReselect,de as haptics,ge as hasNativeMobileHost,Qn as health,Gn as heartRate,to as indoorVerdict,ho as installNativeChrome,xr as installPressables,Pe as isNativeMobile,on as isShown,Un as keepAwake,Ut as largeTitleMetrics,_n as lifecycle,uo as liftToBody,Zn as liveActivities,Bn as location,co as lockBackground,Ro as mirrorTabBar,Io as mobile,Yn as music,Lt as nativeFunction,L as nativeFunctionNow,Mn as nativeTabs,Br as navTrail,Xn as network,Kt as normalizeAppearance,kt as normalizeDeepLinkURL,Ft as normalizeScheduledWorkout,Fn as notifications,Or as observeLargeTitle,br as observeLongPress,io as observeNativeRefresh,zt as observePageScroll,Cr as observePullToRefresh,vr as observeSegmentScrub,lo as observeSheetDrag,rt as onAppearance,Lr as onBackgroundRefresh,O as onCraftEvent,Rr as onMemoryWarning,nr as onMobileReady,Er as onResume,Tr as onSilentPush,xo as onSpotlightTap,Xe as orientation,Ur as paceLabel,pn as pageBackground,fn as pageIsDark,j as pageScrollTop,Xr as pauseSessionClock,Wn as permissions,Nt as placeMenu,bn as placeSpotlightItem,_e as presentActionSheet,He as presentAlert,he as presentChoice,De as presentConfirm,Be as presentContextMenu,po as presentPageAsCard,Fr as previousScreenPath,qt as pullDistance,Jn as pushNotifications,Sn as readSpotlightEntries,mt as readSpotlightKinds,Ln as readTabLinks,I as refresh,vn as removeSpotlightItem,Nr as resolveScrollHost,Jr as resumeSessionClock,lt as routeStats,Pn as routerHandlesTabs,cn as rubberBand,et as scheduledWorkouts,Bt as scheduledWorkoutsUnsupported,Kn as secureStorage,Wt as segmentAt,yr as segmentForKey,Qr as sessionClockElapsed,ln as settleSheet,$n as share,sn as sheetStops,Ge as shortcuts,pr as showContextMenuFor,Oo as snapshots,Vn as speech,jr as speedLabel,No as splash,Y as spotlightAction,gt as spotlightActions,yo as spotlightActivityTypes,wn as spotlightBridge,G as spotlightKind,yn as spotlightRoute,hn as spotlightSlot,ht as spotlightTitle,Vr as startSessionClock,Z as statusBar,Qe as storeKit,D as subscribeWhenReady,qe as symbols,Tn as tabBar,Se as toNativeRect,Kr as trailEntryFor,Ot as trapFocus,no as typedDistanceKm,nn as usableFixes,ur as useActionSheet,er as watchConnectivity,B as whenBridgeReady,tr as whenNativeMobile,Ve as widgets,rr as withNativeFeedback};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AppleWorkoutPlan, ScheduledWorkout, ScheduledWorkoutsAuthorization } from './scheduled-workouts';
|
|
2
|
+
export declare function createScheduledWorkoutsFake(options?: ScheduledWorkoutsFakeOptions): ScheduledWorkoutsFake;
|
|
3
|
+
/** The activities Craft's shell knows by name (HKWorkoutActivityType cases). */
|
|
4
|
+
export declare const SCHEDULED_WORKOUT_ACTIVITIES: readonly string[];
|
|
5
|
+
export declare interface ScheduledWorkoutsFakeOptions {
|
|
6
|
+
supported?: boolean
|
|
7
|
+
authorization?: ScheduledWorkoutsAuthorization
|
|
8
|
+
grant?: 'authorized' | 'denied'
|
|
9
|
+
maxCount?: number
|
|
10
|
+
refuse?: (plan: AppleWorkoutPlan) => string | null | undefined
|
|
11
|
+
dropAlerts?: (plan: AppleWorkoutPlan) => string[]
|
|
12
|
+
}
|
|
13
|
+
export declare interface ScheduledWorkoutsFake {
|
|
14
|
+
readonly bridge: Record<ScheduledWorkoutsMethod, (...args: any[]) => Promise<unknown>>
|
|
15
|
+
readonly craft: { platform: 'ios', capabilities: { scheduledWorkouts: true }, scheduledWorkouts: ScheduledWorkoutsFake['bridge'] }
|
|
16
|
+
readonly scheduled: ScheduledWorkout[]
|
|
17
|
+
readonly calls: string[]
|
|
18
|
+
authorization: ScheduledWorkoutsAuthorization
|
|
19
|
+
}
|
|
20
|
+
declare type ScheduledWorkoutsMethod = 'isSupported' | 'authorization' | 'requestAuthorization' | 'list' | 'schedule' | 'remove' | 'removeAll';
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
declare function native(): Record<string, any> | undefined;
|
|
2
|
+
/** The rejection every call but `isSupported()` gets where nothing can schedule. */
|
|
3
|
+
export declare function scheduledWorkoutsUnsupported(): Error;
|
|
4
|
+
declare function authorizationOf(value: unknown): ScheduledWorkoutsAuthorization;
|
|
5
|
+
/** A row of `list()`, or null for one that is not a scheduled plan. */
|
|
6
|
+
export declare function normalizeScheduledWorkout(value: unknown): ScheduledWorkout | null;
|
|
7
|
+
declare function call<T>(method: ScheduledWorkoutsMethod, normalize: (value: unknown) => T, ...args: unknown[]): Promise<T>;
|
|
8
|
+
export declare const scheduledWorkouts: ScheduledWorkoutsApi;
|
|
9
|
+
export declare interface AppleWorkoutStep {
|
|
10
|
+
goal: AppleWorkoutGoal
|
|
11
|
+
alert?: AppleWorkoutAlert
|
|
12
|
+
displayName?: string
|
|
13
|
+
}
|
|
14
|
+
export declare interface AppleIntervalBlock {
|
|
15
|
+
iterations: number
|
|
16
|
+
steps: Array<{ purpose: 'work' | 'recovery', step: AppleWorkoutStep }>
|
|
17
|
+
}
|
|
18
|
+
export declare interface AppleCustomWorkout {
|
|
19
|
+
activity: string
|
|
20
|
+
location: 'indoor' | 'outdoor' | 'unknown'
|
|
21
|
+
swimmingLocation?: 'pool' | 'openWater'
|
|
22
|
+
poolLengthMeters?: number
|
|
23
|
+
displayName: string
|
|
24
|
+
warmup?: AppleWorkoutStep
|
|
25
|
+
cooldown?: AppleWorkoutStep
|
|
26
|
+
blocks: AppleIntervalBlock[]
|
|
27
|
+
}
|
|
28
|
+
export declare interface AppleWorkoutPlan {
|
|
29
|
+
id: string
|
|
30
|
+
date: string
|
|
31
|
+
hour?: number
|
|
32
|
+
minute?: number
|
|
33
|
+
workout: AppleCustomWorkout
|
|
34
|
+
}
|
|
35
|
+
/** A plan on the watch's schedule. */
|
|
36
|
+
export declare interface ScheduledWorkout {
|
|
37
|
+
id: string
|
|
38
|
+
date: string
|
|
39
|
+
hour?: number
|
|
40
|
+
minute?: number
|
|
41
|
+
complete: boolean
|
|
42
|
+
}
|
|
43
|
+
export declare interface ScheduleWorkoutResult {
|
|
44
|
+
id: string
|
|
45
|
+
droppedAlerts?: string[]
|
|
46
|
+
}
|
|
47
|
+
export declare interface ScheduledWorkoutsApi {
|
|
48
|
+
isAvailable: () => boolean
|
|
49
|
+
supports: (method: ScheduledWorkoutsMethod) => boolean
|
|
50
|
+
isSupported: () => Promise<boolean>
|
|
51
|
+
authorization: () => Promise<ScheduledWorkoutsAuthorization>
|
|
52
|
+
requestAuthorization: () => Promise<ScheduledWorkoutsAuthorization>
|
|
53
|
+
list: () => Promise<ScheduledWorkout[]>
|
|
54
|
+
schedule: (plan: AppleWorkoutPlan) => Promise<ScheduleWorkoutResult>
|
|
55
|
+
remove: (id: string) => Promise<boolean>
|
|
56
|
+
removeAll: () => Promise<number>
|
|
57
|
+
}
|
|
58
|
+
export type ScheduledWorkoutsAuthorization = 'authorized' | 'denied' | 'notDetermined' | 'restricted' | 'unsupported';
|
|
59
|
+
export type AppleWorkoutGoal = | { type: 'open' }
|
|
60
|
+
| { type: 'time', seconds: number }
|
|
61
|
+
| { type: 'distance', meters: number }
|
|
62
|
+
| { type: 'energy', kilocalories: number }
|
|
63
|
+
export type AppleWorkoutAlert = | { type: 'heartRate', min: number, max: number }
|
|
64
|
+
| { type: 'heartRateZone', zone: number }
|
|
65
|
+
/** Watts (PowerRangeAlert). */
|
|
66
|
+
| { type: 'power', min: number, max: number }
|
|
67
|
+
| { type: 'powerZone', zone: number }
|
|
68
|
+
/** Metres per second, the current speed (SpeedRangeAlert); a pace range is sent as speed. */
|
|
69
|
+
| { type: 'speed', min: number, max: number }
|
|
70
|
+
/** Per minute (CadenceRangeAlert). */
|
|
71
|
+
| { type: 'cadence', min: number, max: number }
|
|
72
|
+
export type ScheduledWorkoutsMethod = 'isSupported' | 'authorization' | 'requestAuthorization' | 'list' | 'schedule' | 'remove' | 'removeAll';
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bundled TypeScript declarations
|
|
3
|
-
* Generated from
|
|
3
|
+
* Generated from 4 source files
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { IosMobileConfig } from '@stacksjs/types';
|
|
@@ -9,7 +9,194 @@ import { IosMobileConfig } from '@stacksjs/types';
|
|
|
9
9
|
/** Bun-only build/test entrypoint. The browser runtime never imports the iOS builder. */
|
|
10
10
|
declare function prepareIosSimulatorDriver(config: IosMobileConfig, root?: string): { output: string, projectName: string };
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
// From: src/scheduled-workouts-fake.ts
|
|
13
|
+
declare function createScheduledWorkoutsFake(options?: ScheduledWorkoutsFakeOptions): ScheduledWorkoutsFake;
|
|
14
|
+
/** The activities Craft's shell knows by name (HKWorkoutActivityType cases). */
|
|
15
|
+
declare const SCHEDULED_WORKOUT_ACTIVITIES: readonly string[];
|
|
16
|
+
declare interface ScheduledWorkoutsFakeOptions {
|
|
17
|
+
supported?: boolean
|
|
18
|
+
authorization?: ScheduledWorkoutsAuthorization
|
|
19
|
+
grant?: 'authorized' | 'denied'
|
|
20
|
+
maxCount?: number
|
|
21
|
+
refuse?: (plan: AppleWorkoutPlan) => string | null | undefined
|
|
22
|
+
dropAlerts?: (plan: AppleWorkoutPlan) => string[]
|
|
23
|
+
}
|
|
24
|
+
declare interface ScheduledWorkoutsFake {
|
|
25
|
+
readonly bridge: Record<ScheduledWorkoutsMethod, (...args: any[]) => Promise<unknown>>
|
|
26
|
+
readonly craft: { platform: 'ios', capabilities: { scheduledWorkouts: true }, scheduledWorkouts: ScheduledWorkoutsFake['bridge'] }
|
|
27
|
+
readonly scheduled: ScheduledWorkout[]
|
|
28
|
+
readonly calls: string[]
|
|
29
|
+
authorization: ScheduledWorkoutsAuthorization
|
|
30
|
+
}
|
|
31
|
+
declare type ScheduledWorkoutsMethod = 'isSupported' | 'authorization' | 'requestAuthorization' | 'list' | 'schedule' | 'remove' | 'removeAll';
|
|
32
|
+
|
|
33
|
+
// From: src/scheduled-workouts.ts
|
|
34
|
+
declare function native(): Record<string, any> | undefined;
|
|
35
|
+
/** The rejection every call but `isSupported()` gets where nothing can schedule. */
|
|
36
|
+
declare function scheduledWorkoutsUnsupported(): Error;
|
|
37
|
+
declare function authorizationOf(value: unknown): ScheduledWorkoutsAuthorization;
|
|
38
|
+
/** A row of `list()`, or null for one that is not a scheduled plan. */
|
|
39
|
+
declare function normalizeScheduledWorkout(value: unknown): ScheduledWorkout | null;
|
|
40
|
+
declare function call<T>(method: ScheduledWorkoutsMethod_1, normalize: (value: unknown) => T, ...args: unknown[]): Promise<T>;
|
|
41
|
+
declare const scheduledWorkouts: ScheduledWorkoutsApi;
|
|
42
|
+
declare interface AppleWorkoutStep {
|
|
43
|
+
goal: AppleWorkoutGoal
|
|
44
|
+
alert?: AppleWorkoutAlert
|
|
45
|
+
displayName?: string
|
|
46
|
+
}
|
|
47
|
+
declare interface AppleIntervalBlock {
|
|
48
|
+
iterations: number
|
|
49
|
+
steps: Array<{ purpose: 'work' | 'recovery', step: AppleWorkoutStep }>
|
|
50
|
+
}
|
|
51
|
+
declare interface AppleCustomWorkout {
|
|
52
|
+
activity: string
|
|
53
|
+
location: 'indoor' | 'outdoor' | 'unknown'
|
|
54
|
+
swimmingLocation?: 'pool' | 'openWater'
|
|
55
|
+
poolLengthMeters?: number
|
|
56
|
+
displayName: string
|
|
57
|
+
warmup?: AppleWorkoutStep
|
|
58
|
+
cooldown?: AppleWorkoutStep
|
|
59
|
+
blocks: AppleIntervalBlock[]
|
|
60
|
+
}
|
|
61
|
+
declare interface AppleWorkoutPlan {
|
|
62
|
+
id: string
|
|
63
|
+
date: string
|
|
64
|
+
hour?: number
|
|
65
|
+
minute?: number
|
|
66
|
+
workout: AppleCustomWorkout
|
|
67
|
+
}
|
|
68
|
+
/** A plan on the watch's schedule. */
|
|
69
|
+
declare interface ScheduledWorkout {
|
|
70
|
+
id: string
|
|
71
|
+
date: string
|
|
72
|
+
hour?: number
|
|
73
|
+
minute?: number
|
|
74
|
+
complete: boolean
|
|
75
|
+
}
|
|
76
|
+
declare interface ScheduleWorkoutResult {
|
|
77
|
+
id: string
|
|
78
|
+
droppedAlerts?: string[]
|
|
79
|
+
}
|
|
80
|
+
declare interface ScheduledWorkoutsApi {
|
|
81
|
+
isAvailable: () => boolean
|
|
82
|
+
supports: (method: ScheduledWorkoutsMethod_1) => boolean
|
|
83
|
+
isSupported: () => Promise<boolean>
|
|
84
|
+
authorization: () => Promise<ScheduledWorkoutsAuthorization>
|
|
85
|
+
requestAuthorization: () => Promise<ScheduledWorkoutsAuthorization>
|
|
86
|
+
list: () => Promise<ScheduledWorkout[]>
|
|
87
|
+
schedule: (plan: AppleWorkoutPlan) => Promise<ScheduleWorkoutResult>
|
|
88
|
+
remove: (id: string) => Promise<boolean>
|
|
89
|
+
removeAll: () => Promise<number>
|
|
90
|
+
}
|
|
91
|
+
type ScheduledWorkoutsAuthorization = 'authorized' | 'denied' | 'notDetermined' | 'restricted' | 'unsupported';
|
|
92
|
+
type AppleWorkoutGoal = | { type: 'open' }
|
|
93
|
+
| { type: 'time', seconds: number }
|
|
94
|
+
| { type: 'distance', meters: number }
|
|
95
|
+
| { type: 'energy', kilocalories: number }
|
|
96
|
+
type AppleWorkoutAlert = | { type: 'heartRate', min: number, max: number }
|
|
97
|
+
| { type: 'heartRateZone', zone: number }
|
|
98
|
+
/** Watts (PowerRangeAlert). */
|
|
99
|
+
| { type: 'power', min: number, max: number }
|
|
100
|
+
| { type: 'powerZone', zone: number }
|
|
101
|
+
/** Metres per second, the current speed (SpeedRangeAlert); a pace range is sent as speed. */
|
|
102
|
+
| { type: 'speed', min: number, max: number }
|
|
103
|
+
/** Per minute (CadenceRangeAlert). */
|
|
104
|
+
| { type: 'cadence', min: number, max: number }
|
|
105
|
+
type ScheduledWorkoutsMethod_1 = 'isSupported' | 'authorization' | 'requestAuthorization' | 'list' | 'schedule' | 'remove' | 'removeAll';
|
|
106
|
+
|
|
107
|
+
// From: src/bridge.ts
|
|
108
|
+
/** The page's window, when there is one. */
|
|
109
|
+
declare function craftHost(): CraftHost | undefined;
|
|
110
|
+
/** `window.craft`, the bridge object, once installed. */
|
|
111
|
+
declare function craftRoot(): Record<string, any> | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* Whether this page runs inside Craft's phone shell, before the bridge exists.
|
|
114
|
+
*
|
|
115
|
+
* Craft installs `window.craft` once the page has finished loading on an older
|
|
116
|
+
* shell — images and all — so a bridge check answers `false` during setup on
|
|
117
|
+
* a phone, and a layout that decides then renders the website's chrome in the
|
|
118
|
+
* app. The transports are there from the start: Android's `CraftAndroid`
|
|
119
|
+
* interface, and on iOS the `craft` message handler. Craft's macOS windows
|
|
120
|
+
* carry that handler too, so on iOS an iPhone or iPad user agent is what makes
|
|
121
|
+
* it the phone app.
|
|
122
|
+
*/
|
|
123
|
+
declare function hasNativeMobileHost(): boolean;
|
|
124
|
+
/** A native host whose bridge object is not installed yet: worth waiting for. */
|
|
125
|
+
declare function bridgePending(): boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Resolves once the bridge object (`window.craft`) is installed: `true` then,
|
|
128
|
+
* `false` in a browser at once, or after `timeoutMs` in a host that never
|
|
129
|
+
* installs it.
|
|
130
|
+
*
|
|
131
|
+
* Not whenNativeMobile(), which answers `true` as soon as the phone shell is
|
|
132
|
+
* recognisable, before the bridge exists and before anything can be asked of it.
|
|
133
|
+
*/
|
|
134
|
+
declare function whenBridgeReady(timeoutMs?: unknown): Promise<boolean>;
|
|
135
|
+
/**
|
|
136
|
+
* The bridge function at `path` (`'dialog.confirm'`), or null when this host
|
|
137
|
+
* has none. Synchronous: no waiting for a bridge still on its way.
|
|
138
|
+
*/
|
|
139
|
+
declare function nativeFunctionNow(path: string): ((...args: any[]) => unknown) | null;
|
|
140
|
+
/**
|
|
141
|
+
* The bridge function at `path`, waiting for a native host's bridge to arrive
|
|
142
|
+
* first. Null in a browser, on a shell that predates the API, or when the
|
|
143
|
+
* bridge did not come within `timeoutMs`.
|
|
144
|
+
*/
|
|
145
|
+
declare function nativeFunction(path: string, timeoutMs?: unknown): Promise<((...args: any[]) => unknown) | null>;
|
|
146
|
+
/**
|
|
147
|
+
* Calls the bridge function at `path`, or `fallback` where there is none.
|
|
148
|
+
*
|
|
149
|
+
* Inside a native host whose bridge is still loading, the call is held until
|
|
150
|
+
* it arrives, so an early call reaches the native implementation rather than
|
|
151
|
+
* the web one.
|
|
152
|
+
*/
|
|
153
|
+
declare function callNative<T>(path: string, args: unknown[], fallback: () => T | Promise<T>, options?: CallNativeOptions): Promise<T>;
|
|
154
|
+
/**
|
|
155
|
+
* Runs `run` once a native host's bridge is installed: at once when it is
|
|
156
|
+
* there or in a browser, after it arrives (or `BRIDGE_WAIT_MS` passes) in a
|
|
157
|
+
* host still loading it.
|
|
158
|
+
*
|
|
159
|
+
* craft-native's services read `window.craft` at call time and take their web
|
|
160
|
+
* path when it is missing, which during an older shell's launch it is. The
|
|
161
|
+
* services this package exports call through here, as plain object literals
|
|
162
|
+
* rather than wrapped at import: a bundler drops an object literal nobody
|
|
163
|
+
* imports, and could not drop a call made at module scope once minified.
|
|
164
|
+
*/
|
|
165
|
+
declare function afterBridge<T>(run: () => T | Promise<T>, timeoutMs?: unknown): Promise<T>;
|
|
166
|
+
/**
|
|
167
|
+
* Subscribes once the bridge can take the subscription: at once when it is
|
|
168
|
+
* there or in a browser, otherwise when it arrives. The returned function
|
|
169
|
+
* unsubscribes either way, including before the subscription was made.
|
|
170
|
+
*/
|
|
171
|
+
declare function subscribeWhenReady(subscribe: () => (() => void) | void, timeoutMs?: unknown): () => void;
|
|
172
|
+
/** Listens for a Craft DOM event on the window; the detail is passed through. */
|
|
173
|
+
declare function onCraftEvent<T = Record<string, unknown>>(name: string, callback: (detail: T) => void): () => void;
|
|
174
|
+
/**
|
|
175
|
+
* Reaching Craft's bridge at the right moment.
|
|
176
|
+
*
|
|
177
|
+
* Craft's iOS shell injects `window.craft` at document start, but an older
|
|
178
|
+
* shell installs it once the page has finished loading. A call made before
|
|
179
|
+
* then used to find no bridge and quietly take the web path: a secure-storage
|
|
180
|
+
* read answered from localStorage, a confirm drew the browser's own dialog.
|
|
181
|
+
* Inside a native host, a call now waits for the bridge (briefly: a host that
|
|
182
|
+
* never installs one gets the web fallback after `BRIDGE_WAIT_MS`), and only a
|
|
183
|
+
* browser takes the fallback at once.
|
|
184
|
+
*/
|
|
185
|
+
/** How long a call waits for a native host's bridge before using the web fallback. */
|
|
186
|
+
declare const BRIDGE_WAIT_MS: 2500;
|
|
187
|
+
declare interface CraftHost extends EventTarget {
|
|
188
|
+
craft?: unknown
|
|
189
|
+
CraftAndroid?: unknown
|
|
190
|
+
webkit?: { messageHandlers?: Record<string, unknown> }
|
|
191
|
+
document?: Document
|
|
192
|
+
navigator?: Navigator
|
|
193
|
+
}
|
|
194
|
+
declare interface CallNativeOptions {
|
|
195
|
+
fallbackOnError?: boolean
|
|
196
|
+
timeoutMs?: number
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { prepareIosSimulatorDriver, ScheduledWorkoutsFake, ScheduledWorkoutsFakeOptions, createScheduledWorkoutsFake, SCHEDULED_WORKOUT_ACTIVITIES };
|
|
13
200
|
export { NativeMutationValidator } from 'craft-native/ios';
|
|
14
201
|
export { NativeValidationResult } from 'craft-native/ios';
|
|
15
202
|
export { SimulatorStep } from 'craft-native/ios';
|
package/dist/testing.js
CHANGED
|
@@ -3,6 +3,142 @@
|
|
|
3
3
|
import { resolve } from "path";
|
|
4
4
|
import { initSimulatorDriver } from "craft-native/ios";
|
|
5
5
|
import { createNativeMutationValidator, restoreShell, serializeSimulatorSteps } from "craft-native/ios";
|
|
6
|
+
|
|
7
|
+
// src/scheduled-workouts-fake.ts
|
|
8
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9
|
+
var SCHEDULED_WORKOUT_ACTIVITIES = [
|
|
10
|
+
"running",
|
|
11
|
+
"cycling",
|
|
12
|
+
"swimming",
|
|
13
|
+
"walking",
|
|
14
|
+
"hiking",
|
|
15
|
+
"traditionalStrengthTraining",
|
|
16
|
+
"functionalStrengthTraining",
|
|
17
|
+
"rowing",
|
|
18
|
+
"yoga",
|
|
19
|
+
"flexibility",
|
|
20
|
+
"crossTraining",
|
|
21
|
+
"elliptical",
|
|
22
|
+
"highIntensityIntervalTraining",
|
|
23
|
+
"other",
|
|
24
|
+
"coreTraining",
|
|
25
|
+
"mixedCardio",
|
|
26
|
+
"stairClimbing",
|
|
27
|
+
"stairs",
|
|
28
|
+
"stepTraining",
|
|
29
|
+
"pilates",
|
|
30
|
+
"cardioDance",
|
|
31
|
+
"kickboxing",
|
|
32
|
+
"boxing",
|
|
33
|
+
"jumpRope",
|
|
34
|
+
"cooldown",
|
|
35
|
+
"crossCountrySkiing",
|
|
36
|
+
"paddleSports",
|
|
37
|
+
"handCycling",
|
|
38
|
+
"wheelchairRunPace",
|
|
39
|
+
"wheelchairWalkPace"
|
|
40
|
+
];
|
|
41
|
+
function failure(message, code) {
|
|
42
|
+
return Object.assign(new Error(message), { code });
|
|
43
|
+
}
|
|
44
|
+
function realDay(date) {
|
|
45
|
+
if (typeof date !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(date))
|
|
46
|
+
return false;
|
|
47
|
+
const [year, month, day] = date.split("-").map(Number);
|
|
48
|
+
const parsed = new Date(Date.UTC(year, month - 1, day));
|
|
49
|
+
return parsed.getUTCFullYear() === year && parsed.getUTCMonth() === month - 1 && parsed.getUTCDate() === day;
|
|
50
|
+
}
|
|
51
|
+
function wholeIn(value, min, max) {
|
|
52
|
+
return typeof value === "number" && Number.isInteger(value) && value >= min && value <= max;
|
|
53
|
+
}
|
|
54
|
+
function createScheduledWorkoutsFake(options = {}) {
|
|
55
|
+
const supported = options.supported !== false;
|
|
56
|
+
const maxCount = options.maxCount ?? 15;
|
|
57
|
+
const scheduled = [];
|
|
58
|
+
const calls = [];
|
|
59
|
+
const state = { authorization: supported ? options.authorization ?? "notDetermined" : "unsupported" };
|
|
60
|
+
const allowed = () => {
|
|
61
|
+
if (!supported)
|
|
62
|
+
throw failure("unsupported", "UNSUPPORTED");
|
|
63
|
+
if (state.authorization !== "authorized")
|
|
64
|
+
throw failure("Scheduling workouts on the Apple Watch has not been allowed", "NOT_AUTHORIZED");
|
|
65
|
+
};
|
|
66
|
+
const bridge = {
|
|
67
|
+
isSupported: async () => {
|
|
68
|
+
calls.push("isSupported");
|
|
69
|
+
return supported;
|
|
70
|
+
},
|
|
71
|
+
authorization: async () => {
|
|
72
|
+
calls.push("authorization");
|
|
73
|
+
return state.authorization;
|
|
74
|
+
},
|
|
75
|
+
requestAuthorization: async () => {
|
|
76
|
+
calls.push("requestAuthorization");
|
|
77
|
+
if (supported && state.authorization === "notDetermined")
|
|
78
|
+
state.authorization = options.grant ?? "authorized";
|
|
79
|
+
return state.authorization;
|
|
80
|
+
},
|
|
81
|
+
list: async () => {
|
|
82
|
+
calls.push("list");
|
|
83
|
+
allowed();
|
|
84
|
+
return scheduled.map((row) => ({ ...row }));
|
|
85
|
+
},
|
|
86
|
+
schedule: async (plan) => {
|
|
87
|
+
calls.push("schedule");
|
|
88
|
+
allowed();
|
|
89
|
+
if (!plan || typeof plan.id !== "string" || !UUID.test(plan.id))
|
|
90
|
+
throw failure("A scheduled workout needs an id (a UUID)", "INVALID_ARGUMENT");
|
|
91
|
+
const hour = plan.hour ?? 7;
|
|
92
|
+
const minute = plan.minute ?? 0;
|
|
93
|
+
if (!realDay(plan.date) || !wholeIn(hour, 0, 23) || !wholeIn(minute, 0, 59))
|
|
94
|
+
throw failure("A scheduled workout needs a date ('YYYY-MM-DD') and, when given, an hour 0-23 and a minute 0-59", "INVALID_ARGUMENT");
|
|
95
|
+
const activity = plan.workout?.activity;
|
|
96
|
+
if (!SCHEDULED_WORKOUT_ACTIVITIES.includes(activity))
|
|
97
|
+
throw failure(`WorkoutKit has no activity '${activity ?? ""}'`, "INVALID_ARGUMENT");
|
|
98
|
+
const refusal = options.refuse?.(plan);
|
|
99
|
+
if (refusal)
|
|
100
|
+
throw failure(refusal, "UNSUPPORTED_GOAL");
|
|
101
|
+
const id = plan.id.toLowerCase();
|
|
102
|
+
const same = scheduled.filter((row) => row.id === id);
|
|
103
|
+
if (!same.some((row) => row.date === plan.date && row.hour === hour && row.minute === minute)) {
|
|
104
|
+
if (scheduled.length - same.length >= maxCount)
|
|
105
|
+
throw failure(`The Apple Watch holds at most ${maxCount} scheduled workouts; remove one first`, "LIMIT_REACHED");
|
|
106
|
+
scheduled.splice(0, scheduled.length, ...scheduled.filter((row) => row.id !== id));
|
|
107
|
+
scheduled.push({ id, date: plan.date, hour, minute, complete: false });
|
|
108
|
+
}
|
|
109
|
+
const dropped = options.dropAlerts?.(plan) ?? [];
|
|
110
|
+
return dropped.length ? { id, droppedAlerts: dropped } : { id };
|
|
111
|
+
},
|
|
112
|
+
remove: async (id) => {
|
|
113
|
+
calls.push("remove");
|
|
114
|
+
allowed();
|
|
115
|
+
if (typeof id !== "string" || !UUID.test(id))
|
|
116
|
+
throw failure("remove needs a plan id (a UUID)", "INVALID_ARGUMENT");
|
|
117
|
+
const before = scheduled.length;
|
|
118
|
+
scheduled.splice(0, scheduled.length, ...scheduled.filter((row) => row.id !== id.toLowerCase()));
|
|
119
|
+
return scheduled.length < before;
|
|
120
|
+
},
|
|
121
|
+
removeAll: async () => {
|
|
122
|
+
calls.push("removeAll");
|
|
123
|
+
allowed();
|
|
124
|
+
return scheduled.splice(0).length;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
bridge,
|
|
129
|
+
craft: { platform: "ios", capabilities: { scheduledWorkouts: true }, scheduledWorkouts: bridge },
|
|
130
|
+
scheduled,
|
|
131
|
+
calls,
|
|
132
|
+
get authorization() {
|
|
133
|
+
return state.authorization;
|
|
134
|
+
},
|
|
135
|
+
set authorization(value) {
|
|
136
|
+
state.authorization = value;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/testing.ts
|
|
6
142
|
function prepareIosSimulatorDriver(config, root = process.cwd()) {
|
|
7
143
|
const simulator = config.simulator ?? {};
|
|
8
144
|
const output = resolve(root, simulator.output ?? "storage/framework/mobile/ios-driver");
|
|
@@ -17,7 +153,9 @@ function prepareIosSimulatorDriver(config, root = process.cwd()) {
|
|
|
17
153
|
return { output, projectName };
|
|
18
154
|
}
|
|
19
155
|
export {
|
|
156
|
+
SCHEDULED_WORKOUT_ACTIVITIES,
|
|
20
157
|
createNativeMutationValidator,
|
|
158
|
+
createScheduledWorkoutsFake,
|
|
21
159
|
prepareIosSimulatorDriver,
|
|
22
160
|
restoreShell as restoreIosShell,
|
|
23
161
|
serializeSimulatorSteps
|
package/dist/types.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare interface CraftMobileCapabilities {
|
|
|
23
23
|
deepLinks?: boolean
|
|
24
24
|
flashlight?: boolean
|
|
25
25
|
music?: boolean
|
|
26
|
+
scheduledWorkouts?: boolean
|
|
26
27
|
network?: boolean
|
|
27
28
|
deviceInfo?: boolean
|
|
28
29
|
badge?: boolean
|
|
@@ -71,6 +72,7 @@ export declare interface MobileApi {
|
|
|
71
72
|
brightness: BrightnessApi
|
|
72
73
|
music: MusicApi
|
|
73
74
|
heartRate: HeartRateApi
|
|
75
|
+
scheduledWorkouts: import('./scheduled-workouts').ScheduledWorkoutsApi
|
|
74
76
|
speech: SpeechApi
|
|
75
77
|
network: NetworkApi
|
|
76
78
|
pushNotifications: PushNotificationsApi
|
|
@@ -474,6 +476,32 @@ export declare interface HealthSleepInterval {
|
|
|
474
476
|
sourceName: string
|
|
475
477
|
deviceName?: string
|
|
476
478
|
}
|
|
479
|
+
/** A meditation or breathing session to record as mindful minutes. */
|
|
480
|
+
export declare interface HealthMindfulSession {
|
|
481
|
+
id: string
|
|
482
|
+
startDate: number
|
|
483
|
+
endDate: number
|
|
484
|
+
}
|
|
485
|
+
export declare interface HealthMindfulSessionResult {
|
|
486
|
+
id: string
|
|
487
|
+
externalId: string
|
|
488
|
+
existing: boolean
|
|
489
|
+
}
|
|
490
|
+
export declare interface HealthMindfulSessionQuery extends HealthSampleQuery {
|
|
491
|
+
limit?: number
|
|
492
|
+
}
|
|
493
|
+
/** A mindful session in Apple Health, written by any app (the Mindfulness app, Calm, this one). */
|
|
494
|
+
export declare interface HealthMindfulSample {
|
|
495
|
+
id: string
|
|
496
|
+
startDate: number
|
|
497
|
+
endDate: number
|
|
498
|
+
durationSeconds: number
|
|
499
|
+
sourceName: string
|
|
500
|
+
sourceBundleId: string
|
|
501
|
+
ownApp: boolean
|
|
502
|
+
externalId?: string
|
|
503
|
+
deviceName?: string
|
|
504
|
+
}
|
|
477
505
|
export declare interface HealthAuthorizationOptions {
|
|
478
506
|
write?: boolean
|
|
479
507
|
}
|
|
@@ -485,6 +513,8 @@ export declare interface HealthApi {
|
|
|
485
513
|
getDailyStatistics: (type: HealthDailyType, options?: HealthDataOptions) => Promise<HealthDailyValue[]>
|
|
486
514
|
getHeartRateSamples: (options?: HealthHeartRateQuery) => Promise<HealthHeartRateSample[]>
|
|
487
515
|
getSleepIntervals: (options?: HealthSampleQuery) => Promise<HealthSleepInterval[]>
|
|
516
|
+
saveMindfulSession: (session: HealthMindfulSession) => Promise<HealthMindfulSessionResult | null>
|
|
517
|
+
getMindfulSessions: (options?: HealthMindfulSessionQuery) => Promise<HealthMindfulSample[]>
|
|
488
518
|
supports: (method: HealthReadMethod) => boolean
|
|
489
519
|
}
|
|
490
520
|
export declare interface LiveActivityState {
|
|
@@ -556,9 +586,11 @@ export type HealthDataType = | 'steps'
|
|
|
556
586
|
| 'dietaryEnergy'
|
|
557
587
|
| 'dietaryProtein'
|
|
558
588
|
| 'dietaryCarbohydrates'
|
|
559
|
-
| 'dietaryFat'
|
|
589
|
+
| 'dietaryFat'
|
|
590
|
+
/** Mindful minutes (meditation, breathing): `saveMindfulSession` writes, `getMindfulSessions` reads (Craft 0.0.161). */
|
|
591
|
+
| 'mindful';
|
|
560
592
|
/** The types with one value per day. `sleep` is hours asleep, counted on the day you woke. */
|
|
561
|
-
export type HealthDailyType = Exclude<HealthDataType, 'workouts'>;
|
|
593
|
+
export type HealthDailyType = Exclude<HealthDataType, 'workouts' | 'mindful'>;
|
|
562
594
|
export type HealthWorkoutType = 'running' | 'walking' | 'hiking' | 'cycling';
|
|
563
595
|
/** The activity of a workout read from Apple Health, named independently of the SDK. */
|
|
564
596
|
export type HealthWorkoutActivity = | 'running' | 'cycling' | 'walking' | 'hiking' | 'swimming' | 'rowing' | 'elliptical'
|
|
@@ -566,5 +598,5 @@ export type HealthWorkoutActivity = | 'running' | 'cycling' | 'walking' | 'hikin
|
|
|
566
598
|
| 'crossCountrySkiing' | 'skiing' | 'paddling' | 'climbing' | 'dance' | 'mobility' | 'other';
|
|
567
599
|
/** A sleep analysis stage: in bed, awake, or asleep (staged or not). */
|
|
568
600
|
export type HealthSleepStage = 'inBed' | 'awake' | 'asleep' | 'core' | 'deep' | 'rem';
|
|
569
|
-
/** The health reads an installed app build may or may not answer. */
|
|
570
|
-
export type HealthReadMethod = 'getWorkouts' | 'getDailyStatistics' | 'getHeartRateSamples' | 'getSleepIntervals';
|
|
601
|
+
/** The health reads and writes an installed app build may or may not answer. */
|
|
602
|
+
export type HealthReadMethod = 'getWorkouts' | 'getDailyStatistics' | 'getHeartRateSamples' | 'getSleepIntervals' | 'saveMindfulSession' | 'getMindfulSessions';
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/mobile",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.166",
|
|
6
6
|
"description": "Craft-powered native mobile runtime for Stacks and STX applications",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"license": "MIT",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"test": "bun test"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@stacksjs/types": "0.75.
|
|
42
|
-
"craft-native": ">=0.0.
|
|
41
|
+
"@stacksjs/types": "0.75.166",
|
|
42
|
+
"craft-native": ">=0.0.162"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@stacksjs/build": "0.75.
|
|
45
|
+
"@stacksjs/build": "0.75.166",
|
|
46
46
|
"better-dx": "^0.2.24"
|
|
47
47
|
}
|
|
48
48
|
}
|