@buoy-gg/core 7.0.40 → 7.0.42
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 -85
- package/bin/buoy.js +20 -347
- package/lib/commonjs/Buoy.js +1 -107
- package/lib/commonjs/browserRegister.js +1 -0
- package/lib/commonjs/browserRegister.server.js +1 -0
- 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 -364
- 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 -0
- package/lib/commonjs/floatingMenu/DefaultConfigContext.js +1 -45
- package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +1 -1119
- package/lib/commonjs/floatingMenu/DevToolsSettingsModal.shared.js +1 -0
- package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +1 -1048
- package/lib/commonjs/floatingMenu/DevToolsVisibilityContext.js +1 -49
- package/lib/commonjs/floatingMenu/FloatingDevTools.js +1 -554
- package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +1 -401
- 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 -371
- 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 -461
- package/lib/commonjs/floatingMenu/autoExternalSync.js +1 -434
- 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 -821
- package/lib/commonjs/floatingMenu/dial/DialHyperspace.js +1 -177
- package/lib/commonjs/floatingMenu/dial/DialIcon.js +1 -302
- 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 -23
- 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 -0
- package/lib/commonjs/index.js +1 -291
- package/lib/commonjs/index.web.js +1 -150
- package/lib/commonjs/reactDevtoolsTypes.js +1 -0
- 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 -219
- package/lib/commonjs/utils/createWebTool.js +1 -0
- package/lib/commonjs/utils/createWebTools.js +1 -0
- package/lib/commonjs/version.js +1 -18
- package/lib/module/Buoy.js +1 -102
- package/lib/module/browserRegister.js +1 -0
- package/lib/module/browserRegister.server.js +1 -0
- 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 -356
- 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 -0
- package/lib/module/floatingMenu/DefaultConfigContext.js +1 -39
- package/lib/module/floatingMenu/DevToolsSettingsModal.js +1 -1115
- package/lib/module/floatingMenu/DevToolsSettingsModal.shared.js +1 -0
- package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +1 -1055
- package/lib/module/floatingMenu/DevToolsVisibilityContext.js +1 -44
- package/lib/module/floatingMenu/FloatingDevTools.js +1 -551
- package/lib/module/floatingMenu/FloatingDevTools.web.js +1 -399
- 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 -368
- 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 -457
- package/lib/module/floatingMenu/autoExternalSync.js +1 -427
- 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 -818
- package/lib/module/floatingMenu/dial/DialHyperspace.js +1 -173
- package/lib/module/floatingMenu/dial/DialIcon.js +1 -299
- 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 -19
- 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 -0
- package/lib/module/index.js +1 -41
- package/lib/module/index.web.js +1 -29
- package/lib/module/reactDevtoolsTypes.js +1 -0
- 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 -213
- package/lib/module/utils/createWebTool.js +1 -0
- package/lib/module/utils/createWebTools.js +1 -0
- package/lib/module/version.js +1 -14
- package/lib/typescript/commonjs/browserRegister.d.ts +13 -0
- package/lib/typescript/commonjs/browserRegister.server.d.ts +6 -0
- package/lib/typescript/commonjs/earlyHookScript.d.ts +12 -0
- package/lib/typescript/commonjs/earlyNetwork.d.ts +52 -0
- package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts +3 -3
- package/lib/typescript/commonjs/floatingMenu/BrowserToolRuntime.d.ts +14 -0
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts +2 -67
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.shared.d.ts +71 -0
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts +3 -16
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts +12 -6
- package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +1 -1
- package/lib/typescript/commonjs/floatingMenu/settingsBus.d.ts +1 -9
- package/lib/typescript/commonjs/floatingMenu/useDesktopSyncStatus.web.d.ts +3 -0
- package/lib/typescript/commonjs/index.web.d.ts +7 -0
- package/lib/typescript/commonjs/reactDevtoolsTypes.d.ts +8 -0
- package/lib/typescript/commonjs/releaseOptIn.d.ts +4 -0
- package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts +3 -40
- package/lib/typescript/commonjs/utils/createWebTool.d.ts +6 -0
- package/lib/typescript/commonjs/utils/createWebTools.d.ts +4 -0
- package/lib/typescript/commonjs/version.d.ts +1 -1
- package/lib/typescript/module/browserRegister.d.ts +13 -0
- package/lib/typescript/module/browserRegister.server.d.ts +6 -0
- package/lib/typescript/module/earlyHookScript.d.ts +12 -0
- package/lib/typescript/module/earlyNetwork.d.ts +52 -0
- package/lib/typescript/module/floatingMenu/AppHost.web.d.ts +3 -3
- package/lib/typescript/module/floatingMenu/BrowserToolRuntime.d.ts +14 -0
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts +2 -67
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.shared.d.ts +71 -0
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts +3 -16
- package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts +12 -6
- package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +1 -1
- package/lib/typescript/module/floatingMenu/settingsBus.d.ts +1 -9
- package/lib/typescript/module/floatingMenu/useDesktopSyncStatus.web.d.ts +3 -0
- package/lib/typescript/module/index.web.d.ts +7 -0
- package/lib/typescript/module/reactDevtoolsTypes.d.ts +8 -0
- package/lib/typescript/module/releaseOptIn.d.ts +4 -0
- package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts +3 -40
- package/lib/typescript/module/utils/createWebTool.d.ts +6 -0
- package/lib/typescript/module/utils/createWebTools.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 -0
- package/lib/web/chunks/chunk-R7RGRTY5.mjs +1 -0
- package/lib/web/index.mjs +10 -0
- package/lib/web/register-server.mjs +1 -0
- package/lib/web/register.mjs +1 -0
- package/lib/web/toolkit.mjs +1 -0
- package/package.json +50 -12
- package/lib/typescript/commonjs/Buoy.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/DefaultConfigContext.d.ts.map +0 -1
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.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/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/index.web.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/version.d.ts.map +0 -1
- package/lib/typescript/module/Buoy.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/DefaultConfigContext.d.ts.map +0 -1
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.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/index.d.ts.map +0 -1
- package/lib/typescript/module/index.web.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/version.d.ts.map +0 -1
|
@@ -1,821 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.DialMenu = DialMenu;
|
|
7
|
-
var _react = require("react");
|
|
8
|
-
var _floatingToolsReact = require("@buoy-gg/floating-tools-react");
|
|
9
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
|
-
var _OnboardingTooltipWeb = require("./OnboardingTooltip.web.js");
|
|
11
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
12
|
-
/**
|
|
13
|
-
* DialDevTools - Web renderer for the radial dial menu.
|
|
14
|
-
*
|
|
15
|
-
* Uses shared layout calculations, styling, and animation config from @buoy-gg/floating-tools-core.
|
|
16
|
-
* Platform-specific: CSS animations, mouse events, web JSX.
|
|
17
|
-
*
|
|
18
|
-
* Visuals mirror the native DialDevTools.tsx exactly — values that never made
|
|
19
|
-
* it into the shared dial.ts are inlined here with provenance comments.
|
|
20
|
-
*
|
|
21
|
-
* @platform React DOM Web (Vite, CRA, Next.js, Electron)
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
// native DialDevTools.tsx SETTINGS_TOOLTIP_KEY
|
|
25
|
-
const SETTINGS_TOOLTIP_KEY = '@react_buoy_settings_tooltip_shown';
|
|
26
|
-
|
|
27
|
-
// Inject CSS keyframes once on module load
|
|
28
|
-
let keyframesInjected = false;
|
|
29
|
-
function injectKeyframes() {
|
|
30
|
-
if (keyframesInjected || typeof document === 'undefined') return;
|
|
31
|
-
const style = document.createElement('style');
|
|
32
|
-
style.textContent = (0, _floatingToolsReact.getDialCSSKeyframesString)();
|
|
33
|
-
document.head.appendChild(style);
|
|
34
|
-
keyframesInjected = true;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Easing functions
|
|
38
|
-
const easeOutCubic = t => 1 - Math.pow(1 - t, 3);
|
|
39
|
-
const easeInCubic = t => t * t * t;
|
|
40
|
-
|
|
41
|
-
// =============================
|
|
42
|
-
// Types
|
|
43
|
-
// =============================
|
|
44
|
-
|
|
45
|
-
// =============================
|
|
46
|
-
// Dial Icon Component
|
|
47
|
-
// =============================
|
|
48
|
-
|
|
49
|
-
function DialIconItem({
|
|
50
|
-
icon,
|
|
51
|
-
index,
|
|
52
|
-
totalIcons,
|
|
53
|
-
position,
|
|
54
|
-
progress,
|
|
55
|
-
onPress
|
|
56
|
-
}) {
|
|
57
|
-
const [isHovered, setIsHovered] = (0, _react.useState)(false);
|
|
58
|
-
const [isPressed, setIsPressed] = (0, _react.useState)(false);
|
|
59
|
-
const isEmpty = !icon.icon && icon.id.startsWith('empty-');
|
|
60
|
-
const isUnavailable = !isEmpty && icon.unavailable === true;
|
|
61
|
-
const interactive = !isEmpty && !isUnavailable;
|
|
62
|
-
const {
|
|
63
|
-
icons: iconConfig
|
|
64
|
-
} = _floatingToolsReact.dialAnimationConfig;
|
|
65
|
-
|
|
66
|
-
// Get stagger input range for this icon
|
|
67
|
-
const staggerInputRange = (0, _floatingToolsReact.getIconStaggerInputRange)(index, totalIcons);
|
|
68
|
-
|
|
69
|
-
// Calculate this icon's individual progress based on the global progress
|
|
70
|
-
let iconProgress = 0;
|
|
71
|
-
if (progress <= staggerInputRange[1]) {
|
|
72
|
-
iconProgress = 0;
|
|
73
|
-
} else if (progress <= staggerInputRange[2]) {
|
|
74
|
-
iconProgress = (progress - staggerInputRange[1]) / (staggerInputRange[2] - staggerInputRange[1]);
|
|
75
|
-
} else {
|
|
76
|
-
iconProgress = 1;
|
|
77
|
-
}
|
|
78
|
-
iconProgress = Math.max(0, Math.min(1, iconProgress));
|
|
79
|
-
const iconSize = _floatingToolsReact.DIAL_ICON_SIZE;
|
|
80
|
-
const pressedScale = iconConfig.pressIn.scale;
|
|
81
|
-
const hoveredScale = 1.1; // web-only hover affordance (no native counterpart)
|
|
82
|
-
|
|
83
|
-
const scale = iconProgress * (isPressed ? pressedScale : isHovered ? hoveredScale : 1);
|
|
84
|
-
|
|
85
|
-
// Opacity interpolation — native DialIcon.tsx: [0, 0.3, 1] -> [0, 0.3, 1]
|
|
86
|
-
let opacity = 0;
|
|
87
|
-
if (iconProgress <= 0) {
|
|
88
|
-
opacity = 0;
|
|
89
|
-
} else if (iconProgress <= 0.3) {
|
|
90
|
-
opacity = iconProgress;
|
|
91
|
-
} else {
|
|
92
|
-
opacity = 0.3 + (iconProgress - 0.3) * (0.7 / 0.7);
|
|
93
|
-
}
|
|
94
|
-
const x = position.x * iconProgress;
|
|
95
|
-
const y = position.y * iconProgress;
|
|
96
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
|
|
97
|
-
role: "menuitem",
|
|
98
|
-
"aria-label": isEmpty ? 'Empty slot' : icon.name,
|
|
99
|
-
"aria-disabled": !interactive,
|
|
100
|
-
tabIndex: interactive ? 0 : -1,
|
|
101
|
-
onClick: interactive ? onPress : undefined,
|
|
102
|
-
onMouseEnter: () => interactive && setIsHovered(true),
|
|
103
|
-
onMouseLeave: () => {
|
|
104
|
-
setIsHovered(false);
|
|
105
|
-
setIsPressed(false);
|
|
106
|
-
},
|
|
107
|
-
onMouseDown: () => interactive && setIsPressed(true),
|
|
108
|
-
onMouseUp: () => setIsPressed(false),
|
|
109
|
-
style: {
|
|
110
|
-
position: 'absolute',
|
|
111
|
-
left: '50%',
|
|
112
|
-
top: '50%',
|
|
113
|
-
width: iconSize,
|
|
114
|
-
height: iconSize,
|
|
115
|
-
marginLeft: -iconSize / 2,
|
|
116
|
-
marginTop: -iconSize / 2,
|
|
117
|
-
display: 'flex',
|
|
118
|
-
flexDirection: 'column',
|
|
119
|
-
alignItems: 'center',
|
|
120
|
-
justifyContent: 'center',
|
|
121
|
-
cursor: interactive ? 'pointer' : 'default',
|
|
122
|
-
transform: `translate(${x}px, ${y}px) scale(${scale})`,
|
|
123
|
-
opacity,
|
|
124
|
-
transition: isHovered || isPressed ? 'transform 100ms ease' : 'none',
|
|
125
|
-
background: 'none',
|
|
126
|
-
border: 'none',
|
|
127
|
-
padding: 0
|
|
128
|
-
},
|
|
129
|
-
children: isEmpty ? /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
130
|
-
style: {
|
|
131
|
-
width: _floatingToolsReact.dialStyles.emptySlot.dotSize,
|
|
132
|
-
height: _floatingToolsReact.dialStyles.emptySlot.dotSize,
|
|
133
|
-
borderRadius: _floatingToolsReact.dialStyles.emptySlot.dotSize / 2,
|
|
134
|
-
backgroundColor: _floatingToolsReact.dialColors.emptyDotBackground,
|
|
135
|
-
border: `${_floatingToolsReact.dialStyles.emptySlot.borderWidth}px solid ${_floatingToolsReact.dialColors.emptyDotBorder}`
|
|
136
|
-
}
|
|
137
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
138
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
139
|
-
style: {
|
|
140
|
-
position: 'absolute',
|
|
141
|
-
width: `${_floatingToolsReact.dialStyles.icon.gradientBgSizePercent}%`,
|
|
142
|
-
height: `${_floatingToolsReact.dialStyles.icon.gradientBgSizePercent}%`,
|
|
143
|
-
borderRadius: _floatingToolsReact.dialStyles.icon.gradientBgBorderRadius,
|
|
144
|
-
backgroundColor: 'rgba(0, 0, 0, 0.2)',
|
|
145
|
-
opacity: _floatingToolsReact.dialStyles.icon.gradientBgOpacity
|
|
146
|
-
}
|
|
147
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
148
|
-
style: {
|
|
149
|
-
position: 'absolute',
|
|
150
|
-
width: `${_floatingToolsReact.dialStyles.icon.innerGlowSizePercent}%`,
|
|
151
|
-
height: `${_floatingToolsReact.dialStyles.icon.innerGlowSizePercent}%`,
|
|
152
|
-
borderRadius: _floatingToolsReact.dialStyles.icon.innerGlowBorderRadius,
|
|
153
|
-
backgroundColor: 'rgba(255, 255, 255, 0.02)',
|
|
154
|
-
opacity: _floatingToolsReact.dialStyles.icon.innerGlowOpacity
|
|
155
|
-
}
|
|
156
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
157
|
-
style: {
|
|
158
|
-
marginBottom: _floatingToolsReact.dialStyles.icon.wrapperMarginBottom,
|
|
159
|
-
display: 'flex',
|
|
160
|
-
alignItems: 'center',
|
|
161
|
-
justifyContent: 'center',
|
|
162
|
-
fontSize: 32,
|
|
163
|
-
// native DialIcon.tsx: icon rendered at size 32
|
|
164
|
-
filter: isHovered ? 'brightness(1.2)' : 'none'
|
|
165
|
-
},
|
|
166
|
-
children: icon.icon
|
|
167
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
168
|
-
style: {
|
|
169
|
-
fontSize:
|
|
170
|
-
// native: adjustsFontSizeToFit minimumFontScale 0.7 — long
|
|
171
|
-
// names shrink instead of wrapping/overflowing the slot.
|
|
172
|
-
icon.name.length > 8 ? Math.max(_floatingToolsReact.dialStyles.icon.label.fontSize * 0.7, _floatingToolsReact.dialStyles.icon.label.fontSize * 8 / icon.name.length) : _floatingToolsReact.dialStyles.icon.label.fontSize,
|
|
173
|
-
fontWeight: _floatingToolsReact.dialStyles.icon.label.fontWeight,
|
|
174
|
-
fontFamily: _floatingToolsReact.dialStyles.icon.label.fontFamily,
|
|
175
|
-
color: _floatingToolsReact.dialColors.iconLabel,
|
|
176
|
-
letterSpacing: _floatingToolsReact.dialStyles.icon.label.letterSpacing,
|
|
177
|
-
marginTop: _floatingToolsReact.dialStyles.icon.label.marginTop,
|
|
178
|
-
textTransform: 'uppercase',
|
|
179
|
-
whiteSpace: 'nowrap'
|
|
180
|
-
},
|
|
181
|
-
children: icon.name
|
|
182
|
-
}), isUnavailable &&
|
|
183
|
-
/*#__PURE__*/
|
|
184
|
-
// native DialIcon.tsx unavailableCaption: label size - 1, muted
|
|
185
|
-
(0, _jsxRuntime.jsx)("span", {
|
|
186
|
-
style: {
|
|
187
|
-
fontSize: _floatingToolsReact.dialStyles.icon.label.fontSize - 1,
|
|
188
|
-
fontWeight: _floatingToolsReact.dialStyles.icon.label.fontWeight,
|
|
189
|
-
fontFamily: _floatingToolsReact.dialStyles.icon.label.fontFamily,
|
|
190
|
-
letterSpacing: _floatingToolsReact.dialStyles.icon.label.letterSpacing,
|
|
191
|
-
color: _floatingToolsReact.floatingToolsColors.muted,
|
|
192
|
-
textTransform: 'uppercase',
|
|
193
|
-
whiteSpace: 'nowrap'
|
|
194
|
-
},
|
|
195
|
-
children: "Unavailable"
|
|
196
|
-
})]
|
|
197
|
-
})
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// =============================
|
|
202
|
-
// Pagination (mirrors native DialPagination.tsx)
|
|
203
|
-
// =============================
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Chevron glyph matching the native pager's ChevronLeft/ChevronRight from
|
|
207
|
-
* @buoy-gg/shared-ui (lucide two-line chevron, size 18, strokeWidth 2).
|
|
208
|
-
* Inlined as SVG because shared-ui is React Native-only.
|
|
209
|
-
*/
|
|
210
|
-
function PagerChevron({
|
|
211
|
-
side,
|
|
212
|
-
color
|
|
213
|
-
}) {
|
|
214
|
-
// native lucide-icons.tsx ChevronLeft: (15,18)->(9,12)->(15,6); ChevronRight mirrored
|
|
215
|
-
const lines = side === 'prev' ? [[15, 18, 9, 12], [9, 12, 15, 6]] : [[9, 18, 15, 12], [15, 12, 9, 6]];
|
|
216
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)("svg", {
|
|
217
|
-
width: 18,
|
|
218
|
-
height: 18,
|
|
219
|
-
viewBox: "0 0 24 24",
|
|
220
|
-
"aria-hidden": "true",
|
|
221
|
-
focusable: "false",
|
|
222
|
-
children: lines.map(([x1, y1, x2, y2], i) => /*#__PURE__*/(0, _jsxRuntime.jsx)("line", {
|
|
223
|
-
x1: x1,
|
|
224
|
-
y1: y1,
|
|
225
|
-
x2: x2,
|
|
226
|
-
y2: y2,
|
|
227
|
-
stroke: color,
|
|
228
|
-
strokeWidth: 2
|
|
229
|
-
}, i))
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
function PagerButton({
|
|
233
|
-
side,
|
|
234
|
-
disabled,
|
|
235
|
-
onClick
|
|
236
|
-
}) {
|
|
237
|
-
const [isPressed, setIsPressed] = (0, _react.useState)(false);
|
|
238
|
-
|
|
239
|
-
// native DialPagination.tsx: accent = disabled ? emptyDotBorder : dialColors.accent
|
|
240
|
-
const accent = disabled ? _floatingToolsReact.dialColors.emptyDotBorder : _floatingToolsReact.dialColors.accent;
|
|
241
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
|
|
242
|
-
type: "button",
|
|
243
|
-
"aria-label": `${side === 'prev' ? 'Previous' : 'Next'} dial page`,
|
|
244
|
-
disabled: disabled,
|
|
245
|
-
onClick: onClick,
|
|
246
|
-
onMouseDown: () => !disabled && setIsPressed(true),
|
|
247
|
-
onMouseUp: () => setIsPressed(false),
|
|
248
|
-
onMouseLeave: () => setIsPressed(false),
|
|
249
|
-
style: {
|
|
250
|
-
display: 'flex',
|
|
251
|
-
alignItems: 'center',
|
|
252
|
-
gap: 4,
|
|
253
|
-
// native DialPagination.tsx: gap 4
|
|
254
|
-
padding: '10px 16px',
|
|
255
|
-
// native: paddingVertical 10, paddingHorizontal 16
|
|
256
|
-
borderRadius: 10,
|
|
257
|
-
border: `1px solid ${_floatingToolsReact.dialColors.dialBorder}`,
|
|
258
|
-
backgroundColor: _floatingToolsReact.dialColors.dialBackground,
|
|
259
|
-
// native: buttonText night text, buttonTextDisabled iconLabelMuted
|
|
260
|
-
color: disabled ? _floatingToolsReact.dialColors.iconLabelMuted : _floatingToolsReact.dialColors.centerText,
|
|
261
|
-
fontSize: 12,
|
|
262
|
-
fontWeight: 900,
|
|
263
|
-
fontFamily: _sharedUi.monoFont,
|
|
264
|
-
letterSpacing: 1.5,
|
|
265
|
-
textTransform: 'uppercase',
|
|
266
|
-
cursor: disabled ? 'default' : 'pointer',
|
|
267
|
-
opacity: disabled ? 0.4 : 1,
|
|
268
|
-
// native: buttonDisabled opacity 0.4
|
|
269
|
-
// native: shadowColor dialShadow, shadowOpacity 0.4, shadowRadius 8
|
|
270
|
-
boxShadow: disabled ? 'none' : `0 0 8px ${(0, _floatingToolsReact.withAlpha)(_floatingToolsReact.dialColors.dialShadow, 0.4)}`,
|
|
271
|
-
// native: press-in springs to scale 0.92
|
|
272
|
-
transform: isPressed ? 'scale(0.92)' : 'scale(1)',
|
|
273
|
-
transition: 'transform 100ms ease'
|
|
274
|
-
},
|
|
275
|
-
children: [side === 'prev' && /*#__PURE__*/(0, _jsxRuntime.jsx)(PagerChevron, {
|
|
276
|
-
side: "prev",
|
|
277
|
-
color: accent
|
|
278
|
-
}), side === 'prev' ? 'PREV' : 'NEXT', side === 'next' && /*#__PURE__*/(0, _jsxRuntime.jsx)(PagerChevron, {
|
|
279
|
-
side: "next",
|
|
280
|
-
color: accent
|
|
281
|
-
})]
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// =============================
|
|
286
|
-
// Main DialMenu Component
|
|
287
|
-
// =============================
|
|
288
|
-
|
|
289
|
-
function DialMenu({
|
|
290
|
-
icons,
|
|
291
|
-
onClose,
|
|
292
|
-
centerLabel = 'MENU',
|
|
293
|
-
onCenterPress,
|
|
294
|
-
settingsOpen = false,
|
|
295
|
-
hintsDisabled = false
|
|
296
|
-
}) {
|
|
297
|
-
// Animation values
|
|
298
|
-
const [backdropOpacity, setBackdropOpacity] = (0, _react.useState)(0);
|
|
299
|
-
const [dialScale, setDialScale] = (0, _react.useState)(0);
|
|
300
|
-
const [dialRotation, setDialRotation] = (0, _react.useState)(0);
|
|
301
|
-
const [centerButtonScale, setCenterButtonScale] = (0, _react.useState)(0);
|
|
302
|
-
const [iconProgress, setIconProgress] = (0, _react.useState)(0);
|
|
303
|
-
const [centerPulseScale, setCenterPulseScale] = (0, _react.useState)(1);
|
|
304
|
-
|
|
305
|
-
// UI state
|
|
306
|
-
const [isHoveringCenter, setIsHoveringCenter] = (0, _react.useState)(false);
|
|
307
|
-
const [isExiting, setIsExiting] = (0, _react.useState)(false);
|
|
308
|
-
const [entranceComplete, setEntranceComplete] = (0, _react.useState)(false);
|
|
309
|
-
|
|
310
|
-
// Refs
|
|
311
|
-
const animationRef = (0, _react.useRef)(null);
|
|
312
|
-
const isClosingRef = (0, _react.useRef)(false);
|
|
313
|
-
|
|
314
|
-
// Config
|
|
315
|
-
const {
|
|
316
|
-
entrance,
|
|
317
|
-
exit,
|
|
318
|
-
interaction
|
|
319
|
-
} = _floatingToolsReact.dialAnimationConfig;
|
|
320
|
-
const cssAnimations = (0, _floatingToolsReact.getDialCSSAnimationStyles)();
|
|
321
|
-
|
|
322
|
-
// Layout
|
|
323
|
-
const layout = (0, _react.useMemo)(() => (0, _floatingToolsReact.getDialLayout)({
|
|
324
|
-
screenWidth: window.innerWidth
|
|
325
|
-
}), []);
|
|
326
|
-
const gridRotations = (0, _react.useMemo)(() => (0, _floatingToolsReact.getGridLineRotations)(), []);
|
|
327
|
-
const positions = (0, _react.useMemo)(() => (0, _floatingToolsReact.getAllIconPositions)(_floatingToolsReact.MAX_DIAL_SLOTS, layout.iconRadius), [layout.iconRadius]);
|
|
328
|
-
|
|
329
|
-
// Pagination: tools are split across pages of MAX_DIAL_SLOTS.
|
|
330
|
-
const [currentPage, setCurrentPage] = (0, _react.useState)(0);
|
|
331
|
-
const pageCount = Math.max(1, Math.ceil(icons.length / _floatingToolsReact.MAX_DIAL_SLOTS));
|
|
332
|
-
const safePage = Math.min(currentPage, pageCount - 1);
|
|
333
|
-
const paddedIcons = (0, _react.useMemo)(() => {
|
|
334
|
-
const start = safePage * _floatingToolsReact.MAX_DIAL_SLOTS;
|
|
335
|
-
const result = [...icons.slice(start, start + _floatingToolsReact.MAX_DIAL_SLOTS)];
|
|
336
|
-
while (result.length < _floatingToolsReact.MAX_DIAL_SLOTS) {
|
|
337
|
-
result.push({
|
|
338
|
-
id: `empty-${result.length}`,
|
|
339
|
-
name: '',
|
|
340
|
-
icon: null,
|
|
341
|
-
onPress: () => {}
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
return result;
|
|
345
|
-
}, [icons, safePage]);
|
|
346
|
-
|
|
347
|
-
// Inject keyframes
|
|
348
|
-
(0, _react.useEffect)(() => {
|
|
349
|
-
injectKeyframes();
|
|
350
|
-
}, []);
|
|
351
|
-
|
|
352
|
-
// ENTRANCE Animation - runs once on mount
|
|
353
|
-
(0, _react.useEffect)(() => {
|
|
354
|
-
// Capture config values at mount time
|
|
355
|
-
const backdropDuration = entrance.backdrop.duration;
|
|
356
|
-
const rotationDuration = entrance.dial.rotation.duration;
|
|
357
|
-
const centerButtonDelay = entrance.centerButton.delay;
|
|
358
|
-
const iconsDelay = entrance.icons.delay;
|
|
359
|
-
const iconsDuration = entrance.icons.duration;
|
|
360
|
-
const startTime = performance.now();
|
|
361
|
-
const animate = currentTime => {
|
|
362
|
-
const elapsed = currentTime - startTime;
|
|
363
|
-
|
|
364
|
-
// Backdrop (0-400ms)
|
|
365
|
-
setBackdropOpacity(Math.min(1, elapsed / backdropDuration));
|
|
366
|
-
|
|
367
|
-
// Dial scale with spring overshoot (~400ms)
|
|
368
|
-
const dialProgress = Math.min(1, elapsed / 400);
|
|
369
|
-
let springScale = easeOutCubic(dialProgress) * 1.1;
|
|
370
|
-
if (dialProgress > 0.7) {
|
|
371
|
-
springScale -= (dialProgress - 0.7) * 0.33;
|
|
372
|
-
}
|
|
373
|
-
if (dialProgress >= 1) springScale = 1;
|
|
374
|
-
setDialScale(Math.max(0, Math.min(1.05, springScale)));
|
|
375
|
-
|
|
376
|
-
// Dial rotation (0-800ms)
|
|
377
|
-
const rotProgress = Math.min(1, elapsed / rotationDuration);
|
|
378
|
-
setDialRotation(easeOutCubic(rotProgress) * 360);
|
|
379
|
-
|
|
380
|
-
// Center button (300ms delay)
|
|
381
|
-
if (elapsed >= centerButtonDelay) {
|
|
382
|
-
const centerProgress = Math.min(1, (elapsed - centerButtonDelay) / 300);
|
|
383
|
-
let centerSpring = easeOutCubic(centerProgress) * 1.15;
|
|
384
|
-
if (centerProgress > 0.6) {
|
|
385
|
-
centerSpring -= (centerProgress - 0.6) * 0.375;
|
|
386
|
-
}
|
|
387
|
-
if (centerProgress >= 1) centerSpring = 1;
|
|
388
|
-
setCenterButtonScale(Math.max(0, Math.min(1.05, centerSpring)));
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// Icons (500ms delay, 600ms duration)
|
|
392
|
-
if (elapsed >= iconsDelay) {
|
|
393
|
-
const iconsProgress = Math.min(1, (elapsed - iconsDelay) / iconsDuration);
|
|
394
|
-
setIconProgress(easeOutCubic(iconsProgress));
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Continue or finish
|
|
398
|
-
const totalTime = iconsDelay + iconsDuration;
|
|
399
|
-
if (elapsed < totalTime) {
|
|
400
|
-
animationRef.current = requestAnimationFrame(animate);
|
|
401
|
-
} else {
|
|
402
|
-
// Finalize
|
|
403
|
-
setBackdropOpacity(1);
|
|
404
|
-
setDialScale(1);
|
|
405
|
-
setDialRotation(360);
|
|
406
|
-
setCenterButtonScale(1);
|
|
407
|
-
setIconProgress(1);
|
|
408
|
-
setEntranceComplete(true);
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
|
-
animationRef.current = requestAnimationFrame(animate);
|
|
412
|
-
return () => {
|
|
413
|
-
if (animationRef.current) cancelAnimationFrame(animationRef.current);
|
|
414
|
-
};
|
|
415
|
-
}, []);
|
|
416
|
-
|
|
417
|
-
// EXIT Animation
|
|
418
|
-
const handleClose = (0, _react.useCallback)(() => {
|
|
419
|
-
if (isClosingRef.current) return;
|
|
420
|
-
isClosingRef.current = true;
|
|
421
|
-
setIsExiting(true);
|
|
422
|
-
if (animationRef.current) {
|
|
423
|
-
cancelAnimationFrame(animationRef.current);
|
|
424
|
-
}
|
|
425
|
-
const startTime = performance.now();
|
|
426
|
-
const iconsDuration = exit.icons.duration;
|
|
427
|
-
const centerDuration = exit.centerButton.duration;
|
|
428
|
-
const dialDuration = exit.dialScale.duration;
|
|
429
|
-
const step2Duration = Math.max(centerDuration, dialDuration);
|
|
430
|
-
const backdropDuration = exit.backdrop.duration;
|
|
431
|
-
const animate = currentTime => {
|
|
432
|
-
const elapsed = currentTime - startTime;
|
|
433
|
-
|
|
434
|
-
// Step 1: Icons collapse (0 - 300ms)
|
|
435
|
-
if (elapsed < iconsDuration) {
|
|
436
|
-
const progress = easeInCubic(elapsed / iconsDuration);
|
|
437
|
-
setIconProgress(1 - progress);
|
|
438
|
-
animationRef.current = requestAnimationFrame(animate);
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// Step 2: Dial + Center scale down in parallel — native runs the center
|
|
443
|
-
// button (200ms) and dial (250ms) with their own durations.
|
|
444
|
-
const step2Start = iconsDuration;
|
|
445
|
-
if (elapsed < step2Start + step2Duration) {
|
|
446
|
-
setIconProgress(0);
|
|
447
|
-
const centerProgress = Math.min(1, (elapsed - step2Start) / centerDuration);
|
|
448
|
-
const dialProgress = Math.min(1, (elapsed - step2Start) / dialDuration);
|
|
449
|
-
setCenterButtonScale(1 - easeInCubic(centerProgress));
|
|
450
|
-
setDialScale(1 - easeInCubic(dialProgress));
|
|
451
|
-
animationRef.current = requestAnimationFrame(animate);
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
// Step 3: Backdrop fade (550 - 750ms)
|
|
456
|
-
const step3Start = step2Start + step2Duration;
|
|
457
|
-
if (elapsed < step3Start + backdropDuration) {
|
|
458
|
-
setDialScale(0);
|
|
459
|
-
setCenterButtonScale(0);
|
|
460
|
-
const progress = (elapsed - step3Start) / backdropDuration;
|
|
461
|
-
setBackdropOpacity(1 - progress);
|
|
462
|
-
animationRef.current = requestAnimationFrame(animate);
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// Done
|
|
467
|
-
setBackdropOpacity(0);
|
|
468
|
-
onClose();
|
|
469
|
-
};
|
|
470
|
-
animationRef.current = requestAnimationFrame(animate);
|
|
471
|
-
}, [exit, onClose]);
|
|
472
|
-
|
|
473
|
-
// Document-level Escape key handler
|
|
474
|
-
(0, _react.useEffect)(() => {
|
|
475
|
-
const handleKeyDown = e => {
|
|
476
|
-
if (e.key === 'Escape') {
|
|
477
|
-
handleClose();
|
|
478
|
-
}
|
|
479
|
-
};
|
|
480
|
-
document.addEventListener('keydown', handleKeyDown);
|
|
481
|
-
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
482
|
-
}, [handleClose]);
|
|
483
|
-
|
|
484
|
-
// Settings onboarding tooltip — native DialDevTools.tsx:174-196: shown
|
|
485
|
-
// 1200ms after the dial mounts (entrance animations settle first) if never
|
|
486
|
-
// dismissed; suppressed while settings is open; dismissed forever when
|
|
487
|
-
// settings opens.
|
|
488
|
-
const [showSettingsTooltip, setShowSettingsTooltip] = (0, _react.useState)(false);
|
|
489
|
-
(0, _react.useEffect)(() => {
|
|
490
|
-
if (hintsDisabled) return;
|
|
491
|
-
let cancelled = false;
|
|
492
|
-
const timer = setTimeout(async () => {
|
|
493
|
-
const seen = await _sharedUi.persistentStorage.getItem(SETTINGS_TOOLTIP_KEY);
|
|
494
|
-
if (!cancelled && !seen) setShowSettingsTooltip(true);
|
|
495
|
-
}, 1200);
|
|
496
|
-
return () => {
|
|
497
|
-
cancelled = true;
|
|
498
|
-
clearTimeout(timer);
|
|
499
|
-
};
|
|
500
|
-
}, [hintsDisabled]);
|
|
501
|
-
const dismissSettingsTooltip = (0, _react.useCallback)(() => {
|
|
502
|
-
setShowSettingsTooltip(false);
|
|
503
|
-
void _sharedUi.persistentStorage.setItem(SETTINGS_TOOLTIP_KEY, 'true');
|
|
504
|
-
}, []);
|
|
505
|
-
(0, _react.useEffect)(() => {
|
|
506
|
-
if (settingsOpen && showSettingsTooltip) {
|
|
507
|
-
dismissSettingsTooltip();
|
|
508
|
-
}
|
|
509
|
-
}, [settingsOpen, showSettingsTooltip, dismissSettingsTooltip]);
|
|
510
|
-
|
|
511
|
-
// Icon press handler
|
|
512
|
-
const handleIconPress = (0, _react.useCallback)(icon => {
|
|
513
|
-
if (icon.id.startsWith('empty-') || isClosingRef.current) return;
|
|
514
|
-
|
|
515
|
-
// Pulse animation
|
|
516
|
-
const [pulseIn, pulseOut] = interaction.iconSelect.pulse;
|
|
517
|
-
const startTime = performance.now();
|
|
518
|
-
const pulseDuration = 150;
|
|
519
|
-
const animatePulse = currentTime => {
|
|
520
|
-
const elapsed = currentTime - startTime;
|
|
521
|
-
if (elapsed < pulseDuration) {
|
|
522
|
-
const progress = easeOutCubic(elapsed / pulseDuration);
|
|
523
|
-
setCenterPulseScale(1 - (1 - pulseIn.scale) * progress);
|
|
524
|
-
requestAnimationFrame(animatePulse);
|
|
525
|
-
} else if (elapsed < pulseDuration * 2) {
|
|
526
|
-
const progress = easeOutCubic((elapsed - pulseDuration) / pulseDuration);
|
|
527
|
-
setCenterPulseScale(pulseIn.scale + (pulseOut.scale - pulseIn.scale) * progress);
|
|
528
|
-
requestAnimationFrame(animatePulse);
|
|
529
|
-
} else {
|
|
530
|
-
setCenterPulseScale(1);
|
|
531
|
-
}
|
|
532
|
-
};
|
|
533
|
-
requestAnimationFrame(animatePulse);
|
|
534
|
-
|
|
535
|
-
// Trigger action after delay
|
|
536
|
-
setTimeout(() => {
|
|
537
|
-
icon.onPress();
|
|
538
|
-
handleClose();
|
|
539
|
-
}, interaction.iconSelect.actionDelay);
|
|
540
|
-
}, [interaction.iconSelect, handleClose]);
|
|
541
|
-
|
|
542
|
-
// Page navigation - icons are keyed by slot index, so this only swaps
|
|
543
|
-
// their content in place (no remount, no re-animation) for an instant page
|
|
544
|
-
// change.
|
|
545
|
-
const handlePageChange = (0, _react.useCallback)(next => {
|
|
546
|
-
if (isClosingRef.current) return;
|
|
547
|
-
const clamped = Math.max(0, Math.min(next, pageCount - 1));
|
|
548
|
-
if (clamped !== safePage) setCurrentPage(clamped);
|
|
549
|
-
}, [pageCount, safePage]);
|
|
550
|
-
|
|
551
|
-
// Computed values
|
|
552
|
-
const buttonContainerSize = layout.buttonSize * _floatingToolsReact.dialStyles.centerButton.containerRatio;
|
|
553
|
-
const buttonBorderSize = layout.buttonSize * _floatingToolsReact.dialStyles.centerButton.borderRatio;
|
|
554
|
-
// Grid spokes stop this far from the centre: the hub's outer disc plus a breath.
|
|
555
|
-
const hubClearance = layout.buttonSize * _floatingToolsReact.dialStyles.centerButton.containerRatio / 2 + 6;
|
|
556
|
-
const isAnimating = entranceComplete && !isExiting;
|
|
557
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
558
|
-
role: "dialog",
|
|
559
|
-
"aria-label": "Dial Menu",
|
|
560
|
-
"aria-modal": "true",
|
|
561
|
-
style: {
|
|
562
|
-
position: 'fixed',
|
|
563
|
-
inset: 0,
|
|
564
|
-
zIndex: 10000
|
|
565
|
-
},
|
|
566
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
567
|
-
role: "button",
|
|
568
|
-
"aria-label": "Close dial menu",
|
|
569
|
-
tabIndex: 0,
|
|
570
|
-
onClick: handleClose,
|
|
571
|
-
onKeyDown: e => e.key === 'Escape' && handleClose(),
|
|
572
|
-
style: {
|
|
573
|
-
position: 'absolute',
|
|
574
|
-
inset: 0,
|
|
575
|
-
backgroundColor: _floatingToolsReact.dialColors.dialBackdrop,
|
|
576
|
-
opacity: backdropOpacity
|
|
577
|
-
}
|
|
578
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
579
|
-
style: {
|
|
580
|
-
position: 'absolute',
|
|
581
|
-
left: '50%',
|
|
582
|
-
marginLeft: -layout.circleSize / 2,
|
|
583
|
-
bottom: 80,
|
|
584
|
-
// native DialDevTools.tsx: bottom: 80
|
|
585
|
-
width: layout.circleSize,
|
|
586
|
-
height: layout.circleSize,
|
|
587
|
-
borderRadius: '50%',
|
|
588
|
-
backgroundColor: _floatingToolsReact.dialColors.dialBackground,
|
|
589
|
-
border: `${_floatingToolsReact.dialStyles.circle.borderWidth}px solid ${_floatingToolsReact.dialColors.dialBorder}`,
|
|
590
|
-
// native: shadowColor dialShadow at shadowOpacity 0.5, shadowRadius 20
|
|
591
|
-
boxShadow: `0 0 ${_floatingToolsReact.dialStyles.circle.shadowRadius}px ${(0, _floatingToolsReact.withAlpha)(_floatingToolsReact.dialColors.dialShadow, _floatingToolsReact.dialStyles.circle.shadowOpacity)}`,
|
|
592
|
-
transform: `scale(${dialScale}) rotate(${dialRotation}deg)`,
|
|
593
|
-
opacity: dialScale > 0.01 ? 1 : 0,
|
|
594
|
-
overflow: 'hidden'
|
|
595
|
-
},
|
|
596
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
597
|
-
style: {
|
|
598
|
-
position: 'absolute',
|
|
599
|
-
inset: 0,
|
|
600
|
-
borderRadius: '50%',
|
|
601
|
-
backgroundColor: _floatingToolsReact.dialColors.dialGradient1,
|
|
602
|
-
opacity: _floatingToolsReact.dialStyles.gradientLayers[0].opacity
|
|
603
|
-
}
|
|
604
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
605
|
-
style: {
|
|
606
|
-
position: 'absolute',
|
|
607
|
-
inset: 0,
|
|
608
|
-
top: '30%',
|
|
609
|
-
left: '30%',
|
|
610
|
-
borderRadius: '50%',
|
|
611
|
-
backgroundColor: _floatingToolsReact.dialColors.dialGradient2,
|
|
612
|
-
opacity: _floatingToolsReact.dialStyles.gradientLayers[1].opacity
|
|
613
|
-
}
|
|
614
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
615
|
-
style: {
|
|
616
|
-
position: 'absolute',
|
|
617
|
-
inset: 0,
|
|
618
|
-
top: '50%',
|
|
619
|
-
left: '50%',
|
|
620
|
-
borderRadius: '50%',
|
|
621
|
-
backgroundColor: _floatingToolsReact.dialColors.dialGradient3,
|
|
622
|
-
opacity: _floatingToolsReact.dialStyles.gradientLayers[2].opacity
|
|
623
|
-
}
|
|
624
|
-
}), gridRotations.map(deg => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
625
|
-
style: {
|
|
626
|
-
position: 'absolute',
|
|
627
|
-
top: '50%',
|
|
628
|
-
left: 0,
|
|
629
|
-
right: 0,
|
|
630
|
-
height: _floatingToolsReact.dialStyles.grid.lineHeight,
|
|
631
|
-
transform: `rotate(${deg}deg)`,
|
|
632
|
-
transformOrigin: 'center'
|
|
633
|
-
},
|
|
634
|
-
children: ['left', 'right'].map(side => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
635
|
-
style: {
|
|
636
|
-
position: 'absolute',
|
|
637
|
-
top: 0,
|
|
638
|
-
[side]: 0,
|
|
639
|
-
width: `calc(50% - ${hubClearance}px)`,
|
|
640
|
-
height: _floatingToolsReact.dialStyles.grid.lineHeight,
|
|
641
|
-
backgroundColor: _floatingToolsReact.dialColors.dialGridLine
|
|
642
|
-
}
|
|
643
|
-
}, side))
|
|
644
|
-
}, deg)), paddedIcons.map((icon, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(DialIconItem, {
|
|
645
|
-
icon: icon,
|
|
646
|
-
index: index,
|
|
647
|
-
totalIcons: paddedIcons.length,
|
|
648
|
-
position: positions[index],
|
|
649
|
-
progress: iconProgress,
|
|
650
|
-
onPress: () => handleIconPress(icon)
|
|
651
|
-
}, index)), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
652
|
-
style: {
|
|
653
|
-
position: 'absolute',
|
|
654
|
-
left: '50%',
|
|
655
|
-
top: '50%',
|
|
656
|
-
width: buttonContainerSize,
|
|
657
|
-
height: buttonContainerSize,
|
|
658
|
-
marginLeft: -buttonContainerSize / 2,
|
|
659
|
-
marginTop: -buttonContainerSize / 2,
|
|
660
|
-
display: 'flex',
|
|
661
|
-
alignItems: 'center',
|
|
662
|
-
justifyContent: 'center',
|
|
663
|
-
// Glass hub — see the native twin: a barely-there shade on the outer
|
|
664
|
-
// disc, a soft puck inside, no rings, so the tool background runs
|
|
665
|
-
// through the middle of the dial.
|
|
666
|
-
backgroundColor: _floatingToolsReact.dialColors.hubHalo,
|
|
667
|
-
borderRadius: layout.buttonSize,
|
|
668
|
-
overflow: 'hidden',
|
|
669
|
-
transform: `scale(${centerButtonScale * centerPulseScale})`,
|
|
670
|
-
opacity: centerButtonScale > 0.01 ? 1 : 0
|
|
671
|
-
},
|
|
672
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
673
|
-
style: {
|
|
674
|
-
position: 'absolute',
|
|
675
|
-
inset: 0,
|
|
676
|
-
backgroundColor: _floatingToolsReact.dialColors.dialGradient1,
|
|
677
|
-
opacity: 0.5,
|
|
678
|
-
borderRadius: layout.buttonSize
|
|
679
|
-
}
|
|
680
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
681
|
-
style: {
|
|
682
|
-
position: 'absolute',
|
|
683
|
-
inset: 0,
|
|
684
|
-
top: '20%',
|
|
685
|
-
left: '20%',
|
|
686
|
-
backgroundColor: _floatingToolsReact.dialColors.dialGradient2,
|
|
687
|
-
opacity: 0.3,
|
|
688
|
-
borderRadius: layout.buttonSize
|
|
689
|
-
}
|
|
690
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
691
|
-
style: {
|
|
692
|
-
position: 'absolute',
|
|
693
|
-
inset: 0,
|
|
694
|
-
top: '40%',
|
|
695
|
-
left: '40%',
|
|
696
|
-
backgroundColor: _floatingToolsReact.dialColors.dialGradient3,
|
|
697
|
-
opacity: 0.2,
|
|
698
|
-
borderRadius: layout.buttonSize
|
|
699
|
-
}
|
|
700
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
701
|
-
style: {
|
|
702
|
-
width: buttonBorderSize,
|
|
703
|
-
height: buttonBorderSize,
|
|
704
|
-
borderRadius: layout.buttonSize * _floatingToolsReact.dialStyles.centerButton.borderRadiusRatio,
|
|
705
|
-
backgroundColor: _floatingToolsReact.dialColors.hubFill,
|
|
706
|
-
display: 'flex',
|
|
707
|
-
alignItems: 'center',
|
|
708
|
-
justifyContent: 'center'
|
|
709
|
-
},
|
|
710
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
711
|
-
onClick: onCenterPress,
|
|
712
|
-
onMouseEnter: () => setIsHoveringCenter(true),
|
|
713
|
-
onMouseLeave: () => setIsHoveringCenter(false),
|
|
714
|
-
style: {
|
|
715
|
-
width: layout.buttonSize,
|
|
716
|
-
height: layout.buttonSize,
|
|
717
|
-
borderRadius: layout.buttonSize / 2,
|
|
718
|
-
display: 'flex',
|
|
719
|
-
flexDirection: 'column',
|
|
720
|
-
alignItems: 'center',
|
|
721
|
-
justifyContent: 'center',
|
|
722
|
-
cursor: onCenterPress ? 'pointer' : 'default',
|
|
723
|
-
transform: isHoveringCenter ? `scale(${interaction.centerHover.scale})` : 'scale(1)',
|
|
724
|
-
transition: `transform ${interaction.centerHover.duration}ms ease`,
|
|
725
|
-
animation: isAnimating && !isHoveringCenter ? cssAnimations.pulse : 'none'
|
|
726
|
-
},
|
|
727
|
-
children: settingsOpen ?
|
|
728
|
-
/*#__PURE__*/
|
|
729
|
-
// native DialDevTools.tsx:716-724 — stacked CLOSE / SETTINGS
|
|
730
|
-
(0, _jsxRuntime.jsxs)("span", {
|
|
731
|
-
style: {
|
|
732
|
-
display: 'flex',
|
|
733
|
-
flexDirection: 'column',
|
|
734
|
-
alignItems: 'center',
|
|
735
|
-
fontSize: _floatingToolsReact.dialStyles.centerButton.text.fontSize - 2,
|
|
736
|
-
fontWeight: _floatingToolsReact.dialStyles.centerButton.text.fontWeight,
|
|
737
|
-
fontFamily: _floatingToolsReact.dialStyles.centerButton.text.fontFamily,
|
|
738
|
-
color: _floatingToolsReact.dialColors.centerText,
|
|
739
|
-
letterSpacing: _floatingToolsReact.dialStyles.centerButton.text.letterSpacing,
|
|
740
|
-
textAlign: 'center',
|
|
741
|
-
textShadow: `0 0 4px ${_floatingToolsReact.dialColors.centerTextGlow}`,
|
|
742
|
-
textTransform: 'uppercase',
|
|
743
|
-
lineHeight: 1.2
|
|
744
|
-
},
|
|
745
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
746
|
-
style: {
|
|
747
|
-
marginBottom: -2
|
|
748
|
-
},
|
|
749
|
-
children: "CLOSE"
|
|
750
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
751
|
-
style: {
|
|
752
|
-
marginTop: -2
|
|
753
|
-
},
|
|
754
|
-
children: "SETTINGS"
|
|
755
|
-
})]
|
|
756
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
757
|
-
style: {
|
|
758
|
-
fontSize: _floatingToolsReact.dialStyles.centerButton.text.fontSize,
|
|
759
|
-
fontWeight: _floatingToolsReact.dialStyles.centerButton.text.fontWeight,
|
|
760
|
-
fontFamily: _floatingToolsReact.dialStyles.centerButton.text.fontFamily,
|
|
761
|
-
color: _floatingToolsReact.dialColors.centerText,
|
|
762
|
-
// native DialDevTools.tsx centerText
|
|
763
|
-
letterSpacing: _floatingToolsReact.dialStyles.centerButton.text.letterSpacing,
|
|
764
|
-
textAlign: 'center',
|
|
765
|
-
textShadow: `0 0 4px ${_floatingToolsReact.dialColors.centerTextGlow}`,
|
|
766
|
-
textTransform: 'uppercase'
|
|
767
|
-
},
|
|
768
|
-
children: centerLabel
|
|
769
|
-
})
|
|
770
|
-
})
|
|
771
|
-
})]
|
|
772
|
-
})]
|
|
773
|
-
}), pageCount > 1 && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
774
|
-
style: {
|
|
775
|
-
position: 'absolute',
|
|
776
|
-
left: '50%',
|
|
777
|
-
marginLeft: -layout.circleSize / 2,
|
|
778
|
-
top: 'calc(100% - 64px)',
|
|
779
|
-
// native: screenHeight - 80 + 16
|
|
780
|
-
width: layout.circleSize,
|
|
781
|
-
display: 'flex',
|
|
782
|
-
alignItems: 'center',
|
|
783
|
-
justifyContent: 'space-between',
|
|
784
|
-
opacity: Math.min(1, dialScale),
|
|
785
|
-
transform: `scale(${Math.min(1, dialScale)})`
|
|
786
|
-
},
|
|
787
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(PagerButton, {
|
|
788
|
-
side: "prev",
|
|
789
|
-
disabled: safePage <= 0,
|
|
790
|
-
onClick: () => handlePageChange(safePage - 1)
|
|
791
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
|
|
792
|
-
style: {
|
|
793
|
-
padding: '6px 12px',
|
|
794
|
-
// native indicator: paddingVertical 6, paddingHorizontal 12
|
|
795
|
-
fontSize: 13,
|
|
796
|
-
fontWeight: 900,
|
|
797
|
-
fontFamily: _sharedUi.monoFont,
|
|
798
|
-
letterSpacing: 2,
|
|
799
|
-
color: _floatingToolsReact.dialColors.centerText,
|
|
800
|
-
textShadow: `0 0 6px ${_floatingToolsReact.dialColors.centerTextGlow}`
|
|
801
|
-
},
|
|
802
|
-
children: [String(safePage + 1).padStart(2, '0'), /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
|
|
803
|
-
style: {
|
|
804
|
-
color: _floatingToolsReact.dialColors.iconLabelMuted,
|
|
805
|
-
textShadow: 'none'
|
|
806
|
-
},
|
|
807
|
-
children: [' / ', String(pageCount).padStart(2, '0')]
|
|
808
|
-
})]
|
|
809
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(PagerButton, {
|
|
810
|
-
side: "next",
|
|
811
|
-
disabled: safePage >= pageCount - 1,
|
|
812
|
-
onClick: () => handlePageChange(safePage + 1)
|
|
813
|
-
})]
|
|
814
|
-
}), showSettingsTooltip && !settingsOpen && /*#__PURE__*/(0, _jsxRuntime.jsx)(_OnboardingTooltipWeb.OnboardingTooltip, {
|
|
815
|
-
title: "Welcome to Buoy!",
|
|
816
|
-
message: "Tap the center button to configure and add tools to your dial menu.",
|
|
817
|
-
onDismiss: dismissSettingsTooltip,
|
|
818
|
-
showArrow: false
|
|
819
|
-
})]
|
|
820
|
-
});
|
|
821
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.DialMenu=DialMenu;var _react=require("react");var _floatingToolsReact=require("@buoy-gg/floating-tools-react");var _sharedUi=require("@buoy-gg/shared-ui");var _DialHyperspace=require("./DialHyperspace.js");var _OnboardingTooltipWeb=require("./OnboardingTooltip.web.js");var _jsxRuntime=require("react/jsx-runtime");const DIAL_BACKGROUND_FOCUS={x:.5,y:.5};const SETTINGS_TOOLTIP_KEY="@react_buoy_settings_tooltip_shown";let keyframesInjected=false;function injectKeyframes(){if(keyframesInjected||typeof document==="undefined")return;const o=document.createElement("style");o.textContent=(0,_floatingToolsReact.getDialCSSKeyframesString)();document.head.appendChild(o);keyframesInjected=true}const easeOutCubic=o=>1-Math.pow(1-o,3);const easeInCubic=o=>o*o*o;function DialIconItem({icon:o,index:l,totalIcons:k,position:f,progress:s,onPress:y}){const[w,D]=(0,_react.useState)(false);const[M,v]=(0,_react.useState)(false);const S=!o.icon&&o.id.startsWith("empty-");const $=!S&&o.unavailable===true;const h=!S&&!$;const{icons:F}=_floatingToolsReact.dialAnimationConfig;const m=(0,_floatingToolsReact.getIconStaggerInputRange)(l,k);let c=0;if(s<=m[1]){c=0}else if(s<=m[2]){c=(s-m[1])/(m[2]-m[1])}else{c=1}c=Math.max(0,Math.min(1,c));const b=_floatingToolsReact.DIAL_ICON_SIZE;const q=F.pressIn.scale;const B=1.1;const W=c*(M?q:w?B:1);let T=0;if(c<=0){T=0}else if(c<=.3){T=c}else{T=.3+(c-.3)*(.7/.7)}const H=f.x*c;const U=f.y*c;return(0,_jsxRuntime.jsx)("button",{role:"menuitem","aria-label":S?"Empty slot":o.name,"aria-disabled":!h,tabIndex:h?0:-1,onClick:h?y:void 0,onMouseEnter:()=>h&&D(true),onMouseLeave:()=>{D(false);v(false)},onMouseDown:()=>h&&v(true),onMouseUp:()=>v(false),style:{position:"absolute",left:"50%",top:"50%",width:b,height:b,marginLeft:-b/2,marginTop:-b/2,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",cursor:h?"pointer":"default",transform:`translate(${H}px, ${U}px) scale(${W})`,opacity:T,transition:w||M?"transform 100ms ease":"none",background:"none",border:"none",padding:0},children:S?(0,_jsxRuntime.jsx)("div",{style:{width:_floatingToolsReact.dialStyles.emptySlot.dotSize,height:_floatingToolsReact.dialStyles.emptySlot.dotSize,borderRadius:_floatingToolsReact.dialStyles.emptySlot.dotSize/2,backgroundColor:_floatingToolsReact.dialColors.emptyDotBackground,border:`${_floatingToolsReact.dialStyles.emptySlot.borderWidth}px solid ${_floatingToolsReact.dialColors.emptyDotBorder}`}}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)("div",{style:{position:"absolute",width:`${_floatingToolsReact.dialStyles.icon.gradientBgSizePercent}%`,height:`${_floatingToolsReact.dialStyles.icon.gradientBgSizePercent}%`,borderRadius:_floatingToolsReact.dialStyles.icon.gradientBgBorderRadius,backgroundColor:"rgba(0, 0, 0, 0.2)",opacity:_floatingToolsReact.dialStyles.icon.gradientBgOpacity}}),(0,_jsxRuntime.jsx)("div",{style:{position:"absolute",width:`${_floatingToolsReact.dialStyles.icon.innerGlowSizePercent}%`,height:`${_floatingToolsReact.dialStyles.icon.innerGlowSizePercent}%`,borderRadius:_floatingToolsReact.dialStyles.icon.innerGlowBorderRadius,backgroundColor:"rgba(255, 255, 255, 0.02)",opacity:_floatingToolsReact.dialStyles.icon.innerGlowOpacity}}),(0,_jsxRuntime.jsx)("div",{style:{marginBottom:_floatingToolsReact.dialStyles.icon.wrapperMarginBottom,display:"flex",alignItems:"center",justifyContent:"center",fontSize:32,filter:w?"brightness(1.2)":"none"},children:o.icon}),(0,_jsxRuntime.jsx)("span",{style:{fontSize:o.name.length>8?Math.max(_floatingToolsReact.dialStyles.icon.label.fontSize*.7,_floatingToolsReact.dialStyles.icon.label.fontSize*8/o.name.length):_floatingToolsReact.dialStyles.icon.label.fontSize,fontWeight:_floatingToolsReact.dialStyles.icon.label.fontWeight,fontFamily:_floatingToolsReact.dialStyles.icon.label.fontFamily,color:_floatingToolsReact.dialColors.iconLabel,letterSpacing:_floatingToolsReact.dialStyles.icon.label.letterSpacing,marginTop:_floatingToolsReact.dialStyles.icon.label.marginTop,textTransform:"uppercase",whiteSpace:"nowrap"},children:o.name}),$&&(0,_jsxRuntime.jsx)("span",{style:{fontSize:_floatingToolsReact.dialStyles.icon.label.fontSize-1,fontWeight:_floatingToolsReact.dialStyles.icon.label.fontWeight,fontFamily:_floatingToolsReact.dialStyles.icon.label.fontFamily,letterSpacing:_floatingToolsReact.dialStyles.icon.label.letterSpacing,color:_floatingToolsReact.floatingToolsColors.muted,textTransform:"uppercase",whiteSpace:"nowrap"},children:"Unavailable"})]})})}function PagerChevron({side:o,color:l}){const k=o==="prev"?[[15,18,9,12],[9,12,15,6]]:[[9,18,15,12],[15,12,9,6]];return(0,_jsxRuntime.jsx)("svg",{width:18,height:18,viewBox:"0 0 24 24","aria-hidden":"true",focusable:"false",children:k.map(([f,s,y,w],D)=>(0,_jsxRuntime.jsx)("line",{x1:f,y1:s,x2:y,y2:w,stroke:l,strokeWidth:2},D))})}function PagerButton({side:o,disabled:l,onClick:k}){const[f,s]=(0,_react.useState)(false);const y=l?_floatingToolsReact.dialColors.emptyDotBorder:_floatingToolsReact.dialColors.accent;return(0,_jsxRuntime.jsxs)("button",{type:"button","aria-label":`${o==="prev"?"Previous":"Next"} dial page`,disabled:l,onClick:k,onMouseDown:()=>!l&&s(true),onMouseUp:()=>s(false),onMouseLeave:()=>s(false),style:{display:"flex",alignItems:"center",gap:4,padding:"10px 16px",borderRadius:10,border:`1px solid ${_floatingToolsReact.dialColors.dialBorder}`,backgroundColor:_floatingToolsReact.dialColors.dialBackground,color:l?_floatingToolsReact.dialColors.iconLabelMuted:_floatingToolsReact.dialColors.centerText,fontSize:12,fontWeight:900,fontFamily:_sharedUi.monoFont,letterSpacing:1.5,textTransform:"uppercase",cursor:l?"default":"pointer",opacity:l?.4:1,boxShadow:l?"none":`0 0 8px ${(0,_floatingToolsReact.withAlpha)(_floatingToolsReact.dialColors.dialShadow,.4)}`,transform:f?"scale(0.92)":"scale(1)",transition:"transform 100ms ease"},children:[o==="prev"&&(0,_jsxRuntime.jsx)(PagerChevron,{side:"prev",color:y}),o==="prev"?"PREV":"NEXT",o==="next"&&(0,_jsxRuntime.jsx)(PagerChevron,{side:"next",color:y})]})}function DialMenu({icons:o,onClose:l,centerLabel:k="MENU",onCenterPress:f,settingsOpen:s=false,hintsDisabled:y=false}){const{id:w}=(0,_sharedUi.useToolBackground)();const[D,M]=(0,_react.useState)(0);const[v,S]=(0,_react.useState)(0);const[$,h]=(0,_react.useState)(0);const[F,m]=(0,_react.useState)(0);const[c,b]=(0,_react.useState)(0);const[q,B]=(0,_react.useState)(1);const[W,T]=(0,_react.useState)(false);const[H,U]=(0,_react.useState)(false);const[ne,ie]=(0,_react.useState)(false);const K=(0,_react.useRef)(null);const J=(0,_react.useRef)(null);const g=(0,_react.useRef)(null);const O=(0,_react.useRef)(false);const{entrance:E,exit:L,interaction:P}=_floatingToolsReact.dialAnimationConfig;const ae=(0,_floatingToolsReact.getDialCSSAnimationStyles)();const[N,se]=(0,_react.useState)(()=>({width:window.innerWidth,height:window.innerHeight}));(0,_react.useEffect)(()=>{const t=()=>se({width:window.innerWidth,height:window.innerHeight});window.addEventListener("resize",t);return()=>window.removeEventListener("resize",t)},[]);const i=(0,_react.useMemo)(()=>(0,_floatingToolsReact.getDialLayout)({screenWidth:N.width,maxCircleSize:Math.max(120,Math.min(320,N.height-96))}),[N]);const re=(0,_react.useMemo)(()=>(0,_floatingToolsReact.getGridLineRotations)(),[]);const le=(0,_react.useMemo)(()=>(0,_floatingToolsReact.getAllIconPositions)(_floatingToolsReact.MAX_DIAL_SLOTS,i.iconRadius),[i.iconRadius]);const[ce,de]=(0,_react.useState)(0);const A=Math.max(1,Math.ceil(o.length/_floatingToolsReact.MAX_DIAL_SLOTS));const x=Math.min(ce,A-1);const Q=(0,_react.useMemo)(()=>{const t=x*_floatingToolsReact.MAX_DIAL_SLOTS;const e=[...o.slice(t,t+_floatingToolsReact.MAX_DIAL_SLOTS)];while(e.length<_floatingToolsReact.MAX_DIAL_SLOTS){e.push({id:`empty-${e.length}`,name:"",icon:null,onPress:()=>{}})}return e},[o,x]);(0,_react.useEffect)(()=>{injectKeyframes()},[]);(0,_react.useEffect)(()=>{const t=E.backdrop.duration;const e=E.dial.rotation.duration;const d=E.centerButton.delay;const a=E.icons.delay;const r=E.icons.duration;const u=performance.now();const p=j=>{const n=j-u;M(Math.min(1,n/t));const C=Math.min(1,n/400);let I=easeOutCubic(C)*1.1;if(C>.7){I-=(C-.7)*.33}if(C>=1)I=1;S(Math.max(0,Math.min(1.05,I)));const z=Math.min(1,n/e);h(easeOutCubic(z)*360);if(n>=d){const R=Math.min(1,(n-d)/300);let Z=easeOutCubic(R)*1.15;if(R>.6){Z-=(R-.6)*.375}if(R>=1)Z=1;m(Math.max(0,Math.min(1.05,Z)))}if(n>=a){const R=Math.min(1,(n-a)/r);b(easeOutCubic(R))}const Y=a+r;if(n<Y){g.current=requestAnimationFrame(p)}else{M(1);S(1);h(360);m(1);b(1);ie(true)}};g.current=requestAnimationFrame(p);return()=>{if(g.current)cancelAnimationFrame(g.current)}},[]);const _=(0,_react.useCallback)(()=>{if(O.current)return;O.current=true;U(true);if(g.current){cancelAnimationFrame(g.current)}const t=performance.now();const e=L.icons.duration;const d=L.centerButton.duration;const a=L.dialScale.duration;const r=Math.max(d,a);const u=L.backdrop.duration;const p=j=>{const n=j-t;if(n<e){const z=easeInCubic(n/e);b(1-z);g.current=requestAnimationFrame(p);return}const C=e;if(n<C+r){b(0);const z=Math.min(1,(n-C)/d);const Y=Math.min(1,(n-C)/a);m(1-easeInCubic(z));S(1-easeInCubic(Y));g.current=requestAnimationFrame(p);return}const I=C+r;if(n<I+u){S(0);m(0);const z=(n-I)/u;M(1-z);g.current=requestAnimationFrame(p);return}M(0);l()};g.current=requestAnimationFrame(p)},[L,l]);(0,_react.useEffect)(()=>{const t=document.activeElement;const e=K.current;return()=>{if(t?.isConnected&&(document.activeElement===document.body||e?.contains(document.activeElement))){t.focus()}}},[]);(0,_react.useEffect)(()=>{if(s)return;J.current?.focus();const t=e=>{const d=K.current;if(!d)return;if(e.key==="Escape"){e.preventDefault();_()}else if(e.key==="Tab"){const a=Array.from(d.querySelectorAll('button:not(:disabled):not([aria-disabled="true"]), [tabindex="0"]')).filter(p=>p.getClientRects().length>0);const r=a[0];const u=a[a.length-1];if(!d.contains(document.activeElement)||(e.shiftKey?document.activeElement===r:document.activeElement===u)){e.preventDefault();(e.shiftKey?u:r)?.focus()}}else if(["ArrowRight","ArrowDown","ArrowLeft","ArrowUp","Home","End"].includes(e.key)){const a=Array.from(d.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])'));const r=a.indexOf(document.activeElement);if(r<0||!a.length)return;e.preventDefault();const u=e.key==="Home"?0:e.key==="End"?a.length-1:(r+(e.key==="ArrowRight"||e.key==="ArrowDown"?1:-1)+a.length)%a.length;a[u].focus()}};document.addEventListener("keydown",t);return()=>document.removeEventListener("keydown",t)},[_,s]);const[X,ee]=(0,_react.useState)(false);(0,_react.useEffect)(()=>{if(y)return;let t=false;const e=setTimeout(async()=>{const d=await _sharedUi.persistentStorage.getItem(SETTINGS_TOOLTIP_KEY);if(!t&&!d)ee(true)},1200);return()=>{t=true;clearTimeout(e)}},[y]);const V=(0,_react.useCallback)(()=>{ee(false);void _sharedUi.persistentStorage.setItem(SETTINGS_TOOLTIP_KEY,"true")},[]);(0,_react.useEffect)(()=>{if(s&&X){V()}},[s,X,V]);const ue=(0,_react.useCallback)(t=>{if(t.id.startsWith("empty-")||O.current)return;const[e,d]=P.iconSelect.pulse;const a=performance.now();const r=150;const u=p=>{const j=p-a;if(j<r){const n=easeOutCubic(j/r);B(1-(1-e.scale)*n);requestAnimationFrame(u)}else if(j<r*2){const n=easeOutCubic((j-r)/r);B(e.scale+(d.scale-e.scale)*n);requestAnimationFrame(u)}else{B(1)}};requestAnimationFrame(u);setTimeout(()=>{t.onPress();_()},P.iconSelect.actionDelay)},[P.iconSelect,_]);const te=(0,_react.useCallback)(t=>{if(O.current)return;const e=Math.max(0,Math.min(t,A-1));if(e!==x)de(e)},[A,x]);const G=i.buttonSize*_floatingToolsReact.dialStyles.centerButton.containerRatio;const oe=i.buttonSize*_floatingToolsReact.dialStyles.centerButton.borderRatio;const pe=i.buttonSize*_floatingToolsReact.dialStyles.centerButton.containerRatio/2+6;const fe=ne&&!H;return(0,_jsxRuntime.jsxs)("div",{ref:K,role:"dialog","aria-label":"Dial Menu","aria-modal":"true",style:{position:"fixed",inset:0,zIndex:1e4},children:[(0,_jsxRuntime.jsx)("button",{type:"button","aria-label":"Close dial menu",tabIndex:0,onClick:_,style:{position:"absolute",inset:0,border:0,padding:0,backgroundColor:_floatingToolsReact.dialColors.dialBackdrop,opacity:D}}),(0,_jsxRuntime.jsxs)("div",{style:{position:"absolute",left:"50%",marginLeft:-i.circleSize/2,bottom:80,width:i.circleSize,height:i.circleSize,borderRadius:"50%",backgroundColor:_floatingToolsReact.dialColors.dialBackground,border:`${_floatingToolsReact.dialStyles.circle.borderWidth}px solid ${_floatingToolsReact.dialColors.dialBorder}`,boxShadow:`0 0 ${_floatingToolsReact.dialStyles.circle.shadowRadius}px ${(0,_floatingToolsReact.withAlpha)(_floatingToolsReact.dialColors.dialShadow,_floatingToolsReact.dialStyles.circle.shadowOpacity)}`,transform:`scale(${v}) rotate(${$}deg)`,opacity:v>.01?1:0,overflow:"hidden"},children:[(0,_jsxRuntime.jsx)("div",{style:{position:"absolute",inset:0,borderRadius:"50%",backgroundColor:_floatingToolsReact.dialColors.dialGradient1,opacity:_floatingToolsReact.dialStyles.gradientLayers[0].opacity}}),(0,_jsxRuntime.jsx)("div",{style:{position:"absolute",inset:0,top:"30%",left:"30%",borderRadius:"50%",backgroundColor:_floatingToolsReact.dialColors.dialGradient2,opacity:_floatingToolsReact.dialStyles.gradientLayers[1].opacity}}),(0,_jsxRuntime.jsx)("div",{style:{position:"absolute",inset:0,top:"50%",left:"50%",borderRadius:"50%",backgroundColor:_floatingToolsReact.dialColors.dialGradient3,opacity:_floatingToolsReact.dialStyles.gradientLayers[2].opacity}}),re.map(t=>(0,_jsxRuntime.jsx)("div",{style:{position:"absolute",top:"50%",left:0,right:0,height:_floatingToolsReact.dialStyles.grid.lineHeight,transform:`rotate(${t}deg)`,transformOrigin:"center"},children:["left","right"].map(e=>(0,_jsxRuntime.jsx)("div",{style:{position:"absolute",top:0,[e]:0,width:`calc(50% - ${pe}px)`,height:_floatingToolsReact.dialStyles.grid.lineHeight,backgroundColor:_floatingToolsReact.dialColors.dialGridLine}},e))},t)),(0,_jsxRuntime.jsx)("div",{"data-testid":"dial-background","data-background":w,style:{position:"absolute",inset:0,pointerEvents:"none"},children:w==="hyperspace"?(0,_jsxRuntime.jsx)(_DialHyperspace.DialHyperspace,{size:i.circleSize}):(0,_jsxRuntime.jsx)(_sharedUi.ToolBackground,{focus:DIAL_BACKGROUND_FOCUS})}),Q.map((t,e)=>(0,_jsxRuntime.jsx)(DialIconItem,{icon:t,index:e,totalIcons:Q.length,position:le[e],progress:c,onPress:()=>ue(t)},e)),(0,_jsxRuntime.jsxs)("div",{style:{position:"absolute",left:"50%",top:"50%",width:G,height:G,marginLeft:-G/2,marginTop:-G/2,display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:_floatingToolsReact.dialColors.hubHalo,borderRadius:i.buttonSize,overflow:"hidden",transform:`scale(${F*q})`,opacity:F>.01?1:0},children:[(0,_jsxRuntime.jsx)("div",{style:{position:"absolute",inset:0,backgroundColor:_floatingToolsReact.dialColors.dialGradient1,opacity:.5,borderRadius:i.buttonSize}}),(0,_jsxRuntime.jsx)("div",{style:{position:"absolute",inset:0,top:"20%",left:"20%",backgroundColor:_floatingToolsReact.dialColors.dialGradient2,opacity:.3,borderRadius:i.buttonSize}}),(0,_jsxRuntime.jsx)("div",{style:{position:"absolute",inset:0,top:"40%",left:"40%",backgroundColor:_floatingToolsReact.dialColors.dialGradient3,opacity:.2,borderRadius:i.buttonSize}}),(0,_jsxRuntime.jsx)("div",{style:{width:oe,height:oe,borderRadius:i.buttonSize*_floatingToolsReact.dialStyles.centerButton.borderRadiusRatio,backgroundColor:_floatingToolsReact.dialColors.hubFill,display:"flex",alignItems:"center",justifyContent:"center"},children:(0,_jsxRuntime.jsx)("button",{ref:J,type:"button","aria-label":s?"Close settings":"Open settings",disabled:!f,onClick:f,onMouseEnter:()=>T(true),onMouseLeave:()=>T(false),style:{border:0,padding:0,background:"transparent",width:i.buttonSize,height:i.buttonSize,borderRadius:i.buttonSize/2,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",cursor:f?"pointer":"default",transform:W?`scale(${P.centerHover.scale})`:"scale(1)",transition:`transform ${P.centerHover.duration}ms ease`,animation:fe&&!W?ae.pulse:"none"},children:s?(0,_jsxRuntime.jsxs)("span",{style:{display:"flex",flexDirection:"column",alignItems:"center",fontSize:_floatingToolsReact.dialStyles.centerButton.text.fontSize-2,fontWeight:_floatingToolsReact.dialStyles.centerButton.text.fontWeight,fontFamily:_floatingToolsReact.dialStyles.centerButton.text.fontFamily,color:_floatingToolsReact.dialColors.centerText,letterSpacing:_floatingToolsReact.dialStyles.centerButton.text.letterSpacing,textAlign:"center",textShadow:`0 0 4px ${_floatingToolsReact.dialColors.centerTextGlow}`,textTransform:"uppercase",lineHeight:1.2},children:[(0,_jsxRuntime.jsx)("span",{style:{marginBottom:-2},children:"CLOSE"}),(0,_jsxRuntime.jsx)("span",{style:{marginTop:-2},children:"SETTINGS"})]}):(0,_jsxRuntime.jsx)("span",{style:{fontSize:_floatingToolsReact.dialStyles.centerButton.text.fontSize,fontWeight:_floatingToolsReact.dialStyles.centerButton.text.fontWeight,fontFamily:_floatingToolsReact.dialStyles.centerButton.text.fontFamily,color:_floatingToolsReact.dialColors.centerText,letterSpacing:_floatingToolsReact.dialStyles.centerButton.text.letterSpacing,textAlign:"center",textShadow:`0 0 4px ${_floatingToolsReact.dialColors.centerTextGlow}`,textTransform:"uppercase"},children:k})})})]})]}),A>1&&(0,_jsxRuntime.jsxs)("div",{style:{position:"absolute",left:"50%",marginLeft:-i.circleSize/2,top:"calc(100% - 64px)",width:i.circleSize,display:"flex",alignItems:"center",justifyContent:"space-between",opacity:Math.min(1,v),transform:`scale(${Math.min(1,v)})`},children:[(0,_jsxRuntime.jsx)(PagerButton,{side:"prev",disabled:x<=0,onClick:()=>te(x-1)}),(0,_jsxRuntime.jsxs)("span",{style:{padding:"6px 12px",fontSize:13,fontWeight:900,fontFamily:_sharedUi.monoFont,letterSpacing:2,color:_floatingToolsReact.dialColors.centerText,textShadow:`0 0 6px ${_floatingToolsReact.dialColors.centerTextGlow}`},children:[String(x+1).padStart(2,"0"),(0,_jsxRuntime.jsxs)("span",{style:{color:_floatingToolsReact.dialColors.iconLabelMuted,textShadow:"none"},children:[" / ",String(A).padStart(2,"0")]})]}),(0,_jsxRuntime.jsx)(PagerButton,{side:"next",disabled:x>=A-1,onClick:()=>te(x+1)})]}),X&&!s&&(0,_jsxRuntime.jsx)(_OnboardingTooltipWeb.OnboardingTooltip,{title:"Welcome to Buoy!",message:"Tap the center button to configure and add tools to your dial menu.",onDismiss:V,showArrow:false})]})}
|