@buoy-gg/shared-ui 7.0.32 → 7.0.33

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 (69) hide show
  1. package/lib/commonjs/JsModal.js +13 -6
  2. package/lib/commonjs/hooks/safe-area-impl.js +1 -1
  3. package/lib/commonjs/storage/devToolsStorageKeys.js +12 -0
  4. package/lib/commonjs/ui/components/EmptyState.js +10 -2
  5. package/lib/commonjs/ui/components/ToolEmptyState.js +154 -0
  6. package/lib/commonjs/ui/components/WindowControls.js +8 -5
  7. package/lib/commonjs/ui/components/index.js +13 -0
  8. package/lib/commonjs/ui/index.js +12 -0
  9. package/lib/commonjs/ui/otto/OttoSprite.js +510 -0
  10. package/lib/commonjs/ui/otto/index.js +38 -0
  11. package/lib/commonjs/ui/otto/ottoEngine.js +2734 -0
  12. package/lib/commonjs/ui/otto/ottoSheet.js +191 -0
  13. package/lib/module/JsModal.js +13 -6
  14. package/lib/module/hooks/safe-area-impl.js +1 -1
  15. package/lib/module/storage/devToolsStorageKeys.js +12 -0
  16. package/lib/module/ui/components/EmptyState.js +10 -2
  17. package/lib/module/ui/components/ToolEmptyState.js +149 -0
  18. package/lib/module/ui/components/WindowControls.js +8 -5
  19. package/lib/module/ui/components/index.js +3 -0
  20. package/lib/module/ui/index.js +4 -1
  21. package/lib/module/ui/otto/OttoSprite.js +496 -0
  22. package/lib/module/ui/otto/index.js +20 -0
  23. package/lib/module/ui/otto/ottoEngine.js +2726 -0
  24. package/lib/module/ui/otto/ottoSheet.js +180 -0
  25. package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
  26. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  27. package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts +12 -0
  28. package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts.map +1 -1
  29. package/lib/typescript/commonjs/ui/components/EmptyState.d.ts +14 -1
  30. package/lib/typescript/commonjs/ui/components/EmptyState.d.ts.map +1 -1
  31. package/lib/typescript/commonjs/ui/components/ToolEmptyState.d.ts +113 -0
  32. package/lib/typescript/commonjs/ui/components/ToolEmptyState.d.ts.map +1 -0
  33. package/lib/typescript/commonjs/ui/components/WindowControls.d.ts +7 -1
  34. package/lib/typescript/commonjs/ui/components/WindowControls.d.ts.map +1 -1
  35. package/lib/typescript/commonjs/ui/components/index.d.ts +2 -0
  36. package/lib/typescript/commonjs/ui/components/index.d.ts.map +1 -1
  37. package/lib/typescript/commonjs/ui/index.d.ts +1 -0
  38. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  39. package/lib/typescript/commonjs/ui/otto/OttoSprite.d.ts +103 -0
  40. package/lib/typescript/commonjs/ui/otto/OttoSprite.d.ts.map +1 -0
  41. package/lib/typescript/commonjs/ui/otto/index.d.ts +19 -0
  42. package/lib/typescript/commonjs/ui/otto/index.d.ts.map +1 -0
  43. package/lib/typescript/commonjs/ui/otto/ottoEngine.d.ts +2205 -0
  44. package/lib/typescript/commonjs/ui/otto/ottoEngine.d.ts.map +1 -0
  45. package/lib/typescript/commonjs/ui/otto/ottoSheet.d.ts +73 -0
  46. package/lib/typescript/commonjs/ui/otto/ottoSheet.d.ts.map +1 -0
  47. package/lib/typescript/module/JsModal.d.ts.map +1 -1
  48. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  49. package/lib/typescript/module/storage/devToolsStorageKeys.d.ts +12 -0
  50. package/lib/typescript/module/storage/devToolsStorageKeys.d.ts.map +1 -1
  51. package/lib/typescript/module/ui/components/EmptyState.d.ts +14 -1
  52. package/lib/typescript/module/ui/components/EmptyState.d.ts.map +1 -1
  53. package/lib/typescript/module/ui/components/ToolEmptyState.d.ts +113 -0
  54. package/lib/typescript/module/ui/components/ToolEmptyState.d.ts.map +1 -0
  55. package/lib/typescript/module/ui/components/WindowControls.d.ts +7 -1
  56. package/lib/typescript/module/ui/components/WindowControls.d.ts.map +1 -1
  57. package/lib/typescript/module/ui/components/index.d.ts +2 -0
  58. package/lib/typescript/module/ui/components/index.d.ts.map +1 -1
  59. package/lib/typescript/module/ui/index.d.ts +1 -0
  60. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  61. package/lib/typescript/module/ui/otto/OttoSprite.d.ts +103 -0
  62. package/lib/typescript/module/ui/otto/OttoSprite.d.ts.map +1 -0
  63. package/lib/typescript/module/ui/otto/index.d.ts +19 -0
  64. package/lib/typescript/module/ui/otto/index.d.ts.map +1 -0
  65. package/lib/typescript/module/ui/otto/ottoEngine.d.ts +2205 -0
  66. package/lib/typescript/module/ui/otto/ottoEngine.d.ts.map +1 -0
  67. package/lib/typescript/module/ui/otto/ottoSheet.d.ts +73 -0
  68. package/lib/typescript/module/ui/otto/ottoSheet.d.ts.map +1 -0
  69. package/package.json +4 -4
@@ -437,15 +437,19 @@ const JsModalComponent = ({
437
437
  return () => clearTimeout(timeoutId);
438
438
  }, [mode, panelHeight, dimensions, visible, persistenceKey, enablePersistence, isStateLoaded]);
439
439
 
440
- // Sync with external height if provided
440
+ // Seed the external height ONCE. This used to re-run when `isResizing`
441
+ // flipped, which snapped an externally-controlled sheet back to
442
+ // initialHeight the moment a drag-resize ended (the release handler had
443
+ // just written the real height). The host owns the value after the seed;
444
+ // persistence restore above may overwrite the seed, which is correct.
445
+ const externalHeightSeeded = (0, _react.useRef)(false);
441
446
  (0, _react.useEffect)(() => {
442
- // Height sync effect
443
- if (externalAnimatedHeight && !isResizing) {
447
+ if (externalAnimatedHeight && !externalHeightSeeded.current) {
448
+ externalHeightSeeded.current = true;
444
449
  currentHeightRef.current = initialHeight;
445
450
  externalAnimatedHeight.setValue(initialHeight);
446
- // Set external height
447
451
  }
448
- }, [externalAnimatedHeight, initialHeight, isResizing]);
452
+ }, [externalAnimatedHeight, initialHeight]);
449
453
 
450
454
  // Update refs when dimensions change
451
455
  (0, _react.useEffect)(() => {
@@ -535,11 +539,14 @@ const JsModalComponent = ({
535
539
  onModeChangeRef.current?.(savedState.mode);
536
540
  }
537
541
 
538
- // Restore bottom sheet height
542
+ // Restore bottom sheet height. The external animated height (when a
543
+ // host passes one) IS the rendered height, so it must be restored
544
+ // too or a persisted sheet always reopens at initialHeight.
539
545
  if (savedState.panelHeight) {
540
546
  setPanelHeight(savedState.panelHeight);
541
547
  currentHeightRef.current = savedState.panelHeight;
542
548
  animatedBottomPosition.setValue(savedState.panelHeight);
549
+ externalAnimatedHeight?.setValue(savedState.panelHeight);
543
550
  }
544
551
 
545
552
  // Restore floating dimensions and position
@@ -7,7 +7,7 @@ exports.useNativeSafeAreaInsets = exports.safeAreaType = exports.hasSafeAreaPack
7
7
  /**
8
8
  * Auto-generated safe area implementation
9
9
  * Detected: none
10
- * Generated at: 2026-09-01T17:57:34.045Z
10
+ * Generated at: 2026-09-02T23:25:39.783Z
11
11
  *
12
12
  * DO NOT EDIT - This file is generated by scripts/detect-safe-area.js
13
13
  *
@@ -257,6 +257,18 @@ const devToolsStorageKeys = exports.devToolsStorageKeys = {
257
257
  pausedAt: () => `${devToolsStorageKeys.events.root()}_paused_at`,
258
258
  /** Copy/export settings */
259
259
  copySettings: () => `${devToolsStorageKeys.events.root()}_copy_settings`
260
+ },
261
+ /**
262
+ * Desktop/MCP sync identity
263
+ */
264
+ sync: {
265
+ root: () => `${devToolsStorageKeys.base}_sync`,
266
+ /**
267
+ * The per-install id minted the first time this app dials the broker.
268
+ * It is what makes two devices on the same build register as two
269
+ * devices — see core's deviceIdentity.ts.
270
+ */
271
+ deviceId: () => `${devToolsStorageKeys.sync.root()}_device_id`
260
272
  }
261
273
  };
262
274
 
@@ -9,11 +9,13 @@ exports.NoResultsEmptyState = NoResultsEmptyState;
9
9
  exports.NoSearchResultsEmptyState = NoSearchResultsEmptyState;
10
10
  var _reactNative = require("react-native");
11
11
  var _macOSDesignSystemColors = require("../gameUI/constants/macOSDesignSystemColors.js");
12
+ var _index = require("../otto/index.js");
12
13
  var _jsxRuntime = require("react/jsx-runtime");
13
14
  /**
14
15
  * Reusable empty state component for consistent empty/no-data displays
15
16
  */
16
17
  function EmptyState({
18
+ otto,
17
19
  title,
18
20
  description,
19
21
  icon: Icon,
@@ -28,13 +30,19 @@ function EmptyState({
28
30
  style: containerStyle,
29
31
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
30
32
  style: styles.content,
31
- children: [Icon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
33
+ children: [otto ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
34
+ style: styles.iconContainer,
35
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.Otto, {
36
+ state: otto,
37
+ pixelSize: Math.max(2, Math.round(iconSize / 16))
38
+ })
39
+ }) : Icon ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
32
40
  style: styles.iconContainer,
33
41
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Icon, {
34
42
  size: iconSize,
35
43
  color: iconColor
36
44
  })
37
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
45
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
38
46
  style: styles.title,
39
47
  children: title
40
48
  }), description && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ToolEmptyState = ToolEmptyState;
7
+ exports.resolveListEmptyState = resolveListEmptyState;
8
+ var _reactNative = require("react-native");
9
+ var _index = require("../otto/index.js");
10
+ var _nightTheme = require("../night/nightTheme.js");
11
+ var _jsxRuntime = require("react/jsx-runtime");
12
+ /**
13
+ * The one "nothing here" panel, for every tool that shows a list.
14
+ *
15
+ * WHY THIS EXISTS
16
+ *
17
+ * Every capture tool — network, events, highlight-updates, storage, zustand,
18
+ * redux, jotai, console — renders the same panel with the same four causes and
19
+ * different nouns. Written out per tool, that produced four copies of the same
20
+ * layout (each of which had to be re-inset by hand the first time a sentence
21
+ * was longer than "No events yet"), and four independent guesses at the
22
+ * PRECEDENCE between those causes. The guesses disagreed, and the disagreements
23
+ * were bugs:
24
+ *
25
+ * - A search that matched nothing showed "Enable tracking to start
26
+ * capturing" — pointing at a toggle that was already on.
27
+ * - Turning every source chip off showed "Events will appear here as they
28
+ * occur" — inviting you to go generate events that were already in the
29
+ * store, behind your own filter.
30
+ * - Typing into a search box while the store was empty produced no
31
+ * acknowledgement of the query at all, which reads as a dead search box.
32
+ *
33
+ * So the precedence lives here, once, and each tool supplies only what is
34
+ * genuinely its own: the noun, and what "switched on but waiting" looks like
35
+ * for it (network fishes, events listens, the highlighter stares).
36
+ *
37
+ * SPLIT IN TWO ON PURPOSE
38
+ *
39
+ * `resolveListEmptyState` is a pure function returning `{ otto, title,
40
+ * message }`, and `ToolEmptyState` renders that object. Tools with a cause
41
+ * nobody else has — storage's "no issues found" (which is a PASS, not a
42
+ * failure), zustand's unregistered store — resolve the common cases and
43
+ * substitute their own, or skip the resolver and hand the shell a literal.
44
+ * Adding a mascot to every tool at once is then one edit in this file, which is
45
+ * also what makes the Flutter and Swift ports one component to mirror instead
46
+ * of eight.
47
+ */
48
+
49
+ /** What a "nothing here" panel says. */
50
+
51
+ /**
52
+ * The panel itself: Otto, a heading, a sentence. Nothing else — this only ever
53
+ * renders where the alternative is a blank body, so it has no actions and no
54
+ * decoration to compete with the list it stands in for.
55
+ */
56
+ function ToolEmptyState({
57
+ otto,
58
+ title,
59
+ message,
60
+ testID,
61
+ style
62
+ }) {
63
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
64
+ style: [styles.container, style],
65
+ testID: testID,
66
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index.Otto, {
67
+ state: otto,
68
+ pixelSize: 2
69
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
70
+ style: styles.title,
71
+ testID: testID ? `${testID}-title` : undefined,
72
+ numberOfLines: 2,
73
+ children: title
74
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
75
+ style: styles.message,
76
+ testID: testID ? `${testID}-text` : undefined,
77
+ children: message
78
+ })]
79
+ });
80
+ }
81
+ /**
82
+ * Which "nothing here" this is, in the order the facts answer the question.
83
+ *
84
+ * A typed query first (see `search`), then the user's filters, then the
85
+ * capture switch, then the honest "nothing yet".
86
+ */
87
+ function resolveListEmptyState(facts) {
88
+ const {
89
+ subject,
90
+ verb = "captured",
91
+ search,
92
+ total = 0,
93
+ capturing,
94
+ waiting,
95
+ paused,
96
+ blocked
97
+ } = facts;
98
+ const term = (search ?? "").trim();
99
+ if (term) {
100
+ return {
101
+ otto: "sad",
102
+ // The query goes in the HEADING because checking what you typed is the
103
+ // first thing you do; the body names whichever blocker is in the way.
104
+ title: `No results for “${term}”`,
105
+ message: blocked ?? (total > 0 ? `None of the ${total} ${verb} ${subject} match. Clear the search to see them.` : capturing === false ? `Nothing is ${verb} to search — capture is off. Turn it on to start.` : `Nothing has been ${verb} yet, so there is nothing to match.`)
106
+ };
107
+ }
108
+ if (blocked) {
109
+ return {
110
+ otto: "filtering",
111
+ title: "Filtered Out",
112
+ message: blocked
113
+ };
114
+ }
115
+ if (total > 0) {
116
+ return {
117
+ otto: "filtering",
118
+ title: "Filtered Out",
119
+ message: `${total} ${verb} ${subject} ${total === 1 ? "is" : "are"} hidden by the active filters.`
120
+ };
121
+ }
122
+ if (capturing === false) {
123
+ return {
124
+ otto: paused?.otto ?? "paused",
125
+ title: paused?.title ?? "Not capturing",
126
+ message: paused?.message ?? "Capture is off. Turn it on to start."
127
+ };
128
+ }
129
+ return waiting;
130
+ }
131
+ const styles = _reactNative.StyleSheet.create({
132
+ container: {
133
+ alignItems: "center",
134
+ paddingVertical: 40,
135
+ // The generated sentences are full sentences. Every tool that hand-rolled
136
+ // this panel shipped without an inset and had it run to both edges of the
137
+ // sheet the first time the copy grew past a few words.
138
+ paddingHorizontal: 24
139
+ },
140
+ title: {
141
+ color: _nightTheme.night.color.text,
142
+ fontSize: 14,
143
+ fontWeight: "600",
144
+ marginTop: 12,
145
+ marginBottom: 6,
146
+ textAlign: "center"
147
+ },
148
+ message: {
149
+ color: _nightTheme.night.color.textTertiary,
150
+ fontSize: 12,
151
+ textAlign: "center",
152
+ lineHeight: 17
153
+ }
154
+ });
@@ -74,7 +74,8 @@ function WindowControls({
74
74
  onMinimize,
75
75
  onToggleMode,
76
76
  mode,
77
- variant = "night"
77
+ variant = "night",
78
+ defaultExpanded
78
79
  }) {
79
80
  // Show action-based icon: what will happen when clicked
80
81
  const ToggleModeIcon = mode === "floating" ? _index.DockBottom : _index.FloatWindow;
@@ -129,7 +130,8 @@ function WindowControls({
129
130
  onMinimize: onMinimize,
130
131
  onToggleMode: onToggleMode,
131
132
  mode: mode,
132
- variant: variant
133
+ variant: variant,
134
+ defaultExpanded: defaultExpanded
133
135
  });
134
136
  }
135
137
  function ExpandableWindowControls({
@@ -137,11 +139,12 @@ function ExpandableWindowControls({
137
139
  onMinimize,
138
140
  onToggleMode,
139
141
  mode,
140
- variant = "night"
142
+ variant = "night",
143
+ defaultExpanded = false
141
144
  }) {
142
145
  const isNight = variant === "night";
143
- const [expanded, setExpanded] = (0, _react.useState)(false);
144
- const expandAnim = (0, _react.useRef)(new _reactNative.Animated.Value(0)).current;
146
+ const [expanded, setExpanded] = (0, _react.useState)(defaultExpanded);
147
+ const expandAnim = (0, _react.useRef)(new _reactNative.Animated.Value(defaultExpanded ? 1 : 0)).current;
145
148
  const dismissTimeout = (0, _react.useRef)(null);
146
149
  const ToggleModeIcon = mode === "floating" ? _index.DockBottom : _index.FloatWindow;
147
150
  const toggleModeLabel = mode === "floating" ? "Dock to bottom sheet" : "Make floating window";
@@ -303,6 +303,12 @@ Object.defineProperty(exports, "ToolButton", {
303
303
  return _ToolButton.ToolButton;
304
304
  }
305
305
  });
306
+ Object.defineProperty(exports, "ToolEmptyState", {
307
+ enumerable: true,
308
+ get: function () {
309
+ return _ToolEmptyState.ToolEmptyState;
310
+ }
311
+ });
306
312
  Object.defineProperty(exports, "ToolbarClearButton", {
307
313
  enumerable: true,
308
314
  get: function () {
@@ -345,6 +351,12 @@ Object.defineProperty(exports, "noWindowDragProps", {
345
351
  return _windowDrag.noWindowDragProps;
346
352
  }
347
353
  });
354
+ Object.defineProperty(exports, "resolveListEmptyState", {
355
+ enumerable: true,
356
+ get: function () {
357
+ return _ToolEmptyState.resolveListEmptyState;
358
+ }
359
+ });
348
360
  Object.defineProperty(exports, "setExpandableWindowControls", {
349
361
  enumerable: true,
350
362
  get: function () {
@@ -378,6 +390,7 @@ var _CompactRow = require("./CompactRow.js");
378
390
  var _DevToolsCard = require("./DevToolsCard.js");
379
391
  var _HeaderSearchButton = require("./HeaderSearchButton.js");
380
392
  var _EmptyState = require("./EmptyState.js");
393
+ var _ToolEmptyState = require("./ToolEmptyState.js");
381
394
  var _StatusIndicator = require("./StatusIndicator.js");
382
395
  var _TimeDisplay = require("./TimeDisplay.js");
383
396
  var _DetailView = require("./DetailView.js");
@@ -56,4 +56,16 @@ Object.keys(_index3).forEach(function (key) {
56
56
  return _index3[key];
57
57
  }
58
58
  });
59
+ });
60
+ var _index4 = require("./otto/index.js");
61
+ Object.keys(_index4).forEach(function (key) {
62
+ if (key === "default" || key === "__esModule") return;
63
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
64
+ if (key in exports && exports[key] === _index4[key]) return;
65
+ Object.defineProperty(exports, key, {
66
+ enumerable: true,
67
+ get: function () {
68
+ return _index4[key];
69
+ }
70
+ });
59
71
  });