@comergehq/studio 0.1.8 → 0.1.9
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.
- package/dist/index.js +41 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +46 -53
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/ChatMessageList.tsx +3 -1
- package/src/components/chat/ChatPage.tsx +24 -30
- package/src/components/studio-sheet/StudioBottomSheet.tsx +1 -16
- package/src/studio/ui/StudioOverlay.tsx +8 -4
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { View, type NativeScrollEvent, type NativeSyntheticEvent, type ViewStyle } from 'react-native';
|
|
2
|
+
import { Platform, View, type NativeScrollEvent, type NativeSyntheticEvent, type ViewStyle } from 'react-native';
|
|
3
3
|
import { BottomSheetFlatList } from '@gorhom/bottom-sheet';
|
|
4
4
|
|
|
5
5
|
import type { ChatMessage } from '../models/types';
|
|
@@ -119,6 +119,8 @@ export const ChatMessageList = React.forwardRef<ChatMessageListRef, ChatMessageL
|
|
|
119
119
|
ref={listRef}
|
|
120
120
|
data={messages}
|
|
121
121
|
keyExtractor={(m: ChatMessage) => m.id}
|
|
122
|
+
keyboardDismissMode={Platform.OS === 'ios' ? 'interactive' : 'on-drag'}
|
|
123
|
+
keyboardShouldPersistTaps="handled"
|
|
122
124
|
onScroll={handleScroll}
|
|
123
125
|
scrollEventThrottle={16}
|
|
124
126
|
showsVerticalScrollIndicator={false}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Keyboard, Platform, View, type ViewStyle } from 'react-native';
|
|
3
3
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
4
|
-
import Animated, { useAnimatedKeyboard, useAnimatedStyle } from 'react-native-reanimated';
|
|
5
4
|
|
|
6
5
|
import type { ChatMessage } from '../models/types';
|
|
7
6
|
import { useTheme } from '../../theme';
|
|
@@ -42,11 +41,9 @@ export function ChatPage({
|
|
|
42
41
|
const insets = useSafeAreaInsets();
|
|
43
42
|
const [composerHeight, setComposerHeight] = React.useState(0);
|
|
44
43
|
const [keyboardVisible, setKeyboardVisible] = React.useState(false);
|
|
45
|
-
const animatedKeyboard = useAnimatedKeyboard();
|
|
46
44
|
|
|
47
45
|
React.useEffect(() => {
|
|
48
46
|
if (Platform.OS !== 'ios') return;
|
|
49
|
-
|
|
50
47
|
const show = Keyboard.addListener('keyboardWillShow', () => setKeyboardVisible(true));
|
|
51
48
|
const hide = Keyboard.addListener('keyboardWillHide', () => setKeyboardVisible(false));
|
|
52
49
|
return () => {
|
|
@@ -56,10 +53,6 @@ export function ChatPage({
|
|
|
56
53
|
}, []);
|
|
57
54
|
|
|
58
55
|
const footerBottomPadding = Platform.OS === 'ios' ? (keyboardVisible ? 0 : insets.bottom) : insets.bottom + 10;
|
|
59
|
-
const footerAnimatedStyle = useAnimatedStyle(() => {
|
|
60
|
-
if (Platform.OS !== 'ios') return { paddingBottom: insets.bottom + 10 };
|
|
61
|
-
return { paddingBottom: animatedKeyboard.height.value > 0 ? 0 : insets.bottom };
|
|
62
|
-
});
|
|
63
56
|
const overlayBottom = composerHeight + footerBottomPadding + theme.spacing.lg;
|
|
64
57
|
const bottomInset = composerHeight + footerBottomPadding + theme.spacing.xl;
|
|
65
58
|
|
|
@@ -80,35 +73,36 @@ export function ChatPage({
|
|
|
80
73
|
</View>
|
|
81
74
|
) : null}
|
|
82
75
|
<View style={{ flex: 1 }}>
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
76
|
+
<View
|
|
77
|
+
style={{ flex: 1 }}
|
|
78
|
+
>
|
|
79
|
+
<ChatMessageList
|
|
80
|
+
ref={listRef}
|
|
81
|
+
messages={messages}
|
|
82
|
+
showTypingIndicator={showTypingIndicator}
|
|
83
|
+
renderMessageContent={renderMessageContent}
|
|
84
|
+
onNearBottomChange={onNearBottomChange}
|
|
85
|
+
bottomInset={bottomInset}
|
|
86
|
+
/>
|
|
87
|
+
{resolvedOverlay}
|
|
88
|
+
</View>
|
|
89
|
+
<View
|
|
90
|
+
style={{
|
|
91
|
+
position: 'absolute',
|
|
92
|
+
left: 0,
|
|
93
|
+
right: 0,
|
|
94
|
+
bottom: 0,
|
|
95
|
+
paddingHorizontal: theme.spacing.lg,
|
|
96
|
+
paddingTop: theme.spacing.sm,
|
|
97
|
+
paddingBottom: footerBottomPadding,
|
|
98
|
+
}}
|
|
105
99
|
>
|
|
106
100
|
<ChatComposer
|
|
107
101
|
{...composer}
|
|
108
102
|
attachments={composer.attachments ?? []}
|
|
109
103
|
onLayout={({ height }) => setComposerHeight(height)}
|
|
110
104
|
/>
|
|
111
|
-
</
|
|
105
|
+
</View>
|
|
112
106
|
</View>
|
|
113
107
|
</View>
|
|
114
108
|
);
|
|
@@ -35,8 +35,7 @@ export type StudioBottomSheetProps = {
|
|
|
35
35
|
children: React.ReactNode;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Additional BottomSheet props
|
|
39
|
-
* We intentionally do not expose everything as first-class props to keep SRP.
|
|
38
|
+
* Additional BottomSheet props
|
|
40
39
|
*/
|
|
41
40
|
bottomSheetProps?: Omit<
|
|
42
41
|
BottomSheetProps,
|
|
@@ -93,20 +92,6 @@ export function StudioBottomSheet({
|
|
|
93
92
|
return () => sub.remove();
|
|
94
93
|
}, [open, resolvedSheetRef]);
|
|
95
94
|
|
|
96
|
-
React.useEffect(() => {
|
|
97
|
-
if (Platform.OS !== 'ios') return;
|
|
98
|
-
const sub = Keyboard.addListener('keyboardDidHide', () => {
|
|
99
|
-
const sheet = resolvedSheetRef.current;
|
|
100
|
-
if (!sheet || !open) return;
|
|
101
|
-
const targetIndex = snapPoints.length - 1;
|
|
102
|
-
// Only "re-snap" if we're already at the highest snap point.
|
|
103
|
-
if (currentIndexRef.current === targetIndex) {
|
|
104
|
-
setTimeout(() => sheet.snapToIndex(targetIndex), 10);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
return () => sub.remove();
|
|
108
|
-
}, [open, resolvedSheetRef, snapPoints.length]);
|
|
109
|
-
|
|
110
95
|
React.useEffect(() => {
|
|
111
96
|
const sheet = resolvedSheetRef.current;
|
|
112
97
|
if (!sheet) return;
|
|
@@ -104,11 +104,15 @@ export function StudioOverlay({
|
|
|
104
104
|
[confirmMrId, incomingMergeRequests]
|
|
105
105
|
);
|
|
106
106
|
|
|
107
|
-
const
|
|
108
|
-
setSheetOpen(
|
|
109
|
-
Keyboard.dismiss();
|
|
107
|
+
const handleSheetOpenChange = React.useCallback((open: boolean) => {
|
|
108
|
+
setSheetOpen(open);
|
|
109
|
+
if (!open) Keyboard.dismiss();
|
|
110
110
|
}, []);
|
|
111
111
|
|
|
112
|
+
const closeSheet = React.useCallback(() => {
|
|
113
|
+
handleSheetOpenChange(false);
|
|
114
|
+
}, [handleSheetOpenChange]);
|
|
115
|
+
|
|
112
116
|
const openSheet = React.useCallback(() => setSheetOpen(true), []);
|
|
113
117
|
|
|
114
118
|
const goToChat = React.useCallback(() => {
|
|
@@ -178,7 +182,7 @@ export function StudioOverlay({
|
|
|
178
182
|
{/* Testing glow around runtime */}
|
|
179
183
|
<EdgeGlowFrame visible={isTesting} role="accent" thickness={40} intensity={1} />
|
|
180
184
|
|
|
181
|
-
<StudioBottomSheet open={sheetOpen} onOpenChange={
|
|
185
|
+
<StudioBottomSheet open={sheetOpen} onOpenChange={handleSheetOpenChange}>
|
|
182
186
|
<StudioSheetPager
|
|
183
187
|
activePage={activePage}
|
|
184
188
|
width={width}
|