1- import { ReactScanInternals } from '../../index' ;
1+ import { getReport , ReactScanInternals } from '../../index' ;
22import { createElement } from './utils' ;
33import { MONO_FONT } from './outline' ;
44
@@ -7,16 +7,32 @@ export const createToolbar = () => {
77 `<div id="react-scan-toolbar" title="Number of unnecessary renders and time elapsed" style="position:fixed;bottom:3px;right:3px;background:rgba(0,0,0,0.5);padding:4px 8px;border-radius:4px;color:white;z-index:2147483647;font-family:${ MONO_FONT } " aria-hidden="true">react-scan</div>` ,
88 ) as HTMLDivElement ;
99
10+ // Create a scrollable and resizable div containing checkboxes
11+ const checkboxContainer = createElement (
12+ `<div id="react-scan-checkbox-list" style="position:fixed;bottom:3px;left:3px;min-width:200px;max-width:400px;height:200px;background:rgba(0,0,0,0.5);padding:8px;border:1px solid rgba(255,255,255,0.4);border-radius:6px;box-shadow:0 2px 8px rgba(0,0,0,0.15);z-index:2147483647;font-family:${ MONO_FONT } ;overflow-y:auto;resize:horizontal;display:none;">
13+ <div style="font-weight:400;margin-bottom:8px;color:white;border-bottom:1px solid rgba(255,255,255,0.4);padding-bottom:4px; font-size:14px;">Component Filters</div>
14+ </div>` ,
15+ ) as HTMLDivElement ;
16+
17+ document . documentElement . appendChild ( checkboxContainer ) ;
18+
1019 let isHidden =
11- // discord doesn't support localStorage
20+ // Discord doesn't support localStorage
1221 'localStorage' in globalThis &&
1322 localStorage . getItem ( 'react-scan-hidden' ) === 'true' ;
1423
24+ let isCheckboxContainerHidden = true ;
25+
26+ const toggleButton = createElement (
27+ `<button style="margin-left:8px;background:rgba(255,255,255,0.2);border:1px solid rgba(255,255,255,0.4);color:white;cursor:pointer;padding:3px 6px;border-radius:4px;font-size:16px;transition:all 0.2s;" title="Toggle component list">☰</button>`
28+ ) as HTMLButtonElement ;
29+
1530 const updateVisibility = ( ) => {
1631 const overlay = document . getElementById ( 'react-scan-overlay' ) ;
1732 if ( ! overlay ) return ;
1833 overlay . style . display = isHidden ? 'none' : 'block' ;
19- status . textContent = isHidden ? 'start ►' : 'stop ⏹' ;
34+ status . textContent = isHidden ? 'start' : 'stop' ;
35+ status . appendChild ( toggleButton ) ;
2036 ReactScanInternals . isPaused = isHidden ;
2137 if ( ReactScanInternals . isPaused ) {
2238 ReactScanInternals . activeOutlines = [ ] ;
@@ -29,18 +45,30 @@ export const createToolbar = () => {
2945
3046 updateVisibility ( ) ;
3147
32- status . addEventListener ( 'click' , ( ) => {
48+ status . addEventListener ( 'click' , ( e ) => {
49+ if ( e . target === toggleButton ) return ;
3350 isHidden = ! isHidden ;
3451 updateVisibility ( ) ;
3552 } ) ;
3653
54+ toggleButton . addEventListener ( 'click' , ( ) => {
55+ isCheckboxContainerHidden = ! isCheckboxContainerHidden ;
56+ checkboxContainer . style . display = isCheckboxContainerHidden ? 'none' : 'block' ;
57+ renderCheckbox ( ) ;
58+ } ) ;
59+
3760 status . addEventListener ( 'mouseenter' , ( ) => {
38- status . textContent = isHidden ? 'start ►' : 'stop ⏹' ;
61+ if ( status . textContent !== '☰' ) {
62+ status . textContent = isHidden ? 'start' : 'stop' ;
63+ status . appendChild ( toggleButton ) ;
64+ }
3965 status . style . backgroundColor = 'rgba(0,0,0,1)' ;
66+ toggleButton . style . backgroundColor = 'rgba(255,255,255,0.3)' ;
4067 } ) ;
4168
4269 status . addEventListener ( 'mouseleave' , ( ) => {
4370 status . style . backgroundColor = 'rgba(0,0,0,0.5)' ;
71+ toggleButton . style . backgroundColor = 'rgba(255,255,255,0.2)' ;
4472 } ) ;
4573
4674 const prevElement = document . getElementById ( 'react-scan-toolbar' ) ;
@@ -51,3 +79,41 @@ export const createToolbar = () => {
5179
5280 return status ;
5381} ;
82+
83+ export const renderCheckbox = ( ) => {
84+ const checkboxContainer = document . getElementById ( 'react-scan-checkbox-list' ) ;
85+ if ( ! checkboxContainer ) return ;
86+
87+ checkboxContainer . innerHTML = `
88+ <div style="font-weight:600;margin-bottom:8px;color:white;border-bottom:1px solid rgba(255,255,255,0.4);padding-bottom:4px;">Component Filters</div>
89+ ` ;
90+
91+ for ( const [ name , { count, time } ] of Object . entries ( getReport ( ) ) ) {
92+ const label = createElement (
93+ `<label style="display:flex;align-items:center;padding:4px 0;border-radius:4px;cursor:pointer;transition:background 0.2s;margin:2px 0;color:white;font-size:13px;">
94+ <input type="checkbox" value="${ name } " style="margin-right:8px;">
95+ <div style="flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">${ name } </div>
96+ <div style="margin-left:8px;color:rgba(255,255,255,0.7);white-space:nowrap;">✖︎${ count } · ${ time . toFixed ( 1 ) } ms</div>
97+ </label>` ,
98+ ) as HTMLLabelElement ;
99+
100+ const checkbox = label . querySelector ( 'input' ) ! ;
101+ checkbox . checked = ReactScanInternals . componentNameAllowList . has ( name ) ;
102+
103+ label . addEventListener ( 'mouseenter' , ( ) => {
104+ label . style . background = 'rgba(255,255,255,0.1)' ;
105+ } ) ;
106+
107+ label . addEventListener ( 'mouseleave' , ( ) => {
108+ label . style . background = 'transparent' ;
109+ } ) ;
110+
111+ checkbox . addEventListener ( 'change' , ( ) => {
112+ if ( checkbox . checked )
113+ ReactScanInternals . componentNameAllowList . add ( name ) ;
114+ else ReactScanInternals . componentNameAllowList . delete ( name ) ;
115+ } ) ;
116+
117+ checkboxContainer . appendChild ( label ) ;
118+ }
119+ } ;
0 commit comments