UNPKG

react-native-panda-ui

Version:

A set of easily styled components to get you started fast

254 lines (240 loc) 7.56 kB
import React, { useState, useEffect, useRef } from 'react'; import { StyleSheet, View, ScrollView, Text, Dimensions, Platform } from 'react-native'; import Icon from 'react-native-vector-icons/FontAwesome5'; import SortColumnFlex from './SortColumnFlex'; import SortHeaderFlex from './SortHeaderFlex'; import Button from './Button'; // const PADDING = 10; const ScrollerEnum = { None: 'none', Header: 'header', StickyContent: 'sticky-content', ScrollContent: 'scroll-content' }; const StickyColumnTable = (props) => { const [showLeftChevron, setShowLeftChevron] = useState(false); const [showRightChevron, setShowRightChevron] = useState(false); const { data, columns, headerHeight, stickyHeaderOptions, rowHeight, sortConfig, borderRadius, headerBackgroundColor, backgroundColor, onSortChange, sortIndicatorColor, borderColor, selectedColor, headerTextColor, textColor, scrollArrowColor, maxHeight, maxWidth, width } = props; const horizontalScrollView = useRef(); const contentVerticalScrollView = useRef(); const headerVerticalScrollView = useRef(); const activeScroller = useRef(ScrollerEnum.None); // On mount trigger a small scroll so that the left and right chevrons display correctly. // This is a hacky way to do this, but we're not sure how to read the correct dimensions // outside of a scroll event. useEffect(() => { horizontalScrollView.current.scrollTo({ x: 1 }); }, []); const handleScroll_horizontal = (event) => { activeScroller.current = ScrollerEnum.Header; const positionX = event.nativeEvent.contentOffset.x; const outerWidth = event.nativeEvent.layoutMeasurement.width; const innerWidth = event.nativeEvent.contentSize.width; const positionXRemaining = innerWidth - outerWidth - positionX; setShowLeftChevron(positionX > 20); setShowRightChevron(positionXRemaining > 20); }; const handleScroll_stickyContent = (event) => { if (Platform.OS === 'ios' || activeScroller.current === ScrollerEnum.StickyContent) { const positionY = event.nativeEvent.contentOffset.y; contentVerticalScrollView.current.scrollTo({ y: positionY, animated: false }); } }; const handleScroll_contentVertical = (event) => { if (Platform.OS === 'ios' || activeScroller.current === ScrollerEnum.ScrollContent) { const positionY = event.nativeEvent.contentOffset.y; headerVerticalScrollView.current.scrollTo({ y: positionY, animated: false }); } }; const styles = StyleSheet.create({ container: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', width: width } }); return ( <View style={styles.container}> { /* sticky column */ } <View key="headerColumn" style={{ flex: 0.5, flexShrink: 0.5 }}> <View style={{ height: Platform.OS === 'ios' ? headerHeight - 3 : headerHeight - 1, width: '100%', flexDirection: 'row', backgroundColor: 'transparent', borderWidth: 0, borderTopLeftRadius: borderRadius, borderTopRightRadius: 0 }}> <SortColumnFlex key="0" column={stickyHeaderOptions} columnCount={0} i={0} sortConfig={sortConfig} onSortChange={onSortChange} borderRadiusLeft={borderRadius} backgroundColor={headerBackgroundColor} borderRadiusRight={0} sortIndicatorColor={sortIndicatorColor} borderColor={borderColor} selectedColor={selectedColor} textColor={headerTextColor} screenWidth={Dimensions.get('screen').width} /> </View> <ScrollView contentContainerStyle={{ width: '100%', padding: 0, alignItems: 'space-between' }} ref={headerVerticalScrollView} onScroll={handleScroll_stickyContent} onScrollBeginDrag={() => activeScroller.current = ScrollerEnum.StickyContent} scrollEventThrottle={16} style={{ maxHeight: maxHeight || Dimensions.get('screen').height / 2 }} > <View> { data.map((item, i) => { return ( <View key={i*-1} style={{ backgroundColor: backgroundColor, flexDirection: 'row', height: rowHeight, alignItems: 'center', justifyContent: 'center' }} > <Text style={{ paddingLeft: 10, width: '100%', textAlign: stickyHeaderOptions.textAlign, color: textColor }}>{item[stickyHeaderOptions.key]}</Text> </View> ); })} </View> </ScrollView> </View> { /* content column */ } <View key="contentColumn" style={{ flex: 1, width: maxWidth || Dimensions.get('window').width }}> <ScrollView ref={horizontalScrollView} scrollEventThrottle={16} horizontal onScroll={handleScroll_horizontal} onScrollBeginDrag={() => activeScroller.current = ScrollerEnum.ScrollContent} indicatorStyle="black" persistentScrollbar style={{ width: '100%' }} > {/* This <View> is required to create a flex column layout inside the horizontal <ScrollView> */} <View style={{ minWidth: Dimensions.get('screen').width * 2, marginTop: -1 }}> <SortHeaderFlex columns={columns} sortConfig={sortConfig} onSortChange={onSortChange} borderRadiusLeft={0} borderRadiusRight={borderRadius} height={headerHeight} backgroundColor={headerBackgroundColor} sortIndicatorColor={sortIndicatorColor} borderColor={borderColor} selectedColor={selectedColor} textColor={headerTextColor} /> <ScrollView ref={contentVerticalScrollView} onScroll={handleScroll_contentVertical} showsVerticalScrollIndicator={true} onScrollBeginDrag={() => activeScroller.current = ScrollerEnum.ScrollContent} scrollEventThrottle={16} persistentScrollbar style={{ maxHeight: Dimensions.get('screen').height / 2 }} // stickyHeaderIndices={[0]} > <View style={{ minWidth: Dimensions.get('screen').width * 2 }}> { data.map((item, i) => { return ( <View key={i} style={{ flex: 1, flexDirection: 'row', height: rowHeight, alignItems: 'center', justifyContent: 'center', backgroundColor: backgroundColor }}> { columns.map((detail, ii) => { return ( <Text key={ii*10} style={{ paddingLeft: 10, flexGrow: columns[ii].width, width: 0, textAlign: columns[ii].textAlign, color: textColor }}>{item[columns[ii].key]}</Text> ); }) } </View> ); })} </View> </ScrollView> </View> </ScrollView> {showLeftChevron && <Button iconElement={<Icon name="chevron-left" size={14} color={scrollArrowColor} />} size="small" height={40} width={10} solid={false} style={{ marginLeft: 2, justifyContent: 'center', position: 'absolute' }} disabled border={false} transparent onPress={() => ({}) } key="left-arrow" /> } {showRightChevron && <Button iconElement={<Icon name="chevron-right" size={14} color={scrollArrowColor} />} size="small" height={40} width={10} solid={false} style={{ marginRight: 2, justifyContent: 'center', position: 'absolute', right: 0 }} transparent disabled border={false} onPress={() => ({}) } key="right-arrow" /> } </View> </View> ); }; export default StickyColumnTable;