@buoy-gg/shared-ui 7.0.22 → 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 (154) 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 +50 -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/module/JsModal.js +39 -16
  29. package/lib/module/dataViewer/JsonStringNotice.js +54 -0
  30. package/lib/module/dataViewer/ThemedSplitView.js +20 -1
  31. package/lib/module/dataViewer/TimestampDeltaBar.js +91 -0
  32. package/lib/module/dataViewer/index.js +4 -0
  33. package/lib/module/dataViewer/jsonStringValue.js +89 -0
  34. package/lib/module/dataViewer/timestampDiff.js +139 -0
  35. package/lib/module/hooks/safe-area-impl.js +1 -1
  36. package/lib/module/index.js +1 -1
  37. package/lib/module/license/FeatureGate.js +43 -10
  38. package/lib/module/license/FreeAccountPrompt.js +176 -0
  39. package/lib/module/license/index.js +5 -40
  40. package/lib/module/license/licenseModule.js +92 -0
  41. package/lib/module/license/tierLimits.js +158 -0
  42. package/lib/module/ui/backgrounds/BackgroundSwitcher.js +176 -0
  43. package/lib/module/ui/backgrounds/README.md +115 -0
  44. package/lib/module/ui/backgrounds/ToolBackground.js +70 -0
  45. package/lib/module/ui/backgrounds/backgroundStore.js +111 -0
  46. package/lib/module/ui/backgrounds/index.js +9 -0
  47. package/lib/module/ui/backgrounds/primitives.js +328 -0
  48. package/lib/module/ui/backgrounds/registry.js +105 -0
  49. package/lib/module/ui/backgrounds/rng.js +65 -0
  50. package/lib/module/ui/backgrounds/types.js +1 -0
  51. package/lib/module/ui/backgrounds/variants/deepField.js +347 -0
  52. package/lib/module/ui/backgrounds/variants/lattice.js +575 -0
  53. package/lib/module/ui/backgrounds/variants/starfield.js +206 -0
  54. package/lib/module/ui/index.js +3 -0
  55. package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/dataViewer/JsonStringNotice.d.ts +6 -0
  57. package/lib/typescript/commonjs/dataViewer/JsonStringNotice.d.ts.map +1 -0
  58. package/lib/typescript/commonjs/dataViewer/ThemedSplitView.d.ts.map +1 -1
  59. package/lib/typescript/commonjs/dataViewer/TimestampDeltaBar.d.ts +7 -0
  60. package/lib/typescript/commonjs/dataViewer/TimestampDeltaBar.d.ts.map +1 -0
  61. package/lib/typescript/commonjs/dataViewer/index.d.ts +6 -0
  62. package/lib/typescript/commonjs/dataViewer/index.d.ts.map +1 -1
  63. package/lib/typescript/commonjs/dataViewer/jsonStringValue.d.ts +25 -0
  64. package/lib/typescript/commonjs/dataViewer/jsonStringValue.d.ts.map +1 -0
  65. package/lib/typescript/commonjs/dataViewer/timestampDiff.d.ts +55 -0
  66. package/lib/typescript/commonjs/dataViewer/timestampDiff.d.ts.map +1 -0
  67. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  68. package/lib/typescript/commonjs/index.d.ts +2 -2
  69. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/license/FeatureGate.d.ts +19 -3
  71. package/lib/typescript/commonjs/license/FeatureGate.d.ts.map +1 -1
  72. package/lib/typescript/commonjs/license/FreeAccountPrompt.d.ts +23 -0
  73. package/lib/typescript/commonjs/license/FreeAccountPrompt.d.ts.map +1 -0
  74. package/lib/typescript/commonjs/license/index.d.ts +6 -15
  75. package/lib/typescript/commonjs/license/index.d.ts.map +1 -1
  76. package/lib/typescript/commonjs/license/licenseModule.d.ts +55 -0
  77. package/lib/typescript/commonjs/license/licenseModule.d.ts.map +1 -0
  78. package/lib/typescript/commonjs/license/tierLimits.d.ts +143 -0
  79. package/lib/typescript/commonjs/license/tierLimits.d.ts.map +1 -0
  80. package/lib/typescript/commonjs/ui/backgrounds/BackgroundSwitcher.d.ts +13 -0
  81. package/lib/typescript/commonjs/ui/backgrounds/BackgroundSwitcher.d.ts.map +1 -0
  82. package/lib/typescript/commonjs/ui/backgrounds/ToolBackground.d.ts +30 -0
  83. package/lib/typescript/commonjs/ui/backgrounds/ToolBackground.d.ts.map +1 -0
  84. package/lib/typescript/commonjs/ui/backgrounds/backgroundStore.d.ts +43 -0
  85. package/lib/typescript/commonjs/ui/backgrounds/backgroundStore.d.ts.map +1 -0
  86. package/lib/typescript/commonjs/ui/backgrounds/index.d.ts +7 -0
  87. package/lib/typescript/commonjs/ui/backgrounds/index.d.ts.map +1 -0
  88. package/lib/typescript/commonjs/ui/backgrounds/primitives.d.ts +106 -0
  89. package/lib/typescript/commonjs/ui/backgrounds/primitives.d.ts.map +1 -0
  90. package/lib/typescript/commonjs/ui/backgrounds/registry.d.ts +28 -0
  91. package/lib/typescript/commonjs/ui/backgrounds/registry.d.ts.map +1 -0
  92. package/lib/typescript/commonjs/ui/backgrounds/rng.d.ts +27 -0
  93. package/lib/typescript/commonjs/ui/backgrounds/rng.d.ts.map +1 -0
  94. package/lib/typescript/commonjs/ui/backgrounds/types.d.ts +14 -0
  95. package/lib/typescript/commonjs/ui/backgrounds/types.d.ts.map +1 -0
  96. package/lib/typescript/commonjs/ui/backgrounds/variants/deepField.d.ts +65 -0
  97. package/lib/typescript/commonjs/ui/backgrounds/variants/deepField.d.ts.map +1 -0
  98. package/lib/typescript/commonjs/ui/backgrounds/variants/lattice.d.ts +33 -0
  99. package/lib/typescript/commonjs/ui/backgrounds/variants/lattice.d.ts.map +1 -0
  100. package/lib/typescript/commonjs/ui/backgrounds/variants/starfield.d.ts +12 -0
  101. package/lib/typescript/commonjs/ui/backgrounds/variants/starfield.d.ts.map +1 -0
  102. package/lib/typescript/commonjs/ui/index.d.ts +1 -0
  103. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  104. package/lib/typescript/module/JsModal.d.ts.map +1 -1
  105. package/lib/typescript/module/dataViewer/JsonStringNotice.d.ts +6 -0
  106. package/lib/typescript/module/dataViewer/JsonStringNotice.d.ts.map +1 -0
  107. package/lib/typescript/module/dataViewer/ThemedSplitView.d.ts.map +1 -1
  108. package/lib/typescript/module/dataViewer/TimestampDeltaBar.d.ts +7 -0
  109. package/lib/typescript/module/dataViewer/TimestampDeltaBar.d.ts.map +1 -0
  110. package/lib/typescript/module/dataViewer/index.d.ts +6 -0
  111. package/lib/typescript/module/dataViewer/index.d.ts.map +1 -1
  112. package/lib/typescript/module/dataViewer/jsonStringValue.d.ts +25 -0
  113. package/lib/typescript/module/dataViewer/jsonStringValue.d.ts.map +1 -0
  114. package/lib/typescript/module/dataViewer/timestampDiff.d.ts +55 -0
  115. package/lib/typescript/module/dataViewer/timestampDiff.d.ts.map +1 -0
  116. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  117. package/lib/typescript/module/index.d.ts +2 -2
  118. package/lib/typescript/module/index.d.ts.map +1 -1
  119. package/lib/typescript/module/license/FeatureGate.d.ts +19 -3
  120. package/lib/typescript/module/license/FeatureGate.d.ts.map +1 -1
  121. package/lib/typescript/module/license/FreeAccountPrompt.d.ts +23 -0
  122. package/lib/typescript/module/license/FreeAccountPrompt.d.ts.map +1 -0
  123. package/lib/typescript/module/license/index.d.ts +6 -15
  124. package/lib/typescript/module/license/index.d.ts.map +1 -1
  125. package/lib/typescript/module/license/licenseModule.d.ts +55 -0
  126. package/lib/typescript/module/license/licenseModule.d.ts.map +1 -0
  127. package/lib/typescript/module/license/tierLimits.d.ts +143 -0
  128. package/lib/typescript/module/license/tierLimits.d.ts.map +1 -0
  129. package/lib/typescript/module/ui/backgrounds/BackgroundSwitcher.d.ts +13 -0
  130. package/lib/typescript/module/ui/backgrounds/BackgroundSwitcher.d.ts.map +1 -0
  131. package/lib/typescript/module/ui/backgrounds/ToolBackground.d.ts +30 -0
  132. package/lib/typescript/module/ui/backgrounds/ToolBackground.d.ts.map +1 -0
  133. package/lib/typescript/module/ui/backgrounds/backgroundStore.d.ts +43 -0
  134. package/lib/typescript/module/ui/backgrounds/backgroundStore.d.ts.map +1 -0
  135. package/lib/typescript/module/ui/backgrounds/index.d.ts +7 -0
  136. package/lib/typescript/module/ui/backgrounds/index.d.ts.map +1 -0
  137. package/lib/typescript/module/ui/backgrounds/primitives.d.ts +106 -0
  138. package/lib/typescript/module/ui/backgrounds/primitives.d.ts.map +1 -0
  139. package/lib/typescript/module/ui/backgrounds/registry.d.ts +28 -0
  140. package/lib/typescript/module/ui/backgrounds/registry.d.ts.map +1 -0
  141. package/lib/typescript/module/ui/backgrounds/rng.d.ts +27 -0
  142. package/lib/typescript/module/ui/backgrounds/rng.d.ts.map +1 -0
  143. package/lib/typescript/module/ui/backgrounds/types.d.ts +14 -0
  144. package/lib/typescript/module/ui/backgrounds/types.d.ts.map +1 -0
  145. package/lib/typescript/module/ui/backgrounds/variants/deepField.d.ts +65 -0
  146. package/lib/typescript/module/ui/backgrounds/variants/deepField.d.ts.map +1 -0
  147. package/lib/typescript/module/ui/backgrounds/variants/lattice.d.ts +33 -0
  148. package/lib/typescript/module/ui/backgrounds/variants/lattice.d.ts.map +1 -0
  149. package/lib/typescript/module/ui/backgrounds/variants/starfield.d.ts +12 -0
  150. package/lib/typescript/module/ui/backgrounds/variants/starfield.d.ts.map +1 -0
  151. package/lib/typescript/module/ui/index.d.ts +1 -0
  152. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  153. package/package.json +4 -4
  154. package/scripts/detect-safe-area.js +0 -20
@@ -697,6 +697,14 @@ const JsModalComponent = ({
697
697
  } else {
698
698
  // Floating mode entrance - simple fade without scale pop
699
699
  floatingScale.setValue(1); // Set scale to 1 directly, no animation
700
+ // Minimizing animated the window to the dock icon's corner. Put it
701
+ // back where it actually lives, or reopening leaves it parked
702
+ // off-screen — `initialModalState` only covers the dock's restore
703
+ // path, and the dial opens the same tool without one.
704
+ floatingPosition.setValue({
705
+ x: currentDimensionsRef.current.left,
706
+ y: currentDimensionsRef.current.top
707
+ });
700
708
  openAnimation = _reactNative.Animated.timing(visibilityProgress, {
701
709
  toValue: 1,
702
710
  duration: 200,
@@ -745,7 +753,7 @@ const JsModalComponent = ({
745
753
  // Stopped close animation
746
754
  }
747
755
  };
748
- }, [visible, mode, visibilityProgress, bottomSheetTranslateY, floatingScale, externalAnimatedHeight]); // Removed initialHeight to prevent animation restarts on height changes
756
+ }, [visible, mode, visibilityProgress, bottomSheetTranslateY, floatingScale, floatingPosition, externalAnimatedHeight]); // Removed initialHeight to prevent animation restarts on height changes
749
757
 
750
758
  // ============================================================================
751
759
  // OPTIMIZED PAN RESPONDER: Bottom Sheet Resize
@@ -1115,22 +1123,18 @@ const JsModalComponent = ({
1115
1123
  // RENDER: Modal UI with transform-based animations
1116
1124
  // ============================================================================
1117
1125
 
1118
- // When not visible, render off-screen to keep children mounted (preserves state/listeners)
1119
- // This is similar to how React Navigation keeps screens mounted
1120
- if (!visible) {
1121
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1122
- style: styles.hiddenContainer,
1123
- pointerEvents: "none",
1124
- accessibilityElementsHidden: true,
1125
- importantForAccessibility: "no-hide-descendants",
1126
- children: children
1127
- });
1128
- }
1126
+ // When not visible the SAME tree is rendered, just parked off-screen. It has
1127
+ // to be the same tree: React reconciles by position, so a separate "hidden"
1128
+ // branch would unmount and rebuild every child on each minimize AND each
1129
+ // restore — which is the whole cost minimizing is supposed to avoid.
1129
1130
 
1130
1131
  // Render floating mode
1131
1132
  if (mode === "floating") {
1132
1133
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, {
1133
1134
  nativeID: "jsmodal-root",
1135
+ pointerEvents: visible ? "auto" : "none",
1136
+ accessibilityElementsHidden: !visible,
1137
+ importantForAccessibility: visible ? "auto" : "no-hide-descendants",
1134
1138
  style: [styles.floatingModal, {
1135
1139
  width: dimensions.width,
1136
1140
  // Use state dimensions for real-time updates
@@ -1144,7 +1148,7 @@ const JsModalComponent = ({
1144
1148
  ...(zIndex !== undefined && {
1145
1149
  zIndex
1146
1150
  })
1147
- }, (isDragging || isResizing) && styles.floatingModalDragging, customStyles.container],
1151
+ }, (isDragging || isResizing) && styles.floatingModalDragging, customStyles.container, !visible && styles.parkedOffscreen],
1148
1152
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.DraggableHeader, {
1149
1153
  position: floatingPosition,
1150
1154
  onDragStart: handleFloatingDragStart,
@@ -1241,10 +1245,16 @@ const JsModalComponent = ({
1241
1245
 
1242
1246
  // Render bottom sheet mode with proper height animation
1243
1247
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
1244
- style: [styles.fullScreenContainer, zIndex !== undefined && {
1248
+ style: [
1249
+ // Same box either way — parking it off-screen instead of resizing it
1250
+ // keeps the sheet's layout intact, so coming back is a translate and
1251
+ // not a full relayout.
1252
+ visible ? styles.fullScreenContainer : styles.parkedFullScreen, visible && zIndex !== undefined && {
1245
1253
  zIndex
1246
1254
  }],
1247
- pointerEvents: "box-none",
1255
+ pointerEvents: visible ? "box-none" : "none",
1256
+ accessibilityElementsHidden: !visible,
1257
+ importantForAccessibility: visible ? "auto" : "no-hide-descendants",
1248
1258
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
1249
1259
  nativeID: "jsmodal-root",
1250
1260
  style: [styles.bottomSheetWrapper, {
@@ -1340,10 +1350,23 @@ const styles = _reactNative.StyleSheet.create({
1340
1350
  shadowRadius: 12,
1341
1351
  elevation: 20
1342
1352
  },
1343
- hiddenContainer: {
1353
+ /** Off-screen park for a minimized floating modal — same box, moved away. */
1354
+ parkedOffscreen: {
1355
+ left: -9999,
1356
+ top: -9999,
1357
+ opacity: 0
1358
+ },
1359
+ /**
1360
+ * Off-screen park for a minimized bottom sheet. Screen-sized on purpose:
1361
+ * `fullScreenContainer` is an absolute fill, and shrinking it here would
1362
+ * relayout the whole sheet on every minimize/restore.
1363
+ */
1364
+ parkedFullScreen: {
1344
1365
  position: "absolute",
1345
1366
  left: -9999,
1346
1367
  top: -9999,
1368
+ width: SCREEN.width,
1369
+ height: SCREEN.height,
1347
1370
  opacity: 0
1348
1371
  },
1349
1372
  floatingModal: {
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.JsonStringNotice = void 0;
7
+ var _react = require("react");
8
+ var _reactNative = require("react-native");
9
+ var _jsxRuntime = require("react/jsx-runtime");
10
+ /**
11
+ * Says out loud that the diff below is showing a decoded value.
12
+ *
13
+ * Not decoration: the store holds a STRING, and the rows underneath show an
14
+ * object or an array. Without this line the viewer would be misreporting the
15
+ * type of what is stored — see jsonStringValue.ts.
16
+ */
17
+
18
+ const JsonStringNotice = exports.JsonStringNotice = /*#__PURE__*/(0, _react.memo)(function JsonStringNotice({
19
+ visible,
20
+ theme
21
+ }) {
22
+ if (!visible) return null;
23
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
24
+ style: [styles.container, {
25
+ backgroundColor: theme.summaryBackground,
26
+ borderTopColor: theme.borderColor
27
+ }],
28
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
29
+ style: [styles.glyph, {
30
+ color: theme.lineNumberText
31
+ }],
32
+ children: "{ }"
33
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
34
+ style: [styles.text, {
35
+ color: theme.lineNumberText
36
+ }],
37
+ children: "Stored as a JSON string \u2014 decoded below so the change is readable."
38
+ })]
39
+ });
40
+ });
41
+ const styles = _reactNative.StyleSheet.create({
42
+ container: {
43
+ flexDirection: "row",
44
+ alignItems: "center",
45
+ gap: 7,
46
+ borderTopWidth: _reactNative.StyleSheet.hairlineWidth,
47
+ paddingHorizontal: 10,
48
+ paddingVertical: 6
49
+ },
50
+ glyph: {
51
+ fontSize: 11,
52
+ fontWeight: "700"
53
+ },
54
+ text: {
55
+ flex: 1,
56
+ fontSize: 11,
57
+ lineHeight: 14
58
+ }
59
+ });
@@ -8,6 +8,10 @@ var _react = require("react");
8
8
  var _reactNative = require("react-native");
9
9
  var _lineDiff = require("./lineDiff.js");
10
10
  var _DiffSummary = require("./DiffSummary.js");
11
+ var _TimestampDeltaBar = require("./TimestampDeltaBar.js");
12
+ var _timestampDiff = require("./timestampDiff.js");
13
+ var _JsonStringNotice = require("./JsonStringNotice.js");
14
+ var _jsonStringValue = require("./jsonStringValue.js");
11
15
  var _jsxRuntime = require("react/jsx-runtime");
12
16
  /**
13
17
  * ThemedSplitView — the production-grade split diff renderer, promoted from
@@ -47,7 +51,12 @@ function ThemedSplitView({
47
51
  showDiffOnly: options.showDiffOnly,
48
52
  contextLines: options.contextLines
49
53
  }), [options.compareMethod, options.disableWordDiff, options.showDiffOnly, options.contextLines]);
50
- const lineDiffs = (0, _react.useMemo)(() => (0, _lineDiff.computeLineDiff)(oldValue, newValue, diffComputeOptions), [oldValue, newValue, diffComputeOptions]);
54
+
55
+ // A JSON-encoded string is diffed decoded, or its one real change reads as
56
+ // one unreadable escaped line. Everything downstream — the line diff, the
57
+ // timestamp scan — works off the decoded pair.
58
+ const pair = (0, _react.useMemo)(() => (0, _jsonStringValue.decodeJsonStringPair)(oldValue, newValue), [oldValue, newValue]);
59
+ const lineDiffs = (0, _react.useMemo)(() => (0, _lineDiff.computeLineDiff)(pair.left, pair.right, diffComputeOptions), [pair, diffComputeOptions]);
51
60
 
52
61
  // One pass for the summary instead of three .filter() calls per render.
53
62
  const summary = (0, _react.useMemo)(() => {
@@ -64,6 +73,10 @@ function ThemedSplitView({
64
73
  };
65
74
  }, [lineDiffs]);
66
75
 
76
+ // Detection walks at most one object level, but it runs on every render of
77
+ // a diff that may hold thousands of lines — keep it on the value identities.
78
+ const timestampDeltas = (0, _react.useMemo)(() => (0, _timestampDiff.describeTimestampDeltas)(pair.left, pair.right), [pair]);
79
+
67
80
  // Auto-collapse runs of unchanged lines that aren't near a change. Keeps
68
81
  // CONTEXT_LINES on either side of every change visible (GitHub-style), folds
69
82
  // the rest into a tappable header.
@@ -152,6 +165,12 @@ function ThemedSplitView({
152
165
  removed: summary.removed,
153
166
  modified: summary.modified,
154
167
  theme: theme
168
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_JsonStringNotice.JsonStringNotice, {
169
+ visible: pair.decoded,
170
+ theme: theme
171
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TimestampDeltaBar.TimestampDeltaBar, {
172
+ deltas: timestampDeltas,
173
+ theme: theme
155
174
  }), lineDiffs.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
156
175
  style: dynamicStyles.emptyState,
157
176
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.TimestampDeltaBar = void 0;
7
+ var _react = require("react");
8
+ var _reactNative = require("react-native");
9
+ var _jsxRuntime = require("react/jsx-runtime");
10
+ /**
11
+ * TimestampDeltaBar — reads out the timestamp pairs in a diff.
12
+ *
13
+ * Sits under the diff summary and translates `1787085897165 → 1787012175875`
14
+ * into "20h 29m earlier", with both instants spelled out. The raw values stay
15
+ * on the rows below: this annotates the diff, it never replaces it.
16
+ *
17
+ * Renders nothing when no side of the diff is confidently a timestamp — see
18
+ * timestampDiff.ts for how narrow "confidently" is.
19
+ */
20
+
21
+ const TimestampDeltaBar = exports.TimestampDeltaBar = /*#__PURE__*/(0, _react.memo)(function TimestampDeltaBar({
22
+ deltas,
23
+ theme
24
+ }) {
25
+ if (deltas.length === 0) return null;
26
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
27
+ style: [styles.container, {
28
+ backgroundColor: theme.summaryBackground,
29
+ borderTopColor: theme.borderColor
30
+ }],
31
+ children: deltas.map(delta => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
32
+ style: styles.row,
33
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
34
+ style: [styles.glyph, {
35
+ color: theme.summaryModifiedText
36
+ }],
37
+ children: "\u25F7"
38
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
39
+ style: styles.text,
40
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
41
+ style: styles.headline,
42
+ children: [delta.path ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
43
+ style: [styles.path, {
44
+ color: theme.lineNumberText
45
+ }],
46
+ children: [delta.path, " "]
47
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
48
+ style: {
49
+ color: theme.summaryModifiedText
50
+ },
51
+ children: delta.deltaLabel
52
+ })]
53
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
54
+ style: [styles.instants, {
55
+ color: theme.lineNumberText
56
+ }],
57
+ children: [delta.fromLabel, " \u2192 ", delta.toLabel]
58
+ })]
59
+ })]
60
+ }, delta.path ?? "__value__"))
61
+ });
62
+ });
63
+ const styles = _reactNative.StyleSheet.create({
64
+ container: {
65
+ borderTopWidth: _reactNative.StyleSheet.hairlineWidth,
66
+ paddingHorizontal: 10,
67
+ paddingVertical: 7,
68
+ gap: 6
69
+ },
70
+ row: {
71
+ flexDirection: "row",
72
+ alignItems: "flex-start",
73
+ gap: 7
74
+ },
75
+ glyph: {
76
+ fontSize: 12,
77
+ lineHeight: 15
78
+ },
79
+ text: {
80
+ flex: 1,
81
+ minWidth: 0
82
+ },
83
+ headline: {
84
+ fontSize: 12,
85
+ fontWeight: "600",
86
+ lineHeight: 15
87
+ },
88
+ path: {
89
+ fontWeight: "400"
90
+ },
91
+ instants: {
92
+ fontSize: 11,
93
+ marginTop: 1,
94
+ fontVariant: ["tabular-nums"]
95
+ }
96
+ });
@@ -63,6 +63,12 @@ Object.defineProperty(exports, "IndentGuidesOverlay", {
63
63
  return _IndentGuidesOverlay.IndentGuidesOverlay;
64
64
  }
65
65
  });
66
+ Object.defineProperty(exports, "JsonStringNotice", {
67
+ enumerable: true,
68
+ get: function () {
69
+ return _JsonStringNotice.JsonStringNotice;
70
+ }
71
+ });
66
72
  Object.defineProperty(exports, "SplitDiffViewer", {
67
73
  enumerable: true,
68
74
  get: function () {
@@ -75,6 +81,12 @@ Object.defineProperty(exports, "ThemedSplitView", {
75
81
  return _ThemedSplitView.ThemedSplitView;
76
82
  }
77
83
  });
84
+ Object.defineProperty(exports, "TimestampDeltaBar", {
85
+ enumerable: true,
86
+ get: function () {
87
+ return _TimestampDeltaBar.TimestampDeltaBar;
88
+ }
89
+ });
78
90
  Object.defineProperty(exports, "TreeDiffViewer", {
79
91
  enumerable: true,
80
92
  get: function () {
@@ -117,6 +129,24 @@ Object.defineProperty(exports, "computeLineDiff", {
117
129
  return _lineDiff.computeLineDiff;
118
130
  }
119
131
  });
132
+ Object.defineProperty(exports, "decodeJsonStringPair", {
133
+ enumerable: true,
134
+ get: function () {
135
+ return _jsonStringValue.decodeJsonStringPair;
136
+ }
137
+ });
138
+ Object.defineProperty(exports, "describeTimestampDeltas", {
139
+ enumerable: true,
140
+ get: function () {
141
+ return _timestampDiff.describeTimestampDeltas;
142
+ }
143
+ });
144
+ Object.defineProperty(exports, "detectTimestamp", {
145
+ enumerable: true,
146
+ get: function () {
147
+ return _timestampDiff.detectTimestamp;
148
+ }
149
+ });
120
150
  Object.defineProperty(exports, "devToolsDefaultTheme", {
121
151
  enumerable: true,
122
152
  get: function () {
@@ -129,6 +159,18 @@ Object.defineProperty(exports, "diffThemes", {
129
159
  return _diffThemes.diffThemes;
130
160
  }
131
161
  });
162
+ Object.defineProperty(exports, "formatDuration", {
163
+ enumerable: true,
164
+ get: function () {
165
+ return _timestampDiff.formatDuration;
166
+ }
167
+ });
168
+ Object.defineProperty(exports, "formatInstant", {
169
+ enumerable: true,
170
+ get: function () {
171
+ return _timestampDiff.formatInstant;
172
+ }
173
+ });
132
174
  Object.defineProperty(exports, "getAtPath", {
133
175
  enumerable: true,
134
176
  get: function () {
@@ -165,6 +207,12 @@ Object.defineProperty(exports, "objectDiff", {
165
207
  return _objectDiff.objectDiff;
166
208
  }
167
209
  });
210
+ Object.defineProperty(exports, "parseJsonContainer", {
211
+ enumerable: true,
212
+ get: function () {
213
+ return _jsonStringValue.parseJsonContainer;
214
+ }
215
+ });
168
216
  Object.defineProperty(exports, "selectionPathAfterOp", {
169
217
  enumerable: true,
170
218
  get: function () {
@@ -214,6 +262,10 @@ var _DataTreeActionBar = require("./DataTreeActionBar.js");
214
262
  var _DataTreeActionDock = require("./DataTreeActionDock.js");
215
263
  var _SplitDiffViewer = require("./SplitDiffViewer.js");
216
264
  var _DiffSummary = require("./DiffSummary.js");
265
+ var _TimestampDeltaBar = require("./TimestampDeltaBar.js");
266
+ var _JsonStringNotice = require("./JsonStringNotice.js");
267
+ var _jsonStringValue = require("./jsonStringValue.js");
268
+ var _timestampDiff = require("./timestampDiff.js");
217
269
  var _lineDiff = require("./lineDiff.js");
218
270
  var _diffThemes = require("./diffThemes.js");
219
271
  var _objectDiff = require("./objectDiff.js");
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.decodeJsonStringPair = decodeJsonStringPair;
7
+ exports.parseJsonContainer = parseJsonContainer;
8
+ var _lineDiff = require("./lineDiff.js");
9
+ /**
10
+ * JSON-encoded string values in diffs.
11
+ *
12
+ * Every device storage backend stores STRINGS, so apps write
13
+ * `JSON.stringify(["pikachu"])` and the stored value is the six-character
14
+ * string `["pikachu"]`. Rendering that through the diff's own
15
+ * `JSON.stringify` escapes it a second time and you get `"[\"pikachu\"]"` on
16
+ * one unreadable line — and a real change (one entry added to a list of
17
+ * twenty) becomes a single modified line you can't read.
18
+ *
19
+ * So: when a side is a JSON-encoded OBJECT OR ARRAY, diff the decoded value
20
+ * and say so on screen. The label is the whole contract — the store really
21
+ * does hold a string, and a viewer that quietly showed an array without
22
+ * mentioning it would be lying about the shape of the data.
23
+ *
24
+ * Scalars are deliberately NOT decoded. Turning the stored string `"5"` into
25
+ * the number 5, or `"true"` into a boolean, changes the apparent type while
26
+ * adding no readability — the exact misrepresentation this is trying to
27
+ * avoid.
28
+ */
29
+
30
+ /**
31
+ * Parse a string that encodes a JSON object or array. Returns a wrapper so a
32
+ * successfully decoded `null`-ish payload is still distinguishable from "not
33
+ * decodable" (the prefix check makes that unreachable today, but callers
34
+ * shouldn't have to know that).
35
+ */
36
+ function parseJsonContainer(value) {
37
+ if (typeof value !== "string") return null;
38
+ const trimmed = value.trim();
39
+ // Cheap gate before JSON.parse: only containers qualify, and this keeps a
40
+ // try/catch off the path for every ordinary string in a diff.
41
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
42
+ try {
43
+ const parsed = JSON.parse(trimmed);
44
+ if (typeof parsed !== "object" || parsed === null) return null;
45
+ return {
46
+ value: parsed
47
+ };
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+ /** A side that carries no value at all — an add or a delete, not a change. */
53
+ function isMissing(value) {
54
+ return (0, _lineDiff.isAbsent)(value) || value === undefined || value === null;
55
+ }
56
+
57
+ /**
58
+ * Decode both sides of a diff when they are JSON-encoded containers.
59
+ *
60
+ * One side alone is decoded ONLY when the other side is missing entirely
61
+ * (a key being added or removed). A JSON string on one side and an ordinary
62
+ * value on the other is a change of shape, and decoding just one half would
63
+ * present it as something it isn't.
64
+ */
65
+ function decodeJsonStringPair(left, right) {
66
+ const decodedLeft = parseJsonContainer(left);
67
+ const decodedRight = parseJsonContainer(right);
68
+ if (decodedLeft && decodedRight) {
69
+ return {
70
+ left: decodedLeft.value,
71
+ right: decodedRight.value,
72
+ decoded: true
73
+ };
74
+ }
75
+ if (decodedLeft && isMissing(right)) {
76
+ return {
77
+ left: decodedLeft.value,
78
+ right,
79
+ decoded: true
80
+ };
81
+ }
82
+ if (decodedRight && isMissing(left)) {
83
+ return {
84
+ left,
85
+ right: decodedRight.value,
86
+ decoded: true
87
+ };
88
+ }
89
+ return {
90
+ left,
91
+ right,
92
+ decoded: false
93
+ };
94
+ }
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.describeTimestampDeltas = describeTimestampDeltas;
7
+ exports.detectTimestamp = detectTimestamp;
8
+ exports.formatDuration = formatDuration;
9
+ exports.formatInstant = formatInstant;
10
+ /**
11
+ * Timestamp detection for diff views.
12
+ *
13
+ * `1787085897165 → 1787012175875` is unreadable. It is also the single most
14
+ * common diff in a devtool: `lastSyncTimestamp`, `expiresAt`, `updatedAt`,
15
+ * every cache stamp. This turns that pair into "20h 29m earlier" plus both
16
+ * instants spelled out, WITHOUT hiding the raw values — a devtool that
17
+ * silently reinterprets what is stored is worse than one that says nothing.
18
+ *
19
+ * DETECTION IS DELIBERATELY NARROW, because the failure mode is confidently
20
+ * mislabelling an id or a counter as a date:
21
+ * - Epoch milliseconds only in [2001-09-09, 2100), i.e. 13 digits.
22
+ * - Epoch seconds only in the same window, i.e. 10 digits.
23
+ * The two ranges cannot overlap, so a value is never ambiguous.
24
+ * - ISO 8601 strings that both match the shape AND parse.
25
+ * - BOTH sides must be the same kind. An ISO string against an epoch number
26
+ * is a representation change, not a time delta, and reporting a gap there
27
+ * would bury the more interesting fact.
28
+ */
29
+
30
+ /** Units we recognize. A pair must agree on one of them. */
31
+
32
+ /** 2001-09-09 — below this, a 13-digit-ish number is not a plausible stamp. */
33
+ const MS_MIN = 1_000_000_000_000;
34
+ /** 2100-01-01. */
35
+ const MS_MAX = 4_102_444_800_000;
36
+ const S_MIN = 1_000_000_000;
37
+ const S_MAX = 4_102_444_800;
38
+
39
+ /** Date, or date-time with optional seconds/fraction/zone. */
40
+ const ISO_RE = /^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;
41
+ function fromNumber(n) {
42
+ if (!Number.isInteger(n)) return null;
43
+ if (n >= MS_MIN && n < MS_MAX) return {
44
+ kind: "epoch-ms",
45
+ epochMs: n
46
+ };
47
+ if (n >= S_MIN && n < S_MAX) return {
48
+ kind: "epoch-s",
49
+ epochMs: n * 1000
50
+ };
51
+ return null;
52
+ }
53
+
54
+ /**
55
+ * Read one value as an instant, or null when it isn't confidently a time.
56
+ * Numeric strings count: storage backends hand back everything as strings.
57
+ */
58
+ function detectTimestamp(value) {
59
+ if (value instanceof Date) {
60
+ const ms = value.getTime();
61
+ return Number.isFinite(ms) ? {
62
+ kind: "iso",
63
+ epochMs: ms
64
+ } : null;
65
+ }
66
+ if (typeof value === "number") return fromNumber(value);
67
+ if (typeof value !== "string") return null;
68
+ const trimmed = value.trim();
69
+ if (trimmed === "") return null;
70
+ if (/^\d+$/.test(trimmed)) return fromNumber(Number(trimmed));
71
+ if (!ISO_RE.test(trimmed)) return null;
72
+ const parsed = Date.parse(trimmed);
73
+ return Number.isFinite(parsed) ? {
74
+ kind: "iso",
75
+ epochMs: parsed
76
+ } : null;
77
+ }
78
+ function two(n) {
79
+ return n < 10 ? `0${n}` : String(n);
80
+ }
81
+
82
+ /** Local wall-clock, fixed format — a devtool wants it sortable, not chatty. */
83
+ function formatInstant(epochMs) {
84
+ const d = new Date(epochMs);
85
+ return `${d.getFullYear()}-${two(d.getMonth() + 1)}-${two(d.getDate())} ` + `${two(d.getHours())}:${two(d.getMinutes())}:${two(d.getSeconds())}`;
86
+ }
87
+
88
+ /** Coarsest two units that still carry the magnitude: "3d 4h", "5m 30s". */
89
+ function formatDuration(ms) {
90
+ const abs = Math.abs(ms);
91
+ if (abs < 1000) return `${abs}ms`;
92
+ const seconds = Math.floor(abs / 1000);
93
+ if (seconds < 60) return `${seconds}s`;
94
+ const minutes = Math.floor(seconds / 60);
95
+ const restSeconds = seconds % 60;
96
+ if (minutes < 60) return restSeconds ? `${minutes}m ${restSeconds}s` : `${minutes}m`;
97
+ const hours = Math.floor(minutes / 60);
98
+ const restMinutes = minutes % 60;
99
+ if (hours < 24) return restMinutes ? `${hours}h ${restMinutes}m` : `${hours}h`;
100
+ const days = Math.floor(hours / 24);
101
+ const restHours = hours % 24;
102
+ return restHours ? `${days}d ${restHours}h` : `${days}d`;
103
+ }
104
+ function pair(oldValue, newValue, path) {
105
+ const before = detectTimestamp(oldValue);
106
+ const after = detectTimestamp(newValue);
107
+ if (!before || !after || before.kind !== after.kind) return null;
108
+ const deltaMs = after.epochMs - before.epochMs;
109
+ return {
110
+ path,
111
+ kind: before.kind,
112
+ deltaMs,
113
+ deltaLabel: deltaMs === 0 ? "same instant" : `${formatDuration(deltaMs)} ${deltaMs < 0 ? "earlier" : "later"}`,
114
+ fromLabel: formatInstant(before.epochMs),
115
+ toLabel: formatInstant(after.epochMs)
116
+ };
117
+ }
118
+ function isPlainObject(value) {
119
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
120
+ }
121
+
122
+ /** Beyond a handful the bar stops being a summary and becomes the diff. */
123
+ const MAX_DELTAS = 6;
124
+
125
+ /**
126
+ * Every timestamp pair worth explaining in a diff of these two values.
127
+ *
128
+ * Scalars give at most one entry. Plain objects are inspected ONE level deep
129
+ * — enough for the `{ updatedAt, expiresAt }` shape that dominates, without
130
+ * walking a whole document to hunt for dates.
131
+ */
132
+ function describeTimestampDeltas(oldValue, newValue) {
133
+ const scalar = pair(oldValue, newValue);
134
+ if (scalar) return [scalar];
135
+ if (!isPlainObject(oldValue) || !isPlainObject(newValue)) return [];
136
+ const out = [];
137
+ for (const key of Object.keys(oldValue)) {
138
+ if (out.length >= MAX_DELTAS) break;
139
+ if (!(key in newValue)) continue;
140
+ // Unchanged stamps are noise: the point is explaining what MOVED.
141
+ if (Object.is(oldValue[key], newValue[key])) continue;
142
+ const entry = pair(oldValue[key], newValue[key], key);
143
+ if (entry) out.push(entry);
144
+ }
145
+ return out;
146
+ }
@@ -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-08-18T00:32:52.026Z
10
+ * Generated at: 2026-08-19T20:01:42.950Z
11
11
  *
12
12
  * DO NOT EDIT - This file is generated by scripts/detect-safe-area.js
13
13
  *