@buoy-gg/shared-ui 7.0.21 → 7.0.23

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 (178) hide show
  1. package/lib/commonjs/JsModal.js +39 -16
  2. package/lib/commonjs/dataViewer/JsonStringNotice.js +59 -0
  3. package/lib/commonjs/dataViewer/ThemedSplitView.js +20 -1
  4. package/lib/commonjs/dataViewer/TimestampDeltaBar.js +96 -0
  5. package/lib/commonjs/dataViewer/index.js +52 -0
  6. package/lib/commonjs/dataViewer/jsonStringValue.js +94 -0
  7. package/lib/commonjs/dataViewer/timestampDiff.js +146 -0
  8. package/lib/commonjs/hooks/safe-area-impl.js +1 -1
  9. package/lib/commonjs/index.js +64 -1
  10. package/lib/commonjs/license/FeatureGate.js +43 -10
  11. package/lib/commonjs/license/FreeAccountPrompt.js +181 -0
  12. package/lib/commonjs/license/index.js +57 -42
  13. package/lib/commonjs/license/licenseModule.js +99 -0
  14. package/lib/commonjs/license/tierLimits.js +165 -0
  15. package/lib/commonjs/ui/backgrounds/BackgroundSwitcher.js +180 -0
  16. package/lib/commonjs/ui/backgrounds/README.md +115 -0
  17. package/lib/commonjs/ui/backgrounds/ToolBackground.js +74 -0
  18. package/lib/commonjs/ui/backgrounds/backgroundStore.js +116 -0
  19. package/lib/commonjs/ui/backgrounds/index.js +70 -0
  20. package/lib/commonjs/ui/backgrounds/primitives.js +333 -0
  21. package/lib/commonjs/ui/backgrounds/registry.js +112 -0
  22. package/lib/commonjs/ui/backgrounds/rng.js +72 -0
  23. package/lib/commonjs/ui/backgrounds/types.js +1 -0
  24. package/lib/commonjs/ui/backgrounds/variants/deepField.js +351 -0
  25. package/lib/commonjs/ui/backgrounds/variants/lattice.js +579 -0
  26. package/lib/commonjs/ui/backgrounds/variants/starfield.js +210 -0
  27. package/lib/commonjs/ui/index.js +15 -3
  28. package/lib/commonjs/utils/devServer.js +62 -0
  29. package/lib/commonjs/utils/index.js +13 -0
  30. package/lib/commonjs/utils/renderCaptureRegistry.js +32 -3
  31. package/lib/commonjs/utils/safeExpoRouter.js +27 -2
  32. package/lib/module/JsModal.js +39 -16
  33. package/lib/module/dataViewer/JsonStringNotice.js +54 -0
  34. package/lib/module/dataViewer/ThemedSplitView.js +20 -1
  35. package/lib/module/dataViewer/TimestampDeltaBar.js +91 -0
  36. package/lib/module/dataViewer/index.js +4 -0
  37. package/lib/module/dataViewer/jsonStringValue.js +89 -0
  38. package/lib/module/dataViewer/timestampDiff.js +139 -0
  39. package/lib/module/hooks/safe-area-impl.js +1 -1
  40. package/lib/module/index.js +5 -3
  41. package/lib/module/license/FeatureGate.js +43 -10
  42. package/lib/module/license/FreeAccountPrompt.js +176 -0
  43. package/lib/module/license/index.js +5 -40
  44. package/lib/module/license/licenseModule.js +92 -0
  45. package/lib/module/license/tierLimits.js +158 -0
  46. package/lib/module/ui/backgrounds/BackgroundSwitcher.js +176 -0
  47. package/lib/module/ui/backgrounds/README.md +115 -0
  48. package/lib/module/ui/backgrounds/ToolBackground.js +70 -0
  49. package/lib/module/ui/backgrounds/backgroundStore.js +111 -0
  50. package/lib/module/ui/backgrounds/index.js +9 -0
  51. package/lib/module/ui/backgrounds/primitives.js +328 -0
  52. package/lib/module/ui/backgrounds/registry.js +105 -0
  53. package/lib/module/ui/backgrounds/rng.js +65 -0
  54. package/lib/module/ui/backgrounds/types.js +1 -0
  55. package/lib/module/ui/backgrounds/variants/deepField.js +347 -0
  56. package/lib/module/ui/backgrounds/variants/lattice.js +575 -0
  57. package/lib/module/ui/backgrounds/variants/starfield.js +206 -0
  58. package/lib/module/ui/index.js +3 -0
  59. package/lib/module/utils/devServer.js +58 -0
  60. package/lib/module/utils/index.js +2 -1
  61. package/lib/module/utils/renderCaptureRegistry.js +32 -3
  62. package/lib/module/utils/safeExpoRouter.js +26 -2
  63. package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/dataViewer/JsonStringNotice.d.ts +6 -0
  65. package/lib/typescript/commonjs/dataViewer/JsonStringNotice.d.ts.map +1 -0
  66. package/lib/typescript/commonjs/dataViewer/ThemedSplitView.d.ts.map +1 -1
  67. package/lib/typescript/commonjs/dataViewer/TimestampDeltaBar.d.ts +7 -0
  68. package/lib/typescript/commonjs/dataViewer/TimestampDeltaBar.d.ts.map +1 -0
  69. package/lib/typescript/commonjs/dataViewer/index.d.ts +6 -0
  70. package/lib/typescript/commonjs/dataViewer/index.d.ts.map +1 -1
  71. package/lib/typescript/commonjs/dataViewer/jsonStringValue.d.ts +25 -0
  72. package/lib/typescript/commonjs/dataViewer/jsonStringValue.d.ts.map +1 -0
  73. package/lib/typescript/commonjs/dataViewer/timestampDiff.d.ts +55 -0
  74. package/lib/typescript/commonjs/dataViewer/timestampDiff.d.ts.map +1 -0
  75. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  76. package/lib/typescript/commonjs/index.d.ts +4 -3
  77. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  78. package/lib/typescript/commonjs/license/FeatureGate.d.ts +19 -3
  79. package/lib/typescript/commonjs/license/FeatureGate.d.ts.map +1 -1
  80. package/lib/typescript/commonjs/license/FreeAccountPrompt.d.ts +23 -0
  81. package/lib/typescript/commonjs/license/FreeAccountPrompt.d.ts.map +1 -0
  82. package/lib/typescript/commonjs/license/index.d.ts +6 -15
  83. package/lib/typescript/commonjs/license/index.d.ts.map +1 -1
  84. package/lib/typescript/commonjs/license/licenseModule.d.ts +55 -0
  85. package/lib/typescript/commonjs/license/licenseModule.d.ts.map +1 -0
  86. package/lib/typescript/commonjs/license/tierLimits.d.ts +143 -0
  87. package/lib/typescript/commonjs/license/tierLimits.d.ts.map +1 -0
  88. package/lib/typescript/commonjs/ui/backgrounds/BackgroundSwitcher.d.ts +13 -0
  89. package/lib/typescript/commonjs/ui/backgrounds/BackgroundSwitcher.d.ts.map +1 -0
  90. package/lib/typescript/commonjs/ui/backgrounds/ToolBackground.d.ts +30 -0
  91. package/lib/typescript/commonjs/ui/backgrounds/ToolBackground.d.ts.map +1 -0
  92. package/lib/typescript/commonjs/ui/backgrounds/backgroundStore.d.ts +43 -0
  93. package/lib/typescript/commonjs/ui/backgrounds/backgroundStore.d.ts.map +1 -0
  94. package/lib/typescript/commonjs/ui/backgrounds/index.d.ts +7 -0
  95. package/lib/typescript/commonjs/ui/backgrounds/index.d.ts.map +1 -0
  96. package/lib/typescript/commonjs/ui/backgrounds/primitives.d.ts +106 -0
  97. package/lib/typescript/commonjs/ui/backgrounds/primitives.d.ts.map +1 -0
  98. package/lib/typescript/commonjs/ui/backgrounds/registry.d.ts +28 -0
  99. package/lib/typescript/commonjs/ui/backgrounds/registry.d.ts.map +1 -0
  100. package/lib/typescript/commonjs/ui/backgrounds/rng.d.ts +27 -0
  101. package/lib/typescript/commonjs/ui/backgrounds/rng.d.ts.map +1 -0
  102. package/lib/typescript/commonjs/ui/backgrounds/types.d.ts +14 -0
  103. package/lib/typescript/commonjs/ui/backgrounds/types.d.ts.map +1 -0
  104. package/lib/typescript/commonjs/ui/backgrounds/variants/deepField.d.ts +65 -0
  105. package/lib/typescript/commonjs/ui/backgrounds/variants/deepField.d.ts.map +1 -0
  106. package/lib/typescript/commonjs/ui/backgrounds/variants/lattice.d.ts +33 -0
  107. package/lib/typescript/commonjs/ui/backgrounds/variants/lattice.d.ts.map +1 -0
  108. package/lib/typescript/commonjs/ui/backgrounds/variants/starfield.d.ts +12 -0
  109. package/lib/typescript/commonjs/ui/backgrounds/variants/starfield.d.ts.map +1 -0
  110. package/lib/typescript/commonjs/ui/index.d.ts +1 -0
  111. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  112. package/lib/typescript/commonjs/utils/devServer.d.ts +24 -0
  113. package/lib/typescript/commonjs/utils/devServer.d.ts.map +1 -0
  114. package/lib/typescript/commonjs/utils/index.d.ts +3 -2
  115. package/lib/typescript/commonjs/utils/index.d.ts.map +1 -1
  116. package/lib/typescript/commonjs/utils/renderCaptureRegistry.d.ts +52 -2
  117. package/lib/typescript/commonjs/utils/renderCaptureRegistry.d.ts.map +1 -1
  118. package/lib/typescript/commonjs/utils/safeExpoRouter.d.ts +23 -0
  119. package/lib/typescript/commonjs/utils/safeExpoRouter.d.ts.map +1 -1
  120. package/lib/typescript/module/JsModal.d.ts.map +1 -1
  121. package/lib/typescript/module/dataViewer/JsonStringNotice.d.ts +6 -0
  122. package/lib/typescript/module/dataViewer/JsonStringNotice.d.ts.map +1 -0
  123. package/lib/typescript/module/dataViewer/ThemedSplitView.d.ts.map +1 -1
  124. package/lib/typescript/module/dataViewer/TimestampDeltaBar.d.ts +7 -0
  125. package/lib/typescript/module/dataViewer/TimestampDeltaBar.d.ts.map +1 -0
  126. package/lib/typescript/module/dataViewer/index.d.ts +6 -0
  127. package/lib/typescript/module/dataViewer/index.d.ts.map +1 -1
  128. package/lib/typescript/module/dataViewer/jsonStringValue.d.ts +25 -0
  129. package/lib/typescript/module/dataViewer/jsonStringValue.d.ts.map +1 -0
  130. package/lib/typescript/module/dataViewer/timestampDiff.d.ts +55 -0
  131. package/lib/typescript/module/dataViewer/timestampDiff.d.ts.map +1 -0
  132. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  133. package/lib/typescript/module/index.d.ts +4 -3
  134. package/lib/typescript/module/index.d.ts.map +1 -1
  135. package/lib/typescript/module/license/FeatureGate.d.ts +19 -3
  136. package/lib/typescript/module/license/FeatureGate.d.ts.map +1 -1
  137. package/lib/typescript/module/license/FreeAccountPrompt.d.ts +23 -0
  138. package/lib/typescript/module/license/FreeAccountPrompt.d.ts.map +1 -0
  139. package/lib/typescript/module/license/index.d.ts +6 -15
  140. package/lib/typescript/module/license/index.d.ts.map +1 -1
  141. package/lib/typescript/module/license/licenseModule.d.ts +55 -0
  142. package/lib/typescript/module/license/licenseModule.d.ts.map +1 -0
  143. package/lib/typescript/module/license/tierLimits.d.ts +143 -0
  144. package/lib/typescript/module/license/tierLimits.d.ts.map +1 -0
  145. package/lib/typescript/module/ui/backgrounds/BackgroundSwitcher.d.ts +13 -0
  146. package/lib/typescript/module/ui/backgrounds/BackgroundSwitcher.d.ts.map +1 -0
  147. package/lib/typescript/module/ui/backgrounds/ToolBackground.d.ts +30 -0
  148. package/lib/typescript/module/ui/backgrounds/ToolBackground.d.ts.map +1 -0
  149. package/lib/typescript/module/ui/backgrounds/backgroundStore.d.ts +43 -0
  150. package/lib/typescript/module/ui/backgrounds/backgroundStore.d.ts.map +1 -0
  151. package/lib/typescript/module/ui/backgrounds/index.d.ts +7 -0
  152. package/lib/typescript/module/ui/backgrounds/index.d.ts.map +1 -0
  153. package/lib/typescript/module/ui/backgrounds/primitives.d.ts +106 -0
  154. package/lib/typescript/module/ui/backgrounds/primitives.d.ts.map +1 -0
  155. package/lib/typescript/module/ui/backgrounds/registry.d.ts +28 -0
  156. package/lib/typescript/module/ui/backgrounds/registry.d.ts.map +1 -0
  157. package/lib/typescript/module/ui/backgrounds/rng.d.ts +27 -0
  158. package/lib/typescript/module/ui/backgrounds/rng.d.ts.map +1 -0
  159. package/lib/typescript/module/ui/backgrounds/types.d.ts +14 -0
  160. package/lib/typescript/module/ui/backgrounds/types.d.ts.map +1 -0
  161. package/lib/typescript/module/ui/backgrounds/variants/deepField.d.ts +65 -0
  162. package/lib/typescript/module/ui/backgrounds/variants/deepField.d.ts.map +1 -0
  163. package/lib/typescript/module/ui/backgrounds/variants/lattice.d.ts +33 -0
  164. package/lib/typescript/module/ui/backgrounds/variants/lattice.d.ts.map +1 -0
  165. package/lib/typescript/module/ui/backgrounds/variants/starfield.d.ts +12 -0
  166. package/lib/typescript/module/ui/backgrounds/variants/starfield.d.ts.map +1 -0
  167. package/lib/typescript/module/ui/index.d.ts +1 -0
  168. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  169. package/lib/typescript/module/utils/devServer.d.ts +24 -0
  170. package/lib/typescript/module/utils/devServer.d.ts.map +1 -0
  171. package/lib/typescript/module/utils/index.d.ts +3 -2
  172. package/lib/typescript/module/utils/index.d.ts.map +1 -1
  173. package/lib/typescript/module/utils/renderCaptureRegistry.d.ts +52 -2
  174. package/lib/typescript/module/utils/renderCaptureRegistry.d.ts.map +1 -1
  175. package/lib/typescript/module/utils/safeExpoRouter.d.ts +23 -0
  176. package/lib/typescript/module/utils/safeExpoRouter.d.ts.map +1 -1
  177. package/package.json +4 -4
  178. package/scripts/detect-safe-area.js +1 -0
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Starfield = void 0;
7
+ var _react = require("react");
8
+ var _reactNative = require("react-native");
9
+ var _absoluteFill = require("../../../utils/absoluteFill.js");
10
+ var _primitives = require("../primitives.js");
11
+ var _rng = require("../rng.js");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ /**
14
+ * Starfield — the RN-primitive port of the Everlights parallax-drift starfield.
15
+ *
16
+ * The original is a GPU-instanced Skia `<Atlas>` with a per-star worklet; Buoy
17
+ * can't depend on Skia, so the depth continuum is quantised into five discrete
18
+ * bands. Each band is one rasterized layer of dots sliding at its own speed —
19
+ * five native-driven loops instead of 160 per-frame transforms — and the eye
20
+ * reads five parallax speeds as depth just as well as it reads a continuum.
21
+ */
22
+
23
+ /**
24
+ * Depth bands, far → near. `z` drives both size and speed (drift/sec at z=1 is
25
+ * 0.016 of the width, matching the original), `count` thins out as stars get
26
+ * closer so the fast, big ones stay sparse.
27
+ */
28
+ const BANDS = [
29
+ // dia is the star's core in px; halo is how many core-widths the bloom
30
+ // spreads (0 = no bloom, which is what keeps the far bands cheap).
31
+ {
32
+ z: 1.0,
33
+ count: 38,
34
+ dia: 1.4,
35
+ halo: 0,
36
+ color: "#7C93B5",
37
+ alpha: 0.55
38
+ }, {
39
+ z: 0.78,
40
+ count: 26,
41
+ dia: 1.9,
42
+ halo: 0,
43
+ color: "#A6BBD8",
44
+ alpha: 0.65
45
+ }, {
46
+ z: 0.6,
47
+ count: 18,
48
+ dia: 2.4,
49
+ halo: 0,
50
+ color: "#C9D9F0",
51
+ alpha: 0.8
52
+ }, {
53
+ z: 0.45,
54
+ count: 11,
55
+ dia: 3.1,
56
+ halo: 0,
57
+ color: "#E4EEFC",
58
+ alpha: 0.92
59
+ },
60
+ // Only the closest band gets a bloom: 6 stars x 3 extra discs is 36 views,
61
+ // and it is the entire difference between "dots" and "stars".
62
+ {
63
+ z: 0.3,
64
+ count: 6,
65
+ dia: 4.2,
66
+ halo: 4.4,
67
+ color: "#FFFFFF",
68
+ alpha: 1
69
+ }];
70
+ const DRIFT = 0.016; // fraction of width travelled per second at z=1
71
+
72
+ /** Pre-scattered x/y per band, generated once at module load. */
73
+ const BAND_TABLES = BANDS.map((b, i) => ({
74
+ xs: (0, _rng.scatter)(0x5747 + i * 977, b.count),
75
+ ys: (0, _rng.scatter)(0x91c3 + i * 613, b.count)
76
+ }));
77
+
78
+ /**
79
+ * The bloom around a close star. Three nested discs rather than a `RadialGlow`,
80
+ * because this one is drawn per star and lives INSIDE the band layer — which is
81
+ * the point: the halo travels with its star instead of sitting still while the
82
+ * star drifts off it.
83
+ */
84
+ function haloDiscs(cx, cy, core, spread, color, key) {
85
+ const out = [];
86
+ const steps = [{
87
+ mul: spread,
88
+ alpha: 0.05
89
+ }, {
90
+ mul: spread * 0.62,
91
+ alpha: 0.09
92
+ }, {
93
+ mul: spread * 0.34,
94
+ alpha: 0.16
95
+ }];
96
+ for (let i = 0; i < steps.length; i++) {
97
+ const d = core * steps[i].mul;
98
+ out.push(/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
99
+ style: {
100
+ position: "absolute",
101
+ left: cx - d / 2,
102
+ top: cy - d / 2,
103
+ width: d,
104
+ height: d,
105
+ borderRadius: d / 2,
106
+ backgroundColor: (0, _rng.withAlpha)(color, steps[i].alpha)
107
+ }
108
+ }, `${key}-h${i}`));
109
+ }
110
+ return out;
111
+ }
112
+ const StarBand = /*#__PURE__*/(0, _react.memo)(function StarBand({
113
+ index,
114
+ width,
115
+ height,
116
+ animated
117
+ }) {
118
+ const band = BANDS[index];
119
+ const table = BAND_TABLES[index];
120
+ // One full width of travel takes z / DRIFT seconds — nearer (smaller z) is
121
+ // faster, which is the whole parallax effect.
122
+ const drift = (0, _primitives.useLoop)(band.z / DRIFT * 1000, animated);
123
+ const translateX = drift.interpolate({
124
+ inputRange: [0, 1],
125
+ outputRange: [0, -width]
126
+ });
127
+ const dots = [];
128
+ for (let i = 0; i < band.count; i++) {
129
+ const x = table.xs[i] * width;
130
+ const y = table.ys[i] * height;
131
+ // Each star is drawn twice, one width apart, so the layer tiles seamlessly
132
+ // when the loop snaps back to 0.
133
+ for (let copy = 0; copy < 2; copy++) {
134
+ const cx = x + copy * width;
135
+ const key = `${i}-${copy}`;
136
+ if (band.halo > 0) {
137
+ dots.push(...haloDiscs(cx, y, band.dia, band.halo, band.color, key));
138
+ }
139
+ dots.push(/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
140
+ style: {
141
+ position: "absolute",
142
+ left: cx - band.dia / 2,
143
+ top: y - band.dia / 2,
144
+ width: band.dia,
145
+ height: band.dia,
146
+ borderRadius: band.dia / 2,
147
+ backgroundColor: (0, _rng.withAlpha)(band.color, band.alpha)
148
+ }
149
+ }, key));
150
+ }
151
+ }
152
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
153
+ style: [{
154
+ position: "absolute",
155
+ left: 0,
156
+ top: 0,
157
+ width: width * 2,
158
+ height
159
+ }, {
160
+ transform: [{
161
+ translateX
162
+ }]
163
+ }],
164
+ pointerEvents: "none",
165
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.RasterLayer, {
166
+ style: {
167
+ width: width * 2,
168
+ height
169
+ },
170
+ children: dots
171
+ })
172
+ });
173
+ });
174
+ const Starfield = exports.Starfield = /*#__PURE__*/(0, _react.memo)(function Starfield(props) {
175
+ // A single slow breath over the whole field. One node, and it's what stops
176
+ // the sky looking like a printed dot pattern now that the per-star twinkle
177
+ // from the Skia original isn't affordable.
178
+ const shimmer = (0, _primitives.usePulse)(5200, props.animated);
179
+ const opacity = shimmer.interpolate({
180
+ inputRange: [0, 1],
181
+ outputRange: [0.82, 1]
182
+ });
183
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
184
+ style: _absoluteFill.absoluteFill,
185
+ pointerEvents: "none",
186
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.Base, {
187
+ color: "#05060A"
188
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.RadialGlow, {
189
+ size: props.width * 1.6,
190
+ color: "#1E3A8A",
191
+ alpha: 0.2,
192
+ rings: 8,
193
+ falloff: 2,
194
+ style: {
195
+ position: "absolute",
196
+ left: -props.width * 0.3,
197
+ top: -props.width * 0.9
198
+ }
199
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
200
+ style: [_absoluteFill.absoluteFill, {
201
+ opacity
202
+ }],
203
+ pointerEvents: "none",
204
+ children: BANDS.map((_, i) => /*#__PURE__*/(0, _jsxRuntime.jsx)(StarBand, {
205
+ index: i,
206
+ ...props
207
+ }, i))
208
+ })]
209
+ });
210
+ });
@@ -31,9 +31,7 @@ Object.keys(_index).forEach(function (key) {
31
31
  }
32
32
  });
33
33
  });
34
- var _toolTheme = require("./toolTheme.js");
35
- var _CyberpunkSectionButton = require("./console/CyberpunkSectionButton.js");
36
- var _index2 = require("./gameUI/index.js");
34
+ var _index2 = require("./backgrounds/index.js");
37
35
  Object.keys(_index2).forEach(function (key) {
38
36
  if (key === "default" || key === "__esModule") return;
39
37
  if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
@@ -44,4 +42,18 @@ Object.keys(_index2).forEach(function (key) {
44
42
  return _index2[key];
45
43
  }
46
44
  });
45
+ });
46
+ var _toolTheme = require("./toolTheme.js");
47
+ var _CyberpunkSectionButton = require("./console/CyberpunkSectionButton.js");
48
+ var _index3 = require("./gameUI/index.js");
49
+ Object.keys(_index3).forEach(function (key) {
50
+ if (key === "default" || key === "__esModule") return;
51
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
52
+ if (key in exports && exports[key] === _index3[key]) return;
53
+ Object.defineProperty(exports, key, {
54
+ enumerable: true,
55
+ get: function () {
56
+ return _index3[key];
57
+ }
58
+ });
47
59
  });
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getDevServerOrigin = getDevServerOrigin;
7
+ /**
8
+ * devServer
9
+ *
10
+ * Origin of the Metro/Expo dev server that served this bundle, e.g.
11
+ * `http://192.168.1.20:8081`.
12
+ *
13
+ * Why a remote driver wants it: reloading the app normally runs IN the app
14
+ * (`DevSettings.reload()`), which is exactly what stops working when the app
15
+ * has crashed — a fatal render error unmounts the tree, so no JS action can be
16
+ * answered and the one command that would recover the app is unreachable. The
17
+ * dev server's message socket reloads through the NATIVE side instead (it is
18
+ * what the `r` key and the redbox's Reload button use), so a driver that knows
19
+ * this origin can recover an app that can no longer help itself.
20
+ *
21
+ * Reported once, while the app is healthy, so it is already known by the time
22
+ * it's needed.
23
+ */
24
+
25
+ const ORIGIN_RE = /^(https?:\/\/[^/]+)/;
26
+
27
+ /** Bundle URL this JS realm was loaded from, or null off React Native. */
28
+ function scriptURL() {
29
+ try {
30
+ // Requires stay lexically inside try{} so Metro treats them as optional —
31
+ // react-native-web has neither path and falls through to null.
32
+ const NativeSourceCode =
33
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
34
+ require("react-native/Libraries/NativeModules/specs/NativeSourceCode").default;
35
+ const url = NativeSourceCode?.getConstants?.().scriptURL;
36
+ if (url) return url;
37
+ } catch {
38
+ // RN internals moved, or old architecture — try NativeModules below.
39
+ }
40
+ try {
41
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
42
+ const {
43
+ NativeModules
44
+ } = require("react-native");
45
+ const url = NativeModules?.SourceCode?.getConstants?.().scriptURL ?? NativeModules?.SourceCode?.scriptURL;
46
+ if (url) return url;
47
+ } catch {
48
+ // not React Native
49
+ }
50
+ return null;
51
+ }
52
+
53
+ /**
54
+ * `http://host:port` of the dev server, or null in production / on web (a
55
+ * release bundle's scriptURL is a `file://` path, which has no origin worth
56
+ * reporting).
57
+ */
58
+ function getDevServerOrigin() {
59
+ const url = scriptURL();
60
+ if (!url || !/^https?:\/\//.test(url)) return null;
61
+ return url.match(ORIGIN_RE)?.[1] ?? null;
62
+ }
@@ -57,6 +57,12 @@ Object.defineProperty(exports, "getConstructorName", {
57
57
  return _typeHelpers.getConstructorName;
58
58
  }
59
59
  });
60
+ Object.defineProperty(exports, "getDevServerOrigin", {
61
+ enumerable: true,
62
+ get: function () {
63
+ return _devServer.getDevServerOrigin;
64
+ }
65
+ });
60
66
  Object.defineProperty(exports, "getRenderCaptureProvider", {
61
67
  enumerable: true,
62
68
  get: function () {
@@ -75,6 +81,12 @@ Object.defineProperty(exports, "getSafeCurrentPathname", {
75
81
  return _safeExpoRouter.getSafeCurrentPathname;
76
82
  }
77
83
  });
84
+ Object.defineProperty(exports, "getSafeCurrentRoute", {
85
+ enumerable: true,
86
+ get: function () {
87
+ return _safeExpoRouter.getSafeCurrentRoute;
88
+ }
89
+ });
78
90
  Object.defineProperty(exports, "getSafeRouter", {
79
91
  enumerable: true,
80
92
  get: function () {
@@ -291,6 +303,7 @@ var _renderCaptureRegistry = require("./renderCaptureRegistry.js");
291
303
  var _stateSnapshotRegistry = require("./stateSnapshotRegistry.js");
292
304
  var _minimalSuperJSON = require("./minimalSuperJSON.js");
293
305
  var _reloadApp = require("./reloadApp.js");
306
+ var _devServer = require("./devServer.js");
294
307
  var _subscribable = require("./subscribable.js");
295
308
  var _subscriberCountNotifier = require("./subscriberCountNotifier.js");
296
309
  var _safeExpoRouter = require("./safeExpoRouter.js");
@@ -15,16 +15,45 @@ exports.setRenderCaptureProvider = setRenderCaptureProvider;
15
15
  * `installReaFpsGetter`.
16
16
  */
17
17
 
18
+ /**
19
+ * Why a component rendered, counted across a capture window.
20
+ *
21
+ * The split between `props` and `propsUnstable` is the one that matters in
22
+ * practice. Both mean "my props changed", but they send you to different
23
+ * files: `props` is a genuine update (a value differs) and belongs to the
24
+ * component; `propsUnstable` means the values are equal and only the
25
+ * IDENTITY changed — a fresh arrow or object literal handed down by the
26
+ * parent every render — and the fix is always upstream. Reporting that as
27
+ * plain "props" is technically true and sends people into the wrong file,
28
+ * which is why it gets its own bucket.
29
+ */
30
+
18
31
  /** One component's aggregated renders across a capture window. */
19
32
 
20
33
  /** Result of a capture window (one benchmark recording). */
21
34
 
22
- let provider = null;
35
+ /**
36
+ * The provider lives on a global, NOT in module scope.
37
+ *
38
+ * Package managers routinely give each @buoy-gg/* package its own nested copy
39
+ * of shared-ui — observed in the wild with ten identical 7.0.21 copies and
40
+ * nothing hoisted, simply because shared-ui was nobody's direct dependency.
41
+ * Module-scoped state means highlight-updates registers into its copy and
42
+ * perf-monitor reads a different one, so capture silently produces nothing:
43
+ * no error, no warning, just `renderCommits: null` in every report.
44
+ *
45
+ * A global key survives duplicate module instances. Same reasoning as
46
+ * external-sync's crash-flush registry.
47
+ */
48
+ const PROVIDER_KEY = "__buoyRenderCaptureProvider";
49
+ function providerHost() {
50
+ return globalThis;
51
+ }
23
52
 
24
53
  /** Register (or clear with null) the active provider. Last registration wins. */
25
54
  function setRenderCaptureProvider(p) {
26
- provider = p;
55
+ providerHost()[PROVIDER_KEY] = p;
27
56
  }
28
57
  function getRenderCaptureProvider() {
29
- return provider;
58
+ return providerHost()[PROVIDER_KEY] ?? null;
30
59
  }
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.getSafeCurrentPathname = getSafeCurrentPathname;
7
+ exports.getSafeCurrentRoute = getSafeCurrentRoute;
7
8
  exports.getSafeRouter = getSafeRouter;
8
9
  exports.isExpoRouterAvailable = isExpoRouterAvailable;
9
10
  exports.useSafeGlobalSearchParams = useSafeGlobalSearchParams;
@@ -184,6 +185,7 @@ function getSafeRouter() {
184
185
  // path the require throws and the imperative fallback simply disables (callers
185
186
  // degrade to route-events history). expo-router's store exposes getRouteInfo(),
186
187
  // which returns the live pathname even before any navigation is recorded.
188
+
187
189
  let routerStore;
188
190
  function getRouterStore() {
189
191
  if (routerStore !== undefined) return routerStore;
@@ -205,12 +207,35 @@ function getRouterStore() {
205
207
  * can't be reached.
206
208
  */
207
209
  function getSafeCurrentPathname() {
210
+ return getSafeCurrentRoute()?.pathname ?? null;
211
+ }
212
+
213
+ /** A route location that can be re-visited later via {@link getSafeRouter}. */
214
+
215
+ /**
216
+ * The current route as a re-visitable location, read imperatively from
217
+ * expo-router's store.
218
+ *
219
+ * Like {@link getSafeCurrentPathname} this works before any navigation has
220
+ * been recorded (cold start on the initial route), and returns null when
221
+ * expo-router isn't available or the store can't be reached.
222
+ */
223
+ function getSafeCurrentRoute() {
208
224
  if (!checkExpoRouterAvailability()) {
209
225
  return null;
210
226
  }
211
227
  try {
212
- const pathname = getRouterStore()?.getRouteInfo?.()?.pathname;
213
- return typeof pathname === "string" && pathname.length > 0 ? pathname : null;
228
+ const info = getRouterStore()?.getRouteInfo?.();
229
+ const pathname = info?.pathname;
230
+ if (typeof pathname !== "string" || pathname.length === 0) return null;
231
+ const withParams = info?.pathnameWithParams;
232
+ return {
233
+ pathname,
234
+ href: typeof withParams === "string" && withParams.length > 0 ? withParams : pathname,
235
+ ...(Array.isArray(info?.segments) ? {
236
+ segments: info.segments
237
+ } : {})
238
+ };
214
239
  } catch (error) {
215
240
  return null;
216
241
  }
@@ -693,6 +693,14 @@ const JsModalComponent = ({
693
693
  } else {
694
694
  // Floating mode entrance - simple fade without scale pop
695
695
  floatingScale.setValue(1); // Set scale to 1 directly, no animation
696
+ // Minimizing animated the window to the dock icon's corner. Put it
697
+ // back where it actually lives, or reopening leaves it parked
698
+ // off-screen — `initialModalState` only covers the dock's restore
699
+ // path, and the dial opens the same tool without one.
700
+ floatingPosition.setValue({
701
+ x: currentDimensionsRef.current.left,
702
+ y: currentDimensionsRef.current.top
703
+ });
696
704
  openAnimation = Animated.timing(visibilityProgress, {
697
705
  toValue: 1,
698
706
  duration: 200,
@@ -741,7 +749,7 @@ const JsModalComponent = ({
741
749
  // Stopped close animation
742
750
  }
743
751
  };
744
- }, [visible, mode, visibilityProgress, bottomSheetTranslateY, floatingScale, externalAnimatedHeight]); // Removed initialHeight to prevent animation restarts on height changes
752
+ }, [visible, mode, visibilityProgress, bottomSheetTranslateY, floatingScale, floatingPosition, externalAnimatedHeight]); // Removed initialHeight to prevent animation restarts on height changes
745
753
 
746
754
  // ============================================================================
747
755
  // OPTIMIZED PAN RESPONDER: Bottom Sheet Resize
@@ -1111,22 +1119,18 @@ const JsModalComponent = ({
1111
1119
  // RENDER: Modal UI with transform-based animations
1112
1120
  // ============================================================================
1113
1121
 
1114
- // When not visible, render off-screen to keep children mounted (preserves state/listeners)
1115
- // This is similar to how React Navigation keeps screens mounted
1116
- if (!visible) {
1117
- return /*#__PURE__*/_jsx(View, {
1118
- style: styles.hiddenContainer,
1119
- pointerEvents: "none",
1120
- accessibilityElementsHidden: true,
1121
- importantForAccessibility: "no-hide-descendants",
1122
- children: children
1123
- });
1124
- }
1122
+ // When not visible the SAME tree is rendered, just parked off-screen. It has
1123
+ // to be the same tree: React reconciles by position, so a separate "hidden"
1124
+ // branch would unmount and rebuild every child on each minimize AND each
1125
+ // restore — which is the whole cost minimizing is supposed to avoid.
1125
1126
 
1126
1127
  // Render floating mode
1127
1128
  if (mode === "floating") {
1128
1129
  return /*#__PURE__*/_jsxs(Animated.View, {
1129
1130
  nativeID: "jsmodal-root",
1131
+ pointerEvents: visible ? "auto" : "none",
1132
+ accessibilityElementsHidden: !visible,
1133
+ importantForAccessibility: visible ? "auto" : "no-hide-descendants",
1130
1134
  style: [styles.floatingModal, {
1131
1135
  width: dimensions.width,
1132
1136
  // Use state dimensions for real-time updates
@@ -1140,7 +1144,7 @@ const JsModalComponent = ({
1140
1144
  ...(zIndex !== undefined && {
1141
1145
  zIndex
1142
1146
  })
1143
- }, (isDragging || isResizing) && styles.floatingModalDragging, customStyles.container],
1147
+ }, (isDragging || isResizing) && styles.floatingModalDragging, customStyles.container, !visible && styles.parkedOffscreen],
1144
1148
  children: [/*#__PURE__*/_jsx(DraggableHeader, {
1145
1149
  position: floatingPosition,
1146
1150
  onDragStart: handleFloatingDragStart,
@@ -1237,10 +1241,16 @@ const JsModalComponent = ({
1237
1241
 
1238
1242
  // Render bottom sheet mode with proper height animation
1239
1243
  return /*#__PURE__*/_jsx(View, {
1240
- style: [styles.fullScreenContainer, zIndex !== undefined && {
1244
+ style: [
1245
+ // Same box either way — parking it off-screen instead of resizing it
1246
+ // keeps the sheet's layout intact, so coming back is a translate and
1247
+ // not a full relayout.
1248
+ visible ? styles.fullScreenContainer : styles.parkedFullScreen, visible && zIndex !== undefined && {
1241
1249
  zIndex
1242
1250
  }],
1243
- pointerEvents: "box-none",
1251
+ pointerEvents: visible ? "box-none" : "none",
1252
+ accessibilityElementsHidden: !visible,
1253
+ importantForAccessibility: visible ? "auto" : "no-hide-descendants",
1244
1254
  children: /*#__PURE__*/_jsx(Animated.View, {
1245
1255
  nativeID: "jsmodal-root",
1246
1256
  style: [styles.bottomSheetWrapper, {
@@ -1336,10 +1346,23 @@ const styles = StyleSheet.create({
1336
1346
  shadowRadius: 12,
1337
1347
  elevation: 20
1338
1348
  },
1339
- hiddenContainer: {
1349
+ /** Off-screen park for a minimized floating modal — same box, moved away. */
1350
+ parkedOffscreen: {
1351
+ left: -9999,
1352
+ top: -9999,
1353
+ opacity: 0
1354
+ },
1355
+ /**
1356
+ * Off-screen park for a minimized bottom sheet. Screen-sized on purpose:
1357
+ * `fullScreenContainer` is an absolute fill, and shrinking it here would
1358
+ * relayout the whole sheet on every minimize/restore.
1359
+ */
1360
+ parkedFullScreen: {
1340
1361
  position: "absolute",
1341
1362
  left: -9999,
1342
1363
  top: -9999,
1364
+ width: SCREEN.width,
1365
+ height: SCREEN.height,
1343
1366
  opacity: 0
1344
1367
  },
1345
1368
  floatingModal: {
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Says out loud that the diff below is showing a decoded value.
5
+ *
6
+ * Not decoration: the store holds a STRING, and the rows underneath show an
7
+ * object or an array. Without this line the viewer would be misreporting the
8
+ * type of what is stored — see jsonStringValue.ts.
9
+ */
10
+ import { memo } from "react";
11
+ import { View, Text, StyleSheet } from "react-native";
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ export const JsonStringNotice = /*#__PURE__*/memo(function JsonStringNotice({
14
+ visible,
15
+ theme
16
+ }) {
17
+ if (!visible) return null;
18
+ return /*#__PURE__*/_jsxs(View, {
19
+ style: [styles.container, {
20
+ backgroundColor: theme.summaryBackground,
21
+ borderTopColor: theme.borderColor
22
+ }],
23
+ children: [/*#__PURE__*/_jsx(Text, {
24
+ style: [styles.glyph, {
25
+ color: theme.lineNumberText
26
+ }],
27
+ children: "{ }"
28
+ }), /*#__PURE__*/_jsx(Text, {
29
+ style: [styles.text, {
30
+ color: theme.lineNumberText
31
+ }],
32
+ children: "Stored as a JSON string \u2014 decoded below so the change is readable."
33
+ })]
34
+ });
35
+ });
36
+ const styles = StyleSheet.create({
37
+ container: {
38
+ flexDirection: "row",
39
+ alignItems: "center",
40
+ gap: 7,
41
+ borderTopWidth: StyleSheet.hairlineWidth,
42
+ paddingHorizontal: 10,
43
+ paddingVertical: 6
44
+ },
45
+ glyph: {
46
+ fontSize: 11,
47
+ fontWeight: "700"
48
+ },
49
+ text: {
50
+ flex: 1,
51
+ fontSize: 11,
52
+ lineHeight: 14
53
+ }
54
+ });
@@ -14,6 +14,10 @@ import { Fragment, memo, useCallback, useEffect, useMemo, useRef, useState } fro
14
14
  import { View, Text, FlatList, StyleSheet, TouchableOpacity } from "react-native";
15
15
  import { computeLineDiff, DiffType } from "./lineDiff.js";
16
16
  import { DiffSummary } from "./DiffSummary.js";
17
+ import { TimestampDeltaBar } from "./TimestampDeltaBar.js";
18
+ import { describeTimestampDeltas } from "./timestampDiff.js";
19
+ import { JsonStringNotice } from "./JsonStringNotice.js";
20
+ import { decodeJsonStringPair } from "./jsonStringValue.js";
17
21
 
18
22
  /** Rendering options (the shape storage's DiffOptionsPanel edits). */
19
23
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -42,7 +46,12 @@ export function ThemedSplitView({
42
46
  showDiffOnly: options.showDiffOnly,
43
47
  contextLines: options.contextLines
44
48
  }), [options.compareMethod, options.disableWordDiff, options.showDiffOnly, options.contextLines]);
45
- const lineDiffs = useMemo(() => computeLineDiff(oldValue, newValue, diffComputeOptions), [oldValue, newValue, diffComputeOptions]);
49
+
50
+ // A JSON-encoded string is diffed decoded, or its one real change reads as
51
+ // one unreadable escaped line. Everything downstream — the line diff, the
52
+ // timestamp scan — works off the decoded pair.
53
+ const pair = useMemo(() => decodeJsonStringPair(oldValue, newValue), [oldValue, newValue]);
54
+ const lineDiffs = useMemo(() => computeLineDiff(pair.left, pair.right, diffComputeOptions), [pair, diffComputeOptions]);
46
55
 
47
56
  // One pass for the summary instead of three .filter() calls per render.
48
57
  const summary = useMemo(() => {
@@ -59,6 +68,10 @@ export function ThemedSplitView({
59
68
  };
60
69
  }, [lineDiffs]);
61
70
 
71
+ // Detection walks at most one object level, but it runs on every render of
72
+ // a diff that may hold thousands of lines — keep it on the value identities.
73
+ const timestampDeltas = useMemo(() => describeTimestampDeltas(pair.left, pair.right), [pair]);
74
+
62
75
  // Auto-collapse runs of unchanged lines that aren't near a change. Keeps
63
76
  // CONTEXT_LINES on either side of every change visible (GitHub-style), folds
64
77
  // the rest into a tappable header.
@@ -147,6 +160,12 @@ export function ThemedSplitView({
147
160
  removed: summary.removed,
148
161
  modified: summary.modified,
149
162
  theme: theme
163
+ }), /*#__PURE__*/_jsx(JsonStringNotice, {
164
+ visible: pair.decoded,
165
+ theme: theme
166
+ }), /*#__PURE__*/_jsx(TimestampDeltaBar, {
167
+ deltas: timestampDeltas,
168
+ theme: theme
150
169
  }), lineDiffs.length === 0 ? /*#__PURE__*/_jsx(View, {
151
170
  style: dynamicStyles.emptyState,
152
171
  children: /*#__PURE__*/_jsx(Text, {