@sendbird/uikit-react-native
Version:
Sendbird UIKit for React Native: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.
246 lines • 7.73 kB
JavaScript
import React, { useEffect, useRef, useState } from 'react';
import { Animated, Easing, Pressable, ScrollView, View, useWindowDimensions } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Avatar, Divider, Image, Modal, Text, createStyleSheet, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
import { getReactionCount, truncatedCount } from '@sendbird/uikit-utils';
const ReactionUserListBottomSheet = _ref => {
let {
visible,
onClose,
onDismiss,
reactionCtx,
chatCtx,
localizationCtx,
onPressUserProfile
} = _ref;
const {
width
} = useWindowDimensions();
const {
bottom,
left,
right
} = useSafeAreaInsets();
const {
colors
} = useUIKitTheme();
const [tabIndex, setTabIndex] = useState(0);
const scrollRef = useRef();
const tabIndicatorValue = useRef([]);
const tabIndicatorAnimated = useRef({
x: new Animated.Value(0),
width: new Animated.Value(0)
}).current;
const focusedWithLayoutCalculated = useRef(false);
const {
emojiManager
} = chatCtx;
const {
channel,
message,
focusIndex
} = reactionCtx;
const {
STRINGS
} = localizationCtx;
const color = colors.ui.reaction.default;
const reactions = (message === null || message === void 0 ? void 0 : message.reactions) ?? [];
const focusedReaction = reactions[tabIndex];
const containerSafeArea = {
paddingLeft: left + styles.layout.paddingHorizontal,
paddingRight: right + styles.layout.paddingHorizontal
};
const focusTab = function (index) {
let animated = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
const indicatorValue = tabIndicatorValue.current[index];
if (indicatorValue) {
var _scrollRef$current;
setTabIndex(index);
animateTabIndicator(indicatorValue.x, indicatorValue.width, animated);
(_scrollRef$current = scrollRef.current) === null || _scrollRef$current === void 0 ? void 0 : _scrollRef$current.scrollTo({
x: indicatorValue.x,
animated
});
}
};
const animateTabIndicator = function (x, width) {
let animated = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
const baseConfig = {
duration: animated ? 300 : 0,
easing: Easing.inOut(Easing.ease),
useNativeDriver: false
};
Animated.parallel([Animated.timing(tabIndicatorAnimated.x, {
toValue: x,
...baseConfig
}), Animated.timing(tabIndicatorAnimated.width, {
toValue: width,
...baseConfig
})]).start();
};
const layoutCalculated = () => {
return tabIndicatorValue.current.length === reactions.length && tabIndicatorValue.current.every(Boolean);
};
useEffect(() => {
if (!visible) {
tabIndicatorValue.current = [];
tabIndicatorAnimated.x = new Animated.Value(0);
tabIndicatorAnimated.width = new Animated.Value(0);
focusedWithLayoutCalculated.current = false;
}
}, [visible]);
const renderTabs = () => {
return /*#__PURE__*/React.createElement(Pressable, {
style: styles.tabsWrapper
}, reactions.map((reaction, index) => {
const isFocused = (focusedReaction === null || focusedReaction === void 0 ? void 0 : focusedReaction.key) === reaction.key;
const isLastItem = reactions.length - 1 === index;
const emoji = emojiManager.allEmojiMap[reaction.key];
return /*#__PURE__*/React.createElement(Pressable, {
key: reaction.key,
style: [styles.tabItem, isLastItem && {
marginRight: styles.layout.marginRight
}],
onPress: () => focusTab(index),
onLayout: e => {
tabIndicatorValue.current[index] = e.nativeEvent.layout;
if (layoutCalculated()) {
if (focusedWithLayoutCalculated.current) {
focusTab(tabIndex, false);
} else {
focusedWithLayoutCalculated.current = true;
focusTab(focusIndex);
}
}
}
}, /*#__PURE__*/React.createElement(Image, {
source: {
uri: emoji.url
},
style: styles.tabEmoji
}), /*#__PURE__*/React.createElement(Text, {
button: true,
color: isFocused ? color.selected.highlight : color.enabled.highlight
}, truncatedCount(getReactionCount(reaction))));
}), /*#__PURE__*/React.createElement(Animated.View, {
style: [styles.tabIndicator, {
left: tabIndicatorAnimated.x,
width: tabIndicatorAnimated.width,
backgroundColor: color.selected.highlight
}]
}));
};
const renderPage = () => {
return /*#__PURE__*/React.createElement(React.Fragment, null, focusedReaction === null || focusedReaction === void 0 ? void 0 : focusedReaction.userIds.map(userId => {
if (channel !== null && channel !== void 0 && channel.isGroupChannel()) {
const user = channel.members.find(x => x.userId === userId);
return /*#__PURE__*/React.createElement(Pressable, {
key: userId,
onPress: async () => {
if (user) {
await onClose();
onPressUserProfile(user);
}
},
style: styles.pageItem
}, /*#__PURE__*/React.createElement(Avatar, {
size: 36,
uri: user === null || user === void 0 ? void 0 : user.profileUrl,
containerStyle: styles.avatar
}), /*#__PURE__*/React.createElement(Text, {
subtitle2: true,
style: {
flex: 1
}
}, (user === null || user === void 0 ? void 0 : user.nickname) || STRINGS.LABELS.USER_NO_NAME));
}
return null;
}));
};
return /*#__PURE__*/React.createElement(Modal, {
type: 'slide-no-gesture',
visible: Boolean(visible && channel && message),
onClose: onClose,
onDismiss: onDismiss,
backgroundStyle: styles.modal
}, /*#__PURE__*/React.createElement(View, {
style: [styles.container, {
width,
paddingBottom: bottom,
backgroundColor: colors.ui.dialog.default.none.background
}]
}, /*#__PURE__*/React.createElement(ScrollView, {
ref: scrollRef,
horizontal: true,
bounces: false,
showsHorizontalScrollIndicator: false,
contentContainerStyle: [containerSafeArea, styles.tabsContainer]
}, renderTabs()), /*#__PURE__*/React.createElement(Divider, {
style: {
top: -1
}
}), /*#__PURE__*/React.createElement(ScrollView, {
bounces: false,
showsVerticalScrollIndicator: false,
style: styles.pageContainer,
contentContainerStyle: containerSafeArea
}, renderPage())));
};
const styles = createStyleSheet({
layout: {
paddingHorizontal: 16,
marginRight: 0
},
container: {
overflow: 'hidden',
borderTopLeftRadius: 8,
borderTopRightRadius: 8,
paddingTop: 16,
alignItems: 'center'
},
modal: {
alignItems: 'center',
justifyContent: 'flex-end'
},
tabsContainer: {
flexGrow: 1
},
tabsWrapper: {
flexGrow: 1,
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'center',
height: 44
},
tabItem: {
marginRight: 16,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
tabEmoji: {
width: 28,
height: 28,
marginRight: 4
},
tabIndicator: {
position: 'absolute',
bottom: 0,
height: 3
},
pageContainer: {
height: 216,
width: '100%'
},
pageItem: {
flexDirection: 'row',
width: '100%',
height: 48,
alignItems: 'center'
},
avatar: {
marginRight: 16
}
});
export default ReactionUserListBottomSheet;
//# sourceMappingURL=ReactionUserListBottomSheet.js.map