Skip to content

Commit 5d27b13

Browse files
committed
feat: enhance panel functionality with animated handle and dynamic sizing
1 parent e6eff9a commit 5d27b13

File tree

7 files changed

+100
-18
lines changed

7 files changed

+100
-18
lines changed

src/core/refs.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createRef } from 'react';
22
import type { IndexedStackMethods } from '../ui/components/common/IndexedStack';
3-
import type { TextInput } from 'react-native';
3+
import { Animated, Dimensions, type TextInput } from 'react-native';
44

55
export enum DebuggerVisibility {
66
Hidden = -1,
@@ -27,6 +27,15 @@ const refs = {
2727
panel: createRef<IndexedStackMethods<PanelState>>(),
2828
header: createRef<IndexedStackMethods<HeaderState>>(),
2929
searchInput: createRef<TextInput>(),
30+
panelSize: (() => {
31+
const ref = createRef<Animated.ValueXY>();
32+
const dimensions = Dimensions.get('window');
33+
ref.current = new Animated.ValueXY({
34+
x: dimensions.width,
35+
y: Math.min(dimensions.width, dimensions.height) * 0.75,
36+
});
37+
return ref;
38+
})(),
3039
};
3140

3241
export default refs;

src/core/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export const getConsoleTypeColor = (type: LogMessage['type']) => {
7979
//#region metrics
8080
export const getVerticalSafeMargin = (screenHeight: number) => screenHeight / 8;
8181

82-
export const clamp = (value: number, min: number, max: number) =>
82+
export const clamp = (min: number, max: number, value: number) =>
8383
Math.max(min, Math.min(max, value));
8484

8585
export const getHttpInterceptorId = () => {

src/ui/components/bubble/Bubble.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ const Bubble = forwardRef<View, BubbleProps>(
8080
const verticalSafeMargin = getVerticalSafeMargin(screenHeight);
8181

8282
const finalY = clamp(
83-
gesture.moveY,
8483
verticalSafeMargin,
8584
screenHeight - verticalSafeMargin - bubbleSize,
85+
gesture.moveY,
8686
);
8787

8888
Animated.spring(pan.current, {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { useContext, useMemo, useRef } from 'react';
2+
import { Animated, PanResponder, StyleSheet, View } from 'react-native';
3+
import { MainContext } from '../../../contexts';
4+
import refs from '../../../core/refs';
5+
import { clamp } from '../../../core/utils';
6+
import colors from '../../../theme/colors';
7+
8+
export default function Handle() {
9+
const pan = useRef(new Animated.Value(0));
10+
const {
11+
dimensions,
12+
debuggerState: { position },
13+
} = useContext(MainContext)!;
14+
15+
const panResponder = useMemo(() => {
16+
const minPanelHeight = dimensions.height * 0.25;
17+
const maxPanelHeight = dimensions.height * 0.9;
18+
19+
return PanResponder.create({
20+
onStartShouldSetPanResponder: () => true,
21+
onMoveShouldSetPanResponder: () => true,
22+
onPanResponderMove: (event, gestureState) => {
23+
const value =
24+
position === 'bottom' ? dimensions.height - gestureState.moveY : gestureState.moveY;
25+
26+
refs.panelSize.current?.setValue({
27+
x: dimensions.width,
28+
y: clamp(minPanelHeight, maxPanelHeight, value),
29+
});
30+
31+
return Animated.event([null, { dy: pan.current }], {
32+
useNativeDriver: false,
33+
})(event, gestureState);
34+
},
35+
});
36+
}, [dimensions.height, dimensions.width, position]);
37+
38+
return (
39+
<View style={styles.handleContainer}>
40+
<Animated.View {...panResponder.panHandlers} style={styles.handle} hitSlop={16} />
41+
</View>
42+
);
43+
}
44+
45+
const styles = StyleSheet.create({
46+
handleContainer: {
47+
alignItems: 'center',
48+
justifyContent: 'center',
49+
backgroundColor: colors.lightGray,
50+
borderTopColor: colors.gray,
51+
borderTopWidth: StyleSheet.hairlineWidth,
52+
},
53+
handle: {
54+
width: 48,
55+
height: 4,
56+
marginVertical: 8,
57+
borderRadius: 2,
58+
backgroundColor: colors.gray,
59+
},
60+
});

src/ui/components/panels/ConsolePanel.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
type ViewStyle,
99
} from 'react-native';
1010
import { MainContext } from '../../../contexts';
11-
import refs, { HeaderState, PanelState } from '../../../core/refs';
1211
import { formatLogMessage } from '../../../core/utils';
1312
import { DebuggerPanel, type LogMessage } from '../../../types';
1413
import Empty from '../common/Empty';
@@ -42,8 +41,6 @@ const ConsolePanel = forwardRef<FlatList, { style?: StyleProp<ViewStyle> }>(({ s
4241
<ConsolePanelItem
4342
{...item}
4443
onPress={() => {
45-
refs.header.current?.setCurrentIndex(HeaderState.Console);
46-
refs.panel.current?.setCurrentIndex(PanelState.ConsoleDetail);
4744
setDebuggerState(draft => {
4845
draft.detailsData = {
4946
type: DebuggerPanel.Console,

src/ui/components/panels/NetworkPanel.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
type ViewStyle,
88
} from 'react-native';
99
import { MainContext } from '../../../contexts';
10-
import refs, { HeaderState, PanelState } from '../../../core/refs';
1110
import {
1211
DebuggerPanel,
1312
NetworkType,
@@ -51,8 +50,6 @@ const NetworkPanel = forwardRef<FlatList, { style?: StyleProp<ViewStyle> }>(({ s
5150
endTime={item.endTime}
5251
status={item.status}
5352
onPress={() => {
54-
refs.header.current?.setCurrentIndex(HeaderState.Network);
55-
refs.panel.current?.setCurrentIndex(PanelState.NetworkDetail);
5653
setDebuggerState(draft => {
5754
draft.detailsData = {
5855
type: DebuggerPanel.Network,

src/ui/components/panels/Panel.tsx

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,51 @@
1-
import { Platform, StyleSheet, View, type ViewProps } from 'react-native';
2-
import refs, { PanelState } from '../../../core/refs';
1+
import { Animated, Platform, StyleSheet, View, type ViewProps } from 'react-native';
2+
import refs, { HeaderState, PanelState } from '../../../core/refs';
33
import IndexedStack from '../common/IndexedStack';
44
import LogMessageDetails from '../details/LogMessageDetails';
55
import NetworkRequestDetails from '../details/NetworkRequestDetails';
66
import ConsolePanel from './ConsolePanel';
77
import NetworkPanel from './NetworkPanel';
88
import colors from '../../../theme/colors';
9-
import { forwardRef, useContext, useMemo } from 'react';
9+
import { forwardRef, useContext, useEffect, useMemo } from 'react';
1010
import Header from '../headers/Header';
1111
import { SafeAreaProvider } from 'react-native-safe-area-context';
1212
import SafeArea from '../common/SafeArea';
1313
import { MainContext } from '../../../contexts';
14+
import Handle from '../handle/Handle';
15+
import { DebuggerPanel } from '../../../types';
1416

1517
interface PanelProps extends ViewProps {}
1618

1719
const Panel = forwardRef<View, PanelProps>(({ style, ...props }, ref) => {
1820
const {
19-
debuggerState: { position },
20-
dimensions: { width: screenWidth, height: screenHeight },
21+
debuggerState: { position, detailsData },
2122
} = useContext(MainContext)!;
2223

2324
const containerStyle = useMemo(
24-
() => [styles.container, { [position]: 0, height: Math.min(screenWidth, screenHeight) * 0.75 }],
25-
[position, screenWidth, screenHeight],
25+
() => [
26+
styles.container,
27+
{ [position]: 0, width: refs.panelSize.current?.x, height: refs.panelSize.current?.y },
28+
],
29+
[position],
2630
);
2731

32+
useEffect(() => {
33+
switch (detailsData?.type) {
34+
case DebuggerPanel.Network:
35+
refs.header.current?.setCurrentIndex(HeaderState.Network);
36+
refs.panel.current?.setCurrentIndex(PanelState.NetworkDetail);
37+
break;
38+
case DebuggerPanel.Console:
39+
refs.header.current?.setCurrentIndex(HeaderState.Console);
40+
refs.panel.current?.setCurrentIndex(PanelState.ConsoleDetail);
41+
break;
42+
}
43+
}, [detailsData?.type]);
44+
2845
return (
29-
<View style={[containerStyle, style]} ref={ref} {...props}>
46+
<Animated.View style={[containerStyle, style]} ref={ref} {...props}>
3047
<SafeAreaProvider>
48+
{position === 'bottom' && <Handle />}
3149
{position === 'top' && <SafeArea inset="top" />}
3250

3351
<Header />
@@ -39,9 +57,10 @@ const Panel = forwardRef<View, PanelProps>(({ style, ...props }, ref) => {
3957
<LogMessageDetails />
4058
</IndexedStack>
4159

60+
{position === 'top' && <Handle />}
4261
{position === 'bottom' && <SafeArea inset="bottom" />}
4362
</SafeAreaProvider>
44-
</View>
63+
</Animated.View>
4564
);
4665
});
4766

0 commit comments

Comments
 (0)