@buoy-gg/core 7.0.41 → 7.0.43
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 +14 -95
- package/bin/buoy.js +19 -340
- package/lib/commonjs/Buoy.js +1 -107
- package/lib/commonjs/browserRegister.js +1 -48
- package/lib/commonjs/browserRegister.server.js +1 -10
- package/lib/commonjs/earlyHookScript.js +1 -0
- package/lib/commonjs/earlyNetwork.js +1 -0
- package/lib/commonjs/floatingMenu/AppHost.js +1 -460
- package/lib/commonjs/floatingMenu/AppHost.web.js +1 -376
- package/lib/commonjs/floatingMenu/AppHostLogic.js +1 -50
- package/lib/commonjs/floatingMenu/AppIcon.js +1 -91
- package/lib/commonjs/floatingMenu/AppIcon.web.js +1 -53
- package/lib/commonjs/floatingMenu/BrowserToolRuntime.js +1 -150
- package/lib/commonjs/floatingMenu/DefaultConfigContext.js +1 -45
- package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +1 -18
- package/lib/commonjs/floatingMenu/DevToolsSettingsModal.shared.js +1 -1114
- package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +1 -48
- package/lib/commonjs/floatingMenu/DevToolsVisibilityContext.js +1 -49
- package/lib/commonjs/floatingMenu/FloatingDevTools.js +1 -559
- package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +1 -415
- package/lib/commonjs/floatingMenu/FloatingMenu.js +1 -371
- package/lib/commonjs/floatingMenu/MinimizedToolsContext.js +1 -274
- package/lib/commonjs/floatingMenu/MinimizedToolsStack.js +1 -288
- package/lib/commonjs/floatingMenu/MinimizedToolsStack.web.js +1 -377
- package/lib/commonjs/floatingMenu/ToggleStateManager.js +1 -36
- package/lib/commonjs/floatingMenu/ToolHost.js +1 -281
- package/lib/commonjs/floatingMenu/ToolOpenerBridge.js +1 -41
- package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +1 -471
- package/lib/commonjs/floatingMenu/autoExternalSync.js +1 -443
- package/lib/commonjs/floatingMenu/defaultConfig.js +1 -167
- package/lib/commonjs/floatingMenu/deviceIdentity.js +1 -173
- package/lib/commonjs/floatingMenu/dial/DialDevTools.js +1 -904
- package/lib/commonjs/floatingMenu/dial/DialDevTools.web.js +1 -895
- package/lib/commonjs/floatingMenu/dial/DialHyperspace.js +1 -177
- package/lib/commonjs/floatingMenu/dial/DialIcon.js +1 -304
- package/lib/commonjs/floatingMenu/dial/DialPagination.js +1 -165
- package/lib/commonjs/floatingMenu/dial/DialSnow.js +1 -92
- package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.js +1 -246
- package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.web.js +2 -147
- package/lib/commonjs/floatingMenu/dial/dialUsageStore.js +1 -93
- package/lib/commonjs/floatingMenu/dial/onboardingConstants.js +1 -42
- package/lib/commonjs/floatingMenu/dial/onboardingConstants.web.js +1 -42
- package/lib/commonjs/floatingMenu/externalSyncGate.js +1 -49
- package/lib/commonjs/floatingMenu/floatingTools.js +1 -42
- package/lib/commonjs/floatingMenu/floatingTools.web.js +1 -30
- package/lib/commonjs/floatingMenu/optionalRequire.js +1 -37
- package/lib/commonjs/floatingMenu/settingsBus.js +1 -12
- package/lib/commonjs/floatingMenu/sync/appSyncAdapter.js +1 -115
- package/lib/commonjs/floatingMenu/types.js +1 -5
- package/lib/commonjs/floatingMenu/useDesktopSyncStatus.js +1 -28
- package/lib/commonjs/floatingMenu/useDesktopSyncStatus.web.js +1 -14
- package/lib/commonjs/index.js +1 -291
- package/lib/commonjs/index.web.js +1 -241
- package/lib/commonjs/reactDevtoolsTypes.js +1 -1
- package/lib/commonjs/releaseOptIn.js +1 -0
- package/lib/commonjs/telemetry/installPing.js +1 -131
- package/lib/commonjs/toolkit.js +1 -584
- package/lib/commonjs/toolkitComponents.js +1 -241
- package/lib/commonjs/utils/autoDiscoverPresets.web.js +1 -46
- package/lib/commonjs/utils/createWebTool.js +1 -20
- package/lib/commonjs/utils/createWebTools.js +1 -30
- package/lib/commonjs/version.js +1 -18
- package/lib/module/Buoy.js +1 -102
- package/lib/module/browserRegister.js +1 -44
- package/lib/module/browserRegister.server.js +1 -6
- package/lib/module/earlyHookScript.js +1 -0
- package/lib/module/earlyNetwork.js +1 -0
- package/lib/module/floatingMenu/AppHost.js +1 -452
- package/lib/module/floatingMenu/AppHost.web.js +1 -368
- package/lib/module/floatingMenu/AppHostLogic.js +1 -45
- package/lib/module/floatingMenu/AppIcon.js +1 -84
- package/lib/module/floatingMenu/AppIcon.web.js +1 -47
- package/lib/module/floatingMenu/BrowserToolRuntime.js +1 -146
- package/lib/module/floatingMenu/DefaultConfigContext.js +1 -39
- package/lib/module/floatingMenu/DevToolsSettingsModal.js +1 -3
- package/lib/module/floatingMenu/DevToolsSettingsModal.shared.js +1 -1110
- package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +1 -44
- package/lib/module/floatingMenu/DevToolsVisibilityContext.js +1 -44
- package/lib/module/floatingMenu/FloatingDevTools.js +1 -556
- package/lib/module/floatingMenu/FloatingDevTools.web.js +1 -412
- package/lib/module/floatingMenu/FloatingMenu.js +1 -366
- package/lib/module/floatingMenu/MinimizedToolsContext.js +1 -266
- package/lib/module/floatingMenu/MinimizedToolsStack.js +1 -285
- package/lib/module/floatingMenu/MinimizedToolsStack.web.js +1 -374
- package/lib/module/floatingMenu/ToggleStateManager.js +1 -32
- package/lib/module/floatingMenu/ToolHost.js +1 -273
- package/lib/module/floatingMenu/ToolOpenerBridge.js +1 -37
- package/lib/module/floatingMenu/autoDiscoverPresets.js +1 -467
- package/lib/module/floatingMenu/autoExternalSync.js +1 -436
- package/lib/module/floatingMenu/defaultConfig.js +1 -158
- package/lib/module/floatingMenu/deviceIdentity.js +1 -163
- package/lib/module/floatingMenu/dial/DialDevTools.js +1 -900
- package/lib/module/floatingMenu/dial/DialDevTools.web.js +1 -891
- package/lib/module/floatingMenu/dial/DialHyperspace.js +1 -173
- package/lib/module/floatingMenu/dial/DialIcon.js +1 -301
- package/lib/module/floatingMenu/dial/DialPagination.js +1 -160
- package/lib/module/floatingMenu/dial/DialSnow.js +1 -90
- package/lib/module/floatingMenu/dial/OnboardingTooltip.js +1 -240
- package/lib/module/floatingMenu/dial/OnboardingTooltip.web.js +2 -142
- package/lib/module/floatingMenu/dial/dialUsageStore.js +1 -85
- package/lib/module/floatingMenu/dial/onboardingConstants.js +1 -3
- package/lib/module/floatingMenu/dial/onboardingConstants.web.js +1 -3
- package/lib/module/floatingMenu/externalSyncGate.js +1 -44
- package/lib/module/floatingMenu/floatingTools.js +1 -27
- package/lib/module/floatingMenu/floatingTools.web.js +1 -3
- package/lib/module/floatingMenu/optionalRequire.js +1 -33
- package/lib/module/floatingMenu/settingsBus.js +1 -3
- package/lib/module/floatingMenu/sync/appSyncAdapter.js +1 -112
- package/lib/module/floatingMenu/types.js +1 -3
- package/lib/module/floatingMenu/useDesktopSyncStatus.js +1 -25
- package/lib/module/floatingMenu/useDesktopSyncStatus.web.js +1 -10
- package/lib/module/index.js +1 -41
- package/lib/module/index.web.js +1 -36
- package/lib/module/reactDevtoolsTypes.js +1 -1
- package/lib/module/releaseOptIn.js +1 -0
- package/lib/module/telemetry/installPing.js +1 -127
- package/lib/module/toolkit.js +1 -62
- package/lib/module/toolkitComponents.js +1 -230
- package/lib/module/utils/autoDiscoverPresets.web.js +1 -38
- package/lib/module/utils/createWebTool.js +1 -17
- package/lib/module/utils/createWebTools.js +1 -25
- package/lib/module/version.js +1 -14
- package/lib/typescript/commonjs/browserRegister.d.ts +9 -1
- package/lib/typescript/commonjs/browserRegister.server.d.ts +1 -0
- package/lib/typescript/commonjs/earlyHookScript.d.ts +12 -0
- package/lib/typescript/commonjs/earlyNetwork.d.ts +52 -0
- package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +1 -0
- package/lib/typescript/commonjs/releaseOptIn.d.ts +4 -0
- package/lib/typescript/commonjs/version.d.ts +1 -1
- package/lib/typescript/module/browserRegister.d.ts +9 -1
- package/lib/typescript/module/browserRegister.server.d.ts +1 -0
- package/lib/typescript/module/earlyHookScript.d.ts +12 -0
- package/lib/typescript/module/earlyNetwork.d.ts +52 -0
- package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +1 -1
- package/lib/typescript/module/index.web.d.ts +1 -0
- package/lib/typescript/module/releaseOptIn.d.ts +4 -0
- package/lib/typescript/module/version.d.ts +1 -1
- package/lib/web/chunks/chunk-5SGL6QL4.mjs +1 -0
- package/lib/web/chunks/chunk-FROELTJH.mjs +1 -0
- package/lib/web/chunks/chunk-QZDVCMCT.mjs +1 -2
- package/lib/web/chunks/chunk-R7RGRTY5.mjs +1 -2
- package/lib/web/index.mjs +2 -3
- package/lib/web/register-server.mjs +1 -2
- package/lib/web/register.mjs +1 -2
- package/lib/web/toolkit.mjs +1 -2
- package/package.json +6 -9
- package/lib/typescript/commonjs/Buoy.d.ts.map +0 -1
- package/lib/typescript/commonjs/browserRegister.d.ts.map +0 -1
- package/lib/typescript/commonjs/browserRegister.server.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/AppHost.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/AppIcon.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/AppIcon.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/BrowserToolRuntime.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/DefaultConfigContext.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.shared.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/DevToolsVisibilityContext.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsContext.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/ToggleStateManager.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/ToolHost.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/ToolOpenerBridge.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/deviceIdentity.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialHyperspace.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialPagination.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialSnow.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/dialUsageStore.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/externalSyncGate.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/floatingTools.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/optionalRequire.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/settingsBus.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/sync/appSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/types.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/useDesktopSyncStatus.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/useDesktopSyncStatus.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/index.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/reactDevtoolsTypes.d.ts.map +0 -1
- package/lib/typescript/commonjs/telemetry/installPing.d.ts.map +0 -1
- package/lib/typescript/commonjs/toolkit.d.ts.map +0 -1
- package/lib/typescript/commonjs/toolkitComponents.d.ts.map +0 -1
- package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts.map +0 -1
- package/lib/typescript/commonjs/utils/createWebTool.d.ts.map +0 -1
- package/lib/typescript/commonjs/utils/createWebTools.d.ts.map +0 -1
- package/lib/typescript/commonjs/version.d.ts.map +0 -1
- package/lib/typescript/module/Buoy.d.ts.map +0 -1
- package/lib/typescript/module/browserRegister.d.ts.map +0 -1
- package/lib/typescript/module/browserRegister.server.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/AppHost.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/AppHost.web.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/AppIcon.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/AppIcon.web.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/BrowserToolRuntime.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/DefaultConfigContext.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.shared.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/DevToolsVisibilityContext.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/MinimizedToolsContext.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/MinimizedToolsStack.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/MinimizedToolsStack.web.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/ToggleStateManager.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/ToolHost.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/ToolOpenerBridge.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/defaultConfig.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/deviceIdentity.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/DialHyperspace.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/DialPagination.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/DialSnow.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.web.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/dialUsageStore.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/onboardingConstants.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/dial/onboardingConstants.web.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/externalSyncGate.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/floatingTools.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/optionalRequire.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/settingsBus.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/sync/appSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/types.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/useDesktopSyncStatus.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/useDesktopSyncStatus.web.d.ts.map +0 -1
- package/lib/typescript/module/index.d.ts.map +0 -1
- package/lib/typescript/module/index.web.d.ts.map +0 -1
- package/lib/typescript/module/reactDevtoolsTypes.d.ts.map +0 -1
- package/lib/typescript/module/telemetry/installPing.d.ts.map +0 -1
- package/lib/typescript/module/toolkit.d.ts.map +0 -1
- package/lib/typescript/module/toolkitComponents.d.ts.map +0 -1
- package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts.map +0 -1
- package/lib/typescript/module/utils/createWebTool.d.ts.map +0 -1
- package/lib/typescript/module/utils/createWebTools.d.ts.map +0 -1
- package/lib/typescript/module/version.d.ts.map +0 -1
- package/lib/web/chunks/chunk-5NZOQR6Q.mjs +0 -2
- package/lib/web/chunks/chunk-CGDSLLZF.mjs +0 -2
- package/lib/web/chunks/chunk-DCJDUSNR.mjs +0 -2
- package/lib/web/chunks/chunk-IDSHFS6G.mjs +0 -2
- package/lib/web/chunks/chunk-JOAMJGCS.mjs +0 -2
- package/lib/web/chunks/chunk-KYKZ2N52.mjs +0 -2
- package/lib/web/chunks/chunk-NGM7JGGS.mjs +0 -2
- package/lib/web/chunks/chunk-Z3XWDDIO.mjs +0 -2
- package/lib/web/chunks/chunk-ZTGQ6TTY.mjs +0 -2
|
@@ -1,900 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
-
import { Pressable, StyleSheet, TouchableOpacity, View, useWindowDimensions, Text, Animated, Easing } from "react-native";
|
|
5
|
-
import { absoluteFill, monoFont } from "@buoy-gg/shared-ui";
|
|
6
|
-
// Icons are provided by installedApps; no direct icon imports here.
|
|
7
|
-
import { DialIcon } from "./DialIcon.js";
|
|
8
|
-
import { DialHyperspace } from "./DialHyperspace.js";
|
|
9
|
-
import { DialPagination } from "./DialPagination.js";
|
|
10
|
-
import { getRankedToolIds, isDialUsageLoaded, loadDialUsage, recordToolUsage } from "./dialUsageStore.js";
|
|
11
|
-
import { persistentStorage, useHintsDisabled, devToolsStorageKeys, buoyColors, ToolBackground, useToolBackground } from "@buoy-gg/shared-ui";
|
|
12
|
-
import { DevToolsSettingsModal, useDevToolsSettings } from "../DevToolsSettingsModal";
|
|
13
|
-
import { useProAccess } from "@buoy-gg/license";
|
|
14
|
-
import { renderAppIcon } from "../AppIcon";
|
|
15
|
-
import { useAppHost } from "../AppHost";
|
|
16
|
-
import { OnboardingTooltip } from "./OnboardingTooltip";
|
|
17
|
-
import { getDialLayout, MAX_DIAL_SLOTS, DIAL_BUTTON_SIZE, dialAnimationConfig, dialColors } from "@buoy-gg/floating-tools-core";
|
|
18
|
-
|
|
19
|
-
// The circle size depends on the live window width, so it's computed inside
|
|
20
|
-
// the component via useWindowDimensions — a module-scope Dimensions.get
|
|
21
|
-
// snapshot goes stale when the window resizes after load (web/desktop).
|
|
22
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
23
|
-
const BUTTON_SIZE = DIAL_BUTTON_SIZE;
|
|
24
|
-
/** The dial face is a circle, so its centre is the middle of the measured square. */
|
|
25
|
-
const DIAL_BACKGROUND_FOCUS = {
|
|
26
|
-
x: 0.5,
|
|
27
|
-
y: 0.5
|
|
28
|
-
};
|
|
29
|
-
// Radius kept clear of grid spokes around the glass hub (its outer disc is
|
|
30
|
-
// 0.75 × BUTTON_SIZE, plus a breath).
|
|
31
|
-
const HUB_CLEARANCE = BUTTON_SIZE * 0.75 + 6;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* The centre button's idle pulse, off by design.
|
|
35
|
-
*
|
|
36
|
-
* It is built as `Animated.loop(Animated.sequence([...]))`, and that pairing is
|
|
37
|
-
* NOT handed to the native driver even though every child sets
|
|
38
|
-
* `useNativeDriver: true` — so it ticked on the JS thread for as long as the
|
|
39
|
-
* dial stayed open, taxing every interaction launched from the dial.
|
|
40
|
-
*
|
|
41
|
-
* Re-enabling it means rewriting the loop so it genuinely runs natively;
|
|
42
|
-
* flipping this alone just puts the JS-thread cost back.
|
|
43
|
-
*/
|
|
44
|
-
const DIAL_IDLE_PULSE = false;
|
|
45
|
-
const ONBOARDING_STORAGE_KEY = "@react_buoy_settings_tooltip_shown";
|
|
46
|
-
/** A non-interactive placeholder used to fill out the last dial page. */
|
|
47
|
-
const createEmptySlot = slotIndex => ({
|
|
48
|
-
id: `empty-${slotIndex}`,
|
|
49
|
-
name: `empty-${slotIndex}`,
|
|
50
|
-
icon: null,
|
|
51
|
-
color: "transparent",
|
|
52
|
-
onPress: () => {}
|
|
53
|
-
});
|
|
54
|
-
export const DialDevTools = ({
|
|
55
|
-
onClose,
|
|
56
|
-
onSettingsPress,
|
|
57
|
-
autoOpenSettings = false,
|
|
58
|
-
apps,
|
|
59
|
-
state,
|
|
60
|
-
actions
|
|
61
|
-
}) => {
|
|
62
|
-
const [selectedIcon, setSelectedIcon] = useState(-1);
|
|
63
|
-
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
|
|
64
|
-
const [settingsModalStateLoaded, setSettingsModalStateLoaded] = useState(false);
|
|
65
|
-
const [showOnboardingTooltip, setShowOnboardingTooltip] = useState(false);
|
|
66
|
-
const onboardingDismissedRef = useRef(false); // Track if onboarding was dismissed
|
|
67
|
-
const hintsDisabled = useHintsDisabled();
|
|
68
|
-
const {
|
|
69
|
-
refreshSettings
|
|
70
|
-
} = useDevToolsSettings();
|
|
71
|
-
const {
|
|
72
|
-
open
|
|
73
|
-
} = useAppHost();
|
|
74
|
-
const {
|
|
75
|
-
isPro,
|
|
76
|
-
isWeekendFree
|
|
77
|
-
} = useProAccess();
|
|
78
|
-
|
|
79
|
-
// Live window size — keeps the dial centered and sized correctly when the
|
|
80
|
-
// window resizes (Electron/web) or the device rotates.
|
|
81
|
-
const {
|
|
82
|
-
width: screenWidth,
|
|
83
|
-
height: screenHeight
|
|
84
|
-
} = useWindowDimensions();
|
|
85
|
-
const circleSize = getDialLayout({
|
|
86
|
-
screenWidth
|
|
87
|
-
}).circleSize;
|
|
88
|
-
// The dial face shows the same backdrop the tools use (persisted shared
|
|
89
|
-
// selection). Hyperspace keeps its hand-tuned dial port below.
|
|
90
|
-
const {
|
|
91
|
-
id: backgroundId
|
|
92
|
-
} = useToolBackground();
|
|
93
|
-
const sizeStyles = useMemo(() => ({
|
|
94
|
-
parent: {
|
|
95
|
-
width: circleSize,
|
|
96
|
-
height: circleSize
|
|
97
|
-
},
|
|
98
|
-
circle: {
|
|
99
|
-
width: circleSize,
|
|
100
|
-
height: circleSize,
|
|
101
|
-
borderRadius: circleSize / 2
|
|
102
|
-
},
|
|
103
|
-
rounded: {
|
|
104
|
-
borderRadius: circleSize / 2
|
|
105
|
-
},
|
|
106
|
-
gridLine: {
|
|
107
|
-
width: circleSize
|
|
108
|
-
},
|
|
109
|
-
// Each spoke is two segments that stop short of the glass hub, so the
|
|
110
|
-
// six lines never meet in the middle where the background shows through.
|
|
111
|
-
spoke: {
|
|
112
|
-
width: circleSize / 2 - HUB_CLEARANCE
|
|
113
|
-
}
|
|
114
|
-
}), [circleSize]);
|
|
115
|
-
|
|
116
|
-
// Load persisted settings modal state on mount
|
|
117
|
-
useEffect(() => {
|
|
118
|
-
const loadSettingsModalState = async () => {
|
|
119
|
-
try {
|
|
120
|
-
const savedModalOpen = await persistentStorage.getItem(devToolsStorageKeys.settings.modalOpen());
|
|
121
|
-
if (savedModalOpen === "true") {
|
|
122
|
-
setIsSettingsModalOpen(true);
|
|
123
|
-
}
|
|
124
|
-
} catch (error) {
|
|
125
|
-
// Failed to load settings modal state - use default (closed)
|
|
126
|
-
} finally {
|
|
127
|
-
setSettingsModalStateLoaded(true);
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
loadSettingsModalState();
|
|
131
|
-
}, []);
|
|
132
|
-
|
|
133
|
-
// Persist settings modal state when it changes
|
|
134
|
-
useEffect(() => {
|
|
135
|
-
// Only persist after initial state is loaded to avoid overwriting with default
|
|
136
|
-
if (!settingsModalStateLoaded) return;
|
|
137
|
-
persistentStorage.setItem(devToolsStorageKeys.settings.modalOpen(), isSettingsModalOpen ? "true" : "false").catch(error => {
|
|
138
|
-
// Failed to save settings modal state - continue without persistence
|
|
139
|
-
console.warn("Failed to save settings modal state:", error);
|
|
140
|
-
});
|
|
141
|
-
}, [isSettingsModalOpen, settingsModalStateLoaded]);
|
|
142
|
-
|
|
143
|
-
// Auto-open settings modal when prop is true
|
|
144
|
-
useEffect(() => {
|
|
145
|
-
if (autoOpenSettings && !isSettingsModalOpen) {
|
|
146
|
-
setIsSettingsModalOpen(true);
|
|
147
|
-
}
|
|
148
|
-
}, [autoOpenSettings, isSettingsModalOpen]);
|
|
149
|
-
|
|
150
|
-
// Check if we should show the onboarding tooltip
|
|
151
|
-
useEffect(() => {
|
|
152
|
-
// Skip onboarding if hints are disabled
|
|
153
|
-
if (hintsDisabled) {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
const checkOnboarding = async () => {
|
|
157
|
-
try {
|
|
158
|
-
const hasSeenTooltip = await persistentStorage.getItem(ONBOARDING_STORAGE_KEY);
|
|
159
|
-
if (!hasSeenTooltip) {
|
|
160
|
-
// Small delay to let the entrance animations play first
|
|
161
|
-
setTimeout(() => {
|
|
162
|
-
setShowOnboardingTooltip(true);
|
|
163
|
-
}, 1200);
|
|
164
|
-
}
|
|
165
|
-
} catch (error) {
|
|
166
|
-
// If there's an error reading storage, don't show the tooltip
|
|
167
|
-
// to avoid annoying the user repeatedly
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
checkOnboarding();
|
|
171
|
-
}, [hintsDisabled]);
|
|
172
|
-
|
|
173
|
-
// React Native Animated values
|
|
174
|
-
const backdropOpacity = useRef(new Animated.Value(0)).current;
|
|
175
|
-
const dialScale = useRef(new Animated.Value(0)).current;
|
|
176
|
-
const dialRotation = useRef(new Animated.Value(0)).current;
|
|
177
|
-
const centerButtonScale = useRef(new Animated.Value(0)).current;
|
|
178
|
-
const iconsProgress = useRef(new Animated.Value(0)).current;
|
|
179
|
-
const pulseScale = useRef(new Animated.Value(1)).current;
|
|
180
|
-
const availableApps = useMemo(() => apps.map(({
|
|
181
|
-
id,
|
|
182
|
-
name,
|
|
183
|
-
slot,
|
|
184
|
-
description,
|
|
185
|
-
icon,
|
|
186
|
-
color
|
|
187
|
-
}) => ({
|
|
188
|
-
id,
|
|
189
|
-
name,
|
|
190
|
-
slot,
|
|
191
|
-
description,
|
|
192
|
-
// Settings rows fall back to the app's own icon when the modal has no
|
|
193
|
-
// hardcoded glyph for the tool.
|
|
194
|
-
icon,
|
|
195
|
-
color
|
|
196
|
-
})), [apps]);
|
|
197
|
-
|
|
198
|
-
// Animation tracking refs
|
|
199
|
-
const pulseAnimationRef = useRef(null);
|
|
200
|
-
const toggleSettingsModal = () => {
|
|
201
|
-
if (isSettingsModalOpen) {
|
|
202
|
-
setIsSettingsModalOpen(false);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
setIsSettingsModalOpen(true);
|
|
206
|
-
// Dismiss onboarding tooltip when user opens settings
|
|
207
|
-
if (showOnboardingTooltip && !onboardingDismissedRef.current) {
|
|
208
|
-
handleOnboardingDismiss();
|
|
209
|
-
}
|
|
210
|
-
// Also call external handler if provided
|
|
211
|
-
onSettingsPress?.();
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
// Dial-eligible apps: everything except row-only tools. All of them are
|
|
215
|
-
// shown — paginated across pages of MAX_DIAL_SLOTS — so there is no longer
|
|
216
|
-
// a per-tool show/hide setting.
|
|
217
|
-
const dialApps = useMemo(() => apps.filter(a => (a.slot ?? "both") !== "row"), [apps]);
|
|
218
|
-
|
|
219
|
-
// Build a stable IconType for every dial-eligible app, keyed by id.
|
|
220
|
-
const iconsById = useMemo(() => {
|
|
221
|
-
const map = new Map();
|
|
222
|
-
for (const app of dialApps) {
|
|
223
|
-
map.set(app.id, {
|
|
224
|
-
id: app.id,
|
|
225
|
-
name: app.name,
|
|
226
|
-
// Pass both the pre-rendered icon (for non-function icons; strings
|
|
227
|
-
// resolve to auto-fitting text icons) and the component (for dynamic
|
|
228
|
-
// rendering).
|
|
229
|
-
icon: typeof app.icon === "function" ? null : renderAppIcon(app.icon, {
|
|
230
|
-
slot: "dial",
|
|
231
|
-
size: 20,
|
|
232
|
-
color: app.color
|
|
233
|
-
}),
|
|
234
|
-
// Cast to the expected type - the signature is compatible at runtime.
|
|
235
|
-
iconComponent: typeof app.icon === "function" ? app.icon : undefined,
|
|
236
|
-
color: app.color ?? buoyColors.primary,
|
|
237
|
-
onPress: () => {
|
|
238
|
-
// Put this tool first the next time the dial opens.
|
|
239
|
-
void recordToolUsage(app.id);
|
|
240
|
-
|
|
241
|
-
// Call the app's onPress callback if provided, passing actions for
|
|
242
|
-
// toggle tools.
|
|
243
|
-
app?.onPress?.(actions);
|
|
244
|
-
|
|
245
|
-
// Only open modal if not a toggle-only tool.
|
|
246
|
-
if (app.launchMode !== "toggle-only") {
|
|
247
|
-
const resolvedIcon = renderAppIcon(app.icon, {
|
|
248
|
-
slot: "dial",
|
|
249
|
-
size: 20,
|
|
250
|
-
color: app.color
|
|
251
|
-
});
|
|
252
|
-
open({
|
|
253
|
-
id: app.id,
|
|
254
|
-
title: app.name,
|
|
255
|
-
component: app.component,
|
|
256
|
-
props: app.props,
|
|
257
|
-
launchMode: app.launchMode ?? "self-modal",
|
|
258
|
-
singleton: app.singleton ?? true,
|
|
259
|
-
icon: resolvedIcon,
|
|
260
|
-
color: app.color,
|
|
261
|
-
modal: app.modal
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Close the dial.
|
|
266
|
-
onClose?.();
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
return map;
|
|
271
|
-
}, [dialApps, actions, open, onClose]);
|
|
272
|
-
|
|
273
|
-
// Snapshot the usage-ranked order when the dial opens. It stays stable while
|
|
274
|
-
// open so icons don't jump positions mid-interaction.
|
|
275
|
-
const [rankedIds, setRankedIds] = useState(() => getRankedToolIds(dialApps.map(a => a.id)));
|
|
276
|
-
useEffect(() => {
|
|
277
|
-
const ids = dialApps.map(a => a.id);
|
|
278
|
-
if (isDialUsageLoaded()) {
|
|
279
|
-
setRankedIds(getRankedToolIds(ids));
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
// Usage data not loaded yet — show default order, then re-rank once ready.
|
|
283
|
-
let cancelled = false;
|
|
284
|
-
loadDialUsage().then(() => {
|
|
285
|
-
if (!cancelled) setRankedIds(getRankedToolIds(ids));
|
|
286
|
-
});
|
|
287
|
-
return () => {
|
|
288
|
-
cancelled = true;
|
|
289
|
-
};
|
|
290
|
-
}, [dialApps]);
|
|
291
|
-
|
|
292
|
-
// Page count spans the installed tools (usage-ranked). Only tools the app
|
|
293
|
-
// actually has appear in the dial — nothing is shown for uninstalled ones.
|
|
294
|
-
const pageCount = Math.max(1, Math.ceil(rankedIds.length / MAX_DIAL_SLOTS));
|
|
295
|
-
const [currentPage, setCurrentPage] = useState(0);
|
|
296
|
-
const safePage = Math.min(currentPage, pageCount - 1);
|
|
297
|
-
|
|
298
|
-
// Every dial-eligible icon, with the page/slot it occupies. The ranking is
|
|
299
|
-
// snapshotted on open, so each icon's page and slot are fixed for the
|
|
300
|
-
// session — which lets us mount all icons once and paginate purely by
|
|
301
|
-
// toggling visibility (no remounts on page change).
|
|
302
|
-
const allDialIcons = useMemo(() => {
|
|
303
|
-
return rankedIds.map(id => iconsById.get(id)).filter(icon => Boolean(icon)).map((icon, i) => ({
|
|
304
|
-
icon,
|
|
305
|
-
page: Math.floor(i / MAX_DIAL_SLOTS),
|
|
306
|
-
slot: i % MAX_DIAL_SLOTS
|
|
307
|
-
}));
|
|
308
|
-
}, [rankedIds, iconsById]);
|
|
309
|
-
|
|
310
|
-
// Empty slot indices for the current page (only the last page can be
|
|
311
|
-
// partial). These are cheap placeholder dots.
|
|
312
|
-
const emptySlots = useMemo(() => {
|
|
313
|
-
const onThisPage = allDialIcons.filter(d => d.page === safePage).length;
|
|
314
|
-
const slots = [];
|
|
315
|
-
for (let s = onThisPage; s < MAX_DIAL_SLOTS; s += 1) slots.push(s);
|
|
316
|
-
return slots;
|
|
317
|
-
}, [allDialIcons, safePage]);
|
|
318
|
-
|
|
319
|
-
// Swap to another page. Every icon is already mounted, so this only toggles
|
|
320
|
-
// which ones are visible — no remount, no re-animation — keeping page
|
|
321
|
-
// changes instant.
|
|
322
|
-
const handlePageChange = next => {
|
|
323
|
-
const clamped = Math.max(0, Math.min(next, pageCount - 1));
|
|
324
|
-
if (clamped !== safePage) setCurrentPage(clamped);
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
// Initialize animations on mount - using shared config from core
|
|
328
|
-
useEffect(() => {
|
|
329
|
-
// Fallback config in case dialAnimationConfig hasn't loaded
|
|
330
|
-
const config = dialAnimationConfig ?? {
|
|
331
|
-
entrance: {
|
|
332
|
-
backdrop: {
|
|
333
|
-
duration: 400
|
|
334
|
-
},
|
|
335
|
-
dial: {
|
|
336
|
-
scale: {
|
|
337
|
-
damping: 15,
|
|
338
|
-
stiffness: 150,
|
|
339
|
-
mass: 1
|
|
340
|
-
},
|
|
341
|
-
rotation: {
|
|
342
|
-
duration: 800
|
|
343
|
-
}
|
|
344
|
-
},
|
|
345
|
-
centerButton: {
|
|
346
|
-
delay: 150,
|
|
347
|
-
damping: 10,
|
|
348
|
-
stiffness: 200
|
|
349
|
-
},
|
|
350
|
-
icons: {
|
|
351
|
-
delay: 200,
|
|
352
|
-
duration: 400
|
|
353
|
-
},
|
|
354
|
-
circuitTraces: {
|
|
355
|
-
delay: 600,
|
|
356
|
-
duration: 1000
|
|
357
|
-
}
|
|
358
|
-
},
|
|
359
|
-
continuous: {
|
|
360
|
-
glitch: {
|
|
361
|
-
interval: 3000,
|
|
362
|
-
offset: 2,
|
|
363
|
-
stepDuration: 50
|
|
364
|
-
},
|
|
365
|
-
pulse: {
|
|
366
|
-
maxScale: 1.02,
|
|
367
|
-
minScale: 0.98,
|
|
368
|
-
duration: 1000
|
|
369
|
-
},
|
|
370
|
-
floating: {
|
|
371
|
-
maxY: -8,
|
|
372
|
-
minY: 0,
|
|
373
|
-
duration: 3000
|
|
374
|
-
},
|
|
375
|
-
breathing: {
|
|
376
|
-
maxScale: 1.05,
|
|
377
|
-
minScale: 0.98,
|
|
378
|
-
duration: 2500
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
const {
|
|
383
|
-
entrance,
|
|
384
|
-
continuous
|
|
385
|
-
} = config;
|
|
386
|
-
|
|
387
|
-
// Entrance animation sequence
|
|
388
|
-
Animated.timing(backdropOpacity, {
|
|
389
|
-
toValue: 1,
|
|
390
|
-
duration: entrance.backdrop.duration,
|
|
391
|
-
useNativeDriver: true
|
|
392
|
-
}).start();
|
|
393
|
-
Animated.spring(dialScale, {
|
|
394
|
-
toValue: 1,
|
|
395
|
-
damping: entrance.dial.scale.damping,
|
|
396
|
-
stiffness: entrance.dial.scale.stiffness,
|
|
397
|
-
mass: entrance.dial.scale.mass,
|
|
398
|
-
useNativeDriver: true
|
|
399
|
-
}).start();
|
|
400
|
-
Animated.sequence([Animated.timing(dialRotation, {
|
|
401
|
-
toValue: 1,
|
|
402
|
-
duration: entrance.dial.rotation.duration,
|
|
403
|
-
easing: Easing.out(Easing.cubic),
|
|
404
|
-
useNativeDriver: true
|
|
405
|
-
}), Animated.timing(dialRotation, {
|
|
406
|
-
toValue: 0,
|
|
407
|
-
duration: 0,
|
|
408
|
-
useNativeDriver: true
|
|
409
|
-
})]).start();
|
|
410
|
-
Animated.sequence([Animated.delay(entrance.centerButton.delay), Animated.spring(centerButtonScale, {
|
|
411
|
-
toValue: 1,
|
|
412
|
-
damping: entrance.centerButton.damping,
|
|
413
|
-
stiffness: entrance.centerButton.stiffness,
|
|
414
|
-
useNativeDriver: true
|
|
415
|
-
})]).start();
|
|
416
|
-
Animated.sequence([Animated.delay(entrance.icons.delay), Animated.timing(iconsProgress, {
|
|
417
|
-
toValue: 1,
|
|
418
|
-
duration: entrance.icons.duration,
|
|
419
|
-
easing: Easing.out(Easing.cubic),
|
|
420
|
-
useNativeDriver: true
|
|
421
|
-
})]).start();
|
|
422
|
-
|
|
423
|
-
// Pulse animation - only continuous effect kept for performance
|
|
424
|
-
if (!DIAL_IDLE_PULSE) return;
|
|
425
|
-
pulseAnimationRef.current = Animated.loop(Animated.sequence([Animated.timing(pulseScale, {
|
|
426
|
-
toValue: continuous.pulse.maxScale,
|
|
427
|
-
duration: continuous.pulse.duration,
|
|
428
|
-
easing: Easing.inOut(Easing.ease),
|
|
429
|
-
useNativeDriver: true
|
|
430
|
-
}), Animated.timing(pulseScale, {
|
|
431
|
-
toValue: continuous.pulse.minScale,
|
|
432
|
-
duration: continuous.pulse.duration,
|
|
433
|
-
easing: Easing.inOut(Easing.ease),
|
|
434
|
-
useNativeDriver: true
|
|
435
|
-
})]));
|
|
436
|
-
pulseAnimationRef.current.start();
|
|
437
|
-
return () => {
|
|
438
|
-
pulseAnimationRef.current?.stop();
|
|
439
|
-
};
|
|
440
|
-
}, []);
|
|
441
|
-
const handleOnboardingDismiss = () => {
|
|
442
|
-
// Mark as dismissed immediately in ref (synchronous, no re-render needed)
|
|
443
|
-
onboardingDismissedRef.current = true;
|
|
444
|
-
|
|
445
|
-
// Hide the tooltip
|
|
446
|
-
setShowOnboardingTooltip(false);
|
|
447
|
-
|
|
448
|
-
// Save to storage asynchronously in the background
|
|
449
|
-
persistentStorage.setItem(ONBOARDING_STORAGE_KEY, "true").catch(error => {
|
|
450
|
-
// Silently fail - user already saw onboarding, just won't persist
|
|
451
|
-
console.warn("Failed to save dial onboarding state:", error);
|
|
452
|
-
});
|
|
453
|
-
};
|
|
454
|
-
const handleClose = () => {
|
|
455
|
-
// Stop any ongoing animations first
|
|
456
|
-
if (pulseAnimationRef.current) {
|
|
457
|
-
pulseAnimationRef.current.stop();
|
|
458
|
-
}
|
|
459
|
-
const exit = dialAnimationConfig?.exit ?? {
|
|
460
|
-
icons: {
|
|
461
|
-
duration: 300
|
|
462
|
-
},
|
|
463
|
-
centerButton: {
|
|
464
|
-
duration: 200
|
|
465
|
-
},
|
|
466
|
-
dialScale: {
|
|
467
|
-
duration: 250
|
|
468
|
-
},
|
|
469
|
-
backdrop: {
|
|
470
|
-
duration: 200
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
// Exit animation sequence - reverse order of entrance, using shared config
|
|
475
|
-
Animated.sequence([
|
|
476
|
-
// First animate icons back to center
|
|
477
|
-
Animated.timing(iconsProgress, {
|
|
478
|
-
toValue: 0,
|
|
479
|
-
duration: exit.icons.duration,
|
|
480
|
-
easing: Easing.in(Easing.cubic),
|
|
481
|
-
useNativeDriver: true
|
|
482
|
-
}),
|
|
483
|
-
// Then scale down center button and dial
|
|
484
|
-
Animated.parallel([Animated.timing(centerButtonScale, {
|
|
485
|
-
toValue: 0,
|
|
486
|
-
duration: exit.centerButton.duration,
|
|
487
|
-
easing: Easing.in(Easing.cubic),
|
|
488
|
-
useNativeDriver: true
|
|
489
|
-
}), Animated.timing(dialScale, {
|
|
490
|
-
toValue: 0,
|
|
491
|
-
duration: exit.dialScale.duration,
|
|
492
|
-
easing: Easing.in(Easing.cubic),
|
|
493
|
-
useNativeDriver: true
|
|
494
|
-
})]),
|
|
495
|
-
// Finally fade out backdrop
|
|
496
|
-
Animated.timing(backdropOpacity, {
|
|
497
|
-
toValue: 0,
|
|
498
|
-
duration: exit.backdrop.duration,
|
|
499
|
-
useNativeDriver: true
|
|
500
|
-
})]).start(() => {
|
|
501
|
-
// Use setTimeout to defer the state update to the next tick
|
|
502
|
-
// This avoids the useInsertionEffect warning
|
|
503
|
-
if (onClose) {
|
|
504
|
-
setTimeout(() => {
|
|
505
|
-
onClose();
|
|
506
|
-
}, 0);
|
|
507
|
-
}
|
|
508
|
-
});
|
|
509
|
-
};
|
|
510
|
-
const handleIconPress = icon => {
|
|
511
|
-
setSelectedIcon(1);
|
|
512
|
-
const interaction = dialAnimationConfig?.interaction ?? {
|
|
513
|
-
iconSelect: {
|
|
514
|
-
pulse: [{
|
|
515
|
-
scale: 0.9,
|
|
516
|
-
damping: 15,
|
|
517
|
-
stiffness: 500
|
|
518
|
-
}, {
|
|
519
|
-
scale: 1,
|
|
520
|
-
damping: 10,
|
|
521
|
-
stiffness: 200
|
|
522
|
-
}],
|
|
523
|
-
actionDelay: 50
|
|
524
|
-
}
|
|
525
|
-
};
|
|
526
|
-
const [pulseIn, pulseOut] = interaction.iconSelect.pulse;
|
|
527
|
-
|
|
528
|
-
// Pulse animation on selection - using shared config
|
|
529
|
-
Animated.sequence([Animated.spring(centerButtonScale, {
|
|
530
|
-
toValue: pulseIn.scale,
|
|
531
|
-
damping: pulseIn.damping,
|
|
532
|
-
stiffness: pulseIn.stiffness,
|
|
533
|
-
useNativeDriver: true
|
|
534
|
-
}), Animated.spring(centerButtonScale, {
|
|
535
|
-
toValue: pulseOut.scale,
|
|
536
|
-
damping: pulseOut.damping,
|
|
537
|
-
stiffness: pulseOut.stiffness,
|
|
538
|
-
useNativeDriver: true
|
|
539
|
-
})]).start();
|
|
540
|
-
|
|
541
|
-
// Trigger action - using shared delay
|
|
542
|
-
setTimeout(() => {
|
|
543
|
-
icon.onPress();
|
|
544
|
-
// Only close if it's not the WiFi toggle (by id)
|
|
545
|
-
if (icon.id !== "wifi") {
|
|
546
|
-
handleClose();
|
|
547
|
-
}
|
|
548
|
-
}, interaction.iconSelect.actionDelay);
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
// Animated styles
|
|
552
|
-
const backdropAnimatedStyle = {
|
|
553
|
-
opacity: backdropOpacity
|
|
554
|
-
};
|
|
555
|
-
const centerButtonAnimatedStyle = {
|
|
556
|
-
transform: [{
|
|
557
|
-
scale: centerButtonScale
|
|
558
|
-
}]
|
|
559
|
-
};
|
|
560
|
-
const pulseAnimatedStyle = {
|
|
561
|
-
transform: [{
|
|
562
|
-
scale: selectedIcon >= 0 ? 1 : pulseScale
|
|
563
|
-
}]
|
|
564
|
-
};
|
|
565
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
566
|
-
style: styles.container,
|
|
567
|
-
nativeID: "dial-devtools-root",
|
|
568
|
-
children: [/*#__PURE__*/_jsx(Animated.View, {
|
|
569
|
-
style: [styles.backdrop, backdropAnimatedStyle],
|
|
570
|
-
children: /*#__PURE__*/_jsx(Pressable, {
|
|
571
|
-
style: absoluteFill,
|
|
572
|
-
onPress: handleClose
|
|
573
|
-
})
|
|
574
|
-
}), /*#__PURE__*/_jsxs(Animated.View, {
|
|
575
|
-
style: [styles.parent, sizeStyles.parent, {
|
|
576
|
-
position: "absolute",
|
|
577
|
-
left: (screenWidth - circleSize) / 2,
|
|
578
|
-
bottom: 80,
|
|
579
|
-
transform: [{
|
|
580
|
-
scale: dialScale
|
|
581
|
-
}, {
|
|
582
|
-
rotate: dialRotation.interpolate({
|
|
583
|
-
inputRange: [0, 1],
|
|
584
|
-
outputRange: ["0deg", "360deg"]
|
|
585
|
-
})
|
|
586
|
-
}]
|
|
587
|
-
}],
|
|
588
|
-
children: [/*#__PURE__*/_jsxs(Animated.View, {
|
|
589
|
-
style: [styles.circle, sizeStyles.circle],
|
|
590
|
-
children: [/*#__PURE__*/_jsxs(View, {
|
|
591
|
-
style: [styles.gradientBackground, sizeStyles.rounded],
|
|
592
|
-
children: [/*#__PURE__*/_jsx(View, {
|
|
593
|
-
style: [styles.gradientLayer1, sizeStyles.rounded]
|
|
594
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
595
|
-
style: [styles.gradientLayer2, sizeStyles.rounded]
|
|
596
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
597
|
-
style: [styles.gradientLayer3, sizeStyles.rounded]
|
|
598
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
599
|
-
style: styles.gridPattern,
|
|
600
|
-
children: Array.from({
|
|
601
|
-
length: 6
|
|
602
|
-
}).map((_, i) => /*#__PURE__*/_jsxs(View, {
|
|
603
|
-
style: [styles.gridLine, sizeStyles.gridLine, {
|
|
604
|
-
transform: [{
|
|
605
|
-
rotate: `${i * 60}deg`
|
|
606
|
-
}]
|
|
607
|
-
}],
|
|
608
|
-
children: [/*#__PURE__*/_jsx(View, {
|
|
609
|
-
style: [styles.spoke, sizeStyles.spoke, styles.spokeLeft]
|
|
610
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
611
|
-
style: [styles.spoke, sizeStyles.spoke, styles.spokeRight]
|
|
612
|
-
})]
|
|
613
|
-
}, i))
|
|
614
|
-
}), backgroundId === "hyperspace" ? /*#__PURE__*/_jsx(DialHyperspace, {
|
|
615
|
-
size: circleSize
|
|
616
|
-
}) : /*#__PURE__*/_jsx(ToolBackground, {
|
|
617
|
-
focus: DIAL_BACKGROUND_FOCUS
|
|
618
|
-
})]
|
|
619
|
-
}), allDialIcons.filter(({
|
|
620
|
-
page
|
|
621
|
-
}) => page === safePage).map(({
|
|
622
|
-
icon,
|
|
623
|
-
slot
|
|
624
|
-
}) => /*#__PURE__*/_jsx(DialIcon, {
|
|
625
|
-
onPress: handleIconPress,
|
|
626
|
-
iconsProgress: iconsProgress,
|
|
627
|
-
icon: icon,
|
|
628
|
-
index: slot,
|
|
629
|
-
totalIcons: MAX_DIAL_SLOTS,
|
|
630
|
-
active: true
|
|
631
|
-
}, icon.id ?? `page${safePage}-${slot}`)), emptySlots.map(slot => /*#__PURE__*/_jsx(DialIcon, {
|
|
632
|
-
onPress: handleIconPress,
|
|
633
|
-
iconsProgress: iconsProgress,
|
|
634
|
-
icon: createEmptySlot(slot),
|
|
635
|
-
index: slot,
|
|
636
|
-
totalIcons: MAX_DIAL_SLOTS,
|
|
637
|
-
active: true
|
|
638
|
-
}, `empty-${slot}`))]
|
|
639
|
-
}), /*#__PURE__*/_jsx(Animated.View, {
|
|
640
|
-
style: [styles.buttonContainer, centerButtonAnimatedStyle],
|
|
641
|
-
children: /*#__PURE__*/_jsxs(View, {
|
|
642
|
-
style: styles.buttonGradient,
|
|
643
|
-
children: [/*#__PURE__*/_jsx(View, {
|
|
644
|
-
style: styles.buttonGradientLayer1
|
|
645
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
646
|
-
style: styles.buttonGradientLayer2
|
|
647
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
648
|
-
style: styles.buttonGradientLayer3
|
|
649
|
-
}), /*#__PURE__*/_jsx(View, {
|
|
650
|
-
style: styles.buttonBorder,
|
|
651
|
-
children: /*#__PURE__*/_jsx(Animated.View, {
|
|
652
|
-
style: [styles.button, pulseAnimatedStyle],
|
|
653
|
-
children: /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
654
|
-
accessibilityRole: "button",
|
|
655
|
-
accessibilityLabel: isSettingsModalOpen ? "Close Settings" : "Open Dev Tools Settings",
|
|
656
|
-
onPress: toggleSettingsModal
|
|
657
|
-
// Dims on touch-down so the press registers visually straight
|
|
658
|
-
// away, even though the panel only opens on release.
|
|
659
|
-
,
|
|
660
|
-
activeOpacity: 0.5,
|
|
661
|
-
style: styles.buttonPressable,
|
|
662
|
-
children: isSettingsModalOpen ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
663
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
664
|
-
style: [styles.centerText, styles.closeTextTop],
|
|
665
|
-
children: "CLOSE"
|
|
666
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
667
|
-
style: [styles.centerText, styles.closeTextBottom],
|
|
668
|
-
children: "SETTINGS"
|
|
669
|
-
})]
|
|
670
|
-
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
671
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
672
|
-
style: styles.centerText,
|
|
673
|
-
children: "BUOY"
|
|
674
|
-
}), isPro && /*#__PURE__*/_jsx(Text, {
|
|
675
|
-
style: [styles.proText, isWeekendFree && styles.weekendText],
|
|
676
|
-
children: isWeekendFree ? "WEEKEND" : "PRO"
|
|
677
|
-
})]
|
|
678
|
-
})
|
|
679
|
-
})
|
|
680
|
-
})
|
|
681
|
-
})]
|
|
682
|
-
})
|
|
683
|
-
})]
|
|
684
|
-
}), pageCount > 1 && /*#__PURE__*/_jsx(DialPagination, {
|
|
685
|
-
page: safePage,
|
|
686
|
-
pageCount: pageCount,
|
|
687
|
-
onPrev: () => handlePageChange(safePage - 1),
|
|
688
|
-
onNext: () => handlePageChange(safePage + 1),
|
|
689
|
-
animatedStyle: {
|
|
690
|
-
position: "absolute",
|
|
691
|
-
left: (screenWidth - circleSize) / 2,
|
|
692
|
-
// Circle's bottom edge sits at bottom: 80 -> screenHeight - 80
|
|
693
|
-
// from the top. Place the pager 16px below that edge.
|
|
694
|
-
top: screenHeight - 80 + 16,
|
|
695
|
-
width: circleSize,
|
|
696
|
-
opacity: dialScale,
|
|
697
|
-
transform: [{
|
|
698
|
-
scale: dialScale
|
|
699
|
-
}]
|
|
700
|
-
}
|
|
701
|
-
}), isSettingsModalOpen && /*#__PURE__*/_jsx(DevToolsSettingsModal, {
|
|
702
|
-
visible: true,
|
|
703
|
-
onClose: () => {
|
|
704
|
-
setIsSettingsModalOpen(false);
|
|
705
|
-
refreshSettings(); // Refresh from storage
|
|
706
|
-
},
|
|
707
|
-
availableApps: availableApps
|
|
708
|
-
}), showOnboardingTooltip && !isSettingsModalOpen && !onboardingDismissedRef.current && /*#__PURE__*/_jsx(OnboardingTooltip, {
|
|
709
|
-
visible: true,
|
|
710
|
-
onDismiss: handleOnboardingDismiss
|
|
711
|
-
})]
|
|
712
|
-
});
|
|
713
|
-
};
|
|
714
|
-
const styles = StyleSheet.create({
|
|
715
|
-
container: {
|
|
716
|
-
...absoluteFill,
|
|
717
|
-
zIndex: 9999
|
|
718
|
-
},
|
|
719
|
-
backdrop: {
|
|
720
|
-
...absoluteFill,
|
|
721
|
-
backgroundColor: dialColors.dialBackdrop
|
|
722
|
-
},
|
|
723
|
-
// width/height/borderRadius for the circle pieces come from sizeStyles —
|
|
724
|
-
// they track the live window width.
|
|
725
|
-
parent: {
|
|
726
|
-
alignItems: "center",
|
|
727
|
-
justifyContent: "center"
|
|
728
|
-
},
|
|
729
|
-
circle: {
|
|
730
|
-
position: "absolute",
|
|
731
|
-
backgroundColor: "transparent",
|
|
732
|
-
borderWidth: 1,
|
|
733
|
-
borderColor: dialColors.dialBorder,
|
|
734
|
-
shadowColor: dialColors.dialShadow,
|
|
735
|
-
shadowOffset: {
|
|
736
|
-
width: 0,
|
|
737
|
-
height: 0
|
|
738
|
-
},
|
|
739
|
-
shadowOpacity: 0.5,
|
|
740
|
-
shadowRadius: 20,
|
|
741
|
-
elevation: 10
|
|
742
|
-
},
|
|
743
|
-
gradientBackground: {
|
|
744
|
-
width: "100%",
|
|
745
|
-
height: "100%",
|
|
746
|
-
position: "relative",
|
|
747
|
-
backgroundColor: dialColors.dialBackground,
|
|
748
|
-
overflow: "hidden"
|
|
749
|
-
},
|
|
750
|
-
gradientLayer1: {
|
|
751
|
-
...absoluteFill,
|
|
752
|
-
backgroundColor: dialColors.dialGradient1,
|
|
753
|
-
opacity: 0.6
|
|
754
|
-
},
|
|
755
|
-
gradientLayer2: {
|
|
756
|
-
...absoluteFill,
|
|
757
|
-
backgroundColor: dialColors.dialGradient2,
|
|
758
|
-
opacity: 0.4,
|
|
759
|
-
top: "30%",
|
|
760
|
-
left: "30%"
|
|
761
|
-
},
|
|
762
|
-
gradientLayer3: {
|
|
763
|
-
...absoluteFill,
|
|
764
|
-
backgroundColor: dialColors.dialGradient3,
|
|
765
|
-
opacity: 0.3,
|
|
766
|
-
top: "50%",
|
|
767
|
-
left: "50%"
|
|
768
|
-
},
|
|
769
|
-
gridPattern: {
|
|
770
|
-
...absoluteFill,
|
|
771
|
-
alignItems: "center",
|
|
772
|
-
justifyContent: "center"
|
|
773
|
-
},
|
|
774
|
-
gridLine: {
|
|
775
|
-
position: "absolute",
|
|
776
|
-
height: 1
|
|
777
|
-
},
|
|
778
|
-
spoke: {
|
|
779
|
-
position: "absolute",
|
|
780
|
-
top: 0,
|
|
781
|
-
height: 1,
|
|
782
|
-
backgroundColor: dialColors.dialGridLine
|
|
783
|
-
},
|
|
784
|
-
spokeLeft: {
|
|
785
|
-
left: 0
|
|
786
|
-
},
|
|
787
|
-
spokeRight: {
|
|
788
|
-
right: 0
|
|
789
|
-
},
|
|
790
|
-
buttonContainer: {
|
|
791
|
-
zIndex: 1,
|
|
792
|
-
backgroundColor: "transparent",
|
|
793
|
-
alignItems: "center",
|
|
794
|
-
justifyContent: "center",
|
|
795
|
-
position: "absolute",
|
|
796
|
-
width: BUTTON_SIZE * 1.5,
|
|
797
|
-
height: BUTTON_SIZE * 1.5,
|
|
798
|
-
borderRadius: BUTTON_SIZE
|
|
799
|
-
},
|
|
800
|
-
// The hub is glass: no rings, no opaque fill. The outer disc is a barely-
|
|
801
|
-
// there shade and the inner button a soft puck, so the tool background runs
|
|
802
|
-
// through the middle of the dial while BUOY / PRO stay legible. The spokes
|
|
803
|
-
// stop at HUB_CLEARANCE so nothing draws under it.
|
|
804
|
-
buttonGradient: {
|
|
805
|
-
width: "100%",
|
|
806
|
-
height: "100%",
|
|
807
|
-
borderRadius: BUTTON_SIZE,
|
|
808
|
-
alignItems: "center",
|
|
809
|
-
justifyContent: "center",
|
|
810
|
-
padding: 4,
|
|
811
|
-
backgroundColor: dialColors.hubHalo,
|
|
812
|
-
position: "relative",
|
|
813
|
-
overflow: "hidden"
|
|
814
|
-
},
|
|
815
|
-
buttonGradientLayer1: {
|
|
816
|
-
...absoluteFill,
|
|
817
|
-
backgroundColor: dialColors.dialGradient1,
|
|
818
|
-
opacity: 0.5,
|
|
819
|
-
borderRadius: BUTTON_SIZE
|
|
820
|
-
},
|
|
821
|
-
buttonGradientLayer2: {
|
|
822
|
-
...absoluteFill,
|
|
823
|
-
backgroundColor: dialColors.dialGradient2,
|
|
824
|
-
opacity: 0.3,
|
|
825
|
-
top: "20%",
|
|
826
|
-
left: "20%",
|
|
827
|
-
borderRadius: BUTTON_SIZE
|
|
828
|
-
},
|
|
829
|
-
buttonGradientLayer3: {
|
|
830
|
-
...absoluteFill,
|
|
831
|
-
backgroundColor: dialColors.dialGradient3,
|
|
832
|
-
opacity: 0.2,
|
|
833
|
-
top: "40%",
|
|
834
|
-
left: "40%",
|
|
835
|
-
borderRadius: BUTTON_SIZE
|
|
836
|
-
},
|
|
837
|
-
buttonBorder: {
|
|
838
|
-
backgroundColor: dialColors.hubFill,
|
|
839
|
-
alignItems: "center",
|
|
840
|
-
justifyContent: "center",
|
|
841
|
-
width: BUTTON_SIZE * 1.2,
|
|
842
|
-
height: BUTTON_SIZE * 1.2,
|
|
843
|
-
borderRadius: BUTTON_SIZE * 0.6
|
|
844
|
-
},
|
|
845
|
-
button: {
|
|
846
|
-
width: BUTTON_SIZE,
|
|
847
|
-
height: BUTTON_SIZE,
|
|
848
|
-
borderRadius: BUTTON_SIZE / 2,
|
|
849
|
-
justifyContent: "center",
|
|
850
|
-
alignItems: "center",
|
|
851
|
-
position: "relative",
|
|
852
|
-
overflow: "hidden"
|
|
853
|
-
},
|
|
854
|
-
buttonPressable: {
|
|
855
|
-
width: "100%",
|
|
856
|
-
height: "100%",
|
|
857
|
-
justifyContent: "center",
|
|
858
|
-
alignItems: "center"
|
|
859
|
-
},
|
|
860
|
-
centerText: {
|
|
861
|
-
color: dialColors.centerText,
|
|
862
|
-
fontSize: 10,
|
|
863
|
-
fontWeight: "900",
|
|
864
|
-
fontFamily: monoFont,
|
|
865
|
-
letterSpacing: 1,
|
|
866
|
-
textAlign: "center",
|
|
867
|
-
textTransform: "uppercase",
|
|
868
|
-
textShadowColor: dialColors.centerTextGlow,
|
|
869
|
-
textShadowOffset: {
|
|
870
|
-
width: 0,
|
|
871
|
-
height: 0
|
|
872
|
-
},
|
|
873
|
-
textShadowRadius: 4
|
|
874
|
-
},
|
|
875
|
-
closeTextTop: {
|
|
876
|
-
marginBottom: -2
|
|
877
|
-
},
|
|
878
|
-
closeTextBottom: {
|
|
879
|
-
marginTop: -2
|
|
880
|
-
},
|
|
881
|
-
proText: {
|
|
882
|
-
color: buoyColors.warning,
|
|
883
|
-
fontSize: 8,
|
|
884
|
-
fontWeight: "900",
|
|
885
|
-
fontFamily: monoFont,
|
|
886
|
-
letterSpacing: 2,
|
|
887
|
-
textAlign: "center",
|
|
888
|
-
textShadowColor: dialColors.centerTextGlow,
|
|
889
|
-
textShadowOffset: {
|
|
890
|
-
width: 0,
|
|
891
|
-
height: 0
|
|
892
|
-
},
|
|
893
|
-
textShadowRadius: 4
|
|
894
|
-
},
|
|
895
|
-
// Weekend Pass variant — violet, tighter spacing so "WEEKEND" fits the dial.
|
|
896
|
-
weekendText: {
|
|
897
|
-
color: "#BF5AF2",
|
|
898
|
-
letterSpacing: 1
|
|
899
|
-
}
|
|
900
|
-
});
|
|
1
|
+
"use strict";import{useEffect as b,useMemo as S,useRef as f,useState as w}from"react";import{Pressable as Ie,StyleSheet as Le,TouchableOpacity as Oe,View as s,useWindowDimensions as Be,Text as P,Animated as o,Easing as l}from"react-native";import{absoluteFill as u,monoFont as oe}from"@buoy-gg/shared-ui";import{DialIcon as ne}from"./DialIcon.js";import{DialHyperspace as Pe}from"./DialHyperspace.js";import{DialPagination as Re}from"./DialPagination.js";import{getRankedToolIds as F,isDialUsageLoaded as Ae,loadDialUsage as Ve,recordToolUsage as Ne}from"./dialUsageStore.js";import{persistentStorage as R,useHintsDisabled as Ge,devToolsStorageKeys as ie,buoyColors as re,ToolBackground as Me,useToolBackground as _e}from"@buoy-gg/shared-ui";import{DevToolsSettingsModal as Ee,useDevToolsSettings as Fe}from"../DevToolsSettingsModal";import{useProAccess as je}from"@buoy-gg/license";import{renderAppIcon as ae}from"../AppIcon";import{useAppHost as ze}from"../AppHost";import{OnboardingTooltip as Ue}from"./OnboardingTooltip";import{getDialLayout as We,MAX_DIAL_SLOTS as v,DIAL_BUTTON_SIZE as qe,dialAnimationConfig as j,dialColors as a}from"@buoy-gg/floating-tools-core";import{jsx as i,jsxs as h,Fragment as se}from"react/jsx-runtime";const c=qe;const He={x:.5,y:.5};const $e=c*.75+6;const Ke=false;const le="@react_buoy_settings_tooltip_shown";const Ye=y=>({id:`empty-${y}`,name:`empty-${y}`,icon:null,color:"transparent",onPress:()=>{}});export const DialDevTools=({onClose:y,onSettingsPress:ce,autoOpenSettings:z=false,apps:L,state:Ze,actions:U})=>{const[de,ue]=w(-1);const[g,T]=w(false);const[W,ge]=w(false);const[q,H]=w(false);const A=f(false);const $=Ge();const{refreshSettings:pe}=Fe();const{open:K}=ze();const{isPro:me,isWeekendFree:Y}=je();const{width:V,height:fe}=Be();const d=We({screenWidth:V}).circleSize;const{id:he}=_e();const p=S(()=>({parent:{width:d,height:d},circle:{width:d,height:d,borderRadius:d/2},rounded:{borderRadius:d/2},gridLine:{width:d},spoke:{width:d/2-$e}}),[d]);b(()=>{const t=async()=>{try{const e=await R.getItem(ie.settings.modalOpen());if(e==="true"){T(true)}}catch(e){}finally{ge(true)}};t()},[]);b(()=>{if(!W)return;R.setItem(ie.settings.modalOpen(),g?"true":"false").catch(t=>{console.warn("Failed to save settings modal state:",t)})},[g,W]);b(()=>{if(z&&!g){T(true)}},[z,g]);b(()=>{if($){return}const t=async()=>{try{const e=await R.getItem(le);if(!e){setTimeout(()=>{H(true)},1200)}}catch(e){}};t()},[$]);const N=f(new o.Value(0)).current;const k=f(new o.Value(0)).current;const G=f(new o.Value(0)).current;const D=f(new o.Value(0)).current;const O=f(new o.Value(0)).current;const M=f(new o.Value(1)).current;const ye=S(()=>L.map(({id:t,name:e,slot:r,description:I,icon:xe,color:Ce})=>({id:t,name:e,slot:r,description:I,icon:xe,color:Ce})),[L]);const x=f(null);const be=()=>{if(g){T(false);return}T(true);if(q&&!A.current){Q()}ce?.()};const C=S(()=>L.filter(t=>(t.slot??"both")!=="row"),[L]);const Z=S(()=>{const t=new Map;for(const e of C){t.set(e.id,{id:e.id,name:e.name,icon:typeof e.icon==="function"?null:ae(e.icon,{slot:"dial",size:20,color:e.color}),iconComponent:typeof e.icon==="function"?e.icon:void 0,color:e.color??re.primary,onPress:()=>{void Ne(e.id);e?.onPress?.(U);if(e.launchMode!=="toggle-only"){const r=ae(e.icon,{slot:"dial",size:20,color:e.color});K({id:e.id,title:e.name,component:e.component,props:e.props,launchMode:e.launchMode??"self-modal",singleton:e.singleton??true,icon:r,color:e.color,modal:e.modal})}y?.()}})}return t},[C,U,K,y]);const[_,X]=w(()=>F(C.map(t=>t.id)));b(()=>{const t=C.map(r=>r.id);if(Ae()){X(F(t));return}let e=false;Ve().then(()=>{if(!e)X(F(t))});return()=>{e=true}},[C]);const B=Math.max(1,Math.ceil(_.length/v));const[Se,we]=w(0);const m=Math.min(Se,B-1);const E=S(()=>{return _.map(t=>Z.get(t)).filter(t=>Boolean(t)).map((t,e)=>({icon:t,page:Math.floor(e/v),slot:e%v}))},[_,Z]);const ve=S(()=>{const t=E.filter(r=>r.page===m).length;const e=[];for(let r=t;r<v;r+=1)e.push(r);return e},[E,m]);const J=t=>{const e=Math.max(0,Math.min(t,B-1));if(e!==m)we(e)};b(()=>{const t=j??{entrance:{backdrop:{duration:400},dial:{scale:{damping:15,stiffness:150,mass:1},rotation:{duration:800}},centerButton:{delay:150,damping:10,stiffness:200},icons:{delay:200,duration:400},circuitTraces:{delay:600,duration:1e3}},continuous:{glitch:{interval:3e3,offset:2,stepDuration:50},pulse:{maxScale:1.02,minScale:.98,duration:1e3},floating:{maxY:-8,minY:0,duration:3e3},breathing:{maxScale:1.05,minScale:.98,duration:2500}}};const{entrance:e,continuous:r}=t;o.timing(N,{toValue:1,duration:e.backdrop.duration,useNativeDriver:true}).start();o.spring(k,{toValue:1,damping:e.dial.scale.damping,stiffness:e.dial.scale.stiffness,mass:e.dial.scale.mass,useNativeDriver:true}).start();o.sequence([o.timing(G,{toValue:1,duration:e.dial.rotation.duration,easing:l.out(l.cubic),useNativeDriver:true}),o.timing(G,{toValue:0,duration:0,useNativeDriver:true})]).start();o.sequence([o.delay(e.centerButton.delay),o.spring(D,{toValue:1,damping:e.centerButton.damping,stiffness:e.centerButton.stiffness,useNativeDriver:true})]).start();o.sequence([o.delay(e.icons.delay),o.timing(O,{toValue:1,duration:e.icons.duration,easing:l.out(l.cubic),useNativeDriver:true})]).start();if(!Ke)return;x.current=o.loop(o.sequence([o.timing(M,{toValue:r.pulse.maxScale,duration:r.pulse.duration,easing:l.inOut(l.ease),useNativeDriver:true}),o.timing(M,{toValue:r.pulse.minScale,duration:r.pulse.duration,easing:l.inOut(l.ease),useNativeDriver:true})]));x.current.start();return()=>{x.current?.stop()}},[]);const Q=()=>{A.current=true;H(false);R.setItem(le,"true").catch(t=>{console.warn("Failed to save dial onboarding state:",t)})};const ee=()=>{if(x.current){x.current.stop()}const t=j?.exit??{icons:{duration:300},centerButton:{duration:200},dialScale:{duration:250},backdrop:{duration:200}};o.sequence([o.timing(O,{toValue:0,duration:t.icons.duration,easing:l.in(l.cubic),useNativeDriver:true}),o.parallel([o.timing(D,{toValue:0,duration:t.centerButton.duration,easing:l.in(l.cubic),useNativeDriver:true}),o.timing(k,{toValue:0,duration:t.dialScale.duration,easing:l.in(l.cubic),useNativeDriver:true})]),o.timing(N,{toValue:0,duration:t.backdrop.duration,useNativeDriver:true})]).start(()=>{if(y){setTimeout(()=>{y()},0)}})};const te=t=>{ue(1);const e=j?.interaction??{iconSelect:{pulse:[{scale:.9,damping:15,stiffness:500},{scale:1,damping:10,stiffness:200}],actionDelay:50}};const[r,I]=e.iconSelect.pulse;o.sequence([o.spring(D,{toValue:r.scale,damping:r.damping,stiffness:r.stiffness,useNativeDriver:true}),o.spring(D,{toValue:I.scale,damping:I.damping,stiffness:I.stiffness,useNativeDriver:true})]).start();setTimeout(()=>{t.onPress();if(t.id!=="wifi"){ee()}},e.iconSelect.actionDelay)};const Te={opacity:N};const ke={transform:[{scale:D}]};const De={transform:[{scale:de>=0?1:M}]};return h(s,{style:n.container,nativeID:"dial-devtools-root",children:[i(o.View,{style:[n.backdrop,Te],children:i(Ie,{style:u,onPress:ee})}),h(o.View,{style:[n.parent,p.parent,{position:"absolute",left:(V-d)/2,bottom:80,transform:[{scale:k},{rotate:G.interpolate({inputRange:[0,1],outputRange:["0deg","360deg"]})}]}],children:[h(o.View,{style:[n.circle,p.circle],children:[h(s,{style:[n.gradientBackground,p.rounded],children:[i(s,{style:[n.gradientLayer1,p.rounded]}),i(s,{style:[n.gradientLayer2,p.rounded]}),i(s,{style:[n.gradientLayer3,p.rounded]}),i(s,{style:n.gridPattern,children:Array.from({length:6}).map((t,e)=>h(s,{style:[n.gridLine,p.gridLine,{transform:[{rotate:`${e*60}deg`}]}],children:[i(s,{style:[n.spoke,p.spoke,n.spokeLeft]}),i(s,{style:[n.spoke,p.spoke,n.spokeRight]})]},e))}),he==="hyperspace"?i(Pe,{size:d}):i(Me,{focus:He})]}),E.filter(({page:t})=>t===m).map(({icon:t,slot:e})=>i(ne,{onPress:te,iconsProgress:O,icon:t,index:e,totalIcons:v,active:true},t.id??`page${m}-${e}`)),ve.map(t=>i(ne,{onPress:te,iconsProgress:O,icon:Ye(t),index:t,totalIcons:v,active:true},`empty-${t}`))]}),i(o.View,{style:[n.buttonContainer,ke],children:h(s,{style:n.buttonGradient,children:[i(s,{style:n.buttonGradientLayer1}),i(s,{style:n.buttonGradientLayer2}),i(s,{style:n.buttonGradientLayer3}),i(s,{style:n.buttonBorder,children:i(o.View,{style:[n.button,De],children:i(Oe,{accessibilityRole:"button",accessibilityLabel:g?"Close Settings":"Open Dev Tools Settings",onPress:be,activeOpacity:.5,style:n.buttonPressable,children:g?h(se,{children:[i(P,{style:[n.centerText,n.closeTextTop],children:"CLOSE"}),i(P,{style:[n.centerText,n.closeTextBottom],children:"SETTINGS"})]}):h(se,{children:[i(P,{style:n.centerText,children:"BUOY"}),me&&i(P,{style:[n.proText,Y&&n.weekendText],children:Y?"WEEKEND":"PRO"})]})})})})]})})]}),B>1&&i(Re,{page:m,pageCount:B,onPrev:()=>J(m-1),onNext:()=>J(m+1),animatedStyle:{position:"absolute",left:(V-d)/2,top:fe-80+16,width:d,opacity:k,transform:[{scale:k}]}}),g&&i(Ee,{visible:true,onClose:()=>{T(false);pe()},availableApps:ye}),q&&!g&&!A.current&&i(Ue,{visible:true,onDismiss:Q})]})};const n=Le.create({container:{...u,zIndex:9999},backdrop:{...u,backgroundColor:a.dialBackdrop},parent:{alignItems:"center",justifyContent:"center"},circle:{position:"absolute",backgroundColor:"transparent",borderWidth:1,borderColor:a.dialBorder,shadowColor:a.dialShadow,shadowOffset:{width:0,height:0},shadowOpacity:.5,shadowRadius:20,elevation:10},gradientBackground:{width:"100%",height:"100%",position:"relative",backgroundColor:a.dialBackground,overflow:"hidden"},gradientLayer1:{...u,backgroundColor:a.dialGradient1,opacity:.6},gradientLayer2:{...u,backgroundColor:a.dialGradient2,opacity:.4,top:"30%",left:"30%"},gradientLayer3:{...u,backgroundColor:a.dialGradient3,opacity:.3,top:"50%",left:"50%"},gridPattern:{...u,alignItems:"center",justifyContent:"center"},gridLine:{position:"absolute",height:1},spoke:{position:"absolute",top:0,height:1,backgroundColor:a.dialGridLine},spokeLeft:{left:0},spokeRight:{right:0},buttonContainer:{zIndex:1,backgroundColor:"transparent",alignItems:"center",justifyContent:"center",position:"absolute",width:c*1.5,height:c*1.5,borderRadius:c},buttonGradient:{width:"100%",height:"100%",borderRadius:c,alignItems:"center",justifyContent:"center",padding:4,backgroundColor:a.hubHalo,position:"relative",overflow:"hidden"},buttonGradientLayer1:{...u,backgroundColor:a.dialGradient1,opacity:.5,borderRadius:c},buttonGradientLayer2:{...u,backgroundColor:a.dialGradient2,opacity:.3,top:"20%",left:"20%",borderRadius:c},buttonGradientLayer3:{...u,backgroundColor:a.dialGradient3,opacity:.2,top:"40%",left:"40%",borderRadius:c},buttonBorder:{backgroundColor:a.hubFill,alignItems:"center",justifyContent:"center",width:c*1.2,height:c*1.2,borderRadius:c*.6},button:{width:c,height:c,borderRadius:c/2,justifyContent:"center",alignItems:"center",position:"relative",overflow:"hidden"},buttonPressable:{width:"100%",height:"100%",justifyContent:"center",alignItems:"center"},centerText:{color:a.centerText,fontSize:10,fontWeight:"900",fontFamily:oe,letterSpacing:1,textAlign:"center",textTransform:"uppercase",textShadowColor:a.centerTextGlow,textShadowOffset:{width:0,height:0},textShadowRadius:4},closeTextTop:{marginBottom:-2},closeTextBottom:{marginTop:-2},proText:{color:re.warning,fontSize:8,fontWeight:"900",fontFamily:oe,letterSpacing:2,textAlign:"center",textShadowColor:a.centerTextGlow,textShadowOffset:{width:0,height:0},textShadowRadius:4},weekendText:{color:"#BF5AF2",letterSpacing:1}});
|