react-native-modern-elements
Version:
A modern, customizable UI component library for React Native
188 lines (187 loc) • 9.72 kB
JavaScript
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);