@buoy-gg/jotai 7.0.38 → 7.0.40

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 (50) hide show
  1. package/lib/commonjs/index.js +112 -1
  2. package/lib/commonjs/jotai/components/JotaiAtomBrowser.js +199 -1
  3. package/lib/commonjs/jotai/components/JotaiAtomChangeItem.js +85 -1
  4. package/lib/commonjs/jotai/components/JotaiAtomDetailContent.js +715 -1
  5. package/lib/commonjs/jotai/components/JotaiAtomValueDetailContent.js +444 -1
  6. package/lib/commonjs/jotai/components/JotaiEventFilterView.js +43 -1
  7. package/lib/commonjs/jotai/components/JotaiIcon.js +18 -1
  8. package/lib/commonjs/jotai/components/JotaiModal.js +743 -1
  9. package/lib/commonjs/jotai/hooks/useJotaiAtomChanges.js +69 -1
  10. package/lib/commonjs/jotai/sync/jotaiSyncAdapter.js +306 -1
  11. package/lib/commonjs/jotai/utils/jotaiStateStore.js +321 -1
  12. package/lib/commonjs/jotai/utils/snapshotProvider.js +215 -1
  13. package/lib/commonjs/jotai/utils/testIDs.js +90 -1
  14. package/lib/commonjs/jotai/utils/watchAtoms.js +162 -1
  15. package/lib/commonjs/jotai/utils/writeSemantics.js +47 -1
  16. package/lib/commonjs/preset.js +90 -1
  17. package/lib/module/index.js +85 -1
  18. package/lib/module/jotai/components/JotaiAtomBrowser.js +195 -1
  19. package/lib/module/jotai/components/JotaiAtomChangeItem.js +81 -1
  20. package/lib/module/jotai/components/JotaiAtomDetailContent.js +710 -1
  21. package/lib/module/jotai/components/JotaiAtomValueDetailContent.js +442 -1
  22. package/lib/module/jotai/components/JotaiEventFilterView.js +39 -1
  23. package/lib/module/jotai/components/JotaiIcon.js +11 -1
  24. package/lib/module/jotai/components/JotaiModal.js +738 -1
  25. package/lib/module/jotai/hooks/useJotaiAtomChanges.js +65 -1
  26. package/lib/module/jotai/sync/jotaiSyncAdapter.js +303 -1
  27. package/lib/module/jotai/utils/jotaiStateStore.js +317 -1
  28. package/lib/module/jotai/utils/snapshotProvider.js +214 -1
  29. package/lib/module/jotai/utils/testIDs.js +82 -1
  30. package/lib/module/jotai/utils/watchAtoms.js +157 -1
  31. package/lib/module/jotai/utils/writeSemantics.js +43 -1
  32. package/lib/module/preset.js +87 -1
  33. package/lib/typescript/index.d.ts.map +1 -0
  34. package/lib/typescript/jotai/components/JotaiAtomBrowser.d.ts.map +1 -0
  35. package/lib/typescript/jotai/components/JotaiAtomChangeItem.d.ts.map +1 -0
  36. package/lib/typescript/jotai/components/JotaiAtomDetailContent.d.ts.map +1 -0
  37. package/lib/typescript/jotai/components/JotaiAtomValueDetailContent.d.ts.map +1 -0
  38. package/lib/typescript/jotai/components/JotaiEventFilterView.d.ts.map +1 -0
  39. package/lib/typescript/jotai/components/JotaiIcon.d.ts.map +1 -0
  40. package/lib/typescript/jotai/components/JotaiModal.d.ts.map +1 -0
  41. package/lib/typescript/jotai/hooks/useJotaiAtomChanges.d.ts.map +1 -0
  42. package/lib/typescript/jotai/sync/jotaiSyncAdapter.d.ts.map +1 -0
  43. package/lib/typescript/jotai/types/index.d.ts.map +1 -0
  44. package/lib/typescript/jotai/utils/jotaiStateStore.d.ts.map +1 -0
  45. package/lib/typescript/jotai/utils/snapshotProvider.d.ts.map +1 -0
  46. package/lib/typescript/jotai/utils/testIDs.d.ts.map +1 -0
  47. package/lib/typescript/jotai/utils/watchAtoms.d.ts.map +1 -0
  48. package/lib/typescript/jotai/utils/writeSemantics.d.ts.map +1 -0
  49. package/lib/typescript/preset.d.ts.map +1 -0
  50. package/package.json +3 -3
@@ -1 +1,715 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.JotaiAtomDetailContent=JotaiAtomDetailContent,exports.JotaiAtomDetailFooter=JotaiAtomDetailFooter;var _react=_interopRequireWildcard(require("react")),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_dataViewer=require("@buoy-gg/shared-ui/dataViewer"),_license=require("@buoy-gg/license"),_jotaiStateStore=require("../utils/jotaiStateStore"),_testIDs=require("../utils/testIDs"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireWildcard(e,t){if("function"==typeof WeakMap)var i=new WeakMap,a=new WeakMap;return(_interopRequireWildcard=function(e,t){if(!t&&e&&e.__esModule)return e;var o,n,r={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return r;if(o=t?a:i){if(o.has(e))return o.get(e);o.set(e,r)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((n=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(n.get||n.set)?o(r,t,n):r[t]=e[t]);return r})(e,t)}const VIEW_CONFIGS=[{key:"change",label:"CHANGE",icon:_sharedUi.FileText},{key:"value",label:"VALUE",icon:_sharedUi.Database},{key:"diff",label:"DIFF",icon:_sharedUi.GitBranch}],DIFF_DISABLED=["diff"];function getCategoryInfo(e){return"initial"===e?{label:"INITIAL",color:_sharedUi.night.color.textTertiary,bgColor:_sharedUi.night.color.textTertiary+"26"}:{label:"WRITE",color:_sharedUi.buoyColors.success,bgColor:_sharedUi.buoyColors.success+"26"}}function formatTime(e){const t=new Date(e);return`${t.getHours().toString().padStart(2,"0")}:${t.getMinutes().toString().padStart(2,"0")}:${t.getSeconds().toString().padStart(2,"0")}.${t.getMilliseconds().toString().padStart(3,"0")}`}function formatTimestamp(e){return new Date(e).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"})}function getValueType(e){return null===e?"null":void 0===e?"undefined":Array.isArray(e)?"array":typeof e}function getChangeLabel(e){return"initial"===e?"INIT":"WRITE"}const DIFF_MODE_TABS=[{key:"tree",label:"TREE VIEW"},{key:"split",label:"SPLIT VIEW"}],JotaiAtomInfoView=(0,_react.memo)(function({change:e}){const t=(0,_license.useIsPro)(),[i,a]=(0,_react.useState)(!1),o=getCategoryInfo(e.category),n=_jotaiStateStore.jotaiStateStore.getAtomColor(e.atomLabel),r=(0,_react.useCallback)(async()=>{t?await(0,_sharedUi.copyToClipboard)(e.nextValue):a(!0)},[e.nextValue,t]);return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:infoStyles.container,contentContainerStyle:infoStyles.content,showsVerticalScrollIndicator:!1,testID:`${_testIDs.JOTAI_TEST_ID}-detail-scroll`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:infoStyles.card,testID:`${_testIDs.JOTAI_TEST_ID}-info-card`,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:infoStyles.sectionHeader,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:infoStyles.sectionHeaderLeft,children:[(0,_jsxRuntime.jsx)(_sharedUi.Info,{size:14,color:_sharedUi.night.color.accent}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:infoStyles.sectionTitle,children:"CHANGE INFO"})]})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:infoStyles.cardContent,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:infoStyles.infoRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:infoStyles.infoLabel,children:"Atom"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[infoStyles.infoValue,infoStyles.infoValueMono,{color:n}],numberOfLines:1,ellipsizeMode:"middle",testID:`${_testIDs.JOTAI_TEST_ID}-info-atom`,children:e.atomLabel})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:infoStyles.infoRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:infoStyles.infoLabel,children:"Time"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[infoStyles.infoValue,infoStyles.infoValueMono],testID:`${_testIDs.JOTAI_TEST_ID}-info-time`,children:formatTime(e.timestamp)})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:infoStyles.badgeRow,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[infoStyles.categoryBadge,{backgroundColor:o.bgColor}],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[infoStyles.categoryText,{color:o.color}],testID:`${_testIDs.JOTAI_TEST_ID}-info-category`,children:o.label})}),e.hasValueChange?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:infoStyles.changesBadge,children:[(0,_jsxRuntime.jsx)(_sharedUi.Zap,{size:10,color:_sharedUi.buoyColors.success}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:infoStyles.changesText,testID:`${_testIDs.JOTAI_TEST_ID}-info-changes`,children:e.diffSummary||"changed"})]}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:infoStyles.noChangesBadge,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:infoStyles.noChangesText,testID:`${_testIDs.JOTAI_TEST_ID}-info-no-changes`,children:"no change"})})]})]})]}),e.changedKeys.length>0&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:infoStyles.card,testID:`${_testIDs.JOTAI_TEST_ID}-keys-card`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:infoStyles.sectionHeader,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:infoStyles.sectionHeaderLeft,children:[(0,_jsxRuntime.jsx)(_sharedUi.Zap,{size:14,color:_sharedUi.night.color.accent}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:infoStyles.sectionTitle,children:"CHANGED KEYS"})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:infoStyles.countBadge,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:infoStyles.countText,testID:`${_testIDs.JOTAI_TEST_ID}-keys-count`,children:e.changedKeys.length})})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:infoStyles.cardContent,children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:infoStyles.keysContainer,children:e.changedKeys.map(e=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:infoStyles.keyBadge,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:infoStyles.keyText,testID:`${_testIDs.JOTAI_TEST_ID}-key-${(0,_testIDs.slugForTestID)(e)}`,children:e})},e))})})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:infoStyles.actionsRow,children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:[infoStyles.actionButton,infoStyles.actionButtonCopy],onTouchEnd:r,testID:`${_testIDs.JOTAI_TEST_ID}-copy-value`,accessibilityRole:"button",accessibilityLabel:"Copy value",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[infoStyles.actionButtonText,{color:_sharedUi.night.color.accent}],children:"COPY VALUE"})})}),(0,_jsxRuntime.jsx)(_sharedUi.ProUpgradeModal,{visible:i,onClose:()=>a(!1),featureName:"Copy"})]})});function JotaiAtomDetailContent({change:e,changes:t,selectedIndex:i,onIndexChange:a,disableInternalFooter:o=!1,initialView:n="change"}){const[r,s]=(0,_react.useState)(n),[l,c]=(0,_react.useState)("tree"),d=t.length,_=_jotaiStateStore.jotaiStateStore.getAtomColor(e.atomLabel),u=getChangeLabel(e.category),h=getValueType((0,_sharedUi.parseValue)(e.nextValue)),g=d-i,x=i<d-1?i+1:null,f=null!==x?t[x]:null,m=g-1,y=(0,_react.useMemo)(()=>({index:x??0,label:m>0?`#${m}`:"Initial",timestamp:f?formatTimestamp(f.timestamp):"",relativeTime:f?(0,_sharedUi.formatRelativeTime)(new Date(f.timestamp)):"value",badge:f?(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.changeBadgeSmall,{backgroundColor:`${_jotaiStateStore.jotaiStateStore.getAtomColor(f.atomLabel)}20`}],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.changeTextSmall,{color:_jotaiStateStore.jotaiStateStore.getAtomColor(f.atomLabel)}],children:getChangeLabel(f.category)})}):void 0}),[x,f,m]),j=(0,_react.useMemo)(()=>({index:i,label:`#${g}`,timestamp:formatTimestamp(e.timestamp),relativeTime:(0,_sharedUi.formatRelativeTime)(new Date(e.timestamp)),badge:(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.changeBadgeSmall,{backgroundColor:`${_}20`}],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.changeTextSmall,{color:_}],children:u})})}),[i,e.timestamp,_,u,g]),S=(0,_react.useCallback)(()=>{const t=(0,_sharedUi.parseValue)(e.nextValue);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.contentCard,testID:`${_testIDs.JOTAI_TEST_ID}-value-card`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.valueHeader,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.valueLabel,children:"VALUE AFTER CHANGE"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.valueHeaderBadges,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.changeBadge,{backgroundColor:`${_}20`}],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.changeText,{color:_}],children:u})}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.typeBadge,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.typeText,testID:`${_testIDs.JOTAI_TEST_ID}-value-type`,children:h.toUpperCase()})})]})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:infoStyles.dataViewerContainer,children:(0,_jsxRuntime.jsx)(_dataViewer.DataViewer,{title:"",data:t,showTypeFilter:!0,rawMode:!0,initialExpanded:!0})})]})},[e.nextValue,_,u,h]),T=(0,_react.useCallback)(()=>{const t=(0,_sharedUi.parseValue)(e.prevValue),i=(0,_sharedUi.parseValue)(e.nextValue);return"split"===l?(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{style:{flex:1},showsVerticalScrollIndicator:!0,children:(0,_jsxRuntime.jsx)(_dataViewer.SplitDiffViewer,{oldValue:t,newValue:i,theme:_dataViewer.diffThemes.devToolsDefault,options:{hideLineNumbers:!1,disableWordDiff:!1,showDiffOnly:!1,compareMethod:"words",contextLines:3},showThemeName:!1})}):(0,_jsxRuntime.jsx)(_dataViewer.TreeDiffViewer,{oldValue:t,newValue:i})},[e.prevValue,e.nextValue,l]),p=(0,_react.useCallback)(()=>{a(Math.min(d-1,i+1))},[i,d,a]),I=(0,_react.useCallback)(()=>{a(Math.max(0,i-1))},[i,a]),b=void 0===e.prevValue,v=!o&&d>1;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.container,children:[(0,_jsxRuntime.jsx)(_sharedUi.DetailViewToggle,{views:VIEW_CONFIGS,activeView:r,onViewChange:s,disabledKeys:b?DIFF_DISABLED:void 0,testIDPrefix:_testIDs.JOTAI_TEST_ID}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.contentArea,v&&styles.contentAreaFooterPad],children:["change"===r&&(0,_jsxRuntime.jsx)(JotaiAtomInfoView,{change:e}),"value"===r&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.stateContainer,children:S()}),"diff"===r&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.diffContainer,testID:`${_testIDs.JOTAI_TEST_ID}-diff`,children:[(0,_jsxRuntime.jsx)(_sharedUi.DiffModeTabs,{tabs:DIFF_MODE_TABS,activeTab:l,onTabChange:c,testIDPrefix:`${_testIDs.JOTAI_TEST_ID}-diff-tab`}),(0,_jsxRuntime.jsx)(_sharedUi.CompareBar,{leftEvent:y,rightEvent:j}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.diffContent,testID:`${_testIDs.JOTAI_TEST_ID}-diff-content`,children:T()})]})]}),v&&(0,_jsxRuntime.jsx)(_sharedUi.EventStepperFooter,{currentIndex:g-1,totalItems:d,onPrevious:p,onNext:I,itemLabel:"Change",subtitle:(0,_sharedUi.formatRelativeTime)(new Date(e.timestamp)),absolute:!0})]})}function JotaiAtomDetailFooter({change:e,changes:t,selectedIndex:i,onIndexChange:a}){const o=t.length;if(o<=1)return null;const n=o-i;return(0,_jsxRuntime.jsx)(_sharedUi.EventStepperFooter,{currentIndex:n-1,totalItems:o,onPrevious:()=>a(Math.min(o-1,i+1)),onNext:()=>a(Math.max(0,i-1)),itemLabel:"Change",subtitle:(0,_sharedUi.formatRelativeTime)(new Date(e.timestamp))})}const styles=_reactNative.StyleSheet.create({container:{flex:1,backgroundColor:"transparent"},contentArea:{flex:1},contentAreaFooterPad:{paddingBottom:96},stateContainer:{flex:1,padding:14},contentCard:{backgroundColor:_sharedUi.night.color.surface,borderRadius:14,padding:14,borderWidth:1,borderColor:_sharedUi.night.color.border},valueHeader:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:8},valueLabel:{fontSize:10,color:_sharedUi.night.color.textSecondary,fontFamily:_sharedUi.monoFont,letterSpacing:.5,fontWeight:"600"},valueHeaderBadges:{flexDirection:"row",alignItems:"center",gap:6},changeBadge:{paddingHorizontal:8,paddingVertical:2,borderRadius:4},changeText:{fontSize:9,fontWeight:"700",fontFamily:_sharedUi.monoFont,letterSpacing:.3},typeBadge:{paddingHorizontal:8,paddingVertical:2,borderRadius:4,backgroundColor:_sharedUi.night.color.surfaceElevated},typeText:{fontSize:9,fontWeight:"600",color:_sharedUi.night.color.textTertiary,fontFamily:_sharedUi.monoFont},valueBox:{backgroundColor:_sharedUi.night.color.bg,borderRadius:6,borderWidth:1,borderColor:_sharedUi.night.color.border,padding:8},valueText:{fontSize:12,color:_sharedUi.night.color.text,fontFamily:_sharedUi.monoFont,lineHeight:18},diffContainer:{flex:1},diffContent:{flex:1,paddingHorizontal:14},changeBadgeSmall:{paddingHorizontal:6,paddingVertical:1,borderRadius:3},changeTextSmall:{fontSize:8,fontWeight:"700",fontFamily:_sharedUi.monoFont}}),infoStyles=_reactNative.StyleSheet.create({container:{flex:1},content:{padding:8,paddingBottom:100,gap:16},card:{backgroundColor:_sharedUi.night.color.surface,borderRadius:6,borderWidth:1,borderColor:_sharedUi.night.color.accentBorderStrong,overflow:"hidden",shadowColor:_sharedUi.night.color.accent,shadowOffset:{width:0,height:0},shadowOpacity:.1,shadowRadius:6},sectionHeader:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingHorizontal:12,paddingVertical:10,borderBottomWidth:1,borderBottomColor:_sharedUi.night.color.accentBorder,backgroundColor:_sharedUi.night.color.accentSoft},sectionHeaderLeft:{flexDirection:"row",alignItems:"center",gap:6},sectionTitle:{fontSize:12,fontWeight:"600",letterSpacing:.5,color:_sharedUi.night.color.accent,fontFamily:_sharedUi.monoFont},cardContent:{padding:14,gap:10},infoRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between"},infoLabel:{fontSize:11,color:_sharedUi.night.color.textTertiary,fontWeight:"500"},infoValue:{fontSize:11,color:_sharedUi.night.color.text,fontWeight:"500",flex:1,textAlign:"right",marginLeft:12},infoValueMono:{fontFamily:_sharedUi.monoFont},badgeRow:{flexDirection:"row",flexWrap:"wrap",gap:8,marginTop:6},categoryBadge:{paddingHorizontal:8,paddingVertical:3,borderRadius:4},categoryText:{fontSize:9,fontWeight:"700",letterSpacing:.3},changesBadge:{flexDirection:"row",alignItems:"center",gap:4,paddingHorizontal:8,paddingVertical:3,borderRadius:4,backgroundColor:_sharedUi.buoyColors.success+"26"},changesText:{fontSize:9,fontWeight:"600",color:_sharedUi.buoyColors.success},noChangesBadge:{paddingHorizontal:8,paddingVertical:3,borderRadius:4,backgroundColor:_sharedUi.night.color.surfaceElevated},noChangesText:{fontSize:9,fontWeight:"600",color:_sharedUi.night.color.textTertiary},keysContainer:{flexDirection:"row",flexWrap:"wrap",gap:6},keyBadge:{paddingHorizontal:8,paddingVertical:4,borderRadius:4,backgroundColor:_sharedUi.night.color.accentSoft,borderWidth:1,borderColor:_sharedUi.night.color.accentBorder},keyText:{fontSize:11,fontWeight:"600",color:_sharedUi.night.color.accent,fontFamily:_sharedUi.monoFont},countBadge:{paddingHorizontal:8,paddingVertical:3,borderRadius:4,backgroundColor:_sharedUi.night.color.accentFill},countText:{fontSize:9,fontWeight:"700",color:_sharedUi.night.color.accent,fontFamily:_sharedUi.monoFont},actionsRow:{flexDirection:"row",gap:12},actionButton:{paddingHorizontal:14,paddingVertical:8,borderRadius:8,borderWidth:1},actionButtonCopy:{borderColor:_sharedUi.night.color.accentBorder,backgroundColor:_sharedUi.night.color.accentSoft},actionButtonText:{fontSize:10,fontWeight:"700",fontFamily:_sharedUi.monoFont,letterSpacing:.3},dataViewerContainer:{marginTop:-12,marginHorizontal:-12,marginBottom:-12}});
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.JotaiAtomDetailContent = JotaiAtomDetailContent;
7
+ exports.JotaiAtomDetailFooter = JotaiAtomDetailFooter;
8
+ var _react = _interopRequireWildcard(require("react"));
9
+ var _reactNative = require("react-native");
10
+ var _sharedUi = require("@buoy-gg/shared-ui");
11
+ var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
12
+ var _license = require("@buoy-gg/license");
13
+ var _jotaiStateStore = require("../utils/jotaiStateStore");
14
+ var _testIDs = require("../utils/testIDs");
15
+ var _jsxRuntime = require("react/jsx-runtime");
16
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
17
+ /**
18
+ * JotaiAtomDetailContent
19
+ *
20
+ * Detail view for a Jotai atom change with 3 view modes:
21
+ * - CHANGE: Atom label, timestamp, category, changed keys
22
+ * - VALUE: Full atom value after change
23
+ * - DIFF: Compare prev vs next value
24
+ *
25
+ * Mirrors ZustandStateDetailContent.tsx from @buoy-gg/zustand
26
+ */
27
+
28
+ // ---- View Toggle ----
29
+ const VIEW_CONFIGS = [{
30
+ key: "change",
31
+ label: "CHANGE",
32
+ icon: _sharedUi.FileText
33
+ }, {
34
+ key: "value",
35
+ label: "VALUE",
36
+ icon: _sharedUi.Database
37
+ }, {
38
+ key: "diff",
39
+ label: "DIFF",
40
+ icon: _sharedUi.GitBranch
41
+ }];
42
+ const DIFF_DISABLED = ["diff"];
43
+
44
+ // ---- Helpers ----
45
+
46
+ function getCategoryInfo(category) {
47
+ switch (category) {
48
+ case "initial":
49
+ return {
50
+ label: "INITIAL",
51
+ color: _sharedUi.night.color.textTertiary,
52
+ bgColor: _sharedUi.night.color.textTertiary + "26"
53
+ };
54
+ default:
55
+ return {
56
+ label: "WRITE",
57
+ color: _sharedUi.buoyColors.success,
58
+ bgColor: _sharedUi.buoyColors.success + "26"
59
+ };
60
+ }
61
+ }
62
+ function formatTime(timestamp) {
63
+ const date = new Date(timestamp);
64
+ const h = date.getHours().toString().padStart(2, "0");
65
+ const m = date.getMinutes().toString().padStart(2, "0");
66
+ const s = date.getSeconds().toString().padStart(2, "0");
67
+ const ms = date.getMilliseconds().toString().padStart(3, "0");
68
+ return `${h}:${m}:${s}.${ms}`;
69
+ }
70
+ function formatTimestamp(timestamp) {
71
+ return new Date(timestamp).toLocaleTimeString("en-US", {
72
+ hour12: false,
73
+ hour: "2-digit",
74
+ minute: "2-digit",
75
+ second: "2-digit"
76
+ });
77
+ }
78
+ function getValueType(value) {
79
+ if (value === null) return "null";
80
+ if (value === undefined) return "undefined";
81
+ if (Array.isArray(value)) return "array";
82
+ return typeof value;
83
+ }
84
+ function getChangeLabel(category) {
85
+ return category === "initial" ? "INIT" : "WRITE";
86
+ }
87
+ const DIFF_MODE_TABS = [{
88
+ key: "tree",
89
+ label: "TREE VIEW"
90
+ }, {
91
+ key: "split",
92
+ label: "SPLIT VIEW"
93
+ }];
94
+
95
+ // ---- Change Info View (CHANGE tab) ----
96
+
97
+ const JotaiAtomInfoView = /*#__PURE__*/(0, _react.memo)(function JotaiAtomInfoView({
98
+ change
99
+ }) {
100
+ const isPro = (0, _license.useIsPro)();
101
+ const [showProModal, setShowProModal] = (0, _react.useState)(false);
102
+ const categoryInfo = getCategoryInfo(change.category);
103
+ const atomColor = _jotaiStateStore.jotaiStateStore.getAtomColor(change.atomLabel);
104
+ const handleCopyValue = (0, _react.useCallback)(async () => {
105
+ if (!isPro) {
106
+ setShowProModal(true);
107
+ return;
108
+ }
109
+ await (0, _sharedUi.copyToClipboard)(change.nextValue);
110
+ }, [change.nextValue, isPro]);
111
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
112
+ style: infoStyles.container,
113
+ contentContainerStyle: infoStyles.content,
114
+ showsVerticalScrollIndicator: false,
115
+ testID: `${_testIDs.JOTAI_TEST_ID}-detail-scroll`,
116
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
117
+ style: infoStyles.card,
118
+ testID: `${_testIDs.JOTAI_TEST_ID}-info-card`,
119
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
120
+ style: infoStyles.sectionHeader,
121
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
122
+ style: infoStyles.sectionHeaderLeft,
123
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Info, {
124
+ size: 14,
125
+ color: _sharedUi.night.color.accent
126
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
127
+ style: infoStyles.sectionTitle,
128
+ children: "CHANGE INFO"
129
+ })]
130
+ })
131
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
132
+ style: infoStyles.cardContent,
133
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
134
+ style: infoStyles.infoRow,
135
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
136
+ style: infoStyles.infoLabel,
137
+ children: "Atom"
138
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
139
+ style: [infoStyles.infoValue, infoStyles.infoValueMono, {
140
+ color: atomColor
141
+ }],
142
+ numberOfLines: 1,
143
+ ellipsizeMode: "middle",
144
+ testID: `${_testIDs.JOTAI_TEST_ID}-info-atom`,
145
+ children: change.atomLabel
146
+ })]
147
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
148
+ style: infoStyles.infoRow,
149
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
150
+ style: infoStyles.infoLabel,
151
+ children: "Time"
152
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
153
+ style: [infoStyles.infoValue, infoStyles.infoValueMono],
154
+ testID: `${_testIDs.JOTAI_TEST_ID}-info-time`,
155
+ children: formatTime(change.timestamp)
156
+ })]
157
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
158
+ style: infoStyles.badgeRow,
159
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
160
+ style: [infoStyles.categoryBadge, {
161
+ backgroundColor: categoryInfo.bgColor
162
+ }],
163
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
164
+ style: [infoStyles.categoryText, {
165
+ color: categoryInfo.color
166
+ }],
167
+ testID: `${_testIDs.JOTAI_TEST_ID}-info-category`,
168
+ children: categoryInfo.label
169
+ })
170
+ }), change.hasValueChange ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
171
+ style: infoStyles.changesBadge,
172
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
173
+ size: 10,
174
+ color: _sharedUi.buoyColors.success
175
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
176
+ style: infoStyles.changesText,
177
+ testID: `${_testIDs.JOTAI_TEST_ID}-info-changes`,
178
+ children: change.diffSummary || "changed"
179
+ })]
180
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
181
+ style: infoStyles.noChangesBadge,
182
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
183
+ style: infoStyles.noChangesText,
184
+ testID: `${_testIDs.JOTAI_TEST_ID}-info-no-changes`,
185
+ children: "no change"
186
+ })
187
+ })]
188
+ })]
189
+ })]
190
+ }), change.changedKeys.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
191
+ style: infoStyles.card,
192
+ testID: `${_testIDs.JOTAI_TEST_ID}-keys-card`,
193
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
194
+ style: infoStyles.sectionHeader,
195
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
196
+ style: infoStyles.sectionHeaderLeft,
197
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
198
+ size: 14,
199
+ color: _sharedUi.night.color.accent
200
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
201
+ style: infoStyles.sectionTitle,
202
+ children: "CHANGED KEYS"
203
+ })]
204
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
205
+ style: infoStyles.countBadge,
206
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
207
+ style: infoStyles.countText,
208
+ testID: `${_testIDs.JOTAI_TEST_ID}-keys-count`,
209
+ children: change.changedKeys.length
210
+ })
211
+ })]
212
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
213
+ style: infoStyles.cardContent,
214
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
215
+ style: infoStyles.keysContainer,
216
+ children: change.changedKeys.map(key => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
217
+ style: infoStyles.keyBadge,
218
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
219
+ style: infoStyles.keyText,
220
+ testID: `${_testIDs.JOTAI_TEST_ID}-key-${(0, _testIDs.slugForTestID)(key)}`,
221
+ children: key
222
+ })
223
+ }, key))
224
+ })
225
+ })]
226
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
227
+ style: infoStyles.actionsRow,
228
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
229
+ style: [infoStyles.actionButton, infoStyles.actionButtonCopy],
230
+ onTouchEnd: handleCopyValue,
231
+ testID: `${_testIDs.JOTAI_TEST_ID}-copy-value`,
232
+ accessibilityRole: "button",
233
+ accessibilityLabel: "Copy value",
234
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
235
+ style: [infoStyles.actionButtonText, {
236
+ color: _sharedUi.night.color.accent
237
+ }],
238
+ children: "COPY VALUE"
239
+ })
240
+ })
241
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ProUpgradeModal, {
242
+ visible: showProModal,
243
+ onClose: () => setShowProModal(false),
244
+ featureName: "Copy"
245
+ })]
246
+ });
247
+ });
248
+
249
+ // ---- Main Detail Content ----
250
+
251
+ function JotaiAtomDetailContent({
252
+ change,
253
+ changes,
254
+ selectedIndex,
255
+ onIndexChange,
256
+ disableInternalFooter = false,
257
+ initialView = "change"
258
+ }) {
259
+ // View state (initialView seeds it once; taps own it afterwards)
260
+ const [activeView, setActiveView] = (0, _react.useState)(initialView);
261
+ const [diffMode, setDiffMode] = (0, _react.useState)("tree");
262
+ const totalChanges = changes.length;
263
+ const atomColor = _jotaiStateStore.jotaiStateStore.getAtomColor(change.atomLabel);
264
+ const changeLabel = getChangeLabel(change.category);
265
+ const valueType = getValueType((0, _sharedUi.parseValue)(change.nextValue));
266
+ const chronologicalNumber = totalChanges - selectedIndex;
267
+ const prevChangeIndex = selectedIndex < totalChanges - 1 ? selectedIndex + 1 : null;
268
+ const prevChange = prevChangeIndex !== null ? changes[prevChangeIndex] : null;
269
+ const prevChronologicalNumber = chronologicalNumber - 1;
270
+ const leftEvent = (0, _react.useMemo)(() => ({
271
+ index: prevChangeIndex ?? 0,
272
+ label: prevChronologicalNumber > 0 ? `#${prevChronologicalNumber}` : "Initial",
273
+ timestamp: prevChange ? formatTimestamp(prevChange.timestamp) : "",
274
+ relativeTime: prevChange ? (0, _sharedUi.formatRelativeTime)(new Date(prevChange.timestamp)) : "value",
275
+ badge: prevChange ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
276
+ style: [styles.changeBadgeSmall, {
277
+ backgroundColor: `${_jotaiStateStore.jotaiStateStore.getAtomColor(prevChange.atomLabel)}20`
278
+ }],
279
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
280
+ style: [styles.changeTextSmall, {
281
+ color: _jotaiStateStore.jotaiStateStore.getAtomColor(prevChange.atomLabel)
282
+ }],
283
+ children: getChangeLabel(prevChange.category)
284
+ })
285
+ }) : undefined
286
+ }), [prevChangeIndex, prevChange, prevChronologicalNumber]);
287
+ const rightEvent = (0, _react.useMemo)(() => ({
288
+ index: selectedIndex,
289
+ label: `#${chronologicalNumber}`,
290
+ timestamp: formatTimestamp(change.timestamp),
291
+ relativeTime: (0, _sharedUi.formatRelativeTime)(new Date(change.timestamp)),
292
+ badge: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
293
+ style: [styles.changeBadgeSmall, {
294
+ backgroundColor: `${atomColor}20`
295
+ }],
296
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
297
+ style: [styles.changeTextSmall, {
298
+ color: atomColor
299
+ }],
300
+ children: changeLabel
301
+ })
302
+ })
303
+ }), [selectedIndex, change.timestamp, atomColor, changeLabel, chronologicalNumber]);
304
+ const renderValueView = (0, _react.useCallback)(() => {
305
+ const parsed = (0, _sharedUi.parseValue)(change.nextValue);
306
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
307
+ style: styles.contentCard,
308
+ testID: `${_testIDs.JOTAI_TEST_ID}-value-card`,
309
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
310
+ style: styles.valueHeader,
311
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
312
+ style: styles.valueLabel,
313
+ children: "VALUE AFTER CHANGE"
314
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
315
+ style: styles.valueHeaderBadges,
316
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
317
+ style: [styles.changeBadge, {
318
+ backgroundColor: `${atomColor}20`
319
+ }],
320
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
321
+ style: [styles.changeText, {
322
+ color: atomColor
323
+ }],
324
+ children: changeLabel
325
+ })
326
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
327
+ style: styles.typeBadge,
328
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
329
+ style: styles.typeText,
330
+ testID: `${_testIDs.JOTAI_TEST_ID}-value-type`,
331
+ children: valueType.toUpperCase()
332
+ })
333
+ })]
334
+ })]
335
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
336
+ style: infoStyles.dataViewerContainer,
337
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.DataViewer, {
338
+ title: "",
339
+ data: parsed,
340
+ showTypeFilter: true,
341
+ rawMode: true,
342
+ initialExpanded: true
343
+ })
344
+ })]
345
+ });
346
+ }, [change.nextValue, atomColor, changeLabel, valueType]);
347
+ const renderDiffContent = (0, _react.useCallback)(() => {
348
+ const prevVal = (0, _sharedUi.parseValue)(change.prevValue);
349
+ const nextVal = (0, _sharedUi.parseValue)(change.nextValue);
350
+ if (diffMode === "split") {
351
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
352
+ style: {
353
+ flex: 1
354
+ },
355
+ showsVerticalScrollIndicator: true,
356
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.SplitDiffViewer, {
357
+ oldValue: prevVal,
358
+ newValue: nextVal,
359
+ theme: _dataViewer.diffThemes.devToolsDefault,
360
+ options: {
361
+ hideLineNumbers: false,
362
+ disableWordDiff: false,
363
+ showDiffOnly: false,
364
+ compareMethod: "words",
365
+ contextLines: 3
366
+ },
367
+ showThemeName: false
368
+ })
369
+ });
370
+ }
371
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.TreeDiffViewer, {
372
+ oldValue: prevVal,
373
+ newValue: nextVal
374
+ });
375
+ }, [change.prevValue, change.nextValue, diffMode]);
376
+ const handleFooterPrevious = (0, _react.useCallback)(() => {
377
+ onIndexChange(Math.min(totalChanges - 1, selectedIndex + 1));
378
+ }, [selectedIndex, totalChanges, onIndexChange]);
379
+ const handleFooterNext = (0, _react.useCallback)(() => {
380
+ onIndexChange(Math.max(0, selectedIndex - 1));
381
+ }, [selectedIndex, onIndexChange]);
382
+
383
+ // The diff compares THIS change's prevValue/nextValue — no siblings needed.
384
+ // Gating on `changes.length` greyed DIFF out for every jotai event opened
385
+ // from the Events timeline (a one-element array). Only a change with no
386
+ // captured previous value has nothing to compare.
387
+ const diffDisabled = change.prevValue === undefined;
388
+ const showInternalFooter = !disableInternalFooter && totalChanges > 1;
389
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
390
+ style: styles.container,
391
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.DetailViewToggle, {
392
+ views: VIEW_CONFIGS,
393
+ activeView: activeView,
394
+ onViewChange: setActiveView,
395
+ disabledKeys: diffDisabled ? DIFF_DISABLED : undefined,
396
+ testIDPrefix: _testIDs.JOTAI_TEST_ID
397
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
398
+ style: [styles.contentArea, showInternalFooter && styles.contentAreaFooterPad],
399
+ children: [activeView === "change" && /*#__PURE__*/(0, _jsxRuntime.jsx)(JotaiAtomInfoView, {
400
+ change: change
401
+ }), activeView === "value" && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
402
+ style: styles.stateContainer,
403
+ children: renderValueView()
404
+ }), activeView === "diff" && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
405
+ style: styles.diffContainer,
406
+ testID: `${_testIDs.JOTAI_TEST_ID}-diff`,
407
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.DiffModeTabs, {
408
+ tabs: DIFF_MODE_TABS,
409
+ activeTab: diffMode,
410
+ onTabChange: setDiffMode,
411
+ testIDPrefix: `${_testIDs.JOTAI_TEST_ID}-diff-tab`
412
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CompareBar, {
413
+ leftEvent: leftEvent,
414
+ rightEvent: rightEvent
415
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
416
+ style: styles.diffContent,
417
+ testID: `${_testIDs.JOTAI_TEST_ID}-diff-content`,
418
+ children: renderDiffContent()
419
+ })]
420
+ })]
421
+ }), showInternalFooter && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
422
+ currentIndex: chronologicalNumber - 1,
423
+ totalItems: totalChanges,
424
+ onPrevious: handleFooterPrevious,
425
+ onNext: handleFooterNext,
426
+ itemLabel: "Change",
427
+ subtitle: (0, _sharedUi.formatRelativeTime)(new Date(change.timestamp)),
428
+ absolute: true
429
+ })]
430
+ });
431
+ }
432
+ function JotaiAtomDetailFooter({
433
+ change,
434
+ changes,
435
+ selectedIndex,
436
+ onIndexChange
437
+ }) {
438
+ const totalChanges = changes.length;
439
+ if (totalChanges <= 1) return null;
440
+ const chronologicalNumber = totalChanges - selectedIndex;
441
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
442
+ currentIndex: chronologicalNumber - 1,
443
+ totalItems: totalChanges,
444
+ onPrevious: () => onIndexChange(Math.min(totalChanges - 1, selectedIndex + 1)),
445
+ onNext: () => onIndexChange(Math.max(0, selectedIndex - 1)),
446
+ itemLabel: "Change",
447
+ subtitle: (0, _sharedUi.formatRelativeTime)(new Date(change.timestamp))
448
+ });
449
+ }
450
+ const styles = _reactNative.StyleSheet.create({
451
+ container: {
452
+ flex: 1,
453
+ // Transparent so the night sheet's star field shows through.
454
+ backgroundColor: "transparent"
455
+ },
456
+ contentArea: {
457
+ flex: 1
458
+ },
459
+ // Clearance for the absolute EventStepperFooter — only when it renders,
460
+ // otherwise hosts like the Events tool get a dead band at the sheet bottom.
461
+ contentAreaFooterPad: {
462
+ paddingBottom: 96
463
+ },
464
+ stateContainer: {
465
+ flex: 1,
466
+ padding: 14
467
+ },
468
+ contentCard: {
469
+ backgroundColor: _sharedUi.night.color.surface,
470
+ borderRadius: 14,
471
+ padding: 14,
472
+ borderWidth: 1,
473
+ borderColor: _sharedUi.night.color.border
474
+ },
475
+ valueHeader: {
476
+ flexDirection: "row",
477
+ alignItems: "center",
478
+ justifyContent: "space-between",
479
+ marginBottom: 8
480
+ },
481
+ valueLabel: {
482
+ fontSize: 10,
483
+ color: _sharedUi.night.color.textSecondary,
484
+ fontFamily: _sharedUi.monoFont,
485
+ letterSpacing: 0.5,
486
+ fontWeight: "600"
487
+ },
488
+ valueHeaderBadges: {
489
+ flexDirection: "row",
490
+ alignItems: "center",
491
+ gap: 6
492
+ },
493
+ changeBadge: {
494
+ paddingHorizontal: 8,
495
+ paddingVertical: 2,
496
+ borderRadius: 4
497
+ },
498
+ changeText: {
499
+ fontSize: 9,
500
+ fontWeight: "700",
501
+ fontFamily: _sharedUi.monoFont,
502
+ letterSpacing: 0.3
503
+ },
504
+ typeBadge: {
505
+ paddingHorizontal: 8,
506
+ paddingVertical: 2,
507
+ borderRadius: 4,
508
+ backgroundColor: _sharedUi.night.color.surfaceElevated
509
+ },
510
+ typeText: {
511
+ fontSize: 9,
512
+ fontWeight: "600",
513
+ color: _sharedUi.night.color.textTertiary,
514
+ fontFamily: _sharedUi.monoFont
515
+ },
516
+ valueBox: {
517
+ // Inset code box — darker than the card, the night track color.
518
+ backgroundColor: _sharedUi.night.color.bg,
519
+ borderRadius: 6,
520
+ borderWidth: 1,
521
+ borderColor: _sharedUi.night.color.border,
522
+ padding: 8
523
+ },
524
+ valueText: {
525
+ fontSize: 12,
526
+ color: _sharedUi.night.color.text,
527
+ fontFamily: _sharedUi.monoFont,
528
+ lineHeight: 18
529
+ },
530
+ diffContainer: {
531
+ flex: 1
532
+ },
533
+ diffContent: {
534
+ flex: 1,
535
+ paddingHorizontal: 14
536
+ },
537
+ changeBadgeSmall: {
538
+ paddingHorizontal: 6,
539
+ paddingVertical: 1,
540
+ borderRadius: 3
541
+ },
542
+ changeTextSmall: {
543
+ fontSize: 8,
544
+ fontWeight: "700",
545
+ fontFamily: _sharedUi.monoFont
546
+ }
547
+ });
548
+ const infoStyles = _reactNative.StyleSheet.create({
549
+ container: {
550
+ flex: 1
551
+ },
552
+ content: {
553
+ padding: 8,
554
+ paddingBottom: 100,
555
+ gap: 16
556
+ },
557
+ card: {
558
+ backgroundColor: _sharedUi.night.color.surface,
559
+ borderRadius: 6,
560
+ borderWidth: 1,
561
+ borderColor: _sharedUi.night.color.accentBorderStrong,
562
+ overflow: "hidden",
563
+ shadowColor: _sharedUi.night.color.accent,
564
+ shadowOffset: {
565
+ width: 0,
566
+ height: 0
567
+ },
568
+ shadowOpacity: 0.1,
569
+ shadowRadius: 6
570
+ },
571
+ sectionHeader: {
572
+ flexDirection: "row",
573
+ alignItems: "center",
574
+ justifyContent: "space-between",
575
+ paddingHorizontal: 12,
576
+ paddingVertical: 10,
577
+ borderBottomWidth: 1,
578
+ borderBottomColor: _sharedUi.night.color.accentBorder,
579
+ backgroundColor: _sharedUi.night.color.accentSoft
580
+ },
581
+ sectionHeaderLeft: {
582
+ flexDirection: "row",
583
+ alignItems: "center",
584
+ gap: 6
585
+ },
586
+ sectionTitle: {
587
+ fontSize: 12,
588
+ fontWeight: "600",
589
+ letterSpacing: 0.5,
590
+ color: _sharedUi.night.color.accent,
591
+ fontFamily: _sharedUi.monoFont
592
+ },
593
+ cardContent: {
594
+ padding: 14,
595
+ gap: 10
596
+ },
597
+ infoRow: {
598
+ flexDirection: "row",
599
+ alignItems: "center",
600
+ justifyContent: "space-between"
601
+ },
602
+ infoLabel: {
603
+ fontSize: 11,
604
+ color: _sharedUi.night.color.textTertiary,
605
+ fontWeight: "500"
606
+ },
607
+ infoValue: {
608
+ fontSize: 11,
609
+ color: _sharedUi.night.color.text,
610
+ fontWeight: "500",
611
+ flex: 1,
612
+ textAlign: "right",
613
+ marginLeft: 12
614
+ },
615
+ infoValueMono: {
616
+ fontFamily: _sharedUi.monoFont
617
+ },
618
+ badgeRow: {
619
+ flexDirection: "row",
620
+ flexWrap: "wrap",
621
+ gap: 8,
622
+ marginTop: 6
623
+ },
624
+ categoryBadge: {
625
+ paddingHorizontal: 8,
626
+ paddingVertical: 3,
627
+ borderRadius: 4
628
+ },
629
+ categoryText: {
630
+ fontSize: 9,
631
+ fontWeight: "700",
632
+ letterSpacing: 0.3
633
+ },
634
+ changesBadge: {
635
+ flexDirection: "row",
636
+ alignItems: "center",
637
+ gap: 4,
638
+ paddingHorizontal: 8,
639
+ paddingVertical: 3,
640
+ borderRadius: 4,
641
+ backgroundColor: _sharedUi.buoyColors.success + "26"
642
+ },
643
+ changesText: {
644
+ fontSize: 9,
645
+ fontWeight: "600",
646
+ color: _sharedUi.buoyColors.success
647
+ },
648
+ noChangesBadge: {
649
+ paddingHorizontal: 8,
650
+ paddingVertical: 3,
651
+ borderRadius: 4,
652
+ backgroundColor: _sharedUi.night.color.surfaceElevated
653
+ },
654
+ noChangesText: {
655
+ fontSize: 9,
656
+ fontWeight: "600",
657
+ color: _sharedUi.night.color.textTertiary
658
+ },
659
+ keysContainer: {
660
+ flexDirection: "row",
661
+ flexWrap: "wrap",
662
+ gap: 6
663
+ },
664
+ keyBadge: {
665
+ paddingHorizontal: 8,
666
+ paddingVertical: 4,
667
+ borderRadius: 4,
668
+ backgroundColor: _sharedUi.night.color.accentSoft,
669
+ borderWidth: 1,
670
+ borderColor: _sharedUi.night.color.accentBorder
671
+ },
672
+ keyText: {
673
+ fontSize: 11,
674
+ fontWeight: "600",
675
+ color: _sharedUi.night.color.accent,
676
+ fontFamily: _sharedUi.monoFont
677
+ },
678
+ countBadge: {
679
+ paddingHorizontal: 8,
680
+ paddingVertical: 3,
681
+ borderRadius: 4,
682
+ backgroundColor: _sharedUi.night.color.accentFill
683
+ },
684
+ countText: {
685
+ fontSize: 9,
686
+ fontWeight: "700",
687
+ color: _sharedUi.night.color.accent,
688
+ fontFamily: _sharedUi.monoFont
689
+ },
690
+ actionsRow: {
691
+ flexDirection: "row",
692
+ gap: 12
693
+ },
694
+ actionButton: {
695
+ paddingHorizontal: 14,
696
+ paddingVertical: 8,
697
+ borderRadius: 8,
698
+ borderWidth: 1
699
+ },
700
+ actionButtonCopy: {
701
+ borderColor: _sharedUi.night.color.accentBorder,
702
+ backgroundColor: _sharedUi.night.color.accentSoft
703
+ },
704
+ actionButtonText: {
705
+ fontSize: 10,
706
+ fontWeight: "700",
707
+ fontFamily: _sharedUi.monoFont,
708
+ letterSpacing: 0.3
709
+ },
710
+ dataViewerContainer: {
711
+ marginTop: -12,
712
+ marginHorizontal: -12,
713
+ marginBottom: -12
714
+ }
715
+ });