@buoy-gg/highlight-updates 2.1.9 → 2.1.11

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 (65) hide show
  1. package/lib/commonjs/highlight-updates/HighlightUpdatesOverlay.js +285 -1
  2. package/lib/commonjs/highlight-updates/components/HighlightFilterView.js +1371 -1
  3. package/lib/commonjs/highlight-updates/components/HighlightUpdatesModal.js +591 -1
  4. package/lib/commonjs/highlight-updates/components/IdentifierBadge.js +267 -1
  5. package/lib/commonjs/highlight-updates/components/IsolatedRenderList.js +178 -1
  6. package/lib/commonjs/highlight-updates/components/ModalHeaderContent.js +303 -1
  7. package/lib/commonjs/highlight-updates/components/RenderCauseBadge.js +500 -1
  8. package/lib/commonjs/highlight-updates/components/RenderDetailView.js +830 -1
  9. package/lib/commonjs/highlight-updates/components/RenderHistoryViewer.js +894 -1
  10. package/lib/commonjs/highlight-updates/components/RenderListItem.js +220 -1
  11. package/lib/commonjs/highlight-updates/components/StatsDisplay.js +70 -1
  12. package/lib/commonjs/highlight-updates/components/index.js +97 -1
  13. package/lib/commonjs/highlight-updates/utils/HighlightUpdatesController.js +1435 -1
  14. package/lib/commonjs/highlight-updates/utils/PerformanceLogger.js +359 -1
  15. package/lib/commonjs/highlight-updates/utils/ProfilerInterceptor.js +371 -1
  16. package/lib/commonjs/highlight-updates/utils/RenderCauseDetector.js +1828 -1
  17. package/lib/commonjs/highlight-updates/utils/RenderTracker.js +903 -1
  18. package/lib/commonjs/highlight-updates/utils/ViewTypeMapper.js +264 -1
  19. package/lib/commonjs/highlight-updates/utils/renderExportFormatter.js +58 -1
  20. package/lib/commonjs/index.js +311 -1
  21. package/lib/commonjs/preset.js +278 -1
  22. package/lib/module/highlight-updates/HighlightUpdatesOverlay.js +278 -1
  23. package/lib/module/highlight-updates/components/HighlightFilterView.js +1365 -1
  24. package/lib/module/highlight-updates/components/HighlightUpdatesModal.js +585 -1
  25. package/lib/module/highlight-updates/components/IdentifierBadge.js +259 -1
  26. package/lib/module/highlight-updates/components/IsolatedRenderList.js +174 -1
  27. package/lib/module/highlight-updates/components/ModalHeaderContent.js +298 -1
  28. package/lib/module/highlight-updates/components/RenderCauseBadge.js +491 -1
  29. package/lib/module/highlight-updates/components/RenderDetailView.js +826 -1
  30. package/lib/module/highlight-updates/components/RenderHistoryViewer.js +888 -1
  31. package/lib/module/highlight-updates/components/RenderListItem.js +215 -1
  32. package/lib/module/highlight-updates/components/StatsDisplay.js +67 -1
  33. package/lib/module/highlight-updates/components/index.js +16 -1
  34. package/lib/module/highlight-updates/utils/HighlightUpdatesController.js +1431 -1
  35. package/lib/module/highlight-updates/utils/PerformanceLogger.js +353 -1
  36. package/lib/module/highlight-updates/utils/ProfilerInterceptor.js +358 -1
  37. package/lib/module/highlight-updates/utils/RenderCauseDetector.js +1818 -1
  38. package/lib/module/highlight-updates/utils/RenderTracker.js +900 -1
  39. package/lib/module/highlight-updates/utils/ViewTypeMapper.js +255 -1
  40. package/lib/module/highlight-updates/utils/renderExportFormatter.js +54 -1
  41. package/lib/module/index.js +71 -1
  42. package/lib/module/preset.js +272 -1
  43. package/lib/typescript/highlight-updates/HighlightUpdatesOverlay.d.ts.map +1 -0
  44. package/lib/typescript/highlight-updates/components/HighlightFilterView.d.ts.map +1 -0
  45. package/lib/typescript/highlight-updates/components/HighlightUpdatesModal.d.ts.map +1 -0
  46. package/lib/typescript/highlight-updates/components/IdentifierBadge.d.ts.map +1 -0
  47. package/lib/typescript/highlight-updates/components/IsolatedRenderList.d.ts.map +1 -0
  48. package/lib/typescript/highlight-updates/components/ModalHeaderContent.d.ts.map +1 -0
  49. package/lib/typescript/highlight-updates/components/RenderCauseBadge.d.ts.map +1 -0
  50. package/lib/typescript/highlight-updates/components/RenderDetailView.d.ts.map +1 -0
  51. package/lib/typescript/highlight-updates/components/RenderHistoryViewer.d.ts.map +1 -0
  52. package/lib/typescript/highlight-updates/components/RenderListItem.d.ts.map +1 -0
  53. package/lib/typescript/highlight-updates/components/StatsDisplay.d.ts.map +1 -0
  54. package/lib/typescript/highlight-updates/components/index.d.ts.map +1 -0
  55. package/lib/typescript/highlight-updates/utils/HighlightUpdatesController.d.ts.map +1 -0
  56. package/lib/typescript/highlight-updates/utils/PerformanceLogger.d.ts.map +1 -0
  57. package/lib/typescript/highlight-updates/utils/ProfilerInterceptor.d.ts.map +1 -0
  58. package/lib/typescript/highlight-updates/utils/RenderCauseDetector.d.ts.map +1 -0
  59. package/lib/typescript/highlight-updates/utils/RenderTracker.d.ts.map +1 -0
  60. package/lib/typescript/highlight-updates/utils/ViewTypeMapper.d.ts.map +1 -0
  61. package/lib/typescript/highlight-updates/utils/renderExportFormatter.d.ts.map +1 -0
  62. package/lib/typescript/index.d.ts.map +1 -0
  63. package/lib/typescript/preset.d.ts.map +1 -0
  64. package/package.json +16 -16
  65. package/LICENSE +0 -58
@@ -1 +1,830 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.RenderDetailView=RenderDetailView,exports.default=void 0;var _react=_interopRequireWildcard(require("react")),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_dataViewer=require("@buoy-gg/shared-ui/dataViewer"),_RenderCauseBadge=require("./RenderCauseBadge"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireWildcard(e,t){if("function"==typeof WeakMap)var r=new WeakMap,s=new WeakMap;return(_interopRequireWildcard=function(e,t){if(!t&&e&&e.__esModule)return e;var i,o,a={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return a;if(i=t?s:r){if(i.has(e))return i.get(e);i.set(e,a)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((o=(i=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(o.get||o.set)?i(a,t,o):a[t]=e[t]);return a})(e,t)}function formatRenderDetailForClipboard(e){const t=[];if(t.push(`${e.componentName||e.displayName} (${e.viewType})`),t.push(`Renders: ${e.renderCount}`),e.lastRenderCause){const r=e.lastRenderCause;if(r.componentCause?t.push(`Cause: ${r.componentCause.toUpperCase()} → ${r.type.toUpperCase()}`):t.push(`Cause: ${r.type.toUpperCase()}`),r.hookChanges?.length)for(const e of r.hookChanges)t.push(` ${e.type}[${e.index}]: ${e.previousValue} → ${e.currentValue}`)}if(e.renderHistory?.length){t.push(`\nHistory (${e.renderHistory.length} events):`);for(const r of e.renderHistory){const e=r.cause.componentCause?`${r.cause.componentCause.toUpperCase()} → ${r.cause.type.toUpperCase()}`:r.cause.type.toUpperCase();t.push(` #${r.renderNumber}: ${e}`)}}return t.join("\n")}const FREE_TIER_EVENT_LIMIT=5;function RenderDetailView({render:e,disableInternalFooter:t=!1,selectedEventIndex:r,onEventIndexChange:s,onAddFilter:i,isPro:o=!1}){const[a,n]=(0,_react.useState)(0),l=r??a,d=s??n,c=(0,_react.useMemo)(()=>e.renderHistory&&0!==e.renderHistory.length?[...e.renderHistory].sort((e,t)=>e.timestamp-t.timestamp):[],[e.renderHistory]),u=c.length,y=c[l],x=(0,_react.useMemo)(()=>o?0:Math.max(0,u-FREE_TIER_EVENT_LIMIT),[o,u]),_=y?.cause||e.lastRenderCause,h=(0,_react.useCallback)(()=>{l>0&&d(l-1)},[l,d]),m=(0,_react.useCallback)(()=>{const e=o?u-1:Math.min(FREE_TIER_EVENT_LIMIT-1,u-1);l<e&&d(l+1)},[l,u,d,o]),p=(0,_react.useMemo)(()=>formatRenderDetailForClipboard(e),[e]),b=e.componentName||e.displayName,C=e.viewType,j=e.lastRenderTime-e.firstRenderTime,g=j>0?(e.renderCount/(j/1e3)).toFixed(1):e.renderCount.toString(),f=!t&&u>1;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.container,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.header,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.headerLeft,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.componentName,numberOfLines:1,children:b}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.nativeTypeBadge,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.nativeTypeText,children:C})})]}),(0,_jsxRuntime.jsx)(_sharedUi.CopyButton,{value:p,size:14})]}),(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.scrollView,contentContainerStyle:[styles.scrollContent,f&&{paddingBottom:100}],showsVerticalScrollIndicator:!1,children:[_&&(0,_jsxRuntime.jsx)(AnswerCard,{cause:_,renderNumber:y?.renderNumber}),(0,_jsxRuntime.jsx)(DetailsSection,{render:e,rendersPerSec:g}),x>0&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.lockedBanner,children:[(0,_jsxRuntime.jsx)(_sharedUi.Lock,{size:14,color:_sharedUi.buoyColors.warning}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.lockedBannerText,children:[x," ",1===x?"event":"events"," hidden"]}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.lockedBannerSubtext,children:"Upgrade to Pro"})]}),i&&(0,_jsxRuntime.jsx)(QuickActionsSection,{render:e,onAddFilter:i})]}),f&&(0,_jsxRuntime.jsx)(_sharedUi.EventStepperFooter,{currentIndex:l,totalItems:u,onPrevious:h,onNext:m,itemLabel:"Render",subtitle:y?.timestamp?(0,_sharedUi.formatRelativeTime)(new Date(y.timestamp)):void 0,applySafeAreaInset:!1,absolute:!0})]})}function AnswerCard({cause:e,renderNumber:t}){const r=e.componentCause||e.type,s=e.componentCause?_RenderCauseBadge.COMPONENT_CAUSE_CONFIG[e.componentCause]:_RenderCauseBadge.CAUSE_CONFIG[e.type],i=e.hookChanges&&e.hookChanges.length>0,o=e.changedKeys&&e.changedKeys.length>0;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.answerCard,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.causeBadgeRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.causeLabel,children:"mount"===e.type?"First render":"parent"===r?"Triggered by":"Changed:"}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.causeBadgeLarge,{backgroundColor:s.color+"20"}],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.causeBadgeLargeText,{color:s.color}],children:s.label.toUpperCase()})})]}),i&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.hookChangesContainer,children:e.hookChanges.map((e,t)=>{const r=`${e.type}[${e.index}]`,s={[r]:e.previousValue},i={[r]:e.currentValue};return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.hookDiffContainer,children:(0,_jsxRuntime.jsx)(_dataViewer.TreeDiffViewer,{oldValue:s,newValue:i,theme:"dark",showUnchanged:!1})},t)})}),!i&&o&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.propsChangesContainer,children:e.changedKeys.filter(e=>!e.includes("(ref only)")).slice(0,5).map((e,t)=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.propChangeChip,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.propChangeText,children:e})},t))})]})}function DetailsSection({render:e,rendersPerSec:t}){const r=e.testID||e.nativeID||e.accessibilityLabel,s=e.measurements;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.detailsSection,children:[r&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.detailsCard,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detailsCardTitle,children:"Identifiers"}),e.testID&&(0,_jsxRuntime.jsx)(DetailRow,{label:"testID",value:e.testID}),e.nativeID&&(0,_jsxRuntime.jsx)(DetailRow,{label:"nativeID",value:e.nativeID}),e.accessibilityLabel&&(0,_jsxRuntime.jsx)(DetailRow,{label:"a11y",value:e.accessibilityLabel})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.statsRow,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.statItem,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.statValue,{color:e.color}],children:e.renderCount}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statLabel,children:"renders"})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.statDivider}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.statItem,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statValue,children:t}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statLabel,children:"/sec"})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.statDivider}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.statItem,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statValue,children:e.nativeTag}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statLabel,children:"tag"})]})]}),s&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.measurementsRow,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.measurementItem,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.measurementLabel,children:"x"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.measurementValue,children:Math.round(e.measurements.x)})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.measurementItem,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.measurementLabel,children:"y"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.measurementValue,children:Math.round(e.measurements.y)})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.measurementItem,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.measurementLabel,children:"w"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.measurementValue,children:Math.round(e.measurements.width)})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.measurementItem,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.measurementLabel,children:"h"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.measurementValue,children:Math.round(e.measurements.height)})]})]})]})}function DetailRow({label:e,value:t}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.detailRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detailLabel,children:e}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detailValue,numberOfLines:1,children:t})]})}function QuickActionsSection({render:e,onAddFilter:t}){const[r,s]=(0,_react.useState)(null),i=(0,_react.useMemo)(()=>{const t=[];return e.nativeID&&t.push({type:"nativeID",value:e.nativeID,label:"nativeID"}),e.testID&&t.push({type:"testID",value:e.testID,label:"testID"}),e.accessibilityLabel&&t.push({type:"accessibilityLabel",value:e.accessibilityLabel,label:"a11y"}),e.componentName&&t.push({type:"component",value:e.componentName,label:"component"}),t.push({type:"viewType",value:e.viewType,label:"viewType"}),t},[e]),o=null!==r?i[r]:null,a=(0,_react.useCallback)(e=>{s(t=>t===e?null:e)},[]),n=(0,_react.useCallback)(()=>{o&&(t({type:o.type,value:o.value},"include"),s(null))},[o,t]),l=(0,_react.useCallback)(()=>{o&&(t({type:o.type,value:o.value},"exclude"),s(null))},[o,t]);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.quickActionsSection,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.quickActionsTitle,children:"Quick Filters"}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.filterOptionsList,children:i.map((e,t)=>(0,_jsxRuntime.jsx)(FilterOptionCard,{label:e.label,value:e.value,isSelected:r===t,onSelect:()=>a(t)},e.type))}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.filterActionButtons,children:[(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:[styles.filterActionButton,styles.filterActionButtonInclude,!o&&styles.filterActionButtonDisabled],onPress:n,disabled:!o,activeOpacity:.7,children:[(0,_jsxRuntime.jsx)(_sharedUi.PlusIcon,{size:14,color:o?_sharedUi.buoyColors.success:_sharedUi.buoyColors.textMuted}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.filterActionButtonText,{color:o?_sharedUi.buoyColors.success:_sharedUi.buoyColors.textMuted}],children:"Only Show This"})]}),(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:[styles.filterActionButton,styles.filterActionButtonExclude,!o&&styles.filterActionButtonDisabled],onPress:l,disabled:!o,activeOpacity:.7,children:[(0,_jsxRuntime.jsx)(_sharedUi.MinusIcon,{size:14,color:o?_sharedUi.buoyColors.error:_sharedUi.buoyColors.textMuted}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.filterActionButtonText,{color:o?_sharedUi.buoyColors.error:_sharedUi.buoyColors.textMuted}],children:"Hide This"})]})]})]})}function FilterOptionCard({label:e,value:t,isSelected:r,onSelect:s}){return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:[styles.filterOptionCard,r&&styles.filterOptionCardSelected],onPress:s,activeOpacity:.7,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.filterOptionLabel,r&&styles.filterOptionLabelSelected],children:e}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.filterOptionValue,r&&styles.filterOptionValueSelected],numberOfLines:1,children:t})]})}const styles=_reactNative.StyleSheet.create({container:{flex:1,backgroundColor:_sharedUi.buoyColors.base},header:{flexDirection:"row",alignItems:"center",justifyContent:"center",gap:12,padding:16,paddingBottom:0},scrollView:{flex:1},scrollContent:{padding:16,paddingTop:12,paddingBottom:80,gap:12},headerLeft:{flex:1,flexDirection:"row",alignItems:"center",justifyContent:"center",gap:10},componentName:{fontSize:18,fontWeight:"700",color:_sharedUi.buoyColors.text,flexShrink:1},nativeTypeBadge:{backgroundColor:_sharedUi.buoyColors.input,paddingVertical:3,paddingHorizontal:8,borderRadius:4},nativeTypeText:{fontSize:11,fontWeight:"600",color:_sharedUi.buoyColors.textMuted,fontFamily:"monospace"},answerCard:{backgroundColor:_sharedUi.buoyColors.card,borderRadius:8,borderWidth:1,borderColor:_sharedUi.buoyColors.border,padding:12,gap:6},causeBadgeRow:{flexDirection:"row",alignItems:"center",gap:8},causeBadgeLarge:{paddingVertical:4,paddingHorizontal:10,borderRadius:4},causeBadgeLargeText:{fontSize:11,fontWeight:"700",letterSpacing:.5},causeLabel:{fontSize:12,color:_sharedUi.buoyColors.textSecondary,fontWeight:"500"},hookChangesContainer:{gap:6},hookDiffContainer:{backgroundColor:_sharedUi.buoyColors.input,borderRadius:6,overflow:"hidden"},propsChangesContainer:{flexDirection:"row",flexWrap:"wrap",gap:4},propChangeChip:{backgroundColor:_sharedUi.buoyColors.input,paddingVertical:2,paddingHorizontal:6,borderRadius:4},propChangeText:{fontSize:11,color:_sharedUi.buoyColors.text,fontFamily:"monospace"},detailsSection:{gap:10},detailsCard:{backgroundColor:_sharedUi.buoyColors.card,borderRadius:8,borderWidth:1,borderColor:_sharedUi.buoyColors.border,padding:12,gap:6},detailsCardTitle:{fontSize:10,fontWeight:"600",color:_sharedUi.buoyColors.textMuted,letterSpacing:.5,textTransform:"uppercase",marginBottom:4},detailRow:{flexDirection:"row",alignItems:"center",gap:8},detailLabel:{fontSize:11,fontWeight:"600",color:_sharedUi.buoyColors.textSecondary,minWidth:55},detailValue:{fontSize:12,color:_sharedUi.buoyColors.text,fontFamily:"monospace",flex:1},statsRow:{flexDirection:"row",alignItems:"center",justifyContent:"center",backgroundColor:_sharedUi.buoyColors.card,borderRadius:8,borderWidth:1,borderColor:_sharedUi.buoyColors.border,paddingVertical:10,paddingHorizontal:16},statItem:{flex:1,alignItems:"center"},statValue:{fontSize:16,fontWeight:"700",color:_sharedUi.buoyColors.text,fontFamily:"monospace"},statLabel:{fontSize:10,color:_sharedUi.buoyColors.textMuted,marginTop:2},statDivider:{width:1,height:24,backgroundColor:_sharedUi.buoyColors.border,marginHorizontal:12},measurementsRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-around",backgroundColor:_sharedUi.buoyColors.card,borderRadius:8,borderWidth:1,borderColor:_sharedUi.buoyColors.border,paddingVertical:8,paddingHorizontal:12},measurementItem:{flexDirection:"row",alignItems:"baseline",gap:4},measurementLabel:{fontSize:10,fontWeight:"600",color:_sharedUi.buoyColors.textMuted,textTransform:"uppercase"},measurementValue:{fontSize:12,fontWeight:"600",color:_sharedUi.buoyColors.text,fontFamily:"monospace"},quickActionsSection:{backgroundColor:_sharedUi.buoyColors.card,borderRadius:8,borderWidth:1,borderColor:_sharedUi.buoyColors.border,padding:12,gap:10},quickActionsTitle:{fontSize:10,fontWeight:"600",color:_sharedUi.buoyColors.textMuted,letterSpacing:.5,textTransform:"uppercase",marginBottom:2},filterOptionsList:{gap:6},filterOptionCard:{flexDirection:"row",alignItems:"center",backgroundColor:_sharedUi.buoyColors.input,borderRadius:6,paddingVertical:10,paddingHorizontal:12,borderWidth:1,borderColor:"transparent",gap:10},filterOptionCardSelected:{borderColor:_sharedUi.buoyColors.success,backgroundColor:_sharedUi.buoyColors.success+"15"},filterOptionLabel:{fontSize:10,fontWeight:"600",color:_sharedUi.buoyColors.textMuted,minWidth:70},filterOptionLabelSelected:{color:_sharedUi.buoyColors.success},filterOptionValue:{fontSize:12,color:_sharedUi.buoyColors.text,fontFamily:"monospace",flex:1},filterOptionValueSelected:{color:_sharedUi.buoyColors.text},filterActionButtons:{flexDirection:"row",gap:8,marginTop:12},filterActionButton:{flexDirection:"row",alignItems:"center",justifyContent:"center",gap:4,paddingVertical:8,paddingHorizontal:10,borderRadius:6,borderWidth:1},filterActionButtonInclude:{backgroundColor:_sharedUi.buoyColors.success+"15",borderColor:_sharedUi.buoyColors.success+"40"},filterActionButtonExclude:{backgroundColor:_sharedUi.buoyColors.error+"15",borderColor:_sharedUi.buoyColors.error+"40"},filterActionButtonDisabled:{backgroundColor:_sharedUi.buoyColors.input,borderColor:_sharedUi.buoyColors.border,opacity:.5},filterActionButtonText:{fontSize:11,fontWeight:"600"},lockedBanner:{flexDirection:"row",alignItems:"center",justifyContent:"center",backgroundColor:_sharedUi.buoyColors.card,borderRadius:8,borderWidth:1,borderColor:_sharedUi.buoyColors.warning+"40",paddingVertical:12,paddingHorizontal:16,gap:8},lockedBannerText:{color:_sharedUi.buoyColors.warning,fontSize:13,fontWeight:"600"},lockedBannerSubtext:{color:_sharedUi.buoyColors.textMuted,fontSize:12}});var _default=exports.default=RenderDetailView;
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.RenderDetailView = RenderDetailView;
7
+ exports.default = void 0;
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 _RenderCauseBadge = require("./RenderCauseBadge");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ 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); }
15
+ /**
16
+ * RenderDetailView
17
+ *
18
+ * Minimal, glanceable view for render details.
19
+ * Design principle: Dev should understand WHY in 3 seconds.
20
+ *
21
+ * Layout:
22
+ * - Header: Component name + native type
23
+ * - Answer Card: Cause badges + hook change (THE answer)
24
+ * - History Row: Compact inline navigation
25
+ */
26
+
27
+ /**
28
+ * Format component render data for clipboard
29
+ */function formatRenderDetailForClipboard(render) {
30
+ const lines = [];
31
+ lines.push(`${render.componentName || render.displayName} (${render.viewType})`);
32
+ lines.push(`Renders: ${render.renderCount}`);
33
+ if (render.lastRenderCause) {
34
+ const cause = render.lastRenderCause;
35
+ if (cause.componentCause) {
36
+ lines.push(`Cause: ${cause.componentCause.toUpperCase()} → ${cause.type.toUpperCase()}`);
37
+ } else {
38
+ lines.push(`Cause: ${cause.type.toUpperCase()}`);
39
+ }
40
+ if (cause.hookChanges?.length) {
41
+ for (const hook of cause.hookChanges) {
42
+ lines.push(` ${hook.type}[${hook.index}]: ${hook.previousValue} → ${hook.currentValue}`);
43
+ }
44
+ }
45
+ }
46
+ if (render.renderHistory?.length) {
47
+ lines.push(`\nHistory (${render.renderHistory.length} events):`);
48
+ for (const event of render.renderHistory) {
49
+ const causeStr = event.cause.componentCause ? `${event.cause.componentCause.toUpperCase()} → ${event.cause.type.toUpperCase()}` : event.cause.type.toUpperCase();
50
+ lines.push(` #${event.renderNumber}: ${causeStr}`);
51
+ }
52
+ }
53
+ return lines.join("\n");
54
+ }
55
+ // Free tier limit for render history events
56
+ const FREE_TIER_EVENT_LIMIT = 5;
57
+ function RenderDetailView({
58
+ render,
59
+ disableInternalFooter = false,
60
+ selectedEventIndex: externalIndex,
61
+ onEventIndexChange: externalOnChange,
62
+ onAddFilter,
63
+ isPro = false
64
+ }) {
65
+ // Internal state for event index when not controlled externally
66
+ const [internalIndex, setInternalIndex] = (0, _react.useState)(0);
67
+
68
+ // Use external or internal state
69
+ const selectedEventIndex = externalIndex ?? internalIndex;
70
+ const onEventIndexChange = externalOnChange ?? setInternalIndex;
71
+
72
+ // Get events sorted by timestamp (oldest first)
73
+ const events = (0, _react.useMemo)(() => {
74
+ if (!render.renderHistory || render.renderHistory.length === 0) {
75
+ return [];
76
+ }
77
+ return [...render.renderHistory].sort((a, b) => a.timestamp - b.timestamp);
78
+ }, [render.renderHistory]);
79
+ const totalEvents = events.length;
80
+ const currentEvent = events[selectedEventIndex];
81
+
82
+ // Calculate hidden events for free tier
83
+ const hiddenEventCount = (0, _react.useMemo)(() => {
84
+ if (isPro) return 0;
85
+ return Math.max(0, totalEvents - FREE_TIER_EVENT_LIMIT);
86
+ }, [isPro, totalEvents]);
87
+
88
+ // Use current event's cause if available, otherwise fall back to lastRenderCause
89
+ const displayCause = currentEvent?.cause || render.lastRenderCause;
90
+
91
+ // Navigation handlers
92
+ const goToPrevious = (0, _react.useCallback)(() => {
93
+ if (selectedEventIndex > 0) {
94
+ onEventIndexChange(selectedEventIndex - 1);
95
+ }
96
+ }, [selectedEventIndex, onEventIndexChange]);
97
+ const goToNext = (0, _react.useCallback)(() => {
98
+ // Limit navigation for free tier users
99
+ const maxIndex = isPro ? totalEvents - 1 : Math.min(FREE_TIER_EVENT_LIMIT - 1, totalEvents - 1);
100
+ if (selectedEventIndex < maxIndex) {
101
+ onEventIndexChange(selectedEventIndex + 1);
102
+ }
103
+ }, [selectedEventIndex, totalEvents, onEventIndexChange, isPro]);
104
+
105
+ // Memoize copy data
106
+ const copyData = (0, _react.useMemo)(() => formatRenderDetailForClipboard(render), [render]);
107
+
108
+ // Get component name (prefer componentName, fall back to displayName)
109
+ const componentName = render.componentName || render.displayName;
110
+ const nativeType = render.viewType;
111
+
112
+ // Calculate render stats
113
+ const renderDuration = render.lastRenderTime - render.firstRenderTime;
114
+ const rendersPerSec = renderDuration > 0 ? (render.renderCount / (renderDuration / 1000)).toFixed(1) : render.renderCount.toString();
115
+
116
+ // Determine if we should show footer (either history or filters)
117
+ const showHistoryFooter = !disableInternalFooter && totalEvents > 1;
118
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
119
+ style: styles.container,
120
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
121
+ style: styles.header,
122
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
123
+ style: styles.headerLeft,
124
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
125
+ style: styles.componentName,
126
+ numberOfLines: 1,
127
+ children: componentName
128
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
129
+ style: styles.nativeTypeBadge,
130
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
131
+ style: styles.nativeTypeText,
132
+ children: nativeType
133
+ })
134
+ })]
135
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.CopyButton, {
136
+ value: copyData,
137
+ size: 14
138
+ })]
139
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
140
+ style: styles.scrollView,
141
+ contentContainerStyle: [styles.scrollContent, showHistoryFooter && {
142
+ paddingBottom: 100
143
+ }],
144
+ showsVerticalScrollIndicator: false,
145
+ children: [displayCause && /*#__PURE__*/(0, _jsxRuntime.jsx)(AnswerCard, {
146
+ cause: displayCause,
147
+ renderNumber: currentEvent?.renderNumber
148
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(DetailsSection, {
149
+ render: render,
150
+ rendersPerSec: rendersPerSec
151
+ }), hiddenEventCount > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
152
+ style: styles.lockedBanner,
153
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Lock, {
154
+ size: 14,
155
+ color: _sharedUi.buoyColors.warning
156
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
157
+ style: styles.lockedBannerText,
158
+ children: [hiddenEventCount, " ", hiddenEventCount === 1 ? 'event' : 'events', " hidden"]
159
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
160
+ style: styles.lockedBannerSubtext,
161
+ children: "Upgrade to Pro"
162
+ })]
163
+ }), onAddFilter && /*#__PURE__*/(0, _jsxRuntime.jsx)(QuickActionsSection, {
164
+ render: render,
165
+ onAddFilter: onAddFilter
166
+ })]
167
+ }), showHistoryFooter && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
168
+ currentIndex: selectedEventIndex,
169
+ totalItems: totalEvents,
170
+ onPrevious: goToPrevious,
171
+ onNext: goToNext,
172
+ itemLabel: "Render",
173
+ subtitle: currentEvent?.timestamp ? (0, _sharedUi.formatRelativeTime)(new Date(currentEvent.timestamp)) : undefined,
174
+ applySafeAreaInset: false,
175
+ absolute: true
176
+ })]
177
+ });
178
+ }
179
+
180
+ /**
181
+ * AnswerCard - The hero section showing WHY the component rendered
182
+ * Design: Single badge + what changed below it
183
+ */
184
+ function AnswerCard({
185
+ cause,
186
+ renderNumber
187
+ }) {
188
+ // Use component cause if available, otherwise native cause
189
+ const displayCauseType = cause.componentCause || cause.type;
190
+ const config = cause.componentCause ? _RenderCauseBadge.COMPONENT_CAUSE_CONFIG[cause.componentCause] : _RenderCauseBadge.CAUSE_CONFIG[cause.type];
191
+ const hasHookChanges = cause.hookChanges && cause.hookChanges.length > 0;
192
+ const hasChangedKeys = cause.changedKeys && cause.changedKeys.length > 0;
193
+
194
+ // Get contextual label based on cause type
195
+ const getLabel = () => {
196
+ if (cause.type === "mount") return "First render";
197
+ if (displayCauseType === "parent") return "Triggered by";
198
+ return "Changed:";
199
+ };
200
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
201
+ style: styles.answerCard,
202
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
203
+ style: styles.causeBadgeRow,
204
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
205
+ style: styles.causeLabel,
206
+ children: getLabel()
207
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
208
+ style: [styles.causeBadgeLarge, {
209
+ backgroundColor: config.color + "20"
210
+ }],
211
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
212
+ style: [styles.causeBadgeLargeText, {
213
+ color: config.color
214
+ }],
215
+ children: config.label.toUpperCase()
216
+ })
217
+ })]
218
+ }), hasHookChanges && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
219
+ style: styles.hookChangesContainer,
220
+ children: cause.hookChanges.map((hook, index) => {
221
+ const hookKey = `${hook.type}[${hook.index}]`;
222
+ const oldValue = {
223
+ [hookKey]: hook.previousValue
224
+ };
225
+ const newValue = {
226
+ [hookKey]: hook.currentValue
227
+ };
228
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
229
+ style: styles.hookDiffContainer,
230
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_dataViewer.TreeDiffViewer, {
231
+ oldValue: oldValue,
232
+ newValue: newValue,
233
+ theme: "dark",
234
+ showUnchanged: false
235
+ })
236
+ }, index);
237
+ })
238
+ }), !hasHookChanges && hasChangedKeys && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
239
+ style: styles.propsChangesContainer,
240
+ children: cause.changedKeys.filter(k => !k.includes("(ref only)")).slice(0, 5).map((key, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
241
+ style: styles.propChangeChip,
242
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
243
+ style: styles.propChangeText,
244
+ children: key
245
+ })
246
+ }, index))
247
+ })]
248
+ });
249
+ }
250
+
251
+ /**
252
+ * DetailsSection - Component identifiers, measurements, and stats
253
+ * Helps devs find the component in their codebase
254
+ */
255
+ function DetailsSection({
256
+ render,
257
+ rendersPerSec
258
+ }) {
259
+ const hasIdentifiers = render.testID || render.nativeID || render.accessibilityLabel;
260
+ const hasMeasurements = render.measurements;
261
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
262
+ style: styles.detailsSection,
263
+ children: [hasIdentifiers && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
264
+ style: styles.detailsCard,
265
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
266
+ style: styles.detailsCardTitle,
267
+ children: "Identifiers"
268
+ }), render.testID && /*#__PURE__*/(0, _jsxRuntime.jsx)(DetailRow, {
269
+ label: "testID",
270
+ value: render.testID
271
+ }), render.nativeID && /*#__PURE__*/(0, _jsxRuntime.jsx)(DetailRow, {
272
+ label: "nativeID",
273
+ value: render.nativeID
274
+ }), render.accessibilityLabel && /*#__PURE__*/(0, _jsxRuntime.jsx)(DetailRow, {
275
+ label: "a11y",
276
+ value: render.accessibilityLabel
277
+ })]
278
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
279
+ style: styles.statsRow,
280
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
281
+ style: styles.statItem,
282
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
283
+ style: [styles.statValue, {
284
+ color: render.color
285
+ }],
286
+ children: render.renderCount
287
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
288
+ style: styles.statLabel,
289
+ children: "renders"
290
+ })]
291
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
292
+ style: styles.statDivider
293
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
294
+ style: styles.statItem,
295
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
296
+ style: styles.statValue,
297
+ children: rendersPerSec
298
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
299
+ style: styles.statLabel,
300
+ children: "/sec"
301
+ })]
302
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
303
+ style: styles.statDivider
304
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
305
+ style: styles.statItem,
306
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
307
+ style: styles.statValue,
308
+ children: render.nativeTag
309
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
310
+ style: styles.statLabel,
311
+ children: "tag"
312
+ })]
313
+ })]
314
+ }), hasMeasurements && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
315
+ style: styles.measurementsRow,
316
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
317
+ style: styles.measurementItem,
318
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
319
+ style: styles.measurementLabel,
320
+ children: "x"
321
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
322
+ style: styles.measurementValue,
323
+ children: Math.round(render.measurements.x)
324
+ })]
325
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
326
+ style: styles.measurementItem,
327
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
328
+ style: styles.measurementLabel,
329
+ children: "y"
330
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
331
+ style: styles.measurementValue,
332
+ children: Math.round(render.measurements.y)
333
+ })]
334
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
335
+ style: styles.measurementItem,
336
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
337
+ style: styles.measurementLabel,
338
+ children: "w"
339
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
340
+ style: styles.measurementValue,
341
+ children: Math.round(render.measurements.width)
342
+ })]
343
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
344
+ style: styles.measurementItem,
345
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
346
+ style: styles.measurementLabel,
347
+ children: "h"
348
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
349
+ style: styles.measurementValue,
350
+ children: Math.round(render.measurements.height)
351
+ })]
352
+ })]
353
+ })]
354
+ });
355
+ }
356
+
357
+ /**
358
+ * DetailRow - Single row for identifier display
359
+ */
360
+ function DetailRow({
361
+ label,
362
+ value
363
+ }) {
364
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
365
+ style: styles.detailRow,
366
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
367
+ style: styles.detailLabel,
368
+ children: label
369
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
370
+ style: styles.detailValue,
371
+ numberOfLines: 1,
372
+ children: value
373
+ })]
374
+ });
375
+ }
376
+
377
+ /**
378
+ * QuickActionsSection - Quick filter actions for the component
379
+ * Users select a filter option, then use action buttons to include/exclude
380
+ */
381
+ function QuickActionsSection({
382
+ render,
383
+ onAddFilter
384
+ }) {
385
+ const [selectedIndex, setSelectedIndex] = (0, _react.useState)(null);
386
+
387
+ // Build list of available filter options (most specific to most general)
388
+ const filterOptions = (0, _react.useMemo)(() => {
389
+ const options = [];
390
+
391
+ // Most specific first
392
+ if (render.nativeID) {
393
+ options.push({
394
+ type: "nativeID",
395
+ value: render.nativeID,
396
+ label: "nativeID"
397
+ });
398
+ }
399
+ if (render.testID) {
400
+ options.push({
401
+ type: "testID",
402
+ value: render.testID,
403
+ label: "testID"
404
+ });
405
+ }
406
+ if (render.accessibilityLabel) {
407
+ options.push({
408
+ type: "accessibilityLabel",
409
+ value: render.accessibilityLabel,
410
+ label: "a11y"
411
+ });
412
+ }
413
+ if (render.componentName) {
414
+ options.push({
415
+ type: "component",
416
+ value: render.componentName,
417
+ label: "component"
418
+ });
419
+ }
420
+ // Most general last (always available)
421
+ options.push({
422
+ type: "viewType",
423
+ value: render.viewType,
424
+ label: "viewType"
425
+ });
426
+ return options;
427
+ }, [render]);
428
+ const selectedOption = selectedIndex !== null ? filterOptions[selectedIndex] : null;
429
+ const handleSelectOption = (0, _react.useCallback)(index => {
430
+ setSelectedIndex(prev => prev === index ? null : index);
431
+ }, []);
432
+ const handleInclude = (0, _react.useCallback)(() => {
433
+ if (selectedOption) {
434
+ onAddFilter({
435
+ type: selectedOption.type,
436
+ value: selectedOption.value
437
+ }, "include");
438
+ setSelectedIndex(null);
439
+ }
440
+ }, [selectedOption, onAddFilter]);
441
+ const handleExclude = (0, _react.useCallback)(() => {
442
+ if (selectedOption) {
443
+ onAddFilter({
444
+ type: selectedOption.type,
445
+ value: selectedOption.value
446
+ }, "exclude");
447
+ setSelectedIndex(null);
448
+ }
449
+ }, [selectedOption, onAddFilter]);
450
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
451
+ style: styles.quickActionsSection,
452
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
453
+ style: styles.quickActionsTitle,
454
+ children: "Quick Filters"
455
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
456
+ style: styles.filterOptionsList,
457
+ children: filterOptions.map((option, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(FilterOptionCard, {
458
+ label: option.label,
459
+ value: option.value,
460
+ isSelected: selectedIndex === index,
461
+ onSelect: () => handleSelectOption(index)
462
+ }, option.type))
463
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
464
+ style: styles.filterActionButtons,
465
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
466
+ style: [styles.filterActionButton, styles.filterActionButtonInclude, !selectedOption && styles.filterActionButtonDisabled],
467
+ onPress: handleInclude,
468
+ disabled: !selectedOption,
469
+ activeOpacity: 0.7,
470
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.PlusIcon, {
471
+ size: 14,
472
+ color: selectedOption ? _sharedUi.buoyColors.success : _sharedUi.buoyColors.textMuted
473
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
474
+ style: [styles.filterActionButtonText, {
475
+ color: selectedOption ? _sharedUi.buoyColors.success : _sharedUi.buoyColors.textMuted
476
+ }],
477
+ children: "Only Show This"
478
+ })]
479
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
480
+ style: [styles.filterActionButton, styles.filterActionButtonExclude, !selectedOption && styles.filterActionButtonDisabled],
481
+ onPress: handleExclude,
482
+ disabled: !selectedOption,
483
+ activeOpacity: 0.7,
484
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.MinusIcon, {
485
+ size: 14,
486
+ color: selectedOption ? _sharedUi.buoyColors.error : _sharedUi.buoyColors.textMuted
487
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
488
+ style: [styles.filterActionButtonText, {
489
+ color: selectedOption ? _sharedUi.buoyColors.error : _sharedUi.buoyColors.textMuted
490
+ }],
491
+ children: "Hide This"
492
+ })]
493
+ })]
494
+ })]
495
+ });
496
+ }
497
+
498
+ /**
499
+ * FilterOptionCard - A selectable filter option card
500
+ */
501
+ function FilterOptionCard({
502
+ label,
503
+ value,
504
+ isSelected,
505
+ onSelect
506
+ }) {
507
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
508
+ style: [styles.filterOptionCard, isSelected && styles.filterOptionCardSelected],
509
+ onPress: onSelect,
510
+ activeOpacity: 0.7,
511
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
512
+ style: [styles.filterOptionLabel, isSelected && styles.filterOptionLabelSelected],
513
+ children: label
514
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
515
+ style: [styles.filterOptionValue, isSelected && styles.filterOptionValueSelected],
516
+ numberOfLines: 1,
517
+ children: value
518
+ })]
519
+ });
520
+ }
521
+ const styles = _reactNative.StyleSheet.create({
522
+ container: {
523
+ flex: 1,
524
+ backgroundColor: _sharedUi.buoyColors.base
525
+ },
526
+ // Header
527
+ header: {
528
+ flexDirection: "row",
529
+ alignItems: "center",
530
+ justifyContent: "center",
531
+ gap: 12,
532
+ padding: 16,
533
+ paddingBottom: 0
534
+ },
535
+ // ScrollView
536
+ scrollView: {
537
+ flex: 1
538
+ },
539
+ scrollContent: {
540
+ padding: 16,
541
+ paddingTop: 12,
542
+ paddingBottom: 80,
543
+ gap: 12
544
+ },
545
+ headerLeft: {
546
+ flex: 1,
547
+ flexDirection: "row",
548
+ alignItems: "center",
549
+ justifyContent: "center",
550
+ gap: 10
551
+ },
552
+ componentName: {
553
+ fontSize: 18,
554
+ fontWeight: "700",
555
+ color: _sharedUi.buoyColors.text,
556
+ flexShrink: 1
557
+ },
558
+ nativeTypeBadge: {
559
+ backgroundColor: _sharedUi.buoyColors.input,
560
+ paddingVertical: 3,
561
+ paddingHorizontal: 8,
562
+ borderRadius: 4
563
+ },
564
+ nativeTypeText: {
565
+ fontSize: 11,
566
+ fontWeight: "600",
567
+ color: _sharedUi.buoyColors.textMuted,
568
+ fontFamily: "monospace"
569
+ },
570
+ // Answer Card
571
+ answerCard: {
572
+ backgroundColor: _sharedUi.buoyColors.card,
573
+ borderRadius: 8,
574
+ borderWidth: 1,
575
+ borderColor: _sharedUi.buoyColors.border,
576
+ padding: 12,
577
+ gap: 6
578
+ },
579
+ causeBadgeRow: {
580
+ flexDirection: "row",
581
+ alignItems: "center",
582
+ gap: 8
583
+ },
584
+ causeBadgeLarge: {
585
+ paddingVertical: 4,
586
+ paddingHorizontal: 10,
587
+ borderRadius: 4
588
+ },
589
+ causeBadgeLargeText: {
590
+ fontSize: 11,
591
+ fontWeight: "700",
592
+ letterSpacing: 0.5
593
+ },
594
+ causeLabel: {
595
+ fontSize: 12,
596
+ color: _sharedUi.buoyColors.textSecondary,
597
+ fontWeight: "500"
598
+ },
599
+ hookChangesContainer: {
600
+ gap: 6
601
+ },
602
+ hookDiffContainer: {
603
+ backgroundColor: _sharedUi.buoyColors.input,
604
+ borderRadius: 6,
605
+ overflow: "hidden"
606
+ },
607
+ propsChangesContainer: {
608
+ flexDirection: "row",
609
+ flexWrap: "wrap",
610
+ gap: 4
611
+ },
612
+ propChangeChip: {
613
+ backgroundColor: _sharedUi.buoyColors.input,
614
+ paddingVertical: 2,
615
+ paddingHorizontal: 6,
616
+ borderRadius: 4
617
+ },
618
+ propChangeText: {
619
+ fontSize: 11,
620
+ color: _sharedUi.buoyColors.text,
621
+ fontFamily: "monospace"
622
+ },
623
+ // Details Section
624
+ detailsSection: {
625
+ gap: 10
626
+ },
627
+ detailsCard: {
628
+ backgroundColor: _sharedUi.buoyColors.card,
629
+ borderRadius: 8,
630
+ borderWidth: 1,
631
+ borderColor: _sharedUi.buoyColors.border,
632
+ padding: 12,
633
+ gap: 6
634
+ },
635
+ detailsCardTitle: {
636
+ fontSize: 10,
637
+ fontWeight: "600",
638
+ color: _sharedUi.buoyColors.textMuted,
639
+ letterSpacing: 0.5,
640
+ textTransform: "uppercase",
641
+ marginBottom: 4
642
+ },
643
+ detailRow: {
644
+ flexDirection: "row",
645
+ alignItems: "center",
646
+ gap: 8
647
+ },
648
+ detailLabel: {
649
+ fontSize: 11,
650
+ fontWeight: "600",
651
+ color: _sharedUi.buoyColors.textSecondary,
652
+ minWidth: 55
653
+ },
654
+ detailValue: {
655
+ fontSize: 12,
656
+ color: _sharedUi.buoyColors.text,
657
+ fontFamily: "monospace",
658
+ flex: 1
659
+ },
660
+ // Stats Row
661
+ statsRow: {
662
+ flexDirection: "row",
663
+ alignItems: "center",
664
+ justifyContent: "center",
665
+ backgroundColor: _sharedUi.buoyColors.card,
666
+ borderRadius: 8,
667
+ borderWidth: 1,
668
+ borderColor: _sharedUi.buoyColors.border,
669
+ paddingVertical: 10,
670
+ paddingHorizontal: 16
671
+ },
672
+ statItem: {
673
+ flex: 1,
674
+ alignItems: "center"
675
+ },
676
+ statValue: {
677
+ fontSize: 16,
678
+ fontWeight: "700",
679
+ color: _sharedUi.buoyColors.text,
680
+ fontFamily: "monospace"
681
+ },
682
+ statLabel: {
683
+ fontSize: 10,
684
+ color: _sharedUi.buoyColors.textMuted,
685
+ marginTop: 2
686
+ },
687
+ statDivider: {
688
+ width: 1,
689
+ height: 24,
690
+ backgroundColor: _sharedUi.buoyColors.border,
691
+ marginHorizontal: 12
692
+ },
693
+ // Measurements Row
694
+ measurementsRow: {
695
+ flexDirection: "row",
696
+ alignItems: "center",
697
+ justifyContent: "space-around",
698
+ backgroundColor: _sharedUi.buoyColors.card,
699
+ borderRadius: 8,
700
+ borderWidth: 1,
701
+ borderColor: _sharedUi.buoyColors.border,
702
+ paddingVertical: 8,
703
+ paddingHorizontal: 12
704
+ },
705
+ measurementItem: {
706
+ flexDirection: "row",
707
+ alignItems: "baseline",
708
+ gap: 4
709
+ },
710
+ measurementLabel: {
711
+ fontSize: 10,
712
+ fontWeight: "600",
713
+ color: _sharedUi.buoyColors.textMuted,
714
+ textTransform: "uppercase"
715
+ },
716
+ measurementValue: {
717
+ fontSize: 12,
718
+ fontWeight: "600",
719
+ color: _sharedUi.buoyColors.text,
720
+ fontFamily: "monospace"
721
+ },
722
+ // Quick Actions Section
723
+ quickActionsSection: {
724
+ backgroundColor: _sharedUi.buoyColors.card,
725
+ borderRadius: 8,
726
+ borderWidth: 1,
727
+ borderColor: _sharedUi.buoyColors.border,
728
+ padding: 12,
729
+ gap: 10
730
+ },
731
+ quickActionsTitle: {
732
+ fontSize: 10,
733
+ fontWeight: "600",
734
+ color: _sharedUi.buoyColors.textMuted,
735
+ letterSpacing: 0.5,
736
+ textTransform: "uppercase",
737
+ marginBottom: 2
738
+ },
739
+ filterOptionsList: {
740
+ gap: 6
741
+ },
742
+ filterOptionCard: {
743
+ flexDirection: "row",
744
+ alignItems: "center",
745
+ backgroundColor: _sharedUi.buoyColors.input,
746
+ borderRadius: 6,
747
+ paddingVertical: 10,
748
+ paddingHorizontal: 12,
749
+ borderWidth: 1,
750
+ borderColor: "transparent",
751
+ gap: 10
752
+ },
753
+ filterOptionCardSelected: {
754
+ borderColor: _sharedUi.buoyColors.success,
755
+ backgroundColor: _sharedUi.buoyColors.success + "15"
756
+ },
757
+ filterOptionLabel: {
758
+ fontSize: 10,
759
+ fontWeight: "600",
760
+ color: _sharedUi.buoyColors.textMuted,
761
+ minWidth: 70
762
+ },
763
+ filterOptionLabelSelected: {
764
+ color: _sharedUi.buoyColors.success
765
+ },
766
+ filterOptionValue: {
767
+ fontSize: 12,
768
+ color: _sharedUi.buoyColors.text,
769
+ fontFamily: "monospace",
770
+ flex: 1
771
+ },
772
+ filterOptionValueSelected: {
773
+ color: _sharedUi.buoyColors.text
774
+ },
775
+ filterActionButtons: {
776
+ flexDirection: "row",
777
+ gap: 8,
778
+ marginTop: 12
779
+ },
780
+ filterActionButton: {
781
+ flexDirection: "row",
782
+ alignItems: "center",
783
+ justifyContent: "center",
784
+ gap: 4,
785
+ paddingVertical: 8,
786
+ paddingHorizontal: 10,
787
+ borderRadius: 6,
788
+ borderWidth: 1
789
+ },
790
+ filterActionButtonInclude: {
791
+ backgroundColor: _sharedUi.buoyColors.success + "15",
792
+ borderColor: _sharedUi.buoyColors.success + "40"
793
+ },
794
+ filterActionButtonExclude: {
795
+ backgroundColor: _sharedUi.buoyColors.error + "15",
796
+ borderColor: _sharedUi.buoyColors.error + "40"
797
+ },
798
+ filterActionButtonDisabled: {
799
+ backgroundColor: _sharedUi.buoyColors.input,
800
+ borderColor: _sharedUi.buoyColors.border,
801
+ opacity: 0.5
802
+ },
803
+ filterActionButtonText: {
804
+ fontSize: 11,
805
+ fontWeight: "600"
806
+ },
807
+ // Locked Banner
808
+ lockedBanner: {
809
+ flexDirection: "row",
810
+ alignItems: "center",
811
+ justifyContent: "center",
812
+ backgroundColor: _sharedUi.buoyColors.card,
813
+ borderRadius: 8,
814
+ borderWidth: 1,
815
+ borderColor: _sharedUi.buoyColors.warning + "40",
816
+ paddingVertical: 12,
817
+ paddingHorizontal: 16,
818
+ gap: 8
819
+ },
820
+ lockedBannerText: {
821
+ color: _sharedUi.buoyColors.warning,
822
+ fontSize: 13,
823
+ fontWeight: "600"
824
+ },
825
+ lockedBannerSubtext: {
826
+ color: _sharedUi.buoyColors.textMuted,
827
+ fontSize: 12
828
+ }
829
+ });
830
+ var _default = exports.default = RenderDetailView;