@buoy-gg/highlight-updates 7.0.38 → 7.0.39

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 (103) hide show
  1. package/lib/commonjs/highlight-updates/HighlightUpdatesOverlay.js +281 -1
  2. package/lib/commonjs/highlight-updates/components/HighlightFilterView.js +1474 -1
  3. package/lib/commonjs/highlight-updates/components/HighlightUpdatesModal.js +641 -1
  4. package/lib/commonjs/highlight-updates/components/IdentifierBadge.js +273 -1
  5. package/lib/commonjs/highlight-updates/components/IsolatedRenderList.js +188 -1
  6. package/lib/commonjs/highlight-updates/components/ModalHeaderContent.js +293 -1
  7. package/lib/commonjs/highlight-updates/components/RenderCauseBadge.js +508 -1
  8. package/lib/commonjs/highlight-updates/components/RenderDetailView.js +846 -1
  9. package/lib/commonjs/highlight-updates/components/RenderHistoryViewer.js +915 -1
  10. package/lib/commonjs/highlight-updates/components/RenderListItem.js +235 -1
  11. package/lib/commonjs/highlight-updates/components/RendersCopySettingsView.js +469 -1
  12. package/lib/commonjs/highlight-updates/components/StatsDisplay.js +73 -1
  13. package/lib/commonjs/highlight-updates/types/copySettings.js +107 -1
  14. package/lib/commonjs/highlight-updates/utils/CommitProfiler.js +446 -1
  15. package/lib/commonjs/highlight-updates/utils/HighlightUpdatesController.js +1920 -1
  16. package/lib/commonjs/highlight-updates/utils/PerformanceLogger.js +359 -1
  17. package/lib/commonjs/highlight-updates/utils/ProfilerInterceptor.js +371 -1
  18. package/lib/commonjs/highlight-updates/utils/RenderCauseDetector.js +1840 -1
  19. package/lib/commonjs/highlight-updates/utils/RenderTracker.js +952 -1
  20. package/lib/commonjs/highlight-updates/utils/ViewTypeMapper.js +264 -1
  21. package/lib/commonjs/highlight-updates/utils/copySettingsStorage.js +32 -1
  22. package/lib/commonjs/highlight-updates/utils/devtoolsComponentNames.js +188 -1
  23. package/lib/commonjs/highlight-updates/utils/namedComposite.js +41 -1
  24. package/lib/commonjs/highlight-updates/utils/ownStateChanged.js +103 -1
  25. package/lib/commonjs/highlight-updates/utils/rawEventEmitter.js +50 -1
  26. package/lib/commonjs/highlight-updates/utils/renderExportFormatter.js +58 -1
  27. package/lib/commonjs/highlight-updates/utils/rendersExportFormatter.js +485 -1
  28. package/lib/commonjs/highlight-updates/utils/screenElements.js +1248 -1
  29. package/lib/commonjs/highlight-updates/utils/tapMatch.js +83 -1
  30. package/lib/commonjs/highlight-updates/utils/testIDs.js +68 -1
  31. package/lib/commonjs/highlight-updates/utils/touchCapture.js +277 -1
  32. package/lib/commonjs/index.js +429 -1
  33. package/lib/commonjs/preset.js +278 -1
  34. package/lib/commonjs/sync/highlightUpdatesSyncAdapter.js +235 -1
  35. package/lib/module/highlight-updates/HighlightUpdatesOverlay.js +274 -1
  36. package/lib/module/highlight-updates/components/HighlightFilterView.js +1468 -1
  37. package/lib/module/highlight-updates/components/HighlightUpdatesModal.js +634 -1
  38. package/lib/module/highlight-updates/components/IdentifierBadge.js +265 -1
  39. package/lib/module/highlight-updates/components/IsolatedRenderList.js +183 -1
  40. package/lib/module/highlight-updates/components/ModalHeaderContent.js +288 -1
  41. package/lib/module/highlight-updates/components/RenderCauseBadge.js +499 -1
  42. package/lib/module/highlight-updates/components/RenderDetailView.js +840 -1
  43. package/lib/module/highlight-updates/components/RenderHistoryViewer.js +908 -1
  44. package/lib/module/highlight-updates/components/RenderListItem.js +230 -1
  45. package/lib/module/highlight-updates/components/RendersCopySettingsView.js +465 -1
  46. package/lib/module/highlight-updates/components/StatsDisplay.js +70 -1
  47. package/lib/module/highlight-updates/types/copySettings.js +102 -1
  48. package/lib/module/highlight-updates/utils/CommitProfiler.js +442 -1
  49. package/lib/module/highlight-updates/utils/HighlightUpdatesController.js +1916 -1
  50. package/lib/module/highlight-updates/utils/PerformanceLogger.js +353 -1
  51. package/lib/module/highlight-updates/utils/ProfilerInterceptor.js +358 -1
  52. package/lib/module/highlight-updates/utils/RenderCauseDetector.js +1830 -1
  53. package/lib/module/highlight-updates/utils/RenderTracker.js +949 -1
  54. package/lib/module/highlight-updates/utils/ViewTypeMapper.js +255 -1
  55. package/lib/module/highlight-updates/utils/copySettingsStorage.js +26 -1
  56. package/lib/module/highlight-updates/utils/devtoolsComponentNames.js +178 -1
  57. package/lib/module/highlight-updates/utils/namedComposite.js +36 -1
  58. package/lib/module/highlight-updates/utils/ownStateChanged.js +98 -1
  59. package/lib/module/highlight-updates/utils/rawEventEmitter.js +46 -1
  60. package/lib/module/highlight-updates/utils/renderExportFormatter.js +54 -1
  61. package/lib/module/highlight-updates/utils/rendersExportFormatter.js +478 -1
  62. package/lib/module/highlight-updates/utils/screenElements.js +1242 -1
  63. package/lib/module/highlight-updates/utils/tapMatch.js +76 -1
  64. package/lib/module/highlight-updates/utils/testIDs.js +60 -1
  65. package/lib/module/highlight-updates/utils/touchCapture.js +270 -1
  66. package/lib/module/index.js +130 -1
  67. package/lib/module/preset.js +272 -1
  68. package/lib/module/sync/highlightUpdatesSyncAdapter.js +230 -1
  69. package/lib/typescript/highlight-updates/HighlightUpdatesOverlay.d.ts.map +1 -0
  70. package/lib/typescript/highlight-updates/components/HighlightFilterView.d.ts.map +1 -0
  71. package/lib/typescript/highlight-updates/components/HighlightUpdatesModal.d.ts.map +1 -0
  72. package/lib/typescript/highlight-updates/components/IdentifierBadge.d.ts.map +1 -0
  73. package/lib/typescript/highlight-updates/components/IsolatedRenderList.d.ts.map +1 -0
  74. package/lib/typescript/highlight-updates/components/ModalHeaderContent.d.ts.map +1 -0
  75. package/lib/typescript/highlight-updates/components/RenderCauseBadge.d.ts.map +1 -0
  76. package/lib/typescript/highlight-updates/components/RenderDetailView.d.ts.map +1 -0
  77. package/lib/typescript/highlight-updates/components/RenderHistoryViewer.d.ts.map +1 -0
  78. package/lib/typescript/highlight-updates/components/RenderListItem.d.ts.map +1 -0
  79. package/lib/typescript/highlight-updates/components/RendersCopySettingsView.d.ts.map +1 -0
  80. package/lib/typescript/highlight-updates/components/StatsDisplay.d.ts.map +1 -0
  81. package/lib/typescript/highlight-updates/types/copySettings.d.ts.map +1 -0
  82. package/lib/typescript/highlight-updates/utils/CommitProfiler.d.ts.map +1 -0
  83. package/lib/typescript/highlight-updates/utils/HighlightUpdatesController.d.ts.map +1 -0
  84. package/lib/typescript/highlight-updates/utils/PerformanceLogger.d.ts.map +1 -0
  85. package/lib/typescript/highlight-updates/utils/ProfilerInterceptor.d.ts.map +1 -0
  86. package/lib/typescript/highlight-updates/utils/RenderCauseDetector.d.ts.map +1 -0
  87. package/lib/typescript/highlight-updates/utils/RenderTracker.d.ts.map +1 -0
  88. package/lib/typescript/highlight-updates/utils/ViewTypeMapper.d.ts.map +1 -0
  89. package/lib/typescript/highlight-updates/utils/copySettingsStorage.d.ts.map +1 -0
  90. package/lib/typescript/highlight-updates/utils/devtoolsComponentNames.d.ts.map +1 -0
  91. package/lib/typescript/highlight-updates/utils/namedComposite.d.ts.map +1 -0
  92. package/lib/typescript/highlight-updates/utils/ownStateChanged.d.ts.map +1 -0
  93. package/lib/typescript/highlight-updates/utils/rawEventEmitter.d.ts.map +1 -0
  94. package/lib/typescript/highlight-updates/utils/renderExportFormatter.d.ts.map +1 -0
  95. package/lib/typescript/highlight-updates/utils/rendersExportFormatter.d.ts.map +1 -0
  96. package/lib/typescript/highlight-updates/utils/screenElements.d.ts.map +1 -0
  97. package/lib/typescript/highlight-updates/utils/tapMatch.d.ts.map +1 -0
  98. package/lib/typescript/highlight-updates/utils/testIDs.d.ts.map +1 -0
  99. package/lib/typescript/highlight-updates/utils/touchCapture.d.ts.map +1 -0
  100. package/lib/typescript/index.d.ts.map +1 -0
  101. package/lib/typescript/preset.d.ts.map +1 -0
  102. package/lib/typescript/sync/highlightUpdatesSyncAdapter.d.ts.map +1 -0
  103. package/package.json +7 -7
@@ -1 +1,641 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.HighlightToolView=HighlightToolView,exports.HighlightUpdatesModal=HighlightUpdatesModal,exports.default=void 0;var _react=_interopRequireWildcard(require("react")),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_license=require("@buoy-gg/license"),_HighlightUpdatesController=_interopRequireDefault(require("../utils/HighlightUpdatesController")),_RenderTracker=require("../utils/RenderTracker"),_RenderDetailView=require("./RenderDetailView"),_HighlightFilterView=require("./HighlightFilterView"),_IsolatedRenderList=require("./IsolatedRenderList"),_ModalHeaderContent=require("./ModalHeaderContent"),_RenderHistoryViewer=require("./RenderHistoryViewer"),_RendersCopySettingsView=require("./RendersCopySettingsView"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}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 a,i,s={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return s;if(a=t?n:r){if(a.has(e))return a.get(e);a.set(e,s)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((i=(a=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(i.get||i.set)?a(s,t,i):s[t]=e[t]);return s})(e,t)}const DisabledBanner=_react.default.memo(function(){return(0,_jsxRuntime.jsxs)(_reactNative.View,{testID:"buoy-highlight-disabled-banner",style:styles.disabledBanner,children:[(0,_jsxRuntime.jsx)(_sharedUi.Power,{size:14,color:_sharedUi.night.color.warning}),(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"buoy-highlight-disabled-text",style:styles.disabledText,children:"Render tracking is disabled"})]})});function HighlightUpdatesModal({visible:e,onClose:t,onBack:r,onMinimize:n,enableSharedModalDimensions:a=!1,initialNativeTag:i,onInitialNativeTagHandled:s,onRenderSelect:l,inline:o=!1}){const c=(0,_license.useIsPro)(),[d,u]=(0,_react.useState)(!1),[g,_]=(0,_react.useState)(()=>_HighlightUpdatesController.default.getFrozen()),[h,p]=(0,_react.useState)(()=>_RenderTracker.RenderTracker.getStats().totalComponents>0),[R,f]=(0,_react.useState)(null),[T,x]=(0,_react.useState)(0),[C,k]=(0,_react.useState)(!1),[y,m]=(0,_react.useState)(!1),[b,S]=(0,_react.useState)([]),[v,w]=(0,_react.useState)("filters"),[j,H]=(0,_react.useState)("details"),[U,I]=(0,_react.useState)(0),[P,V]=(0,_react.useState)(""),[D,F]=(0,_react.useState)(!1),N=(0,_react.useRef)(null),M=(0,_react.useRef)([]),q=(0,_react.useRef)(_RenderTracker.RenderTracker.getFilters()),[E,z]=(0,_react.useState)(()=>{const e=_RenderTracker.RenderTracker.getFilters();return e.includePatterns.length+e.excludePatterns.length}),[A,B]=(0,_react.useState)(()=>_RenderTracker.RenderTracker.getFilters()),[O,L]=(0,_react.useState)(()=>_RenderTracker.RenderTracker.getSettings()),W=(0,_react.useRef)(!1),K=(0,_react.useRef)(!1),J=(0,_react.useRef)(!1);(0,_react.useEffect)(()=>{e&&!W.current&&(W.current=!0)},[e]),(0,_react.useEffect)(()=>{e&&!K.current&&(async()=>{try{const e=await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.highlightUpdates.filters());if(e){const t=JSON.parse(e),r={includeTestID:new Set(t.includeTestID||[]),includeNativeID:new Set(t.includeNativeID||[]),includeViewType:new Set(t.includeViewType||[]),includeComponent:new Set(t.includeComponent||[]),excludeTestID:new Set(t.excludeTestID||[]),excludeNativeID:new Set(t.excludeNativeID||[]),excludeViewType:new Set(t.excludeViewType||[]),excludeComponent:new Set(t.excludeComponent||[]),includePatterns:t.includePatterns||[],excludePatterns:t.excludePatterns||[]};_RenderTracker.RenderTracker.setFilters(r);const n=_RenderTracker.RenderTracker.getFilters();q.current=n,B(n),z(n.includePatterns.length+n.excludePatterns.length)}K.current=!0}catch(e){}})()},[e]),(0,_react.useEffect)(()=>{K.current&&(async()=>{try{const e={includeTestID:Array.from(A.includeTestID),includeNativeID:Array.from(A.includeNativeID),includeViewType:Array.from(A.includeViewType),includeComponent:Array.from(A.includeComponent),excludeTestID:Array.from(A.excludeTestID),excludeNativeID:Array.from(A.excludeNativeID),excludeViewType:Array.from(A.excludeViewType),excludeComponent:Array.from(A.excludeComponent),includePatterns:A.includePatterns,excludePatterns:A.excludePatterns};await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.highlightUpdates.filters(),JSON.stringify(e))}catch(e){}})()},[A]),(0,_react.useEffect)(()=>{e&&!J.current&&(async()=>{try{const e=await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.highlightUpdates.settings());if(e){const t=JSON.parse(e),{performanceLogging:r,excludeDevTools:n,...a}=t;_RenderTracker.RenderTracker.setSettings(a),L(_RenderTracker.RenderTracker.getSettings())}J.current=!0}catch(e){J.current=!0}})()},[e]),(0,_react.useEffect)(()=>{J.current&&(async()=>{try{const{performanceLogging:e,excludeDevTools:t,...r}=O;await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.highlightUpdates.settings(),JSON.stringify(r))}catch(e){}})()},[O]),(0,_react.useEffect)(()=>{const e=_RenderTracker.RenderTracker.subscribeToState(e=>{u(e.isTracking)});return()=>{e()}},[]),(0,_react.useEffect)(()=>{const e=_HighlightUpdatesController.default.subscribeToFreeze(e=>{_(e)});return()=>{e()}},[]),(0,_react.useEffect)(()=>{D&&requestAnimationFrame(()=>{N.current?.focus()})},[D]),(0,_react.useEffect)(()=>{e||_HighlightUpdatesController.default.setSpotlight(null)},[e]),(0,_react.useEffect)(()=>{if(e&&null!=i){const e=_RenderTracker.RenderTracker.getRender(String(i));e&&(f(e),x(0),k(!1),_HighlightUpdatesController.default.setSpotlight(e.nativeTag)),s?.()}},[e,i,s]);const G=(0,_react.useCallback)(()=>{_HighlightUpdatesController.default.isInitialized()||_HighlightUpdatesController.default.initialize(),_HighlightUpdatesController.default.toggle()},[]),Q=(0,_react.useCallback)(()=>{_HighlightUpdatesController.default.toggleFreeze()},[]),X=(0,_react.useCallback)(()=>{_HighlightUpdatesController.default.clearRenderCounts(),p(!1)},[]),Y=(0,_react.useCallback)(()=>{S(_RenderTracker.RenderTracker.getFilteredRenders(P)),m(!0)},[P]),Z=(0,_react.useCallback)(()=>{m(!1)},[]),$=(0,_react.useCallback)(e=>{V(e)},[]),ee=(0,_react.useCallback)((e,t,r)=>{f(e),x(t),H("details"),I(0),M.current=r,_HighlightUpdatesController.default.setSpotlight(e.nativeTag)},[]);(0,_react.useEffect)(()=>{if(!R)return;const e=String(R.nativeTag);return _RenderTracker.RenderTracker.subscribe(()=>{const t=_RenderTracker.RenderTracker.getRender(e);t&&f({...t})})},[R?.nativeTag]);const te=(0,_react.useRef)(null);(0,_react.useEffect)(()=>{l&&R&&te.current!==R.nativeTag&&(te.current=R.nativeTag,l(R))},[R,l]);const re=(0,_react.useCallback)(e=>{M.current=e},[]),ne=(0,_react.useCallback)(()=>{f(null),x(0),_HighlightUpdatesController.default.setSpotlight(null)},[]),ae=(0,_react.useCallback)(()=>{const e=M.current;if(T>0){const t=T-1,r=e[t];r&&(f(r),x(t),_HighlightUpdatesController.default.setSpotlight(r.nativeTag))}},[T]),ie=(0,_react.useCallback)(()=>{const e=M.current;if(T<e.length-1){const t=T+1,r=e[t];r&&(f(r),x(t),_HighlightUpdatesController.default.setSpotlight(r.nativeTag))}},[T]),se=(0,_react.useCallback)(()=>{k(!1)},[]),le=(0,_react.useCallback)(()=>{k(!0)},[]),oe=(0,_react.useCallback)(()=>{F(!0)},[]),ce=(0,_react.useCallback)(()=>{F(!1)},[]),de=(0,_react.useCallback)(e=>{_RenderTracker.RenderTracker.setFilters(e);const t=_RenderTracker.RenderTracker.getFilters();q.current=t,B(t),z(t.includePatterns.length+t.excludePatterns.length)},[]),ue=(0,_react.useCallback)((e,t)=>{const r=_RenderTracker.RenderTracker.getFilters(),n={};"include"===t?r.includePatterns.some(t=>t.type===e.type&&t.value===e.value)||(n.includePatterns=[...r.includePatterns,e]):r.excludePatterns.some(t=>t.type===e.type&&t.value===e.value)||(n.excludePatterns=[...r.excludePatterns,e]),Object.keys(n).length>0&&(de(n),f(null),x(0),_HighlightUpdatesController.default.setSpotlight(null))},[de]),ge=(0,_react.useCallback)(e=>{_RenderTracker.RenderTracker.setSettings(e),L(_RenderTracker.RenderTracker.getSettings())},[]),_e=(0,_react.useCallback)(e=>{p(e.totalComponents>0)},[]),he=(0,_react.useCallback)(()=>y?(0,_jsxRuntime.jsx)(_ModalHeaderContent.CopySettingsViewHeader,{onBack:Z}):C?(0,_jsxRuntime.jsx)(_ModalHeaderContent.FilterViewHeader,{onBack:se,activeTab:v,onTabChange:w,activeFilterCount:E}):R?(0,_jsxRuntime.jsx)(_ModalHeaderContent.DetailViewHeader,{onBack:ne,activeTab:j,onTabChange:H,hasHistory:(R.renderHistory?.length??0)>0}):(0,_jsxRuntime.jsx)(_ModalHeaderContent.MainListHeader,{onBack:r,isSearchActive:D,searchText:P,onSearchChange:$,onSearchToggle:oe,onSearchClose:ce,onFilterToggle:le,onToggleTracking:G,onToggleFreeze:Q,onClear:X,onOpenCopySettings:Y,isTracking:d,isFrozen:g,activeFilterCount:E,hasRenders:h,searchInputRef:N}),[y,C,R,r,D,P,d,g,E,h,v,j,se,ne,Z,$,oe,ce,le,G,Q,X,Y]),pe=a?_sharedUi.devToolsStorageKeys.modal.root():_sharedUi.devToolsStorageKeys.highlightUpdates.modal();if(!e)return null;const Re=M.current.length,fe=R?"details"===j?(0,_jsxRuntime.jsx)(_sharedUi.EventStepperFooter,{currentIndex:T,totalItems:Re,onPrevious:ae,onNext:ie,itemLabel:"Component",subtitle:R.componentName||R.displayName||R.viewType}):(0,_jsxRuntime.jsx)(_RenderHistoryViewer.RenderHistoryFooter,{render:R,selectedEventIndex:U,onEventIndexChange:I,isPro:c}):null,Te=(0,_jsxRuntime.jsx)(_reactNative.View,{nativeID:"__rn_buoy__highlight-modal",testID:"buoy-highlight-body",style:styles.container,children:y?(0,_jsxRuntime.jsx)(_RendersCopySettingsView.RendersCopySettingsView,{renders:b}):R?"details"===j?(0,_jsxRuntime.jsx)(_RenderDetailView.RenderDetailView,{render:R,disableInternalFooter:!0,onAddFilter:ue,isPro:c}):(0,_jsxRuntime.jsx)(_RenderHistoryViewer.RenderHistoryViewer,{render:R,disableInternalFooter:!0,selectedEventIndex:U,onEventIndexChange:I,isPro:c}):C?(0,_jsxRuntime.jsx)(_HighlightFilterView.HighlightFilterView,{filters:A,onFilterChange:de,settings:O,onSettingsChange:ge,availableProps:_RenderTracker.RenderTracker.getAvailableProps(),activeTab:v}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[!d&&(0,_jsxRuntime.jsx)(DisabledBanner,{}),(0,_jsxRuntime.jsx)(_IsolatedRenderList.IsolatedRenderList,{searchText:P,filters:A,onSelectRender:ee,onStatsChange:_e,onRendersChange:re,isTracking:d,isPro:c})]})});return o?(0,_jsxRuntime.jsx)(_sharedUi.TickProvider,{children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inlineRoot,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.inlineHeader,..._sharedUi.windowDragProps,children:he()}),Te,fe]})}):(0,_jsxRuntime.jsx)(_sharedUi.TickProvider,{children:(0,_jsxRuntime.jsx)(_sharedUi.JsModal,{visible:e,onClose:t,onMinimize:n,persistenceKey:pe,header:{showToggleButton:!0,customContent:he()},enablePersistence:!0,initialMode:"bottomSheet",enableGlitchEffects:!0,styles:{},footer:fe,footerHeight:R&&("details"===j||(R.renderHistory?.length??0)>1)?68:0,children:Te})})}function HighlightToolView(e={}){return(0,_jsxRuntime.jsx)(HighlightUpdatesModal,{...e,inline:!0,visible:!0,onClose:()=>{}})}const styles=_reactNative.StyleSheet.create({inlineRoot:{flex:1,minHeight:0,backgroundColor:"transparent"},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:_sharedUi.night.color.border,backgroundColor:"transparent"},container:{flex:1,backgroundColor:"transparent"},disabledBanner:{flexDirection:"row",alignItems:"center",gap:8,padding:10,marginHorizontal:12,marginTop:8,backgroundColor:_sharedUi.night.color.warningSoft,borderRadius:8,borderWidth:1,borderColor:_sharedUi.night.color.warning+"20"},disabledText:{color:_sharedUi.night.color.warning,fontSize:11,flex:1}});var _default=exports.default=HighlightUpdatesModal;
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.HighlightToolView = HighlightToolView;
7
+ exports.HighlightUpdatesModal = HighlightUpdatesModal;
8
+ exports.default = void 0;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _reactNative = require("react-native");
11
+ var _sharedUi = require("@buoy-gg/shared-ui");
12
+ var _license = require("@buoy-gg/license");
13
+ var _HighlightUpdatesController = _interopRequireDefault(require("../utils/HighlightUpdatesController"));
14
+ var _RenderTracker = require("../utils/RenderTracker");
15
+ var _RenderDetailView = require("./RenderDetailView");
16
+ var _HighlightFilterView = require("./HighlightFilterView");
17
+ var _IsolatedRenderList = require("./IsolatedRenderList");
18
+ var _ModalHeaderContent = require("./ModalHeaderContent");
19
+ var _RenderHistoryViewer = require("./RenderHistoryViewer");
20
+ var _RendersCopySettingsView = require("./RendersCopySettingsView");
21
+ var _jsxRuntime = require("react/jsx-runtime");
22
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
23
+ 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); }
24
+ /**
25
+ * HighlightUpdatesModal
26
+ *
27
+ * Main modal interface for the Highlight Updates dev tool.
28
+ * Shows a list of tracked component renders with controls for
29
+ * start/stop, clear, and filtering.
30
+ *
31
+ * PERFORMANCE OPTIMIZED:
32
+ * - Uses isolated components to prevent parent re-renders
33
+ * - Stats display is isolated (StatsDisplay)
34
+ * - Render list is isolated (IsolatedRenderList)
35
+ * - Header components are memoized
36
+ * - Uses refs for values not displayed in UI
37
+ */
38
+
39
+ // Disabled banner - memoized since props rarely change
40
+ const DisabledBanner = /*#__PURE__*/_react.default.memo(function DisabledBanner() {
41
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
42
+ testID: "buoy-highlight-disabled-banner",
43
+ style: styles.disabledBanner,
44
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Power, {
45
+ size: 14,
46
+ color: _sharedUi.night.color.warning
47
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
48
+ testID: "buoy-highlight-disabled-text",
49
+ style: styles.disabledText,
50
+ children: "Render tracking is disabled"
51
+ })]
52
+ });
53
+ });
54
+ function HighlightUpdatesModal({
55
+ visible,
56
+ onClose,
57
+ onBack,
58
+ onMinimize,
59
+ enableSharedModalDimensions = false,
60
+ initialNativeTag,
61
+ onInitialNativeTagHandled,
62
+ onRenderSelect,
63
+ inline = false
64
+ }) {
65
+ const isPro = (0, _license.useIsPro)();
66
+
67
+ // ============================================================================
68
+ // TRACKING STATE - subscribed via isolated component
69
+ // ============================================================================
70
+ const [isTracking, setIsTracking] = (0, _react.useState)(false);
71
+ const [isFrozen, setIsFrozen] = (0, _react.useState)(() => _HighlightUpdatesController.default.getFrozen());
72
+
73
+ // Track if there are renders for header clear button state
74
+ const [hasRenders, setHasRenders] = (0, _react.useState)(() => _RenderTracker.RenderTracker.getStats().totalComponents > 0);
75
+
76
+ // ============================================================================
77
+ // UI STATE - kept in parent for view switching
78
+ // ============================================================================
79
+ const [selectedRender, setSelectedRender] = (0, _react.useState)(null);
80
+ const [selectedRenderIndex, setSelectedRenderIndex] = (0, _react.useState)(0);
81
+ const [showFilterView, setShowFilterView] = (0, _react.useState)(false);
82
+ const [showCopySettingsView, setShowCopySettingsView] = (0, _react.useState)(false);
83
+ const [copyRendersSnapshot, setCopyRendersSnapshot] = (0, _react.useState)([]);
84
+ const [filterViewActiveTab, setFilterViewActiveTab] = (0, _react.useState)("filters");
85
+ const [detailViewActiveTab, setDetailViewActiveTab] = (0, _react.useState)("details");
86
+ const [historyEventIndex, setHistoryEventIndex] = (0, _react.useState)(0);
87
+ const [searchText, setSearchText] = (0, _react.useState)("");
88
+ const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
89
+ const searchInputRef = (0, _react.useRef)(null);
90
+
91
+ // Track the renders list for navigation
92
+ const rendersListRef = (0, _react.useRef)([]);
93
+
94
+ // ============================================================================
95
+ // FILTER STATE - use ref for filter config, state for display count only
96
+ // ============================================================================
97
+ const filtersRef = (0, _react.useRef)(_RenderTracker.RenderTracker.getFilters());
98
+ const [activeFilterCount, setActiveFilterCount] = (0, _react.useState)(() => {
99
+ const filters = _RenderTracker.RenderTracker.getFilters();
100
+ return filters.includePatterns.length + filters.excludePatterns.length;
101
+ });
102
+
103
+ // Expose filters via state for HighlightFilterView (it needs to display them)
104
+ const [filters, setFilters] = (0, _react.useState)(() => _RenderTracker.RenderTracker.getFilters());
105
+
106
+ // ============================================================================
107
+ // SETTINGS STATE
108
+ // ============================================================================
109
+ const [settings, setSettings] = (0, _react.useState)(() => _RenderTracker.RenderTracker.getSettings());
110
+
111
+ // ============================================================================
112
+ // PERSISTENCE REFS - prevent saving on initial load
113
+ // ============================================================================
114
+ const hasLoadedTrackingState = (0, _react.useRef)(false);
115
+ const hasLoadedFilters = (0, _react.useRef)(false);
116
+ const hasLoadedSettings = (0, _react.useRef)(false);
117
+
118
+ // ============================================================================
119
+ // LOAD PERSISTED STATE
120
+ // ============================================================================
121
+
122
+ // Tracking state is intentionally NOT persisted.
123
+ // Always starts OFF to prevent infinite re-render loops on load where
124
+ // the overlay highlights its own components before exclusion filters can take effect.
125
+ // The user must explicitly enable tracking each session.
126
+ (0, _react.useEffect)(() => {
127
+ if (!visible || hasLoadedTrackingState.current) return;
128
+ hasLoadedTrackingState.current = true;
129
+ }, [visible]);
130
+
131
+ // Load persisted filters on mount
132
+ (0, _react.useEffect)(() => {
133
+ if (!visible || hasLoadedFilters.current) return;
134
+ const loadFilters = async () => {
135
+ try {
136
+ const storedFilters = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.highlightUpdates.filters());
137
+ if (storedFilters) {
138
+ const parsedFilters = JSON.parse(storedFilters);
139
+ const restoredFilters = {
140
+ includeTestID: new Set(parsedFilters.includeTestID || []),
141
+ includeNativeID: new Set(parsedFilters.includeNativeID || []),
142
+ includeViewType: new Set(parsedFilters.includeViewType || []),
143
+ includeComponent: new Set(parsedFilters.includeComponent || []),
144
+ excludeTestID: new Set(parsedFilters.excludeTestID || []),
145
+ excludeNativeID: new Set(parsedFilters.excludeNativeID || []),
146
+ excludeViewType: new Set(parsedFilters.excludeViewType || []),
147
+ excludeComponent: new Set(parsedFilters.excludeComponent || []),
148
+ includePatterns: parsedFilters.includePatterns || [],
149
+ excludePatterns: parsedFilters.excludePatterns || []
150
+ };
151
+ _RenderTracker.RenderTracker.setFilters(restoredFilters);
152
+ const newFilters = _RenderTracker.RenderTracker.getFilters();
153
+ filtersRef.current = newFilters;
154
+ setFilters(newFilters);
155
+ setActiveFilterCount(newFilters.includePatterns.length + newFilters.excludePatterns.length);
156
+ }
157
+ hasLoadedFilters.current = true;
158
+ } catch (error) {
159
+ // Failed to load filters
160
+ }
161
+ };
162
+ loadFilters();
163
+ }, [visible]);
164
+
165
+ // Save filters when they change
166
+ (0, _react.useEffect)(() => {
167
+ if (!hasLoadedFilters.current) return;
168
+ const saveFilters = async () => {
169
+ try {
170
+ const filtersToSave = {
171
+ includeTestID: Array.from(filters.includeTestID),
172
+ includeNativeID: Array.from(filters.includeNativeID),
173
+ includeViewType: Array.from(filters.includeViewType),
174
+ includeComponent: Array.from(filters.includeComponent),
175
+ excludeTestID: Array.from(filters.excludeTestID),
176
+ excludeNativeID: Array.from(filters.excludeNativeID),
177
+ excludeViewType: Array.from(filters.excludeViewType),
178
+ excludeComponent: Array.from(filters.excludeComponent),
179
+ includePatterns: filters.includePatterns,
180
+ excludePatterns: filters.excludePatterns
181
+ };
182
+ await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.highlightUpdates.filters(), JSON.stringify(filtersToSave));
183
+ } catch (error) {
184
+ // Failed to save filters
185
+ }
186
+ };
187
+ saveFilters();
188
+ }, [filters]);
189
+
190
+ // Load persisted settings on mount
191
+ (0, _react.useEffect)(() => {
192
+ if (!visible || hasLoadedSettings.current) return;
193
+ const loadSettings = async () => {
194
+ try {
195
+ const storedSettings = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.highlightUpdates.settings());
196
+ if (storedSettings) {
197
+ const parsedSettings = JSON.parse(storedSettings);
198
+ // Never restore excludeDevTools or performanceLogging from persistence -
199
+ // excludeDevTools must always default to true to prevent infinite re-render loops
200
+ const {
201
+ performanceLogging: _ignored,
202
+ excludeDevTools: _alwaysTrue,
203
+ ...settingsToRestore
204
+ } = parsedSettings;
205
+ _RenderTracker.RenderTracker.setSettings(settingsToRestore);
206
+ setSettings(_RenderTracker.RenderTracker.getSettings());
207
+ }
208
+ hasLoadedSettings.current = true;
209
+ } catch (error) {
210
+ hasLoadedSettings.current = true;
211
+ }
212
+ };
213
+ loadSettings();
214
+ }, [visible]);
215
+
216
+ // Save settings when they change
217
+ (0, _react.useEffect)(() => {
218
+ if (!hasLoadedSettings.current) return;
219
+ const saveSettings = async () => {
220
+ try {
221
+ // Never persist excludeDevTools - it must always default to true on startup
222
+ const {
223
+ performanceLogging: _ignored,
224
+ excludeDevTools: _neverPersist,
225
+ ...settingsToSave
226
+ } = settings;
227
+ await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.highlightUpdates.settings(), JSON.stringify(settingsToSave));
228
+ } catch (error) {
229
+ // Failed to save settings
230
+ }
231
+ };
232
+ saveSettings();
233
+ }, [settings]);
234
+
235
+ // ============================================================================
236
+ // SUBSCRIPTIONS - only for tracking state, not renders
237
+ // ============================================================================
238
+
239
+ // Subscribe to tracking state changes only
240
+ (0, _react.useEffect)(() => {
241
+ const unsubscribeState = _RenderTracker.RenderTracker.subscribeToState(state => {
242
+ setIsTracking(state.isTracking);
243
+ });
244
+ return () => {
245
+ unsubscribeState();
246
+ };
247
+ }, []);
248
+
249
+ // Subscribe to freeze state changes
250
+ (0, _react.useEffect)(() => {
251
+ const unsubscribeFreeze = _HighlightUpdatesController.default.subscribeToFreeze(frozen => {
252
+ setIsFrozen(frozen);
253
+ });
254
+ return () => {
255
+ unsubscribeFreeze();
256
+ };
257
+ }, []);
258
+
259
+ // Focus search input when activated
260
+ (0, _react.useEffect)(() => {
261
+ if (isSearchActive) {
262
+ requestAnimationFrame(() => {
263
+ searchInputRef.current?.focus();
264
+ });
265
+ }
266
+ }, [isSearchActive]);
267
+
268
+ // Clear spotlight when modal is closed
269
+ (0, _react.useEffect)(() => {
270
+ if (!visible) {
271
+ _HighlightUpdatesController.default.setSpotlight(null);
272
+ }
273
+ }, [visible]);
274
+
275
+ // ============================================================================
276
+ // DEEP LINK NAVIGATION - "Click Overlay Badge → Jump to Detail"
277
+ // ============================================================================
278
+
279
+ // Handle initial navigation when a badge is tapped
280
+ (0, _react.useEffect)(() => {
281
+ if (visible && initialNativeTag != null) {
282
+ // Look up the render by nativeTag
283
+ const render = _RenderTracker.RenderTracker.getRender(String(initialNativeTag));
284
+ if (render) {
285
+ // Navigate to detail view for this component
286
+ setSelectedRender(render);
287
+ setSelectedRenderIndex(0);
288
+ setShowFilterView(false);
289
+ // Set spotlight to show which component is being viewed
290
+ _HighlightUpdatesController.default.setSpotlight(render.nativeTag);
291
+ }
292
+ // Notify parent that we've handled the navigation
293
+ onInitialNativeTagHandled?.();
294
+ }
295
+ }, [visible, initialNativeTag, onInitialNativeTagHandled]);
296
+
297
+ // ============================================================================
298
+ // CALLBACKS - stable references for child components
299
+ // ============================================================================
300
+
301
+ const handleToggleTracking = (0, _react.useCallback)(() => {
302
+ if (!_HighlightUpdatesController.default.isInitialized()) {
303
+ _HighlightUpdatesController.default.initialize();
304
+ }
305
+ _HighlightUpdatesController.default.toggle();
306
+ }, []);
307
+ const handleToggleFreeze = (0, _react.useCallback)(() => {
308
+ _HighlightUpdatesController.default.toggleFreeze();
309
+ }, []);
310
+ const handleClear = (0, _react.useCallback)(() => {
311
+ _HighlightUpdatesController.default.clearRenderCounts();
312
+ setHasRenders(false);
313
+ }, []);
314
+ const handleOpenCopySettings = (0, _react.useCallback)(() => {
315
+ // Snapshot the same filtered list the user sees in the main list view
316
+ // (respects include/exclude patterns and the search box).
317
+ setCopyRendersSnapshot(_RenderTracker.RenderTracker.getFilteredRenders(searchText));
318
+ setShowCopySettingsView(true);
319
+ }, [searchText]);
320
+ const handleCloseCopySettings = (0, _react.useCallback)(() => {
321
+ setShowCopySettingsView(false);
322
+ }, []);
323
+ const handleSearch = (0, _react.useCallback)(text => {
324
+ setSearchText(text);
325
+ }, []);
326
+ const handleRenderPress = (0, _react.useCallback)((render, index, allRenders) => {
327
+ setSelectedRender(render);
328
+ setSelectedRenderIndex(index);
329
+ setDetailViewActiveTab("details"); // Reset to details tab when selecting a new render
330
+ setHistoryEventIndex(0); // Reset history event index when selecting a new render
331
+ rendersListRef.current = allRenders;
332
+ // Set spotlight to show which component is being viewed
333
+ _HighlightUpdatesController.default.setSpotlight(render.nativeTag);
334
+ }, []);
335
+
336
+ // Keep the open detail in sync with the tracker (live counts + hydrated
337
+ // history fetched on demand by a remote host).
338
+ (0, _react.useEffect)(() => {
339
+ if (!selectedRender) return;
340
+ const id = String(selectedRender.nativeTag);
341
+ return _RenderTracker.RenderTracker.subscribe(() => {
342
+ const next = _RenderTracker.RenderTracker.getRender(id);
343
+ if (next) setSelectedRender({
344
+ ...next
345
+ });
346
+ });
347
+ }, [selectedRender?.nativeTag]);
348
+
349
+ // Notify the host on selection (keyed by nativeTag so re-renders with the
350
+ // same selection don't re-fire; remote mirrors fetch history here).
351
+ const lastNotifiedSelectionRef = (0, _react.useRef)(null);
352
+ (0, _react.useEffect)(() => {
353
+ if (!onRenderSelect || !selectedRender) return;
354
+ if (lastNotifiedSelectionRef.current === selectedRender.nativeTag) return;
355
+ lastNotifiedSelectionRef.current = selectedRender.nativeTag;
356
+ onRenderSelect(selectedRender);
357
+ }, [selectedRender, onRenderSelect]);
358
+ const handleRendersChange = (0, _react.useCallback)(renders => {
359
+ rendersListRef.current = renders;
360
+ }, []);
361
+ const handleBackFromDetail = (0, _react.useCallback)(() => {
362
+ setSelectedRender(null);
363
+ setSelectedRenderIndex(0);
364
+ // Clear the spotlight
365
+ _HighlightUpdatesController.default.setSpotlight(null);
366
+ }, []);
367
+ const handlePreviousRender = (0, _react.useCallback)(() => {
368
+ const renders = rendersListRef.current;
369
+ if (selectedRenderIndex > 0) {
370
+ const newIndex = selectedRenderIndex - 1;
371
+ const newRender = renders[newIndex];
372
+ if (newRender) {
373
+ setSelectedRender(newRender);
374
+ setSelectedRenderIndex(newIndex);
375
+ _HighlightUpdatesController.default.setSpotlight(newRender.nativeTag);
376
+ }
377
+ }
378
+ }, [selectedRenderIndex]);
379
+ const handleNextRender = (0, _react.useCallback)(() => {
380
+ const renders = rendersListRef.current;
381
+ if (selectedRenderIndex < renders.length - 1) {
382
+ const newIndex = selectedRenderIndex + 1;
383
+ const newRender = renders[newIndex];
384
+ if (newRender) {
385
+ setSelectedRender(newRender);
386
+ setSelectedRenderIndex(newIndex);
387
+ _HighlightUpdatesController.default.setSpotlight(newRender.nativeTag);
388
+ }
389
+ }
390
+ }, [selectedRenderIndex]);
391
+ const handleBackFromFilter = (0, _react.useCallback)(() => {
392
+ setShowFilterView(false);
393
+ }, []);
394
+ const handleFilterToggle = (0, _react.useCallback)(() => {
395
+ setShowFilterView(true);
396
+ }, []);
397
+ const handleSearchToggle = (0, _react.useCallback)(() => {
398
+ setIsSearchActive(true);
399
+ }, []);
400
+ const handleSearchClose = (0, _react.useCallback)(() => {
401
+ setIsSearchActive(false);
402
+ }, []);
403
+ const handleFilterChange = (0, _react.useCallback)(newFilters => {
404
+ _RenderTracker.RenderTracker.setFilters(newFilters);
405
+ const updatedFilters = _RenderTracker.RenderTracker.getFilters();
406
+ filtersRef.current = updatedFilters;
407
+ setFilters(updatedFilters);
408
+ setActiveFilterCount(updatedFilters.includePatterns.length + updatedFilters.excludePatterns.length);
409
+ }, []);
410
+
411
+ // Handler for adding a filter from the detail view (quick actions)
412
+ const handleAddFilter = (0, _react.useCallback)((pattern, mode) => {
413
+ const currentFilters = _RenderTracker.RenderTracker.getFilters();
414
+ const newFilters = {};
415
+ if (mode === "include") {
416
+ // Check if pattern already exists
417
+ const exists = currentFilters.includePatterns.some(p => p.type === pattern.type && p.value === pattern.value);
418
+ if (!exists) {
419
+ newFilters.includePatterns = [...currentFilters.includePatterns, pattern];
420
+ }
421
+ } else {
422
+ // Check if pattern already exists
423
+ const exists = currentFilters.excludePatterns.some(p => p.type === pattern.type && p.value === pattern.value);
424
+ if (!exists) {
425
+ newFilters.excludePatterns = [...currentFilters.excludePatterns, pattern];
426
+ }
427
+ }
428
+ if (Object.keys(newFilters).length > 0) {
429
+ handleFilterChange(newFilters);
430
+ // Go back to the list view after adding filter
431
+ setSelectedRender(null);
432
+ setSelectedRenderIndex(0);
433
+ // Clear the spotlight
434
+ _HighlightUpdatesController.default.setSpotlight(null);
435
+ }
436
+ }, [handleFilterChange]);
437
+ const handleSettingsChange = (0, _react.useCallback)(newSettings => {
438
+ _RenderTracker.RenderTracker.setSettings(newSettings);
439
+ setSettings(_RenderTracker.RenderTracker.getSettings());
440
+ }, []);
441
+
442
+ // Callback for IsolatedRenderList to update hasRenders (for header clear button)
443
+ const handleStatsChange = (0, _react.useCallback)(stats => {
444
+ setHasRenders(stats.totalComponents > 0);
445
+ }, []);
446
+
447
+ // ============================================================================
448
+ // HEADER RENDERING - using memoized components
449
+ // ============================================================================
450
+
451
+ const renderHeaderContent = (0, _react.useCallback)(() => {
452
+ if (showCopySettingsView) {
453
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ModalHeaderContent.CopySettingsViewHeader, {
454
+ onBack: handleCloseCopySettings
455
+ });
456
+ }
457
+ if (showFilterView) {
458
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ModalHeaderContent.FilterViewHeader, {
459
+ onBack: handleBackFromFilter,
460
+ activeTab: filterViewActiveTab,
461
+ onTabChange: setFilterViewActiveTab,
462
+ activeFilterCount: activeFilterCount
463
+ });
464
+ }
465
+ if (selectedRender) {
466
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ModalHeaderContent.DetailViewHeader, {
467
+ onBack: handleBackFromDetail,
468
+ activeTab: detailViewActiveTab,
469
+ onTabChange: setDetailViewActiveTab,
470
+ hasHistory: (selectedRender.renderHistory?.length ?? 0) > 0
471
+ });
472
+ }
473
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ModalHeaderContent.MainListHeader, {
474
+ onBack: onBack,
475
+ isSearchActive: isSearchActive,
476
+ searchText: searchText,
477
+ onSearchChange: handleSearch,
478
+ onSearchToggle: handleSearchToggle,
479
+ onSearchClose: handleSearchClose,
480
+ onFilterToggle: handleFilterToggle,
481
+ onToggleTracking: handleToggleTracking,
482
+ onToggleFreeze: handleToggleFreeze,
483
+ onClear: handleClear,
484
+ onOpenCopySettings: handleOpenCopySettings,
485
+ isTracking: isTracking,
486
+ isFrozen: isFrozen,
487
+ activeFilterCount: activeFilterCount,
488
+ hasRenders: hasRenders,
489
+ searchInputRef: searchInputRef
490
+ });
491
+ }, [showCopySettingsView, showFilterView, selectedRender, onBack, isSearchActive, searchText, isTracking, isFrozen, activeFilterCount, hasRenders, filterViewActiveTab, detailViewActiveTab, handleBackFromFilter, handleBackFromDetail, handleCloseCopySettings, handleSearch, handleSearchToggle, handleSearchClose, handleFilterToggle, handleToggleTracking, handleToggleFreeze, handleClear, handleOpenCopySettings]);
492
+
493
+ // ============================================================================
494
+ // RENDER
495
+ // ============================================================================
496
+
497
+ const persistenceKey = enableSharedModalDimensions ? _sharedUi.devToolsStorageKeys.modal.root() : _sharedUi.devToolsStorageKeys.highlightUpdates.modal();
498
+ if (!visible) return null;
499
+
500
+ // Footer for navigating through the renders list or history events
501
+ const totalRenders = rendersListRef.current.length;
502
+ const footerNode = selectedRender ? detailViewActiveTab === "details" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
503
+ currentIndex: selectedRenderIndex,
504
+ totalItems: totalRenders,
505
+ onPrevious: handlePreviousRender,
506
+ onNext: handleNextRender,
507
+ itemLabel: "Component",
508
+ subtitle: selectedRender.componentName || selectedRender.displayName || selectedRender.viewType
509
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_RenderHistoryViewer.RenderHistoryFooter, {
510
+ render: selectedRender,
511
+ selectedEventIndex: historyEventIndex,
512
+ onEventIndexChange: setHistoryEventIndex,
513
+ isPro: isPro
514
+ }) : null;
515
+ const body = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
516
+ nativeID: "__rn_buoy__highlight-modal",
517
+ testID: "buoy-highlight-body",
518
+ style: styles.container,
519
+ children: showCopySettingsView ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_RendersCopySettingsView.RendersCopySettingsView, {
520
+ renders: copyRendersSnapshot
521
+ }) : selectedRender ? detailViewActiveTab === "details" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_RenderDetailView.RenderDetailView, {
522
+ render: selectedRender,
523
+ disableInternalFooter: true,
524
+ onAddFilter: handleAddFilter,
525
+ isPro: isPro
526
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_RenderHistoryViewer.RenderHistoryViewer, {
527
+ render: selectedRender,
528
+ disableInternalFooter: true,
529
+ selectedEventIndex: historyEventIndex,
530
+ onEventIndexChange: setHistoryEventIndex,
531
+ isPro: isPro
532
+ }) : showFilterView ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_HighlightFilterView.HighlightFilterView, {
533
+ filters: filters,
534
+ onFilterChange: handleFilterChange,
535
+ settings: settings,
536
+ onSettingsChange: handleSettingsChange,
537
+ availableProps: _RenderTracker.RenderTracker.getAvailableProps(),
538
+ activeTab: filterViewActiveTab
539
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
540
+ children: [!isTracking && /*#__PURE__*/(0, _jsxRuntime.jsx)(DisabledBanner, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_IsolatedRenderList.IsolatedRenderList, {
541
+ searchText: searchText,
542
+ filters: filters,
543
+ onSelectRender: handleRenderPress,
544
+ onStatsChange: handleStatsChange,
545
+ onRendersChange: handleRendersChange,
546
+ isTracking: isTracking,
547
+ isPro: isPro
548
+ })]
549
+ })
550
+ });
551
+
552
+ // The ONLY difference between the phone and the desktop dashboard is which
553
+ // shell the header, body and footer go in. Everything above this is shared.
554
+ if (inline) {
555
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.TickProvider, {
556
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
557
+ style: styles.inlineRoot,
558
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
559
+ style: styles.inlineHeader,
560
+ ..._sharedUi.windowDragProps,
561
+ children: renderHeaderContent()
562
+ }), body, footerNode]
563
+ })
564
+ });
565
+ }
566
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.TickProvider, {
567
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.JsModal, {
568
+ visible: visible,
569
+ onClose: onClose,
570
+ onMinimize: onMinimize,
571
+ persistenceKey: persistenceKey,
572
+ header: {
573
+ showToggleButton: true,
574
+ customContent: renderHeaderContent()
575
+ },
576
+ enablePersistence: true,
577
+ initialMode: "bottomSheet",
578
+ enableGlitchEffects: true,
579
+ styles: {},
580
+ footer: footerNode,
581
+ footerHeight: selectedRender ? detailViewActiveTab === "details" ? 68 : (selectedRender.renderHistory?.length ?? 0) > 1 ? 68 : 0 : 0,
582
+ children: body
583
+ })
584
+ });
585
+ }
586
+
587
+ /**
588
+ * The same renders tool as `HighlightUpdatesModal`, rendered INLINE for hosts
589
+ * that place tools in a panel rather than a modal. Exists so there is exactly
590
+ * one implementation — the desktop dashboard used to ship its own copy of this
591
+ * component's header and screen router.
592
+ */
593
+ function HighlightToolView(props = {}) {
594
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(HighlightUpdatesModal, {
595
+ ...props,
596
+ inline: true,
597
+ visible: true,
598
+ onClose: () => {}
599
+ });
600
+ }
601
+ const styles = _reactNative.StyleSheet.create({
602
+ inlineRoot: {
603
+ flex: 1,
604
+ minHeight: 0,
605
+ // Transparent so the desktop workbench's hoisted sky (one field spanning
606
+ // sidebar + panel) shows through — the shell paints its base beneath it.
607
+ backgroundColor: "transparent"
608
+ },
609
+ inlineHeader: {
610
+ paddingHorizontal: 12,
611
+ paddingVertical: 8,
612
+ borderBottomWidth: 1,
613
+ borderBottomColor: _sharedUi.night.color.border,
614
+ // Clear, like Bench — the host's hoisted sky shows through the header.
615
+ backgroundColor: "transparent"
616
+ },
617
+ container: {
618
+ flex: 1,
619
+ // Transparent so the HOST's field shows through — JsModal's hoisted
620
+ // ToolBackground in the modal, the desktop workbench's hoisted sky inline.
621
+ backgroundColor: "transparent"
622
+ },
623
+ disabledBanner: {
624
+ flexDirection: "row",
625
+ alignItems: "center",
626
+ gap: 8,
627
+ padding: 10,
628
+ marginHorizontal: 12,
629
+ marginTop: 8,
630
+ backgroundColor: _sharedUi.night.color.warningSoft,
631
+ borderRadius: 8,
632
+ borderWidth: 1,
633
+ borderColor: _sharedUi.night.color.warning + "20"
634
+ },
635
+ disabledText: {
636
+ color: _sharedUi.night.color.warning,
637
+ fontSize: 11,
638
+ flex: 1
639
+ }
640
+ });
641
+ var _default = exports.default = HighlightUpdatesModal;