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