@buoy-gg/shared-ui 7.0.15 → 7.0.17

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 (121) hide show
  1. package/lib/commonjs/JsModal.web.js +1588 -0
  2. package/lib/commonjs/env/EnvironmentIndicator.web.js +114 -0
  3. package/lib/commonjs/env/EnvironmentSelectorInline.web.js +178 -0
  4. package/lib/commonjs/hooks/index.js +7 -0
  5. package/lib/commonjs/hooks/safe-area-impl.js +1 -1
  6. package/lib/commonjs/hooks/usePersistedState.js +71 -0
  7. package/lib/commonjs/icons/index.js +28 -0
  8. package/lib/commonjs/index.js +45 -3
  9. package/lib/commonjs/storage/devToolsStorageKeys.js +22 -0
  10. package/lib/commonjs/stores/ignoredPatternsCore.js +68 -0
  11. package/lib/commonjs/stores/ignoredPatternsStore.js +16 -52
  12. package/lib/commonjs/stores/ignoredPatternsStore.web.js +236 -0
  13. package/lib/commonjs/stores/index.js +1 -1
  14. package/lib/commonjs/ui/components/ModalHeader.js +69 -0
  15. package/lib/commonjs/ui/components/ToolButton.js +90 -0
  16. package/lib/commonjs/ui/components/index.js +7 -0
  17. package/lib/commonjs/ui/gameUI/constants/gameUIColors.js +5 -3
  18. package/lib/commonjs/ui/index.js +8 -0
  19. package/lib/commonjs/ui/toolTheme.js +96 -0
  20. package/lib/commonjs/utils/index.js +38 -0
  21. package/lib/commonjs/utils/stateSnapshotRegistry.js +62 -0
  22. package/lib/module/JsModal.web.js +1586 -0
  23. package/lib/module/env/EnvironmentIndicator.web.js +108 -0
  24. package/lib/module/env/EnvironmentSelectorInline.web.js +173 -0
  25. package/lib/module/hooks/index.js +1 -0
  26. package/lib/module/hooks/safe-area-impl.js +1 -1
  27. package/lib/module/hooks/usePersistedState.js +68 -0
  28. package/lib/module/icons/index.js +2 -0
  29. package/lib/module/index.js +7 -3
  30. package/lib/module/storage/devToolsStorageKeys.js +22 -0
  31. package/lib/module/stores/ignoredPatternsCore.js +62 -0
  32. package/lib/module/stores/ignoredPatternsStore.js +5 -51
  33. package/lib/module/stores/ignoredPatternsStore.web.js +221 -0
  34. package/lib/module/stores/index.js +1 -1
  35. package/lib/module/ui/components/ModalHeader.js +70 -2
  36. package/lib/module/ui/components/ToolButton.js +86 -0
  37. package/lib/module/ui/components/index.js +1 -0
  38. package/lib/module/ui/gameUI/constants/gameUIColors.js +4 -2
  39. package/lib/module/ui/index.js +3 -0
  40. package/lib/module/ui/toolTheme.js +93 -0
  41. package/lib/module/utils/index.js +2 -0
  42. package/lib/module/utils/stateSnapshotRegistry.js +55 -0
  43. package/lib/typescript/commonjs/JsModal.web.d.ts +138 -0
  44. package/lib/typescript/commonjs/JsModal.web.d.ts.map +1 -0
  45. package/lib/typescript/commonjs/env/EnvironmentIndicator.web.d.ts +16 -0
  46. package/lib/typescript/commonjs/env/EnvironmentIndicator.web.d.ts.map +1 -0
  47. package/lib/typescript/commonjs/env/EnvironmentSelectorInline.web.d.ts +8 -0
  48. package/lib/typescript/commonjs/env/EnvironmentSelectorInline.web.d.ts.map +1 -0
  49. package/lib/typescript/commonjs/hooks/index.d.ts +1 -0
  50. package/lib/typescript/commonjs/hooks/index.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  52. package/lib/typescript/commonjs/hooks/usePersistedState.d.ts +16 -0
  53. package/lib/typescript/commonjs/hooks/usePersistedState.d.ts.map +1 -0
  54. package/lib/typescript/commonjs/icons/index.d.ts +2 -0
  55. package/lib/typescript/commonjs/icons/index.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/index.d.ts +1 -1
  57. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts +19 -0
  59. package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/stores/ignoredPatternsCore.d.ts +37 -0
  61. package/lib/typescript/commonjs/stores/ignoredPatternsCore.d.ts.map +1 -0
  62. package/lib/typescript/commonjs/stores/ignoredPatternsStore.d.ts +3 -27
  63. package/lib/typescript/commonjs/stores/ignoredPatternsStore.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/stores/ignoredPatternsStore.web.d.ts +72 -0
  65. package/lib/typescript/commonjs/stores/ignoredPatternsStore.web.d.ts.map +1 -0
  66. package/lib/typescript/commonjs/ui/components/ModalHeader.d.ts +13 -1
  67. package/lib/typescript/commonjs/ui/components/ModalHeader.d.ts.map +1 -1
  68. package/lib/typescript/commonjs/ui/components/ToolButton.d.ts +24 -0
  69. package/lib/typescript/commonjs/ui/components/ToolButton.d.ts.map +1 -0
  70. package/lib/typescript/commonjs/ui/components/index.d.ts +4 -0
  71. package/lib/typescript/commonjs/ui/components/index.d.ts.map +1 -1
  72. package/lib/typescript/commonjs/ui/gameUI/constants/gameUIColors.d.ts +56 -0
  73. package/lib/typescript/commonjs/ui/gameUI/constants/gameUIColors.d.ts.map +1 -1
  74. package/lib/typescript/commonjs/ui/index.d.ts +1 -0
  75. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  76. package/lib/typescript/commonjs/ui/toolTheme.d.ts +68 -0
  77. package/lib/typescript/commonjs/ui/toolTheme.d.ts.map +1 -0
  78. package/lib/typescript/commonjs/utils/index.d.ts +2 -0
  79. package/lib/typescript/commonjs/utils/index.d.ts.map +1 -1
  80. package/lib/typescript/commonjs/utils/stateSnapshotRegistry.d.ts +67 -0
  81. package/lib/typescript/commonjs/utils/stateSnapshotRegistry.d.ts.map +1 -0
  82. package/lib/typescript/module/JsModal.web.d.ts +138 -0
  83. package/lib/typescript/module/JsModal.web.d.ts.map +1 -0
  84. package/lib/typescript/module/env/EnvironmentIndicator.web.d.ts +16 -0
  85. package/lib/typescript/module/env/EnvironmentIndicator.web.d.ts.map +1 -0
  86. package/lib/typescript/module/env/EnvironmentSelectorInline.web.d.ts +8 -0
  87. package/lib/typescript/module/env/EnvironmentSelectorInline.web.d.ts.map +1 -0
  88. package/lib/typescript/module/hooks/index.d.ts +1 -0
  89. package/lib/typescript/module/hooks/index.d.ts.map +1 -1
  90. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  91. package/lib/typescript/module/hooks/usePersistedState.d.ts +16 -0
  92. package/lib/typescript/module/hooks/usePersistedState.d.ts.map +1 -0
  93. package/lib/typescript/module/icons/index.d.ts +2 -0
  94. package/lib/typescript/module/icons/index.d.ts.map +1 -1
  95. package/lib/typescript/module/index.d.ts +1 -1
  96. package/lib/typescript/module/index.d.ts.map +1 -1
  97. package/lib/typescript/module/storage/devToolsStorageKeys.d.ts +19 -0
  98. package/lib/typescript/module/storage/devToolsStorageKeys.d.ts.map +1 -1
  99. package/lib/typescript/module/stores/ignoredPatternsCore.d.ts +37 -0
  100. package/lib/typescript/module/stores/ignoredPatternsCore.d.ts.map +1 -0
  101. package/lib/typescript/module/stores/ignoredPatternsStore.d.ts +3 -27
  102. package/lib/typescript/module/stores/ignoredPatternsStore.d.ts.map +1 -1
  103. package/lib/typescript/module/stores/ignoredPatternsStore.web.d.ts +72 -0
  104. package/lib/typescript/module/stores/ignoredPatternsStore.web.d.ts.map +1 -0
  105. package/lib/typescript/module/ui/components/ModalHeader.d.ts +13 -1
  106. package/lib/typescript/module/ui/components/ModalHeader.d.ts.map +1 -1
  107. package/lib/typescript/module/ui/components/ToolButton.d.ts +24 -0
  108. package/lib/typescript/module/ui/components/ToolButton.d.ts.map +1 -0
  109. package/lib/typescript/module/ui/components/index.d.ts +4 -0
  110. package/lib/typescript/module/ui/components/index.d.ts.map +1 -1
  111. package/lib/typescript/module/ui/gameUI/constants/gameUIColors.d.ts +56 -0
  112. package/lib/typescript/module/ui/gameUI/constants/gameUIColors.d.ts.map +1 -1
  113. package/lib/typescript/module/ui/index.d.ts +1 -0
  114. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  115. package/lib/typescript/module/ui/toolTheme.d.ts +68 -0
  116. package/lib/typescript/module/ui/toolTheme.d.ts.map +1 -0
  117. package/lib/typescript/module/utils/index.d.ts +2 -0
  118. package/lib/typescript/module/utils/index.d.ts.map +1 -1
  119. package/lib/typescript/module/utils/stateSnapshotRegistry.d.ts +67 -0
  120. package/lib/typescript/module/utils/stateSnapshotRegistry.d.ts.map +1 -0
  121. package/package.json +4 -4
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * ignoredPatternsStore.web — web twin of ignoredPatternsStore.ts (the shared
5
+ * persisted "ignored patterns" singleton for network-style URL filtering).
6
+ *
7
+ * The native store imports shared's RN `persistentStorage` (whose module graph
8
+ * carries guarded expo-file-system / async-storage requires), which is why the
9
+ * web shims never re-exported it. This twin keeps the ENTIRE store class, hook
10
+ * and persistence contract identical — same class shape, same
11
+ * `devToolsStorageKeys.network.ignoredDomains()` storage key, same persisted
12
+ * JSON shape (`IgnoredPattern[]`, with the legacy `string[]` migration) — and
13
+ * swaps only the storage backing: a file-local localStorage adapter that
14
+ * matches the `persistentStorage` API (async getItem/setItem, best-effort,
15
+ * provenance: example-tauri/src/shims/shared-ui.web.ts's adapter — web Buoy
16
+ * chrome persistence lives in webview localStorage).
17
+ *
18
+ * Everything else — pure matching (`ignoredPatternsCore`), the migration +
19
+ * ensure-defaults logic, the dirty-flag load race guard, the module-scope
20
+ * stable mutation identities — is the native code, not a fork of its
21
+ * semantics. Web consumers get the same shared, persisted pattern list the
22
+ * phone has, keyed identically, so a DOM port and a react-native-web port of
23
+ * the same app read/write the same entry.
24
+ *
25
+ * @platform React DOM Web
26
+ */
27
+
28
+ import { useEffect, useMemo, useState } from "react";
29
+ import { devToolsStorageKeys } from "../storage/devToolsStorageKeys.js";
30
+
31
+ // Pure matching types/helpers live in ignoredPatternsCore.ts (web-shim-safe);
32
+ // re-exported here so this module's surface twins the native store's.
33
+ import { DEFAULT_IGNORED_PATTERNS } from "./ignoredPatternsCore.js";
34
+ export { urlMatchesIgnoredPattern, isUrlIgnored } from "./ignoredPatternsCore.js";
35
+
36
+ /**
37
+ * localStorage-backed implementation of the shared `persistentStorage` API
38
+ * (getItem/setItem returning promises, silent best-effort failure) — the same
39
+ * adapter recipe the web shared-ui shims use for Buoy chrome persistence.
40
+ * Local to this file so the web store pulls zero RN/expo modules.
41
+ */
42
+ const persistentStorage = {
43
+ async getItem(key) {
44
+ try {
45
+ return window.localStorage.getItem(key);
46
+ } catch {
47
+ return null;
48
+ }
49
+ },
50
+ async setItem(key, value) {
51
+ try {
52
+ window.localStorage.setItem(key, value);
53
+ } catch {
54
+ // Ignore quota/availability errors — callers treat this as best-effort.
55
+ }
56
+ }
57
+ };
58
+ const DEFAULT_PATTERNS = DEFAULT_IGNORED_PATTERNS;
59
+
60
+ /** Tolerate the legacy `string[]` persisted format and stray junk. */
61
+ function migratePatterns(raw) {
62
+ if (!Array.isArray(raw)) return [];
63
+ const migrated = [];
64
+ for (const entry of raw) {
65
+ if (typeof entry === "string" && entry.trim()) {
66
+ migrated.push({
67
+ value: entry,
68
+ mode: "contains"
69
+ });
70
+ } else if (entry && typeof entry === "object" && typeof entry.value === "string") {
71
+ const e = entry;
72
+ migrated.push({
73
+ value: e.value,
74
+ mode: e.mode === "exact" ? "exact" : "contains"
75
+ });
76
+ }
77
+ }
78
+ return migrated;
79
+ }
80
+
81
+ /** Always keep the default patterns present (e.g. Buoy's license API). */
82
+ function ensureDefaults(patterns) {
83
+ const result = [...patterns];
84
+ for (const def of DEFAULT_PATTERNS) {
85
+ if (!result.some(p => p.value === def.value)) {
86
+ result.push({
87
+ ...def
88
+ });
89
+ }
90
+ }
91
+ return result;
92
+ }
93
+ /**
94
+ * Singleton store. One instance per JS runtime, so every consumer (Network
95
+ * tool, Events tool, any web panel) shares the same patterns.
96
+ */
97
+ class IgnoredPatternsStore {
98
+ patterns = ensureDefaults(DEFAULT_PATTERNS.map(p => ({
99
+ ...p
100
+ })));
101
+ listeners = new Set();
102
+ loaded = false;
103
+ loadPromise = null;
104
+ /** Set once a mutation happens so a slow initial load can't clobber it. */
105
+ dirty = false;
106
+
107
+ /** Current patterns (stable reference until a mutation occurs). */
108
+ getPatterns() {
109
+ return this.patterns;
110
+ }
111
+ subscribe(listener) {
112
+ this.listeners.add(listener);
113
+ // Lazily hydrate from storage the first time anyone cares.
114
+ void this.ensureLoaded();
115
+ return () => {
116
+ this.listeners.delete(listener);
117
+ };
118
+ }
119
+ emit() {
120
+ this.listeners.forEach(l => l());
121
+ }
122
+ ensureLoaded() {
123
+ if (this.loaded) return Promise.resolve();
124
+ if (this.loadPromise) return this.loadPromise;
125
+ this.loadPromise = (async () => {
126
+ try {
127
+ const stored = await persistentStorage.getItem(devToolsStorageKeys.network.ignoredDomains());
128
+ // A mutation may have raced this read — never overwrite user intent.
129
+ if (stored && !this.dirty) {
130
+ const migrated = ensureDefaults(migratePatterns(JSON.parse(stored)));
131
+ this.patterns = migrated;
132
+ }
133
+ } catch {
134
+ // Silently fall back to defaults.
135
+ } finally {
136
+ this.loaded = true;
137
+ this.emit();
138
+ }
139
+ })();
140
+ return this.loadPromise;
141
+ }
142
+ persist() {
143
+ persistentStorage.setItem(devToolsStorageKeys.network.ignoredDomains(), JSON.stringify(this.patterns)).catch(() => {
144
+ // Silently fail — patterns remain in memory.
145
+ });
146
+ }
147
+ commit(next) {
148
+ this.dirty = true;
149
+ this.patterns = next;
150
+ this.emit();
151
+ this.persist();
152
+ }
153
+
154
+ /** Add a pattern (no-op if its value already exists). */
155
+ add(pattern) {
156
+ const value = pattern.value.trim();
157
+ if (!value) return;
158
+ if (this.patterns.some(p => p.value === value)) return;
159
+ this.commit([...this.patterns, {
160
+ value,
161
+ mode: pattern.mode
162
+ }]);
163
+ }
164
+
165
+ /** Remove a pattern by value. */
166
+ remove(value) {
167
+ if (!this.patterns.some(p => p.value === value)) return;
168
+ this.commit(this.patterns.filter(p => p.value !== value));
169
+ }
170
+
171
+ /** Add as `contains` if absent, otherwise remove (used by detail-view chips). */
172
+ toggle(value) {
173
+ const trimmed = value.trim();
174
+ if (!trimmed) return;
175
+ this.commit(this.patterns.some(p => p.value === trimmed) ? this.patterns.filter(p => p.value !== trimmed) : [...this.patterns, {
176
+ value: trimmed,
177
+ mode: "contains"
178
+ }]);
179
+ }
180
+
181
+ /** Flip an existing pattern between `contains` and `exact`. */
182
+ toggleMode(value) {
183
+ if (!this.patterns.some(p => p.value === value)) return;
184
+ this.commit(this.patterns.map(p => p.value === value ? {
185
+ ...p,
186
+ mode: p.mode === "contains" ? "exact" : "contains"
187
+ } : p));
188
+ }
189
+ }
190
+ export const ignoredPatternsStore = new IgnoredPatternsStore();
191
+ /**
192
+ * Mutations live at module scope so they keep a STABLE identity across
193
+ * renders (same rationale as native: inline arrows handed every consumer a
194
+ * fresh `toggle` per render and defeated `memo` downstream).
195
+ */
196
+ const addPattern = pattern => ignoredPatternsStore.add(pattern);
197
+ const removePattern = value => ignoredPatternsStore.remove(value);
198
+ const togglePattern = value => ignoredPatternsStore.toggle(value);
199
+ const togglePatternMode = value => ignoredPatternsStore.toggleMode(value);
200
+
201
+ /**
202
+ * Subscribe to the shared ignored-patterns store. All consumers in a runtime
203
+ * see the same patterns and the same mutations.
204
+ */
205
+ export function useIgnoredPatterns() {
206
+ const [patterns, setPatterns] = useState(() => ignoredPatternsStore.getPatterns());
207
+ useEffect(() => {
208
+ return ignoredPatternsStore.subscribe(() => {
209
+ setPatterns(ignoredPatternsStore.getPatterns());
210
+ });
211
+ }, []);
212
+ const values = useMemo(() => new Set(patterns.map(p => p.value)), [patterns]);
213
+ return {
214
+ patterns,
215
+ values,
216
+ add: addPattern,
217
+ remove: removePattern,
218
+ toggle: togglePattern,
219
+ toggleMode: togglePatternMode
220
+ };
221
+ }
@@ -5,4 +5,4 @@
5
5
  */
6
6
 
7
7
  export { BaseEventStore } from "./BaseEventStore.js";
8
- export { ignoredPatternsStore, useIgnoredPatterns, urlMatchesIgnoredPattern, isUrlIgnored } from "./ignoredPatternsStore.js";
8
+ export { ignoredPatternsStore, useIgnoredPatterns, urlMatchesIgnoredPattern, isUrlIgnored } from "./ignoredPatternsStore";
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
 
3
- import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
4
- import { ChevronLeft, X } from "../../icons/index.js";
3
+ import { View, Text, TextInput, TouchableOpacity, StyleSheet } from "react-native";
4
+ import { useEffect, useRef } from "react";
5
+ import { ChevronLeft, Search as SearchIcon, X } from "../../icons/index.js";
5
6
  import { buoyColors } from "../gameUI/constants/gameUIColors.js";
6
7
 
7
8
  // Base ModalHeader container component
@@ -111,10 +112,51 @@ export function Actions({
111
112
  }
112
113
  Actions.displayName = "ModalHeaderActions";
113
114
 
115
+ // Expanding search input for the header. Render this IN PLACE OF
116
+ // `ModalHeader.Content` while search is active — it fills the same flex slot.
117
+ // Extracts the idiom env/network/storage each hand-rolled (~50 lines apiece).
118
+
119
+ export function HeaderSearch({
120
+ value,
121
+ onChangeText,
122
+ onCancel,
123
+ placeholder = "Search...",
124
+ autoFocus = true
125
+ }) {
126
+ const inputRef = useRef(null);
127
+ useEffect(() => {
128
+ if (autoFocus) inputRef.current?.focus();
129
+ }, [autoFocus]);
130
+ return /*#__PURE__*/_jsxs(View, {
131
+ style: styles.searchContainer,
132
+ children: [/*#__PURE__*/_jsx(SearchIcon, {
133
+ size: 12,
134
+ color: buoyColors.textSecondary
135
+ }), /*#__PURE__*/_jsx(TextInput, {
136
+ ref: inputRef,
137
+ style: styles.searchInput,
138
+ placeholder: placeholder,
139
+ placeholderTextColor: buoyColors.textMuted,
140
+ value: value,
141
+ onChangeText: onChangeText,
142
+ autoCorrect: false,
143
+ autoCapitalize: "none"
144
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
145
+ onPress: onCancel,
146
+ style: styles.searchCancelButton,
147
+ children: /*#__PURE__*/_jsx(X, {
148
+ size: 12,
149
+ color: buoyColors.textSecondary
150
+ })
151
+ })]
152
+ });
153
+ }
154
+
114
155
  // Attach sub-components to the main component
115
156
  ModalHeader.Navigation = Navigation;
116
157
  ModalHeader.Content = Content;
117
158
  ModalHeader.Actions = Actions;
159
+ ModalHeader.Search = HeaderSearch;
118
160
  const styles = StyleSheet.create({
119
161
  headerContainer: {
120
162
  flexDirection: "row",
@@ -162,5 +204,31 @@ const styles = StyleSheet.create({
162
204
  },
163
205
  headerContentNoMargin: {
164
206
  marginHorizontal: 0
207
+ },
208
+ searchContainer: {
209
+ flexDirection: "row",
210
+ alignItems: "center",
211
+ flex: 1,
212
+ backgroundColor: buoyColors.input,
213
+ borderRadius: 6,
214
+ paddingHorizontal: 10,
215
+ paddingVertical: 4,
216
+ marginHorizontal: 12,
217
+ marginVertical: 4,
218
+ height: 32,
219
+ borderWidth: 1,
220
+ borderColor: buoyColors.border
221
+ },
222
+ searchInput: {
223
+ flex: 1,
224
+ marginLeft: 8,
225
+ fontSize: 13,
226
+ color: buoyColors.text,
227
+ padding: 0,
228
+ height: "100%"
229
+ },
230
+ searchCancelButton: {
231
+ padding: 4,
232
+ marginLeft: 4
165
233
  }
166
234
  });
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+
3
+ import { StyleSheet, Text, TouchableOpacity } from "react-native";
4
+ import { buoyColors, gameUIColors } from "../gameUI/constants/gameUIColors.js";
5
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
+ /**
7
+ * The shared action button for dev-tool surfaces. Fills the gap where every
8
+ * tool hand-styled its own TouchableOpacity for "Clear", "Apply", "Reset".
9
+ */
10
+ export function ToolButton({
11
+ label,
12
+ onPress,
13
+ variant = "primary",
14
+ size = "medium",
15
+ disabled = false,
16
+ icon,
17
+ style
18
+ }) {
19
+ const palette = VARIANTS[variant];
20
+ return /*#__PURE__*/_jsxs(TouchableOpacity, {
21
+ accessibilityRole: "button",
22
+ accessibilityLabel: label,
23
+ onPress: onPress,
24
+ disabled: disabled,
25
+ style: [styles.base, size === "small" ? styles.small : styles.medium, {
26
+ backgroundColor: palette.background,
27
+ borderColor: palette.border,
28
+ borderWidth: variant === "ghost" ? 0 : 1
29
+ }, disabled && styles.disabled, style],
30
+ children: [icon, /*#__PURE__*/_jsx(Text, {
31
+ style: [styles.label, size === "small" && styles.labelSmall, {
32
+ color: palette.text
33
+ }],
34
+ children: label
35
+ })]
36
+ });
37
+ }
38
+ const VARIANTS = {
39
+ primary: {
40
+ background: buoyColors.primary + "22",
41
+ border: buoyColors.primary + "66",
42
+ text: buoyColors.primary
43
+ },
44
+ danger: {
45
+ background: gameUIColors.error + "15",
46
+ border: gameUIColors.error + "60",
47
+ text: gameUIColors.error
48
+ },
49
+ warning: {
50
+ background: gameUIColors.warning + "15",
51
+ border: gameUIColors.warning + "60",
52
+ text: gameUIColors.warning
53
+ },
54
+ ghost: {
55
+ background: "transparent",
56
+ border: "transparent",
57
+ text: buoyColors.textSecondary
58
+ }
59
+ };
60
+ const styles = StyleSheet.create({
61
+ base: {
62
+ flexDirection: "row",
63
+ alignItems: "center",
64
+ justifyContent: "center",
65
+ gap: 6,
66
+ borderRadius: 8
67
+ },
68
+ medium: {
69
+ paddingVertical: 8,
70
+ paddingHorizontal: 14
71
+ },
72
+ small: {
73
+ paddingVertical: 5,
74
+ paddingHorizontal: 10
75
+ },
76
+ disabled: {
77
+ opacity: 0.4
78
+ },
79
+ label: {
80
+ fontSize: 12,
81
+ fontWeight: "600"
82
+ },
83
+ labelSmall: {
84
+ fontSize: 11
85
+ }
86
+ });
@@ -13,6 +13,7 @@ export { FilterSection, FilterBadge, AddFilterInput, AddFilterButton, FilterList
13
13
  export { CompactFilterChips } from "./CompactFilterChips.js";
14
14
  export { Badge, StatusBadge, CountBadge, TypeBadge, MethodBadge } from "./Badge.js";
15
15
  export { TabSelector } from "./TabSelector.js";
16
+ export { ToolButton } from "./ToolButton.js";
16
17
  export { EventListItem } from "./EventListItem.js";
17
18
  export { StatsCard } from "./StatsCard.js";
18
19
  export { CompactRow } from "./CompactRow.js";
@@ -15,7 +15,9 @@ import { macOSGameUIColors, refreshMacOSGameUIColors } from "./macOSDesignSystem
15
15
  // THEME DEFINITIONS
16
16
  // ============================================
17
17
 
18
- const defaultTheme = {
18
+ // Kept (and exported) as the reference palette for theme swapping — see the
19
+ // header comment. Unused by the active theme selection.
20
+ export const _defaultTheme = {
19
21
  // Base colors
20
22
  border: "#00B8E666",
21
23
  blackTint1: "rgba(8, 12, 21, 0.95)",
@@ -119,7 +121,7 @@ const macOSTheme = macOSGameUIColors;
119
121
  // THEME SELECTION - Just change this one line!
120
122
  // ============================================
121
123
 
122
- // const activeTheme = defaultTheme; // DEFAULT - Mixed colors (original)
124
+ // const activeTheme = _defaultTheme; // DEFAULT - Mixed colors (original)
123
125
  const activeTheme = macOSTheme; // macOS - Apple HIG design system
124
126
 
125
127
  // ============================================
@@ -5,6 +5,9 @@
5
5
  // Components
6
6
  export * from "./components/index.js";
7
7
 
8
+ // Semantic design tokens for tool surfaces
9
+ export { toolTheme } from "./toolTheme.js";
10
+
8
11
  // Console UI bits
9
12
  export { CyberpunkSectionButton } from "./console/CyberpunkSectionButton.js";
10
13
 
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+
3
+ import { buoyColors, gameUIColors } from "./gameUI/constants/gameUIColors.js";
4
+
5
+ /**
6
+ * Semantic design tokens for dev-tool surfaces — the single documented entry
7
+ * point for custom-tool authors (and, over time, internal tools).
8
+ *
9
+ * Buoy historically grew three color systems (`buoyColors`, `gameUIColors`,
10
+ * `macOSColors`) with tribal knowledge about which to use where. `toolTheme`
11
+ * encodes that knowledge: surfaces/text come from the brand palette, semantic
12
+ * status colors from the gameUI palette. Consumers should not need to know
13
+ * that split exists.
14
+ */
15
+ export const toolTheme = {
16
+ colors: {
17
+ /** Modal/page background. */
18
+ surface: buoyColors.base,
19
+ /** Card / row background, one step above surface. */
20
+ card: buoyColors.card,
21
+ /** Pressed/hover background. */
22
+ hover: buoyColors.hover,
23
+ /** Text-input background. */
24
+ input: buoyColors.input,
25
+ border: buoyColors.border,
26
+ borderStrong: buoyColors.borderStrong,
27
+ text: buoyColors.text,
28
+ textSecondary: buoyColors.textSecondary,
29
+ textMuted: buoyColors.textMuted,
30
+ /** Buoy teal — primary accent. */
31
+ accent: buoyColors.primary,
32
+ success: gameUIColors.success,
33
+ warning: gameUIColors.warning,
34
+ error: gameUIColors.error,
35
+ info: gameUIColors.info
36
+ },
37
+ /**
38
+ * Text presets matching the styles internal tools re-declare per file.
39
+ * Spread into a style: `style={[toolTheme.text.label, { color: ... }]}`.
40
+ */
41
+ text: {
42
+ /** Modal/section titles. */
43
+ title: {
44
+ fontSize: 14,
45
+ fontWeight: "600",
46
+ color: buoyColors.text
47
+ },
48
+ /** Default body copy. */
49
+ body: {
50
+ fontSize: 13,
51
+ color: buoyColors.text
52
+ },
53
+ /** Secondary copy under a primary line. */
54
+ subtitle: {
55
+ fontSize: 12,
56
+ color: buoyColors.textSecondary
57
+ },
58
+ /** ALL-CAPS section labels ("LOCAL OVERRIDES"). */
59
+ label: {
60
+ fontSize: 10,
61
+ fontWeight: "700",
62
+ color: buoyColors.textMuted,
63
+ letterSpacing: 1.2,
64
+ fontFamily: "monospace"
65
+ },
66
+ /** Monospace values (keys, ids, payload snippets). */
67
+ mono: {
68
+ fontSize: 11,
69
+ color: buoyColors.textSecondary,
70
+ fontFamily: "monospace"
71
+ },
72
+ /** Timestamps and fine print. */
73
+ small: {
74
+ fontSize: 9,
75
+ color: buoyColors.textMuted,
76
+ fontFamily: "monospace"
77
+ }
78
+ },
79
+ /** 4-based spacing scale used across tool surfaces. */
80
+ spacing: {
81
+ xs: 4,
82
+ sm: 8,
83
+ md: 12,
84
+ lg: 16,
85
+ xl: 24
86
+ },
87
+ radius: {
88
+ sm: 6,
89
+ md: 8,
90
+ lg: 12,
91
+ pill: 9999
92
+ }
93
+ };
@@ -9,6 +9,8 @@ export { getValueType, isPrimitive, isJsonSerializable, isValidJson, getConstruc
9
9
  export { parseValue, formatValue, getTypeColor, truncateText, flattenObject, formatPath } from "./valueFormatting.js";
10
10
  export { loadOptionalModule, getCachedOptionalModule } from "./loadOptionalModule.js";
11
11
  export { setRenderCaptureProvider, getRenderCaptureProvider } from "./renderCaptureRegistry.js";
12
+ export { registerStateSnapshotProvider, getStateSnapshotProviders, getStateSnapshotProvider, subscribeToStateSnapshotProviders } from "./stateSnapshotRegistry.js";
13
+ export { serialize as superJsonSerialize, deserialize as superJsonDeserialize } from "./minimalSuperJSON.js";
12
14
  export { reloadApp, scheduleReloadApp, resolveReloadStrategy, REMOTE_RELOAD_DELAY_MS } from "./reloadApp.js";
13
15
  export { Subscribable } from "./subscribable.js";
14
16
  export { subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange } from "./subscriberCountNotifier.js";
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Cross-package bridge for app-state snapshot & restore (Time Machine).
5
+ *
6
+ * Each state tool (`@buoy-gg/storage`, `@buoy-gg/redux`, `@buoy-gg/zustand`,
7
+ * `@buoy-gg/jotai`, `@buoy-gg/react-query`) registers a provider here at
8
+ * module init (or from its app-lifetime sync hook); `@buoy-gg/time-machine`
9
+ * consumes the registry. Neither side imports the other — same
10
+ * optional-capability pattern as renderCaptureRegistry.
11
+ *
12
+ * Apps can also register custom providers for state Buoy doesn't know about.
13
+ */
14
+
15
+ const providers = new Map();
16
+ const listeners = new Set();
17
+ function notify() {
18
+ listeners.forEach(l => {
19
+ try {
20
+ l();
21
+ } catch {
22
+ // listener errors must not break registration
23
+ }
24
+ });
25
+ }
26
+
27
+ /**
28
+ * Register a provider. Last registration wins for a given id.
29
+ * Returns an unregister function (only removes the provider if it is still
30
+ * the registered one for that id).
31
+ */
32
+ export function registerStateSnapshotProvider(provider) {
33
+ providers.set(provider.id, provider);
34
+ notify();
35
+ return () => {
36
+ if (providers.get(provider.id) === provider) {
37
+ providers.delete(provider.id);
38
+ notify();
39
+ }
40
+ };
41
+ }
42
+ export function getStateSnapshotProviders() {
43
+ return Array.from(providers.values());
44
+ }
45
+ export function getStateSnapshotProvider(id) {
46
+ return providers.get(id) ?? null;
47
+ }
48
+
49
+ /** Notifies when providers register/unregister (query registers late). */
50
+ export function subscribeToStateSnapshotProviders(listener) {
51
+ listeners.add(listener);
52
+ return () => {
53
+ listeners.delete(listener);
54
+ };
55
+ }