Skip to content

Commit 71418fd

Browse files
author
Brian Vaughn
committed
Rearranged some DevTools Components code
1 parent d166319 commit 71418fd

File tree

4 files changed

+238
-258
lines changed

4 files changed

+238
-258
lines changed

packages/react-devtools-shared/src/devtools/views/Components/Components.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
.Components {
2+
position: relative;
3+
width: 100%;
4+
height: 100%;
5+
display: flex;
6+
flex-direction: row;
7+
background-color: var(--color-background);
8+
color: var(--color-text);
9+
font-family: var(--font-family-sans);
10+
}
11+
112
.TreeWrapper {
213
flex: 0 0 var(--horizontal-resize-percentage);
314
overflow: auto;
@@ -23,6 +34,10 @@
2334
}
2435

2536
@media screen and (max-width: 600px) {
37+
.Components {
38+
flex-direction: column;
39+
}
40+
2641
.TreeWrapper {
2742
flex: 0 0 var(--vertical-resize-percentage);
2843
}

packages/react-devtools-shared/src/devtools/views/Components/Components.js

Lines changed: 223 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,49 +8,155 @@
88
*/
99

1010
import * as React from 'react';
11-
import {Suspense, Fragment} from 'react';
11+
import {
12+
Fragment,
13+
Suspense,
14+
useEffect,
15+
useLayoutEffect,
16+
useReducer,
17+
useRef,
18+
} from 'react';
1219
import Tree from './Tree';
13-
import SelectedElement from './SelectedElement';
1420
import {InspectedElementContextController} from './InspectedElementContext';
15-
import {NativeStyleContextController} from './NativeStyleEditor/context';
1621
import {OwnersListContextController} from './OwnersListContext';
17-
import ComponentsResizer from './ComponentsResizer';
1822
import portaledContent from '../portaledContent';
23+
import {SettingsModalContextController} from 'react-devtools-shared/src/devtools/views/Settings/SettingsModalContext';
24+
import {
25+
localStorageGetItem,
26+
localStorageSetItem,
27+
} from 'react-devtools-shared/src/storage';
28+
import SelectedElement from './SelectedElement';
1929
import {ModalDialog} from '../ModalDialog';
2030
import SettingsModal from 'react-devtools-shared/src/devtools/views/Settings/SettingsModal';
21-
import {SettingsModalContextController} from 'react-devtools-shared/src/devtools/views/Settings/SettingsModalContext';
31+
import {NativeStyleContextController} from './NativeStyleEditor/context';
2232

2333
import styles from './Components.css';
2434

2535
function Components(_: {||}) {
36+
const wrapperElementRef = useRef<HTMLElement>(null);
37+
const resizeElementRef = useRef<HTMLElement>(null);
38+
39+
const [state, dispatch] = useReducer<ResizeState, ResizeAction>(
40+
resizeReducer,
41+
null,
42+
initResizeState,
43+
);
44+
45+
const {horizontalPercentage, verticalPercentage} = state;
46+
47+
useLayoutEffect(() => {
48+
const resizeElement = resizeElementRef.current;
49+
50+
setResizeCSSVariable(
51+
resizeElement,
52+
'horizontal',
53+
horizontalPercentage * 100,
54+
);
55+
setResizeCSSVariable(resizeElement, 'vertical', verticalPercentage * 100);
56+
}, []);
57+
58+
useEffect(() => {
59+
const timeoutID = setTimeout(() => {
60+
localStorageSetItem(
61+
LOCAL_STORAGE_KEY,
62+
JSON.stringify({
63+
horizontalPercentage,
64+
verticalPercentage,
65+
}),
66+
);
67+
}, 500);
68+
69+
return () => clearTimeout(timeoutID);
70+
}, [horizontalPercentage, verticalPercentage]);
71+
72+
const {isResizing} = state;
73+
74+
const onResizeStart = () =>
75+
dispatch({type: 'ACTION_SET_IS_RESIZING', payload: true});
76+
77+
let onResize;
78+
let onResizeEnd;
79+
if (isResizing) {
80+
onResizeEnd = () =>
81+
dispatch({type: 'ACTION_SET_IS_RESIZING', payload: false});
82+
83+
onResize = event => {
84+
const resizeElement = resizeElementRef.current;
85+
const wrapperElement = wrapperElementRef.current;
86+
87+
if (!isResizing || wrapperElement === null || resizeElement === null) {
88+
return;
89+
}
90+
91+
event.preventDefault();
92+
93+
const orientation = getOrientation(wrapperElement);
94+
95+
const {height, width, left, top} = wrapperElement.getBoundingClientRect();
96+
97+
const currentMousePosition =
98+
orientation === 'horizontal'
99+
? event.clientX - left
100+
: event.clientY - top;
101+
102+
const boundaryMin = MINIMUM_SIZE;
103+
const boundaryMax =
104+
orientation === 'horizontal'
105+
? width - MINIMUM_SIZE
106+
: height - MINIMUM_SIZE;
107+
108+
const isMousePositionInBounds =
109+
currentMousePosition > boundaryMin &&
110+
currentMousePosition < boundaryMax;
111+
112+
if (isMousePositionInBounds) {
113+
const resizedElementDimension =
114+
orientation === 'horizontal' ? width : height;
115+
const actionType =
116+
orientation === 'horizontal'
117+
? 'ACTION_SET_HORIZONTAL_PERCENTAGE'
118+
: 'ACTION_SET_VERTICAL_PERCENTAGE';
119+
const percentage =
120+
(currentMousePosition / resizedElementDimension) * 100;
121+
122+
setResizeCSSVariable(resizeElement, orientation, percentage);
123+
124+
dispatch({
125+
type: actionType,
126+
payload: currentMousePosition / resizedElementDimension,
127+
});
128+
}
129+
};
130+
}
131+
26132
return (
27133
<SettingsModalContextController>
28134
<OwnersListContextController>
29135
<InspectedElementContextController>
30-
<ComponentsResizer>
31-
{({resizeElementRef, onResizeStart}) => (
32-
<Fragment>
33-
<div ref={resizeElementRef} className={styles.TreeWrapper}>
34-
<Tree />
35-
</div>
36-
<div className={styles.ResizeBarWrapper}>
37-
<div
38-
onMouseDown={onResizeStart}
39-
className={styles.ResizeBar}
40-
/>
41-
</div>
42-
<div className={styles.SelectedElementWrapper}>
43-
<NativeStyleContextController>
44-
<Suspense fallback={<Loading />}>
45-
<SelectedElement />
46-
</Suspense>
47-
</NativeStyleContextController>
48-
</div>
49-
<ModalDialog />
50-
<SettingsModal />
51-
</Fragment>
52-
)}
53-
</ComponentsResizer>
136+
<div
137+
ref={wrapperElementRef}
138+
className={styles.Components}
139+
onMouseMove={onResize}
140+
onMouseLeave={onResizeEnd}
141+
onMouseUp={onResizeEnd}>
142+
<Fragment>
143+
<div ref={resizeElementRef} className={styles.TreeWrapper}>
144+
<Tree />
145+
</div>
146+
<div className={styles.ResizeBarWrapper}>
147+
<div onMouseDown={onResizeStart} className={styles.ResizeBar} />
148+
</div>
149+
<div className={styles.SelectedElementWrapper}>
150+
<NativeStyleContextController>
151+
<Suspense fallback={<Loading />}>
152+
<SelectedElement />
153+
</Suspense>
154+
</NativeStyleContextController>
155+
</div>
156+
<ModalDialog />
157+
<SettingsModal />
158+
</Fragment>
159+
</div>
54160
</InspectedElementContextController>
55161
</OwnersListContextController>
56162
</SettingsModalContextController>
@@ -61,4 +167,92 @@ function Loading() {
61167
return <div className={styles.Loading}>Loading...</div>;
62168
}
63169

170+
const LOCAL_STORAGE_KEY = 'React::DevTools::createResizeReducer';
171+
const VERTICAL_MODE_MAX_WIDTH = 600;
172+
const MINIMUM_SIZE = 50;
173+
174+
type Orientation = 'horizontal' | 'vertical';
175+
176+
type ResizeActionType =
177+
| 'ACTION_SET_DID_MOUNT'
178+
| 'ACTION_SET_IS_RESIZING'
179+
| 'ACTION_SET_HORIZONTAL_PERCENTAGE'
180+
| 'ACTION_SET_VERTICAL_PERCENTAGE';
181+
182+
type ResizeAction = {|
183+
type: ResizeActionType,
184+
payload: any,
185+
|};
186+
187+
type ResizeState = {|
188+
horizontalPercentage: number,
189+
isResizing: boolean,
190+
verticalPercentage: number,
191+
|};
192+
193+
function initResizeState(): ResizeState {
194+
let horizontalPercentage = 0.65;
195+
let verticalPercentage = 0.5;
196+
197+
try {
198+
let data = localStorageGetItem(LOCAL_STORAGE_KEY);
199+
if (data != null) {
200+
data = JSON.parse(data);
201+
horizontalPercentage = data.horizontalPercentage;
202+
verticalPercentage = data.verticalPercentage;
203+
}
204+
} catch (error) {}
205+
206+
return {
207+
horizontalPercentage,
208+
isResizing: false,
209+
verticalPercentage,
210+
};
211+
}
212+
213+
function resizeReducer(state: ResizeState, action: ResizeAction): ResizeState {
214+
switch (action.type) {
215+
case 'ACTION_SET_IS_RESIZING':
216+
return {
217+
...state,
218+
isResizing: action.payload,
219+
};
220+
case 'ACTION_SET_HORIZONTAL_PERCENTAGE':
221+
return {
222+
...state,
223+
horizontalPercentage: action.payload,
224+
};
225+
case 'ACTION_SET_VERTICAL_PERCENTAGE':
226+
return {
227+
...state,
228+
verticalPercentage: action.payload,
229+
};
230+
default:
231+
return state;
232+
}
233+
}
234+
235+
function getOrientation(
236+
wrapperElement: null | HTMLElement,
237+
): null | Orientation {
238+
if (wrapperElement != null) {
239+
const {width} = wrapperElement.getBoundingClientRect();
240+
return width > VERTICAL_MODE_MAX_WIDTH ? 'horizontal' : 'vertical';
241+
}
242+
return null;
243+
}
244+
245+
function setResizeCSSVariable(
246+
resizeElement: null | HTMLElement,
247+
orientation: null | Orientation,
248+
percentage: number,
249+
): void {
250+
if (resizeElement !== null && orientation !== null) {
251+
resizeElement.style.setProperty(
252+
`--${orientation}-resize-percentage`,
253+
`${percentage}%`,
254+
);
255+
}
256+
}
257+
64258
export default portaledContent(Components);

packages/react-devtools-shared/src/devtools/views/Components/ComponentsResizer.css

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)