@idealyst/datagrid 1.0.40 → 1.0.44

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.
@@ -0,0 +1,74 @@
1
+ import React from 'react';
2
+
3
+ interface SimpleColumn {
4
+ key: string;
5
+ header: string;
6
+ width?: number;
7
+ }
8
+
9
+ interface SimpleDataGridProps {
10
+ data: any[];
11
+ columns: SimpleColumn[];
12
+ }
13
+
14
+ export const SimpleDataGrid: React.FC<SimpleDataGridProps> = ({ data, columns }) => {
15
+ return (
16
+ <div style={{
17
+ border: '1px solid #ccc',
18
+ borderRadius: '4px',
19
+ overflow: 'hidden'
20
+ }}>
21
+ <table style={{
22
+ width: '100%',
23
+ borderCollapse: 'collapse',
24
+ tableLayout: 'fixed'
25
+ }}>
26
+ <thead>
27
+ <tr style={{
28
+ backgroundColor: '#f5f5f5',
29
+ borderBottom: '2px solid #ddd'
30
+ }}>
31
+ {columns.map(column => (
32
+ <th
33
+ key={column.key}
34
+ style={{
35
+ padding: '12px 8px',
36
+ textAlign: 'left',
37
+ fontWeight: 'bold',
38
+ borderRight: '1px solid #ddd',
39
+ ...(column.width ? { width: column.width } : {})
40
+ }}
41
+ >
42
+ {column.header}
43
+ </th>
44
+ ))}
45
+ </tr>
46
+ </thead>
47
+ <tbody>
48
+ {data.map((row, index) => (
49
+ <tr
50
+ key={index}
51
+ style={{
52
+ borderBottom: '1px solid #eee',
53
+ backgroundColor: index % 2 === 0 ? '#fafafa' : '#fff'
54
+ }}
55
+ >
56
+ {columns.map(column => (
57
+ <td
58
+ key={column.key}
59
+ style={{
60
+ padding: '12px 8px',
61
+ borderRight: '1px solid #eee',
62
+ verticalAlign: 'middle'
63
+ }}
64
+ >
65
+ {row[column.key]}
66
+ </td>
67
+ ))}
68
+ </tr>
69
+ ))}
70
+ </tbody>
71
+ </table>
72
+ </div>
73
+ );
74
+ };
@@ -0,0 +1,2 @@
1
+ export { DataGrid } from './DataGrid.native';
2
+ export type { DataGridProps, Column, CellProps, RowProps, HeaderCellProps } from './types';
@@ -0,0 +1,2 @@
1
+ export { DataGrid } from './DataGrid';
2
+ export type { DataGridProps, Column, CellProps, RowProps, HeaderCellProps } from './types';
@@ -122,7 +122,7 @@ export function BasicExample() {
122
122
  data={data}
123
123
  columns={columns}
124
124
  height={500}
125
- virtualized={true}
125
+ virtualized={false}
126
126
  selectedRows={selectedRows}
127
127
  onSelectionChange={setSelectedRows}
128
128
  multiSelect={true}
@@ -0,0 +1,296 @@
1
+ import React, { useState } from 'react';
2
+ import { View, Text, Button, Screen, Card, Badge } from '@idealyst/components';
3
+ import { DataGrid } from '../DataGrid';
4
+ import type { Column } from '../DataGrid/types';
5
+
6
+ interface Product {
7
+ id: number;
8
+ name: string;
9
+ category: string;
10
+ price: number;
11
+ stock: number;
12
+ status: 'in-stock' | 'low-stock' | 'out-of-stock';
13
+ vendor: string;
14
+ lastUpdated: string;
15
+ }
16
+
17
+ const generateSampleProducts = (count: number = 100): Product[] => {
18
+ const categories = ['Electronics', 'Clothing', 'Food', 'Books', 'Toys', 'Sports'];
19
+ const vendors = ['Vendor A', 'Vendor B', 'Vendor C', 'Vendor D'];
20
+ const products: Product[] = [];
21
+
22
+ for (let i = 1; i <= count; i++) {
23
+ const stock = Math.floor(Math.random() * 100);
24
+ products.push({
25
+ id: i,
26
+ name: `Product ${i}`,
27
+ category: categories[Math.floor(Math.random() * categories.length)],
28
+ price: parseFloat((Math.random() * 999 + 1).toFixed(2)),
29
+ stock,
30
+ status: stock === 0 ? 'out-of-stock' : stock < 10 ? 'low-stock' : 'in-stock',
31
+ vendor: vendors[Math.floor(Math.random() * vendors.length)],
32
+ lastUpdated: new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
33
+ });
34
+ }
35
+
36
+ return products;
37
+ };
38
+
39
+ interface DataGridShowcaseProps {
40
+ /** Number of sample products to generate */
41
+ productCount?: number;
42
+ /** Whether to show all columns (false hides vendor and lastUpdated) */
43
+ showAllColumns?: boolean;
44
+ /** Height of the DataGrid */
45
+ height?: number;
46
+ }
47
+
48
+ export function DataGridShowcase({
49
+ productCount = 100,
50
+ showAllColumns = true,
51
+ height = 500
52
+ }: DataGridShowcaseProps = {}) {
53
+ const [products, setProducts] = useState<Product[]>(() => generateSampleProducts(productCount));
54
+ const [selectedRows, setSelectedRows] = useState<number[]>([]);
55
+ const [virtualized, setVirtualized] = useState(false);
56
+
57
+ const baseColumns: Column<Product>[] = [
58
+ {
59
+ key: 'id',
60
+ header: 'ID',
61
+ width: showAllColumns ? 60 : 50,
62
+ sortable: true,
63
+ },
64
+ {
65
+ key: 'name',
66
+ header: showAllColumns ? 'Product Name' : 'Product',
67
+ width: showAllColumns ? 150 : 120,
68
+ sortable: true,
69
+ },
70
+ {
71
+ key: 'category',
72
+ header: 'Category',
73
+ width: showAllColumns ? 120 : 100,
74
+ sortable: true,
75
+ render: (value) => (
76
+ <Badge variant="outlined" size="small">
77
+ {value}
78
+ </Badge>
79
+ ),
80
+ },
81
+ {
82
+ key: 'price',
83
+ header: 'Price',
84
+ width: showAllColumns ? 100 : 80,
85
+ sortable: true,
86
+ render: (value) => (
87
+ <Text weight="semibold" size={showAllColumns ? 'medium' : 'small'}>
88
+ ${value.toFixed(2)}
89
+ </Text>
90
+ ),
91
+ },
92
+ {
93
+ key: 'stock',
94
+ header: 'Stock',
95
+ width: showAllColumns ? 80 : 60,
96
+ sortable: true,
97
+ render: (value, row) => (
98
+ <Text
99
+ size="small"
100
+ style={{
101
+ color: row.status === 'out-of-stock' ? '#ef4444' :
102
+ row.status === 'low-stock' ? '#f59e0b' : '#22c55e'
103
+ }}
104
+ >
105
+ {value}
106
+ </Text>
107
+ ),
108
+ },
109
+ {
110
+ key: 'status',
111
+ header: 'Status',
112
+ width: showAllColumns ? 120 : 100,
113
+ render: (value) => {
114
+ const intent = value === 'in-stock' ? 'success' :
115
+ value === 'low-stock' ? 'warning' : 'error';
116
+ return (
117
+ <Badge variant="filled" intent={intent} size="small">
118
+ {value}
119
+ </Badge>
120
+ );
121
+ },
122
+ },
123
+ ];
124
+
125
+ const additionalColumns: Column<Product>[] = showAllColumns ? [
126
+ {
127
+ key: 'vendor',
128
+ header: 'Vendor',
129
+ width: 100,
130
+ sortable: true,
131
+ },
132
+ {
133
+ key: 'lastUpdated',
134
+ header: 'Last Updated',
135
+ width: 120,
136
+ sortable: true,
137
+ },
138
+ ] : [];
139
+
140
+ const columns = [...baseColumns, ...additionalColumns];
141
+
142
+ const handleSort = (column: Column<Product>, direction: 'asc' | 'desc') => {
143
+ const sorted = [...products].sort((a, b) => {
144
+ const aVal = a[column.key as keyof Product];
145
+ const bVal = b[column.key as keyof Product];
146
+
147
+ if (typeof aVal === 'number' && typeof bVal === 'number') {
148
+ return direction === 'asc' ? aVal - bVal : bVal - aVal;
149
+ }
150
+
151
+ const aStr = String(aVal);
152
+ const bStr = String(bVal);
153
+ return direction === 'asc'
154
+ ? aStr.localeCompare(bStr)
155
+ : bStr.localeCompare(aStr);
156
+ });
157
+ setProducts(sorted);
158
+ };
159
+
160
+ const handleDeleteSelected = () => {
161
+ const newProducts = products.filter((_, index) => !selectedRows.includes(index));
162
+ setProducts(newProducts);
163
+ setSelectedRows([]);
164
+ };
165
+
166
+ const handleResetData = () => {
167
+ setProducts(generateSampleProducts(productCount));
168
+ setSelectedRows([]);
169
+ };
170
+
171
+ return (
172
+ <Screen background="primary" safeArea scrollable={false}>
173
+ <View spacing={showAllColumns ? "lg" : "md"} style={{ padding: showAllColumns ? 16 : 12, flex: 1 }}>
174
+ <Text size={showAllColumns ? "xlarge" : "large"} weight="bold">
175
+ DataGrid {showAllColumns ? 'Component ' : ''}Showcase
176
+ </Text>
177
+
178
+ <Card variant="outlined">
179
+ <View spacing={showAllColumns ? "md" : "sm"}>
180
+ <Text weight="semibold" size="medium">Controls</Text>
181
+
182
+ <View
183
+ spacing="sm"
184
+ style={{
185
+ flexDirection: showAllColumns ? 'row' : 'column',
186
+ alignItems: showAllColumns ? 'center' : 'stretch',
187
+ flexWrap: showAllColumns ? 'wrap' : 'nowrap',
188
+ gap: 8
189
+ }}
190
+ >
191
+ <Button
192
+ variant="outlined"
193
+ size="small"
194
+ onPress={() => setVirtualized(!virtualized)}
195
+ >
196
+ {virtualized ? 'Disable' : 'Enable'} Virtualization
197
+ </Button>
198
+
199
+ {!showAllColumns && (
200
+ <View style={{ flexDirection: 'row', gap: 8 }}>
201
+ <Button
202
+ variant="outlined"
203
+ size="small"
204
+ onPress={() => setSelectedRows([])}
205
+ disabled={selectedRows.length === 0}
206
+ >
207
+ Clear ({selectedRows.length})
208
+ </Button>
209
+
210
+ <Button
211
+ variant="outlined"
212
+ intent="error"
213
+ size="small"
214
+ onPress={handleDeleteSelected}
215
+ disabled={selectedRows.length === 0}
216
+ >
217
+ Delete Selected
218
+ </Button>
219
+ </View>
220
+ )}
221
+
222
+ {showAllColumns && (
223
+ <>
224
+ <Button
225
+ variant="outlined"
226
+ size="small"
227
+ onPress={() => setSelectedRows([])}
228
+ disabled={selectedRows.length === 0}
229
+ >
230
+ Clear Selection ({selectedRows.length})
231
+ </Button>
232
+
233
+ <Button
234
+ variant="outlined"
235
+ intent="error"
236
+ size="small"
237
+ onPress={handleDeleteSelected}
238
+ disabled={selectedRows.length === 0}
239
+ >
240
+ Delete Selected
241
+ </Button>
242
+ </>
243
+ )}
244
+
245
+ <Button
246
+ variant="outlined"
247
+ size="small"
248
+ onPress={handleResetData}
249
+ >
250
+ Reset Data
251
+ </Button>
252
+ </View>
253
+
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>
258
+ </View>
259
+ </View>
260
+ </Card>
261
+
262
+ <Card variant="elevated" style={{ flex: 1, overflow: 'hidden' }}>
263
+ <DataGrid
264
+ data={products}
265
+ columns={columns}
266
+ height={height}
267
+ virtualized={virtualized}
268
+ selectedRows={selectedRows}
269
+ onSelectionChange={setSelectedRows}
270
+ multiSelect={true}
271
+ onSort={handleSort}
272
+ stickyHeader={true}
273
+ rowHeight={showAllColumns ? 48 : 44}
274
+ headerHeight={48}
275
+ rowStyle={(row, index) => ({
276
+ backgroundColor: index % 2 === 0 ? '#fafafa' : '#ffffff',
277
+ })}
278
+ />
279
+ </Card>
280
+
281
+ <Card variant="outlined">
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>}
291
+ </View>
292
+ </Card>
293
+ </View>
294
+ </Screen>
295
+ );
296
+ }
@@ -1 +1,2 @@
1
- export { BasicExample } from './BasicExample';
1
+ export { BasicExample } from './BasicExample';
2
+ export { DataGridShowcase } from './DataGridShowcase';
@@ -1,2 +1,2 @@
1
- export { DataGrid } from './DataGrid';
1
+ export { DataGrid } from './DataGrid/DataGrid.native';
2
2
  export type { DataGridProps, Column, CellProps, RowProps, HeaderCellProps } from './DataGrid/types';
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+
4
+ interface CellProps {
5
+ children: React.ReactNode;
6
+ style?: any;
7
+ }
8
+
9
+ export const Cell: React.FC<CellProps> = ({ children, style }) => {
10
+ return (
11
+ <View style={[{ justifyContent: 'center' }, style]}>
12
+ {children}
13
+ </View>
14
+ );
15
+ };
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import { UnistylesRuntime } from 'react-native-unistyles';
3
+
4
+ interface CellProps {
5
+ children: React.ReactNode;
6
+ style?: any;
7
+ }
8
+
9
+ export const Cell: React.FC<CellProps> = ({ children, style }) => {
10
+ // Handle function-based styles (Unistyles 3) with proper theme access
11
+ let resolvedStyle = {};
12
+ if (typeof style === 'function') {
13
+ try {
14
+ resolvedStyle = style(UnistylesRuntime.theme);
15
+ } catch (error) {
16
+ console.warn('Error resolving Cell style:', error);
17
+ resolvedStyle = {};
18
+ }
19
+ } else if (style) {
20
+ resolvedStyle = style;
21
+ }
22
+
23
+ const combinedStyle = {
24
+ display: 'flex',
25
+ flexDirection: 'column' as const,
26
+ justifyContent: 'center',
27
+ alignItems: 'stretch',
28
+ ...resolvedStyle,
29
+ };
30
+
31
+ return (
32
+ <div style={combinedStyle}>
33
+ {children}
34
+ </div>
35
+ );
36
+ };
@@ -0,0 +1 @@
1
+ export { Cell } from './Cell.native';
@@ -0,0 +1 @@
1
+ export { Cell } from './Cell.web';
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
+
4
+ interface RowProps {
5
+ children: React.ReactNode;
6
+ style?: any;
7
+ onPress?: () => void;
8
+ }
9
+
10
+ export const Row: React.FC<RowProps> = ({ children, style, onPress }) => {
11
+ const Wrapper = onPress ? TouchableOpacity : View;
12
+
13
+ return (
14
+ <Wrapper
15
+ style={[{ flexDirection: 'row' }, style]}
16
+ onPress={onPress}
17
+ >
18
+ {children}
19
+ </Wrapper>
20
+ );
21
+ };
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+ import { UnistylesRuntime } from 'react-native-unistyles';
3
+
4
+ interface RowProps {
5
+ children: React.ReactNode;
6
+ style?: any;
7
+ onPress?: () => void;
8
+ }
9
+
10
+ export const Row: React.FC<RowProps> = ({ children, style, onPress }) => {
11
+ // Handle function-based styles (Unistyles 3) with proper theme access
12
+ let resolvedStyle = {};
13
+ if (typeof style === 'function') {
14
+ try {
15
+ resolvedStyle = style(UnistylesRuntime.theme);
16
+ } catch (error) {
17
+ console.warn('Error resolving Row style:', error);
18
+ resolvedStyle = {};
19
+ }
20
+ } else if (style) {
21
+ resolvedStyle = style;
22
+ }
23
+
24
+ const combinedStyle = {
25
+ display: 'flex',
26
+ flexDirection: 'row' as const,
27
+ width: '100%',
28
+ boxSizing: 'border-box' as const,
29
+ ...resolvedStyle,
30
+ };
31
+
32
+ return (
33
+ <div
34
+ style={combinedStyle}
35
+ onClick={onPress}
36
+ role={onPress ? 'button' : undefined}
37
+ tabIndex={onPress ? 0 : undefined}
38
+ onKeyDown={onPress ? (e) => {
39
+ if (e.key === 'Enter' || e.key === ' ') {
40
+ e.preventDefault();
41
+ onPress();
42
+ }
43
+ } : undefined}
44
+ >
45
+ {children}
46
+ </div>
47
+ );
48
+ };
@@ -0,0 +1 @@
1
+ export { Row } from './Row.native';
@@ -0,0 +1 @@
1
+ export { Row } from './Row.web';
@@ -20,6 +20,9 @@ export const ScrollView: React.FC<ScrollViewProps> = ({
20
20
  onScroll,
21
21
  showsHorizontalScrollIndicator = true,
22
22
  showsVerticalScrollIndicator = true,
23
+ scrollEventThrottle: _scrollEventThrottle, // native property
24
+ bounces: _bounces, // native property
25
+ directionalLockEnabled: _directionalLockEnabled, // native property
23
26
  ...props
24
27
  }) => {
25
28
  const scrollStyle = {
@@ -0,0 +1,99 @@
1
+ import React from 'react';
2
+ import { View, TouchableOpacity } from 'react-native';
3
+ import { UnistylesRuntime } from 'react-native-unistyles';
4
+
5
+ interface TableProps {
6
+ children: React.ReactNode;
7
+ style?: any;
8
+ }
9
+
10
+ export const Table: React.FC<TableProps> = ({ children, style }) => {
11
+ let resolvedStyle = {};
12
+ if (typeof style === 'function') {
13
+ try {
14
+ resolvedStyle = style(UnistylesRuntime.theme);
15
+ } catch (error) {
16
+ resolvedStyle = {};
17
+ }
18
+ } else if (style) {
19
+ resolvedStyle = style;
20
+ }
21
+
22
+ return (
23
+ <View style={[
24
+ { flex: 1 },
25
+ resolvedStyle,
26
+ // If width is specified, don't flex
27
+ resolvedStyle?.width ? { flex: 0 } : {}
28
+ ]}>
29
+ {children}
30
+ </View>
31
+ );
32
+ };
33
+
34
+ interface TableRowProps {
35
+ children: React.ReactNode;
36
+ style?: any;
37
+ onPress?: () => void;
38
+ }
39
+
40
+ export const TableRow: React.FC<TableRowProps> = ({ children, style, onPress }) => {
41
+ const Wrapper = onPress ? TouchableOpacity : View;
42
+
43
+ let resolvedStyle = {};
44
+ if (typeof style === 'function') {
45
+ try {
46
+ resolvedStyle = style(UnistylesRuntime.theme);
47
+ } catch (error) {
48
+ resolvedStyle = {};
49
+ }
50
+ } else if (style) {
51
+ resolvedStyle = style;
52
+ }
53
+
54
+ // Ensure flexDirection is always 'row' - force it with !important-like behavior
55
+ const finalStyle = [resolvedStyle, { flexDirection: 'row', display: 'flex' }];
56
+
57
+ return (
58
+ <Wrapper
59
+ style={finalStyle}
60
+ onPress={onPress}
61
+ >
62
+ {children}
63
+ </Wrapper>
64
+ );
65
+ };
66
+
67
+ interface TableCellProps {
68
+ children: React.ReactNode;
69
+ style?: any;
70
+ width?: number | string;
71
+ colSpan?: number;
72
+ }
73
+
74
+ export const TableCell: React.FC<TableCellProps> = ({ children, style, width, colSpan }) => {
75
+ const flexValue = colSpan ? colSpan : 1;
76
+
77
+ let resolvedStyle = {};
78
+ if (typeof style === 'function') {
79
+ try {
80
+ resolvedStyle = style(UnistylesRuntime.theme);
81
+ } catch (error) {
82
+ resolvedStyle = {};
83
+ }
84
+ } else if (style) {
85
+ resolvedStyle = style;
86
+ }
87
+
88
+ const combinedStyle = [
89
+ { justifyContent: 'center' },
90
+ width ? { width, flex: 0 } : { flex: flexValue },
91
+ resolvedStyle
92
+ ];
93
+
94
+ return (
95
+ <View style={combinedStyle}>
96
+ {children}
97
+ </View>
98
+ );
99
+ };