UNPKG

react-native-modern-elements

Version:

A modern, customizable UI component library for React Native

188 lines (187 loc) 9.72 kB
import React, { memo } from "react"; import { FlatList, Image, RefreshControl, StyleSheet, Text, TouchableOpacity, View, } from "react-native"; import Divider from "./Divider"; import ListFooter from "./ListFooter"; export function TableInner({ columns, data, height = 300, onRowPress, defaultAlign = "left", tableStyles, borderColor = "black", borderWidth = 0.5, headerborderRight = false, showsVerticalScrollIndicator = true, HeaderRowStyle, headerTexts, cellRowBottomBorder, cellRowRightBorder = false, cellRowStyle, enableHeaderShadow = false, headerShadowStyle, summary, headerborderBottom = false, showHeader = true, contentContainerStyle, handleRefresh, hasMore, initialLoader, loadMore, loadingMore, refreshing, totalResult, pagination = false, Refreshing = false, divider = false, dividerWight = "90%", }) { const [isScrolled, setIsScrolled] = React.useState(false); const isNavigatingRef = React.useRef(false); const getAlignStyle = (align) => { const textAlign = align || defaultAlign; switch (textAlign) { case "center": return { justifyContent: "center", alignItems: "center" }; case "right": return { justifyContent: "flex-end", alignItems: "center" }; default: return { justifyContent: "flex-start", alignItems: "center" }; } }; const handleScroll = (event) => { const offsetY = event.nativeEvent.contentOffset.y; setIsScrolled(offsetY > 0); }; return (React.createElement(View, { style: [styles.maingContainer] }, React.createElement(View, { style: [styles.tableWrapper, { height }, tableStyles] }, showHeader !== false && (React.createElement(View, { style: [ styles.HeaderRow, HeaderRowStyle, headerborderBottom && { borderBottomColor: borderColor, borderBottomWidth: borderWidth, }, enableHeaderShadow && isScrolled && (headerShadowStyle !== null && headerShadowStyle !== void 0 ? headerShadowStyle : styles.defaultHeaderShadow), ] }, columns.map((col, i) => { var _a; return (React.createElement(View, { key: i, style: [ styles.cell, cellRowStyle, { flex: (_a = col.flex) !== null && _a !== void 0 ? _a : 1 }, getAlignStyle(col.headerTextAlign || col.align), col.headerStyle, i !== columns.length - 1 && headerborderRight && { borderRightColor: borderColor, borderRightWidth: borderWidth, }, ] }, React.createElement(Text, { style: [ styles.headerText, headerTexts, { textAlign: col.headerTextAlign || col.align || defaultAlign, alignSelf: col.headerTextAlign === "center" ? "center" : col.headerTextAlign === "right" ? "flex-end" : "flex-start", color: col.headerTextColors || "#000", }, ] }, col.label))); }))), React.createElement(FlatList, { data: data, keyboardShouldPersistTaps: "always", keyExtractor: (_, index) => index.toString(), showsVerticalScrollIndicator: showsVerticalScrollIndicator, onScroll: enableHeaderShadow ? handleScroll : undefined, contentContainerStyle: contentContainerStyle, ItemSeparatorComponent: divider ? () => (React.createElement(View, { style: { alignItems: "center", overflow: "hidden" } }, React.createElement(Divider, { width: dividerWight, align: "center", // bg={dividerColors} bg: borderColor, // height={dividerHeight} height: borderWidth }))) : undefined, scrollEventThrottle: 16, refreshControl: Refreshing ? (React.createElement(RefreshControl, { refreshing: refreshing, onRefresh: handleRefresh, colors: ["#ff6f00", "#ff8f00", "#ffa000"], tintColor: "#ff6f00", title: "Refreshing...", titleColor: "#ff6f00" })) : undefined, ListFooterComponent: pagination ? (React.createElement(ListFooter, { dataLength: data === null || data === void 0 ? void 0 : data.length, loadingMore: loadingMore, totalResult: totalResult, hasMore: hasMore })) : null, onEndReached: pagination ? loadMore : undefined, onEndReachedThreshold: pagination ? 0.2 : undefined, renderItem: ({ item, index: rowIndex }) => (React.createElement(TouchableOpacity // onPress={() => onRowPress?.(item, rowIndex)} , { // onPress={() => onRowPress?.(item, rowIndex)} activeOpacity: onRowPress ? 0.4 : 1, onPress: () => { if (isNavigatingRef.current) return; isNavigatingRef.current = true; onRowPress === null || onRowPress === void 0 ? void 0 : onRowPress(item, rowIndex); setTimeout(() => { isNavigatingRef.current = false; }, 500); } }, React.createElement(View, { style: [styles.cellRow] }, columns.map((col, colIndex) => { var _a, _b; return (React.createElement(View, { key: colIndex, style: [ styles.cell, cellRowStyle, { flex: (_a = col.flex) !== null && _a !== void 0 ? _a : 1 }, getAlignStyle(col.align), col.headerStyle, colIndex !== columns.length - 1 && cellRowRightBorder && { borderRightColor: borderColor, borderRightWidth: borderWidth, }, cellRowBottomBorder && rowIndex === data.length - 1 && { borderBottomColor: borderColor, borderBottomWidth: borderWidth, }, ] }, col.render ? (col.render(item[col.key], item, rowIndex)) : typeof item[col.key] === "string" && item[col.key].startsWith("http") ? (React.createElement(Image, { source: { uri: item[col.key] }, style: { width: 40, height: 40, borderRadius: 20 } })) : (React.createElement(Text, { style: [ styles.cellText, { textAlign: col.align || defaultAlign }, ] }, String((_b = item[col.key]) !== null && _b !== void 0 ? _b : ""))))); })))) })), (summary === null || summary === void 0 ? void 0 : summary.content) && (React.createElement(View, { style: [ styles.summaryWrapper, summary === null || summary === void 0 ? void 0 : summary.summaryWrapper, { justifyContent: summary.align === "right" ? "flex-end" : "flex-start", }, ] }, React.createElement(View, { style: [styles.summaryBox, summary.style] }, summary.content))))); } // 🧠 Custom comparison logic for memoization function areEqual(prevProps, nextProps) { return (prevProps.data === nextProps.data && prevProps.columns === nextProps.columns && prevProps.refreshing === nextProps.refreshing && prevProps.loadingMore === nextProps.loadingMore && prevProps.totalResult === nextProps.totalResult && prevProps.hasMore === nextProps.hasMore); } const styles = StyleSheet.create({ tableWrapper: { backgroundColor: "#fff", width: "100%", overflow: "hidden", }, maingContainer: { width: "100%", overflow: "hidden", }, HeaderRow: { flexDirection: "row", backgroundColor: "#eee", }, cellRow: { flexDirection: "row", }, cell: { paddingVertical: 10, paddingHorizontal: 12, }, headerText: { fontWeight: "bold", fontSize: 14, color: "#000", }, cellText: { fontSize: 14, color: "#333", }, defaultHeaderShadow: { shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, shadowRadius: 4, elevation: 4, }, summaryContainer: { flexDirection: "row", marginTop: 10, gap: 12, alignItems: "center", }, summaryBox: { padding: 10, backgroundColor: "#f2f2f2", borderRadius: 6, }, summaryWrapper: { width: "100%", marginTop: 10, // paddingHorizontal: 12, flexDirection: "row", }, stickyHeader: { position: "absolute", top: 0, left: 0, right: 0, zIndex: 10, }, }); export const Table = memo(TableInner, areEqual);