@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.
- package/lib/commonjs/JsModal.js +39 -16
- package/lib/commonjs/dataViewer/JsonStringNotice.js +59 -0
- package/lib/commonjs/dataViewer/ThemedSplitView.js +20 -1
- package/lib/commonjs/dataViewer/TimestampDeltaBar.js +96 -0
- package/lib/commonjs/dataViewer/index.js +52 -0
- package/lib/commonjs/dataViewer/jsonStringValue.js +94 -0
- package/lib/commonjs/dataViewer/timestampDiff.js +146 -0
- package/lib/commonjs/hooks/safe-area-impl.js +1 -1
- package/lib/commonjs/index.js +64 -1
- package/lib/commonjs/license/FeatureGate.js +43 -10
- package/lib/commonjs/license/FreeAccountPrompt.js +181 -0
- package/lib/commonjs/license/index.js +57 -42
- package/lib/commonjs/license/licenseModule.js +99 -0
- package/lib/commonjs/license/tierLimits.js +165 -0
- package/lib/commonjs/ui/backgrounds/BackgroundSwitcher.js +180 -0
- package/lib/commonjs/ui/backgrounds/README.md +115 -0
- package/lib/commonjs/ui/backgrounds/ToolBackground.js +74 -0
- package/lib/commonjs/ui/backgrounds/backgroundStore.js +116 -0
- package/lib/commonjs/ui/backgrounds/index.js +70 -0
- package/lib/commonjs/ui/backgrounds/primitives.js +333 -0
- package/lib/commonjs/ui/backgrounds/registry.js +112 -0
- package/lib/commonjs/ui/backgrounds/rng.js +72 -0
- package/lib/commonjs/ui/backgrounds/types.js +1 -0
- package/lib/commonjs/ui/backgrounds/variants/deepField.js +351 -0
- package/lib/commonjs/ui/backgrounds/variants/lattice.js +579 -0
- package/lib/commonjs/ui/backgrounds/variants/starfield.js +210 -0
- package/lib/commonjs/ui/index.js +15 -3
- package/lib/commonjs/utils/devServer.js +62 -0
- package/lib/commonjs/utils/index.js +13 -0
- package/lib/commonjs/utils/renderCaptureRegistry.js +32 -3
- package/lib/commonjs/utils/safeExpoRouter.js +27 -2
- package/lib/module/JsModal.js +39 -16
- package/lib/module/dataViewer/JsonStringNotice.js +54 -0
- package/lib/module/dataViewer/ThemedSplitView.js +20 -1
- package/lib/module/dataViewer/TimestampDeltaBar.js +91 -0
- package/lib/module/dataViewer/index.js +4 -0
- package/lib/module/dataViewer/jsonStringValue.js +89 -0
- package/lib/module/dataViewer/timestampDiff.js +139 -0
- package/lib/module/hooks/safe-area-impl.js +1 -1
- package/lib/module/index.js +5 -3
- package/lib/module/license/FeatureGate.js +43 -10
- package/lib/module/license/FreeAccountPrompt.js +176 -0
- package/lib/module/license/index.js +5 -40
- package/lib/module/license/licenseModule.js +92 -0
- package/lib/module/license/tierLimits.js +158 -0
- package/lib/module/ui/backgrounds/BackgroundSwitcher.js +176 -0
- package/lib/module/ui/backgrounds/README.md +115 -0
- package/lib/module/ui/backgrounds/ToolBackground.js +70 -0
- package/lib/module/ui/backgrounds/backgroundStore.js +111 -0
- package/lib/module/ui/backgrounds/index.js +9 -0
- package/lib/module/ui/backgrounds/primitives.js +328 -0
- package/lib/module/ui/backgrounds/registry.js +105 -0
- package/lib/module/ui/backgrounds/rng.js +65 -0
- package/lib/module/ui/backgrounds/types.js +1 -0
- package/lib/module/ui/backgrounds/variants/deepField.js +347 -0
- package/lib/module/ui/backgrounds/variants/lattice.js +575 -0
- package/lib/module/ui/backgrounds/variants/starfield.js +206 -0
- package/lib/module/ui/index.js +3 -0
- package/lib/module/utils/devServer.js +58 -0
- package/lib/module/utils/index.js +2 -1
- package/lib/module/utils/renderCaptureRegistry.js +32 -3
- package/lib/module/utils/safeExpoRouter.js +26 -2
- package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/JsonStringNotice.d.ts +6 -0
- package/lib/typescript/commonjs/dataViewer/JsonStringNotice.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/ThemedSplitView.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/TimestampDeltaBar.d.ts +7 -0
- package/lib/typescript/commonjs/dataViewer/TimestampDeltaBar.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/index.d.ts +6 -0
- package/lib/typescript/commonjs/dataViewer/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/dataViewer/jsonStringValue.d.ts +25 -0
- package/lib/typescript/commonjs/dataViewer/jsonStringValue.d.ts.map +1 -0
- package/lib/typescript/commonjs/dataViewer/timestampDiff.d.ts +55 -0
- package/lib/typescript/commonjs/dataViewer/timestampDiff.d.ts.map +1 -0
- package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -3
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/license/FeatureGate.d.ts +19 -3
- package/lib/typescript/commonjs/license/FeatureGate.d.ts.map +1 -1
- package/lib/typescript/commonjs/license/FreeAccountPrompt.d.ts +23 -0
- package/lib/typescript/commonjs/license/FreeAccountPrompt.d.ts.map +1 -0
- package/lib/typescript/commonjs/license/index.d.ts +6 -15
- package/lib/typescript/commonjs/license/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/license/licenseModule.d.ts +55 -0
- package/lib/typescript/commonjs/license/licenseModule.d.ts.map +1 -0
- package/lib/typescript/commonjs/license/tierLimits.d.ts +143 -0
- package/lib/typescript/commonjs/license/tierLimits.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/BackgroundSwitcher.d.ts +13 -0
- package/lib/typescript/commonjs/ui/backgrounds/BackgroundSwitcher.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/ToolBackground.d.ts +30 -0
- package/lib/typescript/commonjs/ui/backgrounds/ToolBackground.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/backgroundStore.d.ts +43 -0
- package/lib/typescript/commonjs/ui/backgrounds/backgroundStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/index.d.ts +7 -0
- package/lib/typescript/commonjs/ui/backgrounds/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/primitives.d.ts +106 -0
- package/lib/typescript/commonjs/ui/backgrounds/primitives.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/registry.d.ts +28 -0
- package/lib/typescript/commonjs/ui/backgrounds/registry.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/rng.d.ts +27 -0
- package/lib/typescript/commonjs/ui/backgrounds/rng.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/types.d.ts +14 -0
- package/lib/typescript/commonjs/ui/backgrounds/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/variants/deepField.d.ts +65 -0
- package/lib/typescript/commonjs/ui/backgrounds/variants/deepField.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/variants/lattice.d.ts +33 -0
- package/lib/typescript/commonjs/ui/backgrounds/variants/lattice.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/backgrounds/variants/starfield.d.ts +12 -0
- package/lib/typescript/commonjs/ui/backgrounds/variants/starfield.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/index.d.ts +1 -0
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/devServer.d.ts +24 -0
- package/lib/typescript/commonjs/utils/devServer.d.ts.map +1 -0
- package/lib/typescript/commonjs/utils/index.d.ts +3 -2
- package/lib/typescript/commonjs/utils/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/renderCaptureRegistry.d.ts +52 -2
- package/lib/typescript/commonjs/utils/renderCaptureRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/safeExpoRouter.d.ts +23 -0
- package/lib/typescript/commonjs/utils/safeExpoRouter.d.ts.map +1 -1
- package/lib/typescript/module/JsModal.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/JsonStringNotice.d.ts +6 -0
- package/lib/typescript/module/dataViewer/JsonStringNotice.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/ThemedSplitView.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/TimestampDeltaBar.d.ts +7 -0
- package/lib/typescript/module/dataViewer/TimestampDeltaBar.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/index.d.ts +6 -0
- package/lib/typescript/module/dataViewer/index.d.ts.map +1 -1
- package/lib/typescript/module/dataViewer/jsonStringValue.d.ts +25 -0
- package/lib/typescript/module/dataViewer/jsonStringValue.d.ts.map +1 -0
- package/lib/typescript/module/dataViewer/timestampDiff.d.ts +55 -0
- package/lib/typescript/module/dataViewer/timestampDiff.d.ts.map +1 -0
- package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/module/index.d.ts +4 -3
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/license/FeatureGate.d.ts +19 -3
- package/lib/typescript/module/license/FeatureGate.d.ts.map +1 -1
- package/lib/typescript/module/license/FreeAccountPrompt.d.ts +23 -0
- package/lib/typescript/module/license/FreeAccountPrompt.d.ts.map +1 -0
- package/lib/typescript/module/license/index.d.ts +6 -15
- package/lib/typescript/module/license/index.d.ts.map +1 -1
- package/lib/typescript/module/license/licenseModule.d.ts +55 -0
- package/lib/typescript/module/license/licenseModule.d.ts.map +1 -0
- package/lib/typescript/module/license/tierLimits.d.ts +143 -0
- package/lib/typescript/module/license/tierLimits.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/BackgroundSwitcher.d.ts +13 -0
- package/lib/typescript/module/ui/backgrounds/BackgroundSwitcher.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/ToolBackground.d.ts +30 -0
- package/lib/typescript/module/ui/backgrounds/ToolBackground.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/backgroundStore.d.ts +43 -0
- package/lib/typescript/module/ui/backgrounds/backgroundStore.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/index.d.ts +7 -0
- package/lib/typescript/module/ui/backgrounds/index.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/primitives.d.ts +106 -0
- package/lib/typescript/module/ui/backgrounds/primitives.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/registry.d.ts +28 -0
- package/lib/typescript/module/ui/backgrounds/registry.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/rng.d.ts +27 -0
- package/lib/typescript/module/ui/backgrounds/rng.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/types.d.ts +14 -0
- package/lib/typescript/module/ui/backgrounds/types.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/variants/deepField.d.ts +65 -0
- package/lib/typescript/module/ui/backgrounds/variants/deepField.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/variants/lattice.d.ts +33 -0
- package/lib/typescript/module/ui/backgrounds/variants/lattice.d.ts.map +1 -0
- package/lib/typescript/module/ui/backgrounds/variants/starfield.d.ts +12 -0
- package/lib/typescript/module/ui/backgrounds/variants/starfield.d.ts.map +1 -0
- package/lib/typescript/module/ui/index.d.ts +1 -0
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/utils/devServer.d.ts +24 -0
- package/lib/typescript/module/utils/devServer.d.ts.map +1 -0
- package/lib/typescript/module/utils/index.d.ts +3 -2
- package/lib/typescript/module/utils/index.d.ts.map +1 -1
- package/lib/typescript/module/utils/renderCaptureRegistry.d.ts +52 -2
- package/lib/typescript/module/utils/renderCaptureRegistry.d.ts.map +1 -1
- package/lib/typescript/module/utils/safeExpoRouter.d.ts +23 -0
- package/lib/typescript/module/utils/safeExpoRouter.d.ts.map +1 -1
- package/package.json +4 -4
- package/scripts/detect-safe-area.js +1 -0
package/lib/commonjs/JsModal.js
CHANGED
|
@@ -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,
|
|
1119
|
-
//
|
|
1120
|
-
|
|
1121
|
-
|
|
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: [
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
*
|