@idealyst/datagrid 1.0.83 → 1.0.84

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idealyst/datagrid",
3
- "version": "1.0.83",
3
+ "version": "1.0.84",
4
4
  "description": "High-performance datagrid component for React and React Native",
5
5
  "documentation": "https://github.com/IdealystIO/idealyst-framework/tree/main/packages/datagrid#readme",
6
6
  "readme": "README.md",
@@ -36,8 +36,8 @@
36
36
  "publish:npm": "npm publish"
37
37
  },
38
38
  "peerDependencies": {
39
- "@idealyst/components": "^1.0.83",
40
- "@idealyst/theme": "^1.0.83",
39
+ "@idealyst/components": "^1.0.84",
40
+ "@idealyst/theme": "^1.0.84",
41
41
  "react": ">=16.8.0",
42
42
  "react-native": ">=0.60.0",
43
43
  "react-native-unistyles": "^3.0.4",
@@ -61,8 +61,13 @@
61
61
  }
62
62
  },
63
63
  "devDependencies": {
64
+ "@idealyst/components": "^1.0.84",
65
+ "@idealyst/theme": "^1.0.84",
64
66
  "@types/react": "^19.1.0",
65
67
  "@types/react-window": "^1.8.8",
68
+ "react": "^19.1.0",
69
+ "react-native": "^0.80.1",
70
+ "react-native-unistyles": "^3.0.10",
66
71
  "typescript": "^5.0.0"
67
72
  },
68
73
  "files": [
@@ -71,6 +71,7 @@ export function DataGrid<T extends Record<string, any>>({
71
71
  shadowOffset: { width: 0, height: 2 },
72
72
  shadowOpacity: 0.1,
73
73
  shadowRadius: 4,
74
+ minHeight: 300,
74
75
  },
75
76
  headerStyle
76
77
  ]}>
@@ -97,7 +98,7 @@ export function DataGrid<T extends Record<string, any>>({
97
98
  >
98
99
  <Text
99
100
  weight="bold"
100
- size="small"
101
+ size="sm"
101
102
  onPress={column.sortable ? () => handleSort(column) : undefined}
102
103
  style={{
103
104
  color: '#374151',
@@ -163,7 +164,7 @@ export function DataGrid<T extends Record<string, any>>({
163
164
  ]}
164
165
  >
165
166
  {typeof cellContent === 'string' || typeof cellContent === 'number' ? (
166
- <Text size="small" numberOfLines={1}>
167
+ <Text size="sm" numberOfLines={1}>
167
168
  {cellContent}
168
169
  </Text>
169
170
  ) : (
@@ -0,0 +1,188 @@
1
+ import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, StylesheetStyles } from '@idealyst/theme';
3
+
4
+ type CellAlignment = 'left' | 'center' | 'right';
5
+
6
+ type DataGridVariants = {
7
+ stickyHeader: boolean;
8
+ virtualized: boolean;
9
+ selected: boolean;
10
+ clickable: boolean;
11
+ alignment: CellAlignment;
12
+ };
13
+
14
+ export type ExpandedDataGridStyles = StylesheetStyles<keyof DataGridVariants>;
15
+
16
+ export type DataGridStylesheet = {
17
+ container: ExpandedDataGridStyles;
18
+ scrollView: ExpandedDataGridStyles;
19
+ scrollViewContent: ExpandedDataGridStyles;
20
+ table: ExpandedDataGridStyles;
21
+ header: ExpandedDataGridStyles;
22
+ headerRow: ExpandedDataGridStyles;
23
+ headerCell: ExpandedDataGridStyles;
24
+ headerText: ExpandedDataGridStyles;
25
+ row: ExpandedDataGridStyles;
26
+ cell: ExpandedDataGridStyles;
27
+ spacerRow: ExpandedDataGridStyles;
28
+ spacerCell: ExpandedDataGridStyles;
29
+ };
30
+
31
+ /**
32
+ * Generate DataGrid styles
33
+ */
34
+ export const dataGridStyles = StyleSheet.create((theme: Theme) => {
35
+ return {
36
+ container: {
37
+ borderWidth: 1,
38
+ borderColor: theme.colors.border.primary,
39
+ borderStyle: 'solid',
40
+ overflow: 'hidden',
41
+ display: 'flex',
42
+ flexDirection: 'column',
43
+ _web: {
44
+ boxSizing: 'border-box',
45
+ },
46
+ },
47
+
48
+ scrollView: {
49
+ flex: 1,
50
+ },
51
+
52
+ scrollViewContent: {
53
+ // Dynamic width set in component based on column widths
54
+ },
55
+
56
+ table: {
57
+ // Dynamic width and height set in component
58
+ },
59
+
60
+ header: ({ stickyHeader }: DataGridVariants) => ({
61
+ variants: {
62
+ stickyHeader: {
63
+ true: {
64
+ _web: {
65
+ position: 'sticky',
66
+ top: 0,
67
+ zIndex: 100,
68
+ boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
69
+ },
70
+ _native: {
71
+ elevation: 4,
72
+ zIndex: 100,
73
+ shadowColor: '#000',
74
+ shadowOffset: { width: 0, height: 2 },
75
+ shadowOpacity: 0.1,
76
+ shadowRadius: 4,
77
+ },
78
+ },
79
+ false: {},
80
+ },
81
+ },
82
+ }),
83
+
84
+ headerRow: ({ stickyHeader }: DataGridVariants) => ({
85
+ backgroundColor: stickyHeader ? theme.colors.surface.primary : theme.colors.surface.secondary,
86
+ borderBottomWidth: 2,
87
+ borderBottomColor: theme.colors.border.secondary,
88
+ borderStyle: 'solid',
89
+ flexDirection: 'row',
90
+ variants: {
91
+ stickyHeader: {
92
+ true: {
93
+ backgroundColor: theme.colors.surface.primary,
94
+ },
95
+ false: {
96
+ backgroundColor: theme.colors.surface.secondary,
97
+ },
98
+ },
99
+ },
100
+ }),
101
+
102
+ headerCell: {
103
+ padding: theme.sizes.view.md.spacing,
104
+ borderRightWidth: 1,
105
+ borderRightColor: theme.colors.border.secondary,
106
+ borderStyle: 'solid',
107
+ _web: {
108
+ boxSizing: 'border-box',
109
+ },
110
+ },
111
+
112
+ headerText: ({ clickable }: DataGridVariants) => ({
113
+ userSelect: 'none',
114
+ display: 'flex',
115
+ alignItems: 'center',
116
+ variants: {
117
+ clickable: {
118
+ true: {
119
+ _web: {
120
+ cursor: 'pointer',
121
+ },
122
+ },
123
+ false: {
124
+ _web: {
125
+ cursor: 'default',
126
+ },
127
+ },
128
+ },
129
+ },
130
+ }),
131
+
132
+ row: ({ selected }: DataGridVariants) => ({
133
+ borderBottomWidth: 1,
134
+ borderBottomColor: theme.colors.border.primary,
135
+ borderStyle: 'solid',
136
+ backgroundColor: theme.colors.surface.primary,
137
+ flexDirection: 'row',
138
+ _web: {
139
+ transition: 'background-color 0.2s ease',
140
+ },
141
+ variants: {
142
+ selected: {
143
+ true: {
144
+ backgroundColor: theme.intents.primary.hover,
145
+ },
146
+ false: {
147
+ backgroundColor: theme.colors.surface.primary,
148
+ },
149
+ },
150
+ },
151
+ }),
152
+
153
+ cell: ({ alignment }: DataGridVariants) => ({
154
+ padding: theme.sizes.view.md.spacing,
155
+ borderRightWidth: 1,
156
+ borderRightColor: theme.colors.border.primary,
157
+ borderStyle: 'solid',
158
+ _web: {
159
+ boxSizing: 'border-box',
160
+ },
161
+ variants: {
162
+ alignment: {
163
+ left: {
164
+ justifyContent: 'flex-start',
165
+ alignItems: 'flex-start',
166
+ },
167
+ center: {
168
+ justifyContent: 'center',
169
+ alignItems: 'center',
170
+ },
171
+ right: {
172
+ justifyContent: 'flex-end',
173
+ alignItems: 'flex-end',
174
+ },
175
+ },
176
+ },
177
+ }),
178
+
179
+ spacerRow: {
180
+ // Dynamic height set in component
181
+ },
182
+
183
+ spacerCell: {
184
+ padding: 0,
185
+ borderWidth: 0,
186
+ },
187
+ };
188
+ });
@@ -1,8 +1,9 @@
1
- import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react';
1
+ import React, { useState, useCallback, useMemo, useRef } from 'react';
2
2
  import { View, Text } from '@idealyst/components';
3
3
  import { ScrollView } from '../primitives/ScrollView';
4
4
  import { Table, TableRow, TableCell, TableHeader, TableBody } from '../primitives/Table';
5
5
  import type { DataGridProps, Column } from './types';
6
+ import { dataGridStyles } from './DataGrid.styles';
6
7
 
7
8
  export function DataGrid<T extends Record<string, any>>({
8
9
  data,
@@ -25,7 +26,6 @@ export function DataGrid<T extends Record<string, any>>({
25
26
  const [sortColumn, setSortColumn] = useState<string | null>(null);
26
27
  const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
27
28
  const [scrollTop, setScrollTop] = useState(0);
28
- const scrollRef = useRef<any>(null);
29
29
 
30
30
  // Virtualization calculations
31
31
  const visibleRange = useMemo(() => {
@@ -72,7 +72,7 @@ export function DataGrid<T extends Record<string, any>>({
72
72
  boxSizing: 'border-box' as const,
73
73
  flexShrink: 0,
74
74
  };
75
-
75
+
76
76
  if (column.width) {
77
77
  return {
78
78
  ...baseStyle,
@@ -91,39 +91,6 @@ export function DataGrid<T extends Record<string, any>>({
91
91
  }
92
92
  };
93
93
 
94
- // Helper function for consistent cell base styles
95
- const getCellBaseStyle = (theme: any) => ({
96
- padding: theme.spacing.sm,
97
- borderRightWidth: 1,
98
- });
99
-
100
- // Helper function for platform-specific header styles
101
- const getStickyHeaderStyle = (theme: any) => {
102
- if (!stickyHeader) return {};
103
-
104
- // Platform detection - check if we're on web or native
105
- const isWeb = typeof document !== 'undefined';
106
-
107
- if (isWeb) {
108
- return {
109
- position: 'sticky' as const,
110
- top: 0,
111
- zIndex: 100,
112
- boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
113
- };
114
- } else {
115
- // React Native - use elevation instead of boxShadow
116
- return {
117
- elevation: 4,
118
- zIndex: 100,
119
- shadowColor: '#000',
120
- shadowOffset: { width: 0, height: 2 },
121
- shadowOpacity: 0.1,
122
- shadowRadius: 4,
123
- };
124
- }
125
- };
126
-
127
94
  const handleSort = useCallback((column: Column<T>) => {
128
95
  if (!column.sortable) return;
129
96
 
@@ -151,37 +118,28 @@ export function DataGrid<T extends Record<string, any>>({
151
118
  }, [selectedRows, onSelectionChange, multiSelect, onRowClick]);
152
119
 
153
120
  const renderHeader = () => (
154
- <TableRow style={(theme) => ({
155
- backgroundColor: stickyHeader ? '#ffffff' : theme.colors.neutral[50],
156
- borderBottomWidth: 2,
157
- borderBottomColor: theme.colors.neutral[200],
121
+ <TableRow style={{
122
+ ...dataGridStyles.headerRow({ stickyHeader }),
158
123
  minHeight: headerHeight,
159
- flexDirection: 'row',
160
- ...getStickyHeaderStyle(theme),
161
124
  ...headerStyle,
162
- })}>
125
+ }}>
163
126
  {columns.map((column) => (
164
127
  <TableCell
165
128
  key={column.key}
166
129
  width={column.width}
167
- style={(theme) => ({
168
- ...getCellBaseStyle(theme),
169
- borderRightColor: theme.colors.neutral[200],
170
- backgroundColor: stickyHeader ? '#ffffff' : theme.colors.neutral[50],
171
- ...column.headerStyle,
172
- })}
130
+ style={{
131
+ ...dataGridStyles.headerCell,
132
+ ...getColumnStyle(column),
133
+ }}
134
+ onPress={column.sortable ? () => handleSort(column) : undefined}
173
135
  >
174
- <Text weight="bold" style={(theme) => ({
175
- fontSize: 14,
176
- color: theme.colors.neutral[700],
177
- })}>
136
+ <Text
137
+ weight="bold"
138
+ style={dataGridStyles.headerText({ clickable: column.sortable || false })}
139
+ >
178
140
  {column.header}
179
141
  {column.sortable && (
180
- <Text as="span" style={(theme) => ({
181
- fontSize: 10,
182
- marginLeft: theme.spacing.xs,
183
- color: theme.colors.primary[500],
184
- })}>
142
+ <Text style={{ marginLeft: 4 }}>
185
143
  {sortColumn === column.key ? ` ${sortDirection === 'asc' ? '▲' : '▼'}` : ''}
186
144
  </Text>
187
145
  )}
@@ -195,36 +153,33 @@ export function DataGrid<T extends Record<string, any>>({
195
153
  const actualIndex = virtualized ? visibleRange.start + virtualIndex : virtualIndex;
196
154
  const isSelected = selectedRows.includes(actualIndex);
197
155
  const computedRowStyle = typeof rowStyle === 'function' ? rowStyle(item, actualIndex) : rowStyle;
198
-
156
+
199
157
  return (
200
158
  <TableRow
201
159
  key={actualIndex}
202
- style={(theme) => ({
203
- borderBottomWidth: 1,
204
- borderBottomColor: theme.colors.neutral[100],
205
- backgroundColor: isSelected ? theme.colors.primary[50] : theme.colors.background,
160
+ style={{
161
+ ...dataGridStyles.row({ selected: isSelected }),
206
162
  minHeight: rowHeight,
207
- flexDirection: 'row',
208
163
  ...computedRowStyle,
209
- })}
164
+ }}
210
165
  onPress={() => handleRowClick(item, actualIndex)}
211
166
  >
212
167
  {columns.map((column) => {
213
168
  const value = column.accessor ? column.accessor(item) : item[column.key];
214
169
  const cellContent = column.render ? column.render(value, item, actualIndex) : value;
215
- const computedCellStyle = typeof column.cellStyle === 'function'
216
- ? column.cellStyle(value, item)
170
+ const computedCellStyle = typeof column.cellStyle === 'function'
171
+ ? column.cellStyle(value, item)
217
172
  : column.cellStyle;
218
-
173
+
219
174
  return (
220
175
  <TableCell
221
176
  key={column.key}
222
177
  width={column.width}
223
- style={(theme) => ({
224
- ...getCellBaseStyle(theme),
225
- borderRightColor: theme.colors.neutral[100],
178
+ style={{
179
+ ...dataGridStyles.cell({ alignment: column.align || 'left' }),
180
+ ...getColumnStyle(column),
226
181
  ...computedCellStyle,
227
- })}
182
+ }}
228
183
  >
229
184
  {typeof cellContent === 'string' || typeof cellContent === 'number' ? (
230
185
  <Text>{cellContent}</Text>
@@ -241,57 +196,53 @@ export function DataGrid<T extends Record<string, any>>({
241
196
  const containerHeight = typeof height === 'number' ? height : undefined;
242
197
 
243
198
  return (
244
- <View style={(theme) => ({
245
- backgroundColor: theme.colors.background,
246
- borderWidth: 1,
247
- borderColor: theme.colors.neutral[200],
248
- borderRadius: theme.radius.md,
249
- overflow: 'hidden',
199
+ <View style={{
200
+ ...dataGridStyles.container,
250
201
  width,
251
202
  height,
252
- display: 'flex',
253
- flexDirection: 'column',
254
203
  ...style,
255
- })}>
204
+ }}>
256
205
  <ScrollView
257
- style={{
258
- flex: 1,
206
+ style={{
207
+ ...dataGridStyles.scrollView,
259
208
  ...(containerHeight ? { maxHeight: containerHeight } : {})
260
209
  }}
261
210
  contentContainerStyle={{
211
+ ...dataGridStyles.scrollViewContent,
262
212
  width: minTableWidth,
263
213
  }}
264
214
  showsVerticalScrollIndicator={true}
265
215
  showsHorizontalScrollIndicator={true}
266
- bounces={false}
267
- directionalLockEnabled={false}
268
216
  onScroll={handleScroll}
269
217
  scrollEventThrottle={16}
270
218
  >
271
219
  <Table style={{
220
+ ...dataGridStyles.table,
272
221
  width: minTableWidth,
273
222
  ...(virtualized ? { height: totalHeight } : {})
274
223
  }}>
275
- <TableHeader>
224
+ <TableHeader style={dataGridStyles.header({ stickyHeader })}>
276
225
  {renderHeader()}
277
226
  </TableHeader>
278
227
  <TableBody>
279
228
  {virtualized && visibleRange.offsetY > 0 && (
280
- <TableRow style={{ height: visibleRange.offsetY }}>
281
- <TableCell
282
- style={{ padding: 0, borderWidth: 0, height: visibleRange.offsetY }}
229
+ <TableRow style={{ ...dataGridStyles.spacerRow, height: visibleRange.offsetY }}>
230
+ <TableCell
231
+ style={{ ...dataGridStyles.spacerCell, height: visibleRange.offsetY }}
283
232
  colSpan={columns.length}
284
233
  >
234
+ <View />
285
235
  </TableCell>
286
236
  </TableRow>
287
237
  )}
288
238
  {visibleData.map((item, index) => renderRow(item, index))}
289
239
  {virtualized && (data.length - visibleRange.end - 1) > 0 && (
290
- <TableRow style={{ height: (data.length - visibleRange.end - 1) * rowHeight }}>
291
- <TableCell
292
- style={{ padding: 0, borderWidth: 0, height: (data.length - visibleRange.end - 1) * rowHeight }}
240
+ <TableRow style={{ ...dataGridStyles.spacerRow, height: (data.length - visibleRange.end - 1) * rowHeight }}>
241
+ <TableCell
242
+ style={{ ...dataGridStyles.spacerCell, height: (data.length - visibleRange.end - 1) * rowHeight }}
293
243
  colSpan={columns.length}
294
244
  >
245
+ <View />
295
246
  </TableCell>
296
247
  </TableRow>
297
248
  )}
@@ -8,6 +8,7 @@ export interface Column<T = any> {
8
8
  maxWidth?: number;
9
9
  resizable?: boolean;
10
10
  sortable?: boolean;
11
+ align?: 'left' | 'center' | 'right';
11
12
  accessor?: (row: T) => any;
12
13
  render?: (value: any, row: T, index: number) => React.ReactNode;
13
14
  headerStyle?: ViewStyle;
@@ -57,7 +57,7 @@ export function BasicExample() {
57
57
  width: 100,
58
58
  render: (value) => (
59
59
  <View style={{ paddingHorizontal: 8, paddingVertical: 4, backgroundColor: '#f0f0f0', borderRadius: 4 }}>
60
- <Text size="small">{value}</Text>
60
+ <Text size="sm">{value}</Text>
61
61
  </View>
62
62
  ),
63
63
  },
@@ -67,7 +67,7 @@ export function BasicExample() {
67
67
  width: 100,
68
68
  render: (value) => (
69
69
  <Text
70
- size="small"
70
+ size="sm"
71
71
  weight="medium"
72
72
  style={{ color: value === 'active' ? '#22c55e' : '#ef4444' }}
73
73
  >
@@ -103,13 +103,13 @@ export function BasicExample() {
103
103
 
104
104
  return (
105
105
  <View spacing="lg" style={{ padding: 20 }}>
106
- <Text size="xlarge" weight="bold">DataGrid Example</Text>
106
+ <Text size="xl" weight="bold">DataGrid Example</Text>
107
107
 
108
108
  <View spacing="sm">
109
109
  <Text>Selected rows: {selectedRows.length}</Text>
110
110
  {selectedRows.length > 0 && (
111
111
  <Button
112
- size="small"
112
+ size="sm"
113
113
  variant="outlined"
114
114
  onPress={() => setSelectedRows([])}
115
115
  >
@@ -73,7 +73,7 @@ export function DataGridShowcase({
73
73
  width: showAllColumns ? 120 : 100,
74
74
  sortable: true,
75
75
  render: (value) => (
76
- <Badge variant="outlined" size="small">
76
+ <Badge variant="outlined" size="sm">
77
77
  {value}
78
78
  </Badge>
79
79
  ),
@@ -84,7 +84,7 @@ export function DataGridShowcase({
84
84
  width: showAllColumns ? 100 : 80,
85
85
  sortable: true,
86
86
  render: (value) => (
87
- <Text weight="semibold" size={showAllColumns ? 'medium' : 'small'}>
87
+ <Text weight="semibold" size={showAllColumns ? 'md' : 'sm'}>
88
88
  ${value.toFixed(2)}
89
89
  </Text>
90
90
  ),
@@ -96,7 +96,7 @@ export function DataGridShowcase({
96
96
  sortable: true,
97
97
  render: (value, row) => (
98
98
  <Text
99
- size="small"
99
+ size="sm"
100
100
  style={{
101
101
  color: row.status === 'out-of-stock' ? '#ef4444' :
102
102
  row.status === 'low-stock' ? '#f59e0b' : '#22c55e'
@@ -114,7 +114,7 @@ export function DataGridShowcase({
114
114
  const intent = value === 'in-stock' ? 'success' :
115
115
  value === 'low-stock' ? 'warning' : 'error';
116
116
  return (
117
- <Badge variant="filled" intent={intent} size="small">
117
+ <Badge variant="filled" intent={intent} size="sm">
118
118
  {value}
119
119
  </Badge>
120
120
  );
@@ -171,13 +171,13 @@ export function DataGridShowcase({
171
171
  return (
172
172
  <Screen background="primary" safeArea scrollable={false}>
173
173
  <View spacing={showAllColumns ? "lg" : "md"} style={{ padding: showAllColumns ? 16 : 12, flex: 1 }}>
174
- <Text size={showAllColumns ? "xlarge" : "large"} weight="bold">
174
+ <Text size={showAllColumns ? "xl" : "lg"} weight="bold">
175
175
  DataGrid {showAllColumns ? 'Component ' : ''}Showcase
176
176
  </Text>
177
177
 
178
178
  <Card variant="outlined">
179
179
  <View spacing={showAllColumns ? "md" : "sm"}>
180
- <Text weight="semibold" size="medium">Controls</Text>
180
+ <Text weight="semibold" size="md">Controls</Text>
181
181
 
182
182
  <View
183
183
  spacing="sm"
@@ -190,7 +190,7 @@ export function DataGridShowcase({
190
190
  >
191
191
  <Button
192
192
  variant="outlined"
193
- size="small"
193
+ size="sm"
194
194
  onPress={() => setVirtualized(!virtualized)}
195
195
  >
196
196
  {virtualized ? 'Disable' : 'Enable'} Virtualization
@@ -200,7 +200,7 @@ export function DataGridShowcase({
200
200
  <View style={{ flexDirection: 'row', gap: 8 }}>
201
201
  <Button
202
202
  variant="outlined"
203
- size="small"
203
+ size="sm"
204
204
  onPress={() => setSelectedRows([])}
205
205
  disabled={selectedRows.length === 0}
206
206
  >
@@ -210,7 +210,7 @@ export function DataGridShowcase({
210
210
  <Button
211
211
  variant="outlined"
212
212
  intent="error"
213
- size="small"
213
+ size="sm"
214
214
  onPress={handleDeleteSelected}
215
215
  disabled={selectedRows.length === 0}
216
216
  >
@@ -223,7 +223,7 @@ export function DataGridShowcase({
223
223
  <>
224
224
  <Button
225
225
  variant="outlined"
226
- size="small"
226
+ size="sm"
227
227
  onPress={() => setSelectedRows([])}
228
228
  disabled={selectedRows.length === 0}
229
229
  >
@@ -233,7 +233,7 @@ export function DataGridShowcase({
233
233
  <Button
234
234
  variant="outlined"
235
235
  intent="error"
236
- size="small"
236
+ size="sm"
237
237
  onPress={handleDeleteSelected}
238
238
  disabled={selectedRows.length === 0}
239
239
  >
@@ -244,7 +244,7 @@ export function DataGridShowcase({
244
244
 
245
245
  <Button
246
246
  variant="outlined"
247
- size="small"
247
+ size="sm"
248
248
  onPress={handleResetData}
249
249
  >
250
250
  Reset Data
@@ -252,9 +252,9 @@ export function DataGridShowcase({
252
252
  </View>
253
253
 
254
254
  <View spacing="xs">
255
- <Text size="small">• {showAllColumns ? 'Total ' : ''}Products: {products.length}</Text>
256
- <Text size="small">• Selected: {selectedRows.length}</Text>
257
- <Text size="small">• Virtualization: {virtualized ? (showAllColumns ? 'Enabled' : 'On') : (showAllColumns ? 'Disabled' : 'Off')}</Text>
255
+ <Text size="sm">• {showAllColumns ? 'Total ' : ''}Products: {products.length}</Text>
256
+ <Text size="sm">• Selected: {selectedRows.length}</Text>
257
+ <Text size="sm">• Virtualization: {virtualized ? (showAllColumns ? 'Enabled' : 'On') : (showAllColumns ? 'Disabled' : 'Off')}</Text>
258
258
  </View>
259
259
  </View>
260
260
  </Card>
@@ -280,14 +280,14 @@ export function DataGridShowcase({
280
280
 
281
281
  <Card variant="outlined">
282
282
  <View spacing={showAllColumns ? "sm" : "xs"}>
283
- <Text weight="semibold" size="medium">Features {showAllColumns ? 'Demonstrated' : ''}</Text>
284
- <Text size="small">✓ Virtualized rendering{showAllColumns ? ` with ${productCount} rows` : ''}</Text>
285
- <Text size="small">✓ Sortable columns{showAllColumns ? ' (ID, Name, Category, Price, Stock, Vendor, Date)' : ''}</Text>
286
- <Text size="small">✓ Multi-row selection{showAllColumns ? ' with visual feedback' : ''}</Text>
287
- <Text size="small">✓ Custom cell rendering{showAllColumns ? ' (badges, colored text)' : ''}</Text>
288
- <Text size="small">✓ Sticky header{showAllColumns ? ' while scrolling' : ''}</Text>
289
- <Text size="small">✓ Alternating row colors</Text>
290
- {showAllColumns && <Text size="small">✓ Responsive column widths</Text>}
283
+ <Text weight="semibold" size="md">Features {showAllColumns ? 'Demonstrated' : ''}</Text>
284
+ <Text size="sm">✓ Virtualized rendering{showAllColumns ? ` with ${productCount} rows` : ''}</Text>
285
+ <Text size="sm">✓ Sortable columns{showAllColumns ? ' (ID, Name, Category, Price, Stock, Vendor, Date)' : ''}</Text>
286
+ <Text size="sm">✓ Multi-row selection{showAllColumns ? ' with visual feedback' : ''}</Text>
287
+ <Text size="sm">✓ Custom cell rendering{showAllColumns ? ' (badges, colored text)' : ''}</Text>
288
+ <Text size="sm">✓ Sticky header{showAllColumns ? ' while scrolling' : ''}</Text>
289
+ <Text size="sm">✓ Alternating row colors</Text>
290
+ {showAllColumns && <Text size="sm">✓ Responsive column widths</Text>}
291
291
  </View>
292
292
  </Card>
293
293
  </View>
@@ -69,11 +69,13 @@ interface TableCellProps {
69
69
  style?: any;
70
70
  width?: number | string;
71
71
  colSpan?: number;
72
+ onPress?: () => void;
72
73
  }
73
74
 
74
- export const TableCell: React.FC<TableCellProps> = ({ children, style, width, colSpan }) => {
75
+ export const TableCell: React.FC<TableCellProps> = ({ children, style, width, colSpan, onPress }) => {
75
76
  const flexValue = colSpan ? colSpan : 1;
76
-
77
+ const Wrapper = onPress ? TouchableOpacity : View;
78
+
77
79
  let resolvedStyle = {};
78
80
  if (typeof style === 'function') {
79
81
  try {
@@ -84,16 +86,16 @@ export const TableCell: React.FC<TableCellProps> = ({ children, style, width, co
84
86
  } else if (style) {
85
87
  resolvedStyle = style;
86
88
  }
87
-
89
+
88
90
  const combinedStyle = [
89
91
  { justifyContent: 'center' },
90
92
  width ? { width, flex: 0 } : { flex: flexValue },
91
93
  resolvedStyle
92
94
  ];
93
-
95
+
94
96
  return (
95
- <View style={combinedStyle}>
97
+ <Wrapper style={combinedStyle} onPress={onPress}>
96
98
  {children}
97
- </View>
99
+ </Wrapper>
98
100
  );
99
101
  };
@@ -74,9 +74,10 @@ interface TableCellProps {
74
74
  style?: any;
75
75
  width?: number | string;
76
76
  colSpan?: number;
77
+ onPress?: () => void;
77
78
  }
78
79
 
79
- export const TableCell: React.FC<TableCellProps> = ({ children, style, width, colSpan }) => {
80
+ export const TableCell: React.FC<TableCellProps> = ({ children, style, width, colSpan, onPress }) => {
80
81
  let resolvedStyle = {};
81
82
  if (typeof style === 'function') {
82
83
  try {
@@ -87,15 +88,27 @@ export const TableCell: React.FC<TableCellProps> = ({ children, style, width, co
87
88
  } else if (style) {
88
89
  resolvedStyle = style;
89
90
  }
90
-
91
+
91
92
  const combinedStyle = {
92
93
  verticalAlign: 'middle',
93
94
  ...(width && { width }),
94
95
  ...resolvedStyle,
95
96
  };
96
-
97
+
97
98
  return (
98
- <td style={combinedStyle} colSpan={colSpan}>
99
+ <td
100
+ style={combinedStyle}
101
+ colSpan={colSpan}
102
+ onClick={onPress}
103
+ role={onPress ? 'button' : undefined}
104
+ tabIndex={onPress ? 0 : undefined}
105
+ onKeyDown={onPress ? (e) => {
106
+ if (e.key === 'Enter' || e.key === ' ') {
107
+ e.preventDefault();
108
+ onPress();
109
+ }
110
+ } : undefined}
111
+ >
99
112
  {children}
100
113
  </td>
101
114
  );