@buoy-gg/core 1.7.5 → 1.7.8

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 (75) hide show
  1. package/lib/commonjs/floatingMenu/AppHost.js +1 -1
  2. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +20 -8
  3. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +746 -0
  4. package/lib/commonjs/floatingMenu/FloatingDevTools.js +16 -4
  5. package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +154 -0
  6. package/lib/commonjs/floatingMenu/FloatingMenu.js +8 -8
  7. package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +15 -0
  8. package/lib/commonjs/floatingMenu/defaultConfig.js +14 -7
  9. package/lib/commonjs/floatingMenu/dial/DialDevTools.js +8 -2
  10. package/lib/commonjs/floatingMenu/dial/DialDevTools.web.js +593 -0
  11. package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.js +2 -2
  12. package/lib/commonjs/floatingMenu/floatingTools.web.js +357 -0
  13. package/lib/commonjs/index.js +2 -2
  14. package/lib/commonjs/index.web.js +131 -0
  15. package/lib/commonjs/utils/autoDiscoverPresets.web.js +181 -0
  16. package/lib/module/floatingMenu/AppHost.js +1 -1
  17. package/lib/module/floatingMenu/DevToolsSettingsModal.js +21 -9
  18. package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +756 -0
  19. package/lib/module/floatingMenu/FloatingDevTools.js +17 -5
  20. package/lib/module/floatingMenu/FloatingDevTools.web.js +150 -0
  21. package/lib/module/floatingMenu/FloatingMenu.js +8 -8
  22. package/lib/module/floatingMenu/autoDiscoverPresets.js +15 -0
  23. package/lib/module/floatingMenu/defaultConfig.js +14 -7
  24. package/lib/module/floatingMenu/dial/DialDevTools.js +8 -2
  25. package/lib/module/floatingMenu/dial/DialDevTools.web.js +590 -0
  26. package/lib/module/floatingMenu/dial/OnboardingTooltip.js +2 -2
  27. package/lib/module/floatingMenu/floatingTools.web.js +357 -0
  28. package/lib/module/index.js +2 -2
  29. package/lib/module/index.web.js +24 -0
  30. package/lib/module/utils/autoDiscoverPresets.web.js +174 -0
  31. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  32. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts +23 -0
  33. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -0
  34. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts +1 -1
  35. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  36. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts +48 -0
  37. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +1 -0
  38. package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts.map +1 -1
  39. package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  40. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +8 -7
  41. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts.map +1 -1
  42. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  43. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts +26 -0
  44. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -0
  45. package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.d.ts +1 -1
  46. package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts +27 -0
  48. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts.map +1 -0
  49. package/lib/typescript/commonjs/index.web.d.ts +20 -0
  50. package/lib/typescript/commonjs/index.web.d.ts.map +1 -0
  51. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts +58 -0
  52. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts.map +1 -0
  53. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  54. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts +23 -0
  55. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -0
  56. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts +1 -1
  57. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  58. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts +48 -0
  59. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +1 -0
  60. package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts.map +1 -1
  61. package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  62. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +8 -7
  63. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts.map +1 -1
  64. package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  65. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts +26 -0
  66. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -0
  67. package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.d.ts +1 -1
  68. package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.d.ts.map +1 -1
  69. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts +27 -0
  70. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts.map +1 -0
  71. package/lib/typescript/module/index.web.d.ts +20 -0
  72. package/lib/typescript/module/index.web.d.ts.map +1 -0
  73. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts +58 -0
  74. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts.map +1 -0
  75. package/package.json +5 -4
@@ -0,0 +1,756 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * DevToolsSettingsModal - Web renderer for the dev tools settings modal.
5
+ *
6
+ * Uses shared configuration and logic from @buoy-gg/floating-tools-react.
7
+ * Platform-specific: CSS, mouse events, web JSX.
8
+ *
9
+ * This follows the same pattern as DialDevTools - all colors, labels, descriptions,
10
+ * and styling constants come from the shared core package.
11
+ *
12
+ * @platform React DOM Web (Vite, CRA, Next.js, Electron)
13
+ */
14
+
15
+ import { useState, useCallback, useEffect } from 'react';
16
+ import {
17
+ // Hook
18
+ useSettings,
19
+ // Tab configuration
20
+ settingsTabs,
21
+ // Colors & styling
22
+ settingsColors, settingsStyles, getToolColor,
23
+ // Tool metadata
24
+ getToolLabel, getToolDescription,
25
+ // Global settings config
26
+ globalSettingsConfig,
27
+ // Constants
28
+ MAX_SETTINGS_DIAL_SLOTS
29
+ // Types
30
+ } from '@buoy-gg/floating-tools-react';
31
+ import { ReduxIcon } from '@buoy-gg/floating-tools-core';
32
+
33
+ // =============================
34
+ // Types
35
+ // =============================
36
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
37
+ // =============================
38
+ // Web Storage Adapter
39
+ // =============================
40
+
41
+ const webStorageAdapter = {
42
+ getItem: key => localStorage.getItem(key),
43
+ setItem: (key, value) => localStorage.setItem(key, value)
44
+ };
45
+
46
+ // =============================
47
+ // Icon Components (Web SVGs)
48
+ // =============================
49
+
50
+ const Laptop = ({
51
+ size = 24,
52
+ color = 'currentColor'
53
+ }) => /*#__PURE__*/_jsx("svg", {
54
+ width: size,
55
+ height: size,
56
+ viewBox: "0 0 24 24",
57
+ fill: "none",
58
+ stroke: color,
59
+ strokeWidth: "2",
60
+ children: /*#__PURE__*/_jsx("path", {
61
+ d: "M20 16V7a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v9m16 0H4m16 0 1.28 2.55a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45L4 16"
62
+ })
63
+ });
64
+ const Database = ({
65
+ size = 24,
66
+ color = 'currentColor'
67
+ }) => /*#__PURE__*/_jsxs("svg", {
68
+ width: size,
69
+ height: size,
70
+ viewBox: "0 0 24 24",
71
+ fill: "none",
72
+ stroke: color,
73
+ strokeWidth: "2",
74
+ children: [/*#__PURE__*/_jsx("ellipse", {
75
+ cx: "12",
76
+ cy: "5",
77
+ rx: "9",
78
+ ry: "3"
79
+ }), /*#__PURE__*/_jsx("path", {
80
+ d: "M3 5V19A9 3 0 0 0 21 19V5"
81
+ }), /*#__PURE__*/_jsx("path", {
82
+ d: "M3 12A9 3 0 0 0 21 12"
83
+ })]
84
+ });
85
+ const Wifi = ({
86
+ size = 24,
87
+ color = 'currentColor'
88
+ }) => /*#__PURE__*/_jsxs("svg", {
89
+ width: size,
90
+ height: size,
91
+ viewBox: "0 0 24 24",
92
+ fill: "none",
93
+ stroke: color,
94
+ strokeWidth: "2",
95
+ children: [/*#__PURE__*/_jsx("path", {
96
+ d: "M5 13a10 10 0 0 1 14 0"
97
+ }), /*#__PURE__*/_jsx("path", {
98
+ d: "M8.5 16.5a5 5 0 0 1 7 0"
99
+ }), /*#__PURE__*/_jsx("path", {
100
+ d: "M2 8.82a15 15 0 0 1 20 0"
101
+ }), /*#__PURE__*/_jsx("line", {
102
+ x1: "12",
103
+ y1: "20",
104
+ x2: "12.01",
105
+ y2: "20"
106
+ })]
107
+ });
108
+ const Search = ({
109
+ size = 24,
110
+ color = 'currentColor'
111
+ }) => /*#__PURE__*/_jsxs("svg", {
112
+ width: size,
113
+ height: size,
114
+ viewBox: "0 0 24 24",
115
+ fill: "none",
116
+ stroke: color,
117
+ strokeWidth: "2",
118
+ children: [/*#__PURE__*/_jsx("circle", {
119
+ cx: "11",
120
+ cy: "11",
121
+ r: "8"
122
+ }), /*#__PURE__*/_jsx("path", {
123
+ d: "m21 21-4.3-4.3"
124
+ })]
125
+ });
126
+ const Map = ({
127
+ size = 24,
128
+ color = 'currentColor'
129
+ }) => /*#__PURE__*/_jsxs("svg", {
130
+ width: size,
131
+ height: size,
132
+ viewBox: "0 0 24 24",
133
+ fill: "none",
134
+ stroke: color,
135
+ strokeWidth: "2",
136
+ children: [/*#__PURE__*/_jsx("path", {
137
+ d: "M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0z"
138
+ }), /*#__PURE__*/_jsx("path", {
139
+ d: "M15 5.764v15"
140
+ }), /*#__PURE__*/_jsx("path", {
141
+ d: "M9 3.236v15"
142
+ })]
143
+ });
144
+ const Zap = ({
145
+ size = 24,
146
+ color = 'currentColor'
147
+ }) => /*#__PURE__*/_jsx("svg", {
148
+ width: size,
149
+ height: size,
150
+ viewBox: "0 0 24 24",
151
+ fill: "none",
152
+ stroke: color,
153
+ strokeWidth: "2",
154
+ children: /*#__PURE__*/_jsx("path", {
155
+ d: "M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"
156
+ })
157
+ });
158
+ const Sparkles = ({
159
+ size = 24,
160
+ color = 'currentColor'
161
+ }) => /*#__PURE__*/_jsxs("svg", {
162
+ width: size,
163
+ height: size,
164
+ viewBox: "0 0 24 24",
165
+ fill: "none",
166
+ stroke: color,
167
+ strokeWidth: "2",
168
+ children: [/*#__PURE__*/_jsx("path", {
169
+ d: "M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"
170
+ }), /*#__PURE__*/_jsx("path", {
171
+ d: "M20 3v4"
172
+ }), /*#__PURE__*/_jsx("path", {
173
+ d: "M22 5h-4"
174
+ }), /*#__PURE__*/_jsx("path", {
175
+ d: "M4 17v2"
176
+ }), /*#__PURE__*/_jsx("path", {
177
+ d: "M5 18H3"
178
+ })]
179
+ });
180
+ const Square = ({
181
+ size = 24,
182
+ color = 'currentColor'
183
+ }) => /*#__PURE__*/_jsx("svg", {
184
+ width: size,
185
+ height: size,
186
+ viewBox: "0 0 24 24",
187
+ fill: "none",
188
+ stroke: color,
189
+ strokeWidth: "2",
190
+ children: /*#__PURE__*/_jsx("rect", {
191
+ width: "18",
192
+ height: "18",
193
+ x: "3",
194
+ y: "3",
195
+ rx: "2"
196
+ })
197
+ });
198
+ const AlertTriangle = ({
199
+ size = 24,
200
+ color = 'currentColor'
201
+ }) => /*#__PURE__*/_jsxs("svg", {
202
+ width: size,
203
+ height: size,
204
+ viewBox: "0 0 24 24",
205
+ fill: "none",
206
+ stroke: color,
207
+ strokeWidth: "2",
208
+ children: [/*#__PURE__*/_jsx("path", {
209
+ d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"
210
+ }), /*#__PURE__*/_jsx("path", {
211
+ d: "M12 9v4"
212
+ }), /*#__PURE__*/_jsx("path", {
213
+ d: "M12 17h.01"
214
+ })]
215
+ });
216
+ const SettingsIcon = ({
217
+ size = 24,
218
+ color = 'currentColor'
219
+ }) => /*#__PURE__*/_jsxs("svg", {
220
+ width: size,
221
+ height: size,
222
+ viewBox: "0 0 24 24",
223
+ fill: "none",
224
+ stroke: color,
225
+ strokeWidth: "2",
226
+ children: [/*#__PURE__*/_jsx("path", {
227
+ d: "M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"
228
+ }), /*#__PURE__*/_jsx("circle", {
229
+ cx: "12",
230
+ cy: "12",
231
+ r: "3"
232
+ })]
233
+ });
234
+ function ChevronRightIcon() {
235
+ return /*#__PURE__*/_jsx("svg", {
236
+ width: "18",
237
+ height: "18",
238
+ viewBox: "0 0 24 24",
239
+ fill: "none",
240
+ stroke: "currentColor",
241
+ strokeWidth: "2",
242
+ children: /*#__PURE__*/_jsx("path", {
243
+ d: "M9 18l6-6-6-6"
244
+ })
245
+ });
246
+ }
247
+ function CloseIcon() {
248
+ return /*#__PURE__*/_jsx("svg", {
249
+ width: "20",
250
+ height: "20",
251
+ viewBox: "0 0 24 24",
252
+ fill: "none",
253
+ stroke: "currentColor",
254
+ strokeWidth: "2",
255
+ children: /*#__PURE__*/_jsx("path", {
256
+ d: "M18 6L6 18M6 6l12 12"
257
+ })
258
+ });
259
+ }
260
+
261
+ // Tool icon mapping using SVG components
262
+ function ToolIcon({
263
+ toolId,
264
+ color
265
+ }) {
266
+ const size = 16;
267
+ const iconMap = {
268
+ env: /*#__PURE__*/_jsx(Laptop, {
269
+ size: size,
270
+ color: color
271
+ }),
272
+ storage: /*#__PURE__*/_jsx(Database, {
273
+ size: size,
274
+ color: color
275
+ }),
276
+ network: /*#__PURE__*/_jsx(Wifi, {
277
+ size: size,
278
+ color: color
279
+ }),
280
+ query: /*#__PURE__*/_jsx(Search, {
281
+ size: size,
282
+ color: color
283
+ }),
284
+ 'route-events': /*#__PURE__*/_jsx(Map, {
285
+ size: size,
286
+ color: color
287
+ }),
288
+ routes: /*#__PURE__*/_jsx(Map, {
289
+ size: size,
290
+ color: color
291
+ }),
292
+ benchmark: /*#__PURE__*/_jsx(Zap, {
293
+ size: size,
294
+ color: color
295
+ }),
296
+ 'highlight-updates': /*#__PURE__*/_jsx(Sparkles, {
297
+ size: size,
298
+ color: color
299
+ }),
300
+ renders: /*#__PURE__*/_jsx(Sparkles, {
301
+ size: size,
302
+ color: color
303
+ }),
304
+ 'debug-borders': /*#__PURE__*/_jsx(Square, {
305
+ size: size,
306
+ color: color
307
+ }),
308
+ sentry: /*#__PURE__*/_jsx(AlertTriangle, {
309
+ size: size,
310
+ color: color
311
+ }),
312
+ environment: /*#__PURE__*/_jsx(SettingsIcon, {
313
+ size: size,
314
+ color: color
315
+ }),
316
+ redux: /*#__PURE__*/_jsx(ReduxIcon, {
317
+ size: size
318
+ })
319
+ };
320
+ return iconMap[toolId] || /*#__PURE__*/_jsx(SettingsIcon, {
321
+ size: size,
322
+ color: color
323
+ });
324
+ }
325
+
326
+ // =============================
327
+ // Tool Card Component
328
+ // =============================
329
+
330
+ function ToolCard({
331
+ toolId,
332
+ enabled,
333
+ disabled,
334
+ availableTools,
335
+ onToggle
336
+ }) {
337
+ const [isHovered, setIsHovered] = useState(false);
338
+ const color = getToolColor(toolId);
339
+ const label = getToolLabel(toolId, availableTools);
340
+ const description = getToolDescription(toolId, availableTools);
341
+ const cardStyle = {
342
+ display: 'flex',
343
+ flexDirection: 'row',
344
+ alignItems: 'center',
345
+ gap: settingsStyles.cardInner.gap,
346
+ paddingTop: settingsStyles.card.paddingVertical,
347
+ paddingBottom: settingsStyles.card.paddingVertical,
348
+ paddingLeft: settingsStyles.card.paddingHorizontal,
349
+ paddingRight: settingsStyles.card.paddingHorizontal,
350
+ backgroundColor: settingsColors.cardBackground,
351
+ borderRadius: settingsStyles.card.borderRadius,
352
+ borderWidth: settingsStyles.card.borderWidth,
353
+ borderStyle: 'solid',
354
+ borderColor: isHovered && !disabled ? settingsColors.cardBorderHover : settingsColors.cardBorder,
355
+ marginBottom: settingsStyles.card.marginBottom,
356
+ cursor: disabled ? 'not-allowed' : 'pointer',
357
+ opacity: disabled ? 0.6 : 1,
358
+ transition: 'all 150ms ease',
359
+ boxShadow: enabled ? `0 0 6px ${color}33, 0 0 12px ${color}20` : 'none'
360
+ };
361
+ const toggleStyle = {
362
+ paddingLeft: settingsStyles.toggle.paddingHorizontal,
363
+ paddingRight: settingsStyles.toggle.paddingHorizontal,
364
+ paddingTop: settingsStyles.toggle.paddingVertical,
365
+ paddingBottom: settingsStyles.toggle.paddingVertical,
366
+ borderRadius: settingsStyles.toggle.borderRadius,
367
+ borderWidth: settingsStyles.toggle.borderWidth,
368
+ borderStyle: 'solid',
369
+ backgroundColor: enabled ? settingsColors.toggleOnBg(color) : settingsColors.toggleOffBg,
370
+ borderColor: enabled ? settingsColors.toggleOnBorder(color) : settingsColors.toggleOffBorder,
371
+ color: enabled ? color : settingsColors.toggleOffText,
372
+ fontSize: settingsStyles.toggle.fontSize,
373
+ fontWeight: settingsStyles.toggle.fontWeight,
374
+ cursor: disabled ? 'not-allowed' : 'pointer',
375
+ transition: 'all 150ms ease',
376
+ boxShadow: enabled ? `0 0 8px ${color}66` : 'none'
377
+ };
378
+ return /*#__PURE__*/_jsxs("div", {
379
+ onClick: disabled ? undefined : onToggle,
380
+ onMouseEnter: () => setIsHovered(true),
381
+ onMouseLeave: () => setIsHovered(false),
382
+ style: cardStyle,
383
+ children: [/*#__PURE__*/_jsx("div", {
384
+ style: {
385
+ width: settingsStyles.iconContainer.width,
386
+ height: settingsStyles.iconContainer.height,
387
+ display: 'flex',
388
+ alignItems: 'center',
389
+ justifyContent: 'center'
390
+ },
391
+ children: /*#__PURE__*/_jsx(ToolIcon, {
392
+ toolId: toolId,
393
+ color: color
394
+ })
395
+ }), /*#__PURE__*/_jsxs("div", {
396
+ style: {
397
+ flex: 1,
398
+ minWidth: 0
399
+ },
400
+ children: [/*#__PURE__*/_jsxs("div", {
401
+ style: {
402
+ color: settingsColors.text,
403
+ fontWeight: settingsStyles.toolName.fontWeight,
404
+ fontSize: settingsStyles.toolName.fontSize
405
+ },
406
+ children: [label, disabled && ' (MAX 6)']
407
+ }), description && /*#__PURE__*/_jsx("div", {
408
+ style: {
409
+ color: settingsColors.textMuted,
410
+ fontSize: settingsStyles.toolDescription.fontSize,
411
+ overflow: 'hidden',
412
+ textOverflow: 'ellipsis',
413
+ whiteSpace: 'nowrap'
414
+ },
415
+ children: description
416
+ })]
417
+ }), /*#__PURE__*/_jsx("button", {
418
+ onClick: e => {
419
+ e.stopPropagation();
420
+ if (!disabled) onToggle();
421
+ },
422
+ disabled: disabled,
423
+ style: toggleStyle,
424
+ children: enabled ? 'ON' : 'OFF'
425
+ }), /*#__PURE__*/_jsx("div", {
426
+ style: {
427
+ color: settingsColors.textMuted
428
+ },
429
+ children: /*#__PURE__*/_jsx(ChevronRightIcon, {})
430
+ })]
431
+ });
432
+ }
433
+
434
+ // =============================
435
+ // Main Component
436
+ // =============================
437
+
438
+ export function SettingsModal({
439
+ visible,
440
+ onClose,
441
+ availableTools = [],
442
+ defaultFloatingTools,
443
+ defaultDialTools,
444
+ storage = webStorageAdapter,
445
+ onSettingsChange
446
+ }) {
447
+ const [activeTab, setActiveTab] = useState('dial');
448
+ const [isExiting, setIsExiting] = useState(false);
449
+
450
+ // Use the shared settings hook
451
+ const {
452
+ settings,
453
+ isLoading,
454
+ actions,
455
+ helpers
456
+ } = useSettings({
457
+ availableTools,
458
+ defaultFloatingTools,
459
+ defaultDialTools,
460
+ storage,
461
+ onSettingsChange
462
+ });
463
+
464
+ // Handle close with animation
465
+ const handleClose = useCallback(() => {
466
+ setIsExiting(true);
467
+ setTimeout(() => {
468
+ setIsExiting(false);
469
+ onClose();
470
+ }, 200);
471
+ }, [onClose]);
472
+
473
+ // Escape key handler
474
+ useEffect(() => {
475
+ if (!visible) return;
476
+ const handleKeyDown = e => {
477
+ if (e.key === 'Escape') {
478
+ handleClose();
479
+ }
480
+ };
481
+ document.addEventListener('keydown', handleKeyDown);
482
+ return () => document.removeEventListener('keydown', handleKeyDown);
483
+ }, [visible, handleClose]);
484
+ if (!visible) return null;
485
+
486
+ // Filter tabs - exclude 'pro' for now on web
487
+ const displayTabs = settingsTabs.filter(tab => tab.key !== 'pro');
488
+ const containerStyle = {
489
+ position: 'fixed',
490
+ inset: 0,
491
+ zIndex: 10000,
492
+ display: 'flex',
493
+ alignItems: 'center',
494
+ justifyContent: 'center'
495
+ };
496
+ const backdropStyle = {
497
+ position: 'absolute',
498
+ inset: 0,
499
+ backgroundColor: settingsColors.backdrop,
500
+ opacity: isExiting ? 0 : 1,
501
+ transition: 'opacity 200ms ease'
502
+ };
503
+ const modalStyle = {
504
+ position: 'relative',
505
+ width: '90%',
506
+ maxWidth: 450,
507
+ maxHeight: '80vh',
508
+ backgroundColor: settingsColors.panel,
509
+ borderRadius: 12,
510
+ border: `1px solid ${settingsColors.cardBorder}`,
511
+ boxShadow: `0 24px 48px rgba(0, 0, 0, 0.5), 0 0 24px ${settingsColors.info}20`,
512
+ display: 'flex',
513
+ flexDirection: 'column',
514
+ overflow: 'hidden',
515
+ transform: isExiting ? 'scale(0.95)' : 'scale(1)',
516
+ opacity: isExiting ? 0 : 1,
517
+ transition: 'transform 200ms ease, opacity 200ms ease'
518
+ };
519
+ return /*#__PURE__*/_jsxs("div", {
520
+ role: "dialog",
521
+ "aria-label": "Settings",
522
+ "aria-modal": "true",
523
+ style: containerStyle,
524
+ children: [/*#__PURE__*/_jsx("div", {
525
+ role: "button",
526
+ "aria-label": "Close settings",
527
+ tabIndex: 0,
528
+ onClick: handleClose,
529
+ style: backdropStyle
530
+ }), /*#__PURE__*/_jsxs("div", {
531
+ style: modalStyle,
532
+ children: [/*#__PURE__*/_jsxs("div", {
533
+ style: {
534
+ display: 'flex',
535
+ alignItems: 'center',
536
+ padding: '12px 16px',
537
+ borderBottom: `1px solid ${settingsColors.cardBorder}`
538
+ },
539
+ children: [/*#__PURE__*/_jsx("div", {
540
+ style: {
541
+ flex: 1,
542
+ display: 'flex',
543
+ backgroundColor: settingsColors.panel,
544
+ borderRadius: 6,
545
+ padding: 2,
546
+ border: `1px solid ${settingsColors.cardBorder}`
547
+ },
548
+ children: displayTabs.map(tab => {
549
+ const isActive = activeTab === tab.key;
550
+ return /*#__PURE__*/_jsx("button", {
551
+ onClick: () => setActiveTab(tab.key),
552
+ style: {
553
+ flex: 1,
554
+ paddingLeft: settingsStyles.tab.paddingHorizontal,
555
+ paddingRight: settingsStyles.tab.paddingHorizontal,
556
+ paddingTop: settingsStyles.tab.paddingVertical,
557
+ paddingBottom: settingsStyles.tab.paddingVertical,
558
+ borderRadius: settingsStyles.tab.borderRadius,
559
+ backgroundColor: isActive ? settingsColors.tabActiveBg : settingsColors.tabInactiveBg,
560
+ border: isActive ? `1px solid ${settingsColors.tabActiveBorder}40` : '1px solid transparent',
561
+ color: isActive ? settingsColors.info : settingsColors.tabInactiveText,
562
+ fontSize: settingsStyles.tab.fontSize,
563
+ fontWeight: settingsStyles.tab.fontWeight,
564
+ letterSpacing: settingsStyles.tab.letterSpacing,
565
+ cursor: 'pointer',
566
+ transition: 'all 150ms ease',
567
+ textTransform: 'uppercase',
568
+ fontFamily: 'monospace'
569
+ },
570
+ children: tab.label
571
+ }, tab.key);
572
+ })
573
+ }), /*#__PURE__*/_jsx("button", {
574
+ "aria-label": "Close",
575
+ onClick: handleClose,
576
+ style: {
577
+ marginLeft: 12,
578
+ background: 'none',
579
+ border: 'none',
580
+ padding: 4,
581
+ cursor: 'pointer',
582
+ color: settingsColors.textMuted,
583
+ display: 'flex',
584
+ alignItems: 'center',
585
+ justifyContent: 'center'
586
+ },
587
+ children: /*#__PURE__*/_jsx(CloseIcon, {})
588
+ })]
589
+ }), /*#__PURE__*/_jsx("div", {
590
+ style: {
591
+ flex: 1,
592
+ overflow: 'auto',
593
+ paddingTop: settingsStyles.scrollContent.paddingTop,
594
+ paddingBottom: settingsStyles.scrollContent.paddingBottom,
595
+ paddingLeft: settingsStyles.section.marginHorizontal,
596
+ paddingRight: settingsStyles.section.marginHorizontal
597
+ },
598
+ children: isLoading ? /*#__PURE__*/_jsx("div", {
599
+ style: {
600
+ display: 'flex',
601
+ alignItems: 'center',
602
+ justifyContent: 'center',
603
+ padding: 40,
604
+ color: settingsColors.textMuted
605
+ },
606
+ children: "Loading settings..."
607
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
608
+ children: [activeTab === 'dial' && /*#__PURE__*/_jsxs("div", {
609
+ children: [/*#__PURE__*/_jsxs("div", {
610
+ style: {
611
+ fontSize: settingsStyles.sectionTitle.fontSize,
612
+ fontWeight: settingsStyles.sectionTitle.fontWeight,
613
+ letterSpacing: settingsStyles.sectionTitle.letterSpacing,
614
+ textTransform: settingsStyles.sectionTitle.textTransform,
615
+ color: settingsColors.textMuted,
616
+ marginBottom: settingsStyles.sectionHeader.marginBottom
617
+ },
618
+ children: ["SELECT UP TO ", MAX_SETTINGS_DIAL_SLOTS, " TOOLS (", helpers.dialToolCount, "/", MAX_SETTINGS_DIAL_SLOTS, ")"]
619
+ }), Object.entries(settings.dialTools).map(([id, enabled]) => {
620
+ const isDisabled = !enabled && helpers.isDialFull;
621
+ return /*#__PURE__*/_jsx(ToolCard, {
622
+ toolId: id,
623
+ enabled: enabled,
624
+ disabled: isDisabled,
625
+ availableTools: availableTools,
626
+ onToggle: () => actions.toggleDialTool(id)
627
+ }, id);
628
+ })]
629
+ }), activeTab === 'floating' && /*#__PURE__*/_jsxs("div", {
630
+ children: [/*#__PURE__*/_jsx("div", {
631
+ style: {
632
+ fontSize: settingsStyles.sectionTitle.fontSize,
633
+ fontWeight: settingsStyles.sectionTitle.fontWeight,
634
+ letterSpacing: settingsStyles.sectionTitle.letterSpacing,
635
+ textTransform: settingsStyles.sectionTitle.textTransform,
636
+ color: settingsColors.textMuted,
637
+ marginBottom: settingsStyles.sectionHeader.marginBottom
638
+ },
639
+ children: "CONFIGURE FLOATING TOOLBAR ITEMS"
640
+ }), Object.entries(settings.floatingTools).map(([id, enabled]) => /*#__PURE__*/_jsx(ToolCard, {
641
+ toolId: id,
642
+ enabled: enabled,
643
+ availableTools: availableTools,
644
+ onToggle: () => id === 'environment' ? actions.toggleEnvironment() : actions.toggleFloatingTool(id)
645
+ }, id))]
646
+ }), activeTab === 'settings' && /*#__PURE__*/_jsxs("div", {
647
+ children: [/*#__PURE__*/_jsx("div", {
648
+ style: {
649
+ fontSize: settingsStyles.sectionTitle.fontSize,
650
+ fontWeight: settingsStyles.sectionTitle.fontWeight,
651
+ letterSpacing: settingsStyles.sectionTitle.letterSpacing,
652
+ textTransform: settingsStyles.sectionTitle.textTransform,
653
+ color: settingsColors.textMuted,
654
+ marginBottom: settingsStyles.sectionHeader.marginBottom
655
+ },
656
+ children: "GLOBAL SETTINGS"
657
+ }), globalSettingsConfig.map(config => {
658
+ const value = settings.globalSettings?.[config.key] ?? false;
659
+ const color = settingsColors.success;
660
+ return /*#__PURE__*/_jsx("div", {
661
+ style: {
662
+ padding: 12,
663
+ backgroundColor: settingsColors.cardBackground,
664
+ borderRadius: 8,
665
+ border: `1px solid ${settingsColors.cardBorder}`,
666
+ marginBottom: 10
667
+ },
668
+ children: /*#__PURE__*/_jsxs("div", {
669
+ style: {
670
+ display: 'flex',
671
+ alignItems: 'center',
672
+ gap: 12
673
+ },
674
+ children: [/*#__PURE__*/_jsx("div", {
675
+ style: {
676
+ backgroundColor: `${settingsColors.info}20`,
677
+ border: `1px solid ${settingsColors.info}40`,
678
+ borderRadius: 4,
679
+ padding: '4px 8px'
680
+ },
681
+ children: /*#__PURE__*/_jsx("span", {
682
+ style: {
683
+ fontSize: 10,
684
+ fontWeight: 700,
685
+ color: settingsColors.info,
686
+ letterSpacing: 0.5
687
+ },
688
+ children: config.category
689
+ })
690
+ }), /*#__PURE__*/_jsxs("div", {
691
+ style: {
692
+ flex: 1
693
+ },
694
+ children: [/*#__PURE__*/_jsx("div", {
695
+ style: {
696
+ fontFamily: 'monospace',
697
+ fontSize: 12,
698
+ fontWeight: 700,
699
+ color: settingsColors.text
700
+ },
701
+ children: config.label
702
+ }), /*#__PURE__*/_jsx("div", {
703
+ style: {
704
+ fontSize: 10,
705
+ color: settingsColors.textMuted,
706
+ marginTop: 2
707
+ },
708
+ children: config.shortDescription
709
+ })]
710
+ }), /*#__PURE__*/_jsx("button", {
711
+ onClick: () => actions.toggleGlobalSetting(config.key),
712
+ style: {
713
+ paddingLeft: settingsStyles.toggle.paddingHorizontal,
714
+ paddingRight: settingsStyles.toggle.paddingHorizontal,
715
+ paddingTop: settingsStyles.toggle.paddingVertical,
716
+ paddingBottom: settingsStyles.toggle.paddingVertical,
717
+ borderRadius: settingsStyles.toggle.borderRadius,
718
+ borderWidth: settingsStyles.toggle.borderWidth,
719
+ borderStyle: 'solid',
720
+ backgroundColor: value ? settingsColors.toggleOnBg(color) : settingsColors.toggleOffBg,
721
+ borderColor: value ? settingsColors.toggleOnBorder(color) : settingsColors.toggleOffBorder,
722
+ color: value ? color : settingsColors.toggleOffText,
723
+ fontSize: settingsStyles.toggle.fontSize,
724
+ fontWeight: settingsStyles.toggle.fontWeight,
725
+ cursor: 'pointer',
726
+ transition: 'all 150ms ease',
727
+ boxShadow: value ? `0 0 8px ${color}66` : 'none'
728
+ },
729
+ children: value ? 'ON' : 'OFF'
730
+ })]
731
+ })
732
+ }, config.key);
733
+ }), /*#__PURE__*/_jsx("button", {
734
+ onClick: () => actions.resetToDefaults(),
735
+ style: {
736
+ width: '100%',
737
+ padding: '12px 16px',
738
+ marginTop: 8,
739
+ borderRadius: 6,
740
+ border: `1px solid ${settingsColors.error}40`,
741
+ backgroundColor: `${settingsColors.error}15`,
742
+ color: settingsColors.error,
743
+ fontSize: 12,
744
+ fontWeight: 700,
745
+ letterSpacing: 0.5,
746
+ cursor: 'pointer',
747
+ transition: 'all 150ms ease'
748
+ },
749
+ children: "CLEAR ALL SETTINGS"
750
+ })]
751
+ })]
752
+ })
753
+ })]
754
+ })]
755
+ });
756
+ }