react-native-mantine 0.15.0 → 0.16.0

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.
Files changed (36) hide show
  1. package/README.md +45 -345
  2. package/lib/commonjs/components/RingProgress/index.js +76 -53
  3. package/lib/commonjs/components/RingProgress/index.js.map +1 -1
  4. package/lib/commonjs/components/Table/index.js +257 -273
  5. package/lib/commonjs/components/Table/index.js.map +1 -1
  6. package/lib/commonjs/components/index.js +29 -29
  7. package/lib/commonjs/components/index.js.map +1 -1
  8. package/lib/module/components/RingProgress/index.js +77 -54
  9. package/lib/module/components/RingProgress/index.js.map +1 -1
  10. package/lib/module/components/Table/index.js +257 -274
  11. package/lib/module/components/Table/index.js.map +1 -1
  12. package/lib/module/components/index.js +3 -1
  13. package/lib/module/components/index.js.map +1 -1
  14. package/lib/typescript/commonjs/src/components/RingProgress/index.d.ts.map +1 -1
  15. package/lib/typescript/commonjs/src/components/Table/index.d.ts +17 -83
  16. package/lib/typescript/commonjs/src/components/Table/index.d.ts.map +1 -1
  17. package/lib/typescript/commonjs/src/components/index.d.ts +1 -1
  18. package/lib/typescript/commonjs/src/components/index.d.ts.map +1 -1
  19. package/lib/typescript/module/src/components/RingProgress/index.d.ts.map +1 -1
  20. package/lib/typescript/module/src/components/Table/index.d.ts +17 -83
  21. package/lib/typescript/module/src/components/Table/index.d.ts.map +1 -1
  22. package/lib/typescript/module/src/components/index.d.ts +1 -1
  23. package/lib/typescript/module/src/components/index.d.ts.map +1 -1
  24. package/package.json +1 -1
  25. package/src/components/RingProgress/index.tsx +88 -55
  26. package/src/components/Table/index.tsx +333 -413
  27. package/src/components/index.tsx +3 -1
  28. package/lib/commonjs/components/Table/Table.example.js +0 -323
  29. package/lib/commonjs/components/Table/Table.example.js.map +0 -1
  30. package/lib/module/components/Table/Table.example.js +0 -318
  31. package/lib/module/components/Table/Table.example.js.map +0 -1
  32. package/lib/typescript/commonjs/src/components/Table/Table.example.d.ts +0 -13
  33. package/lib/typescript/commonjs/src/components/Table/Table.example.d.ts.map +0 -1
  34. package/lib/typescript/module/src/components/Table/Table.example.d.ts +0 -13
  35. package/lib/typescript/module/src/components/Table/Table.example.d.ts.map +0 -1
  36. package/src/components/Table/Table.example.tsx +0 -215
@@ -1,370 +1,271 @@
1
- import React, { forwardRef, createContext, useContext, useState, useCallback } from 'react';
2
- import { ScrollView } from 'react-native';
3
- import type { LayoutChangeEvent, DimensionValue } from 'react-native';
1
+ import React, { forwardRef } from 'react';
2
+ import { View, ScrollView } from 'react-native';
4
3
  import { BoxView } from '../BoxView';
5
4
  import { Text } from '../Text';
6
- import type { DefaultProps, SpacingValue } from '../../theme/types';
5
+ import type { DefaultProps, MantineNumberSize } from '../../theme/types';
7
6
  import { useComponentDefaultProps } from '../../theme/theme-provider';
8
7
  import { createStyles } from '../../theme';
9
8
  import { rem } from '../../theme/utils/rem';
10
- import { withTextWrapper, type WithTextWrapperProps } from '../../theme/utils/withTextWrapper';
11
-
12
- interface TableContextValue {
13
- striped: boolean;
14
- highlightOnHover: boolean;
15
- withBorder: boolean;
16
- withColumnBorders: boolean;
17
- fontSize: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
18
- verticalSpacing: SpacingValue;
19
- horizontalSpacing: SpacingValue;
20
- columnWidths: number[];
21
- onCellLayout: (columnIndex: number, width: number) => void;
22
- }
23
-
24
- const TableContext = createContext<TableContextValue | null>(null);
25
-
26
- const useTableContext = () => {
27
- const context = useContext(TableContext);
28
- return context;
29
- };
30
9
 
31
10
  export interface TableProps extends DefaultProps {
32
- /** Table children (Thead, Tbody, Tfoot) */
33
- children?: React.ReactNode;
34
-
35
- /** Horizontal scroll on overflow */
36
- horizontalSpacing?: SpacingValue;
37
-
38
- /** Vertical spacing between rows */
39
- verticalSpacing?: SpacingValue;
40
-
41
- /** Font size */
42
- fontSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
43
-
44
- /** Add striped rows styling */
11
+ /** If true every odd row of table will have gray background color */
45
12
  striped?: boolean;
46
13
 
47
- /** Highlight row on hover */
14
+ /** If true row will have hover color */
48
15
  highlightOnHover?: boolean;
49
16
 
50
- /** Add border to table */
51
- withBorder?: boolean;
52
-
53
- /** Add borders between columns */
54
- withColumnBorders?: boolean;
55
-
56
- /** Caption position */
17
+ /** Table caption position */
57
18
  captionSide?: 'top' | 'bottom';
58
19
 
59
- /** Table caption */
60
- caption?: React.ReactNode;
61
-
62
- /** Flex value for the table container (e.g., 1 to fill available space) */
63
- flex?: number;
20
+ /** Horizontal cells spacing from theme.spacing or any valid value */
21
+ horizontalSpacing?: MantineNumberSize;
64
22
 
65
- /** Flex grow value for the table container */
66
- flexGrow?: number;
23
+ /** Vertical cells spacing from theme.spacing or any valid value */
24
+ verticalSpacing?: MantineNumberSize;
67
25
 
68
- /** Flex shrink value for the table container */
69
- flexShrink?: number;
26
+ /** Sets font size of all text inside table */
27
+ fontSize?: MantineNumberSize;
70
28
 
71
- /** Flex basis value for the table container */
72
- flexBasis?: DimensionValue;
29
+ /** Add border to table */
30
+ withBorder?: boolean;
73
31
 
74
- /** Additional styles */
75
- style?: any;
76
- }
32
+ /** Add border to columns */
33
+ withColumnBorders?: boolean;
77
34
 
78
- export interface TableTheadProps extends DefaultProps {
79
- /** Thead children */
35
+ /** Table children (THead, TBody, TFoot, Caption) */
80
36
  children?: React.ReactNode;
81
37
 
82
38
  /** Additional styles */
83
39
  style?: any;
84
- }
85
-
86
- export interface TableTbodyProps extends DefaultProps {
87
- /** Tbody children */
88
- children?: React.ReactNode;
89
40
 
90
- /** Additional styles */
91
- style?: any;
41
+ /** Enable horizontal scrolling */
42
+ horizontallyScrollable?: boolean;
92
43
  }
93
44
 
94
- export interface TableTfootProps extends DefaultProps {
95
- /** Tfoot children */
45
+ interface TableCellProps extends DefaultProps {
46
+ /** Cell content */
96
47
  children?: React.ReactNode;
97
48
 
98
49
  /** Additional styles */
99
50
  style?: any;
51
+
52
+ /** Column span */
53
+ colSpan?: number;
100
54
  }
101
55
 
102
- export interface TableTrProps extends DefaultProps {
103
- /** Tr children */
56
+ interface TableRowProps extends DefaultProps {
57
+ /** Row content */
104
58
  children?: React.ReactNode;
105
59
 
106
60
  /** Additional styles */
107
61
  style?: any;
108
-
109
- /** Internal row index */
110
- __index?: number;
111
62
  }
112
63
 
113
- export interface TableThProps extends DefaultProps, WithTextWrapperProps {
114
- /** Th children */
64
+ interface TableSectionProps extends DefaultProps {
65
+ /** Section content */
115
66
  children?: React.ReactNode;
116
67
 
117
68
  /** Additional styles */
118
69
  style?: any;
119
-
120
- /** Internal column index */
121
- __columnIndex?: number;
122
70
  }
123
71
 
124
- export interface TableTdProps extends DefaultProps, WithTextWrapperProps {
125
- /** Td children */
72
+ interface TableCaptionProps extends DefaultProps {
73
+ /** Caption content */
126
74
  children?: React.ReactNode;
127
75
 
128
76
  /** Additional styles */
129
77
  style?: any;
130
-
131
- /** Internal column index */
132
- __columnIndex?: number;
133
78
  }
134
79
 
135
- const fontSizes = {
136
- xs: rem(10),
137
- sm: rem(12),
138
- md: rem(14),
139
- lg: rem(16),
140
- xl: rem(18),
141
- };
142
-
143
- const useTableStyles = createStyles(
144
- (
145
- theme,
146
- {
147
- withBorder,
148
- captionSide,
149
- flex,
150
- flexGrow,
151
- flexShrink,
152
- flexBasis,
153
- }: {
154
- withBorder: boolean;
155
- captionSide: 'top' | 'bottom';
156
- flex?: number;
157
- flexGrow?: number;
158
- flexShrink?: number;
159
- flexBasis?: DimensionValue;
160
- }
161
- ) => ({
162
- wrapper: {
163
- // Apply flex properties to allow table to expand in container
164
- ...(flex !== undefined && { flex }),
165
- ...(flexGrow !== undefined && { flexGrow }),
166
- ...(flexShrink !== undefined && { flexShrink }),
167
- ...(flexBasis !== undefined && { flexBasis }),
168
- } as any,
169
- root: {
170
- width: '100%',
171
- borderCollapse: 'collapse' as any,
172
- ...(withBorder && {
173
- borderWidth: 1,
174
- borderColor:
175
- theme.colorScheme === 'dark'
176
- ? theme.colors.dark?.[4]
177
- : theme.colors.gray?.[3],
178
- }),
179
- },
180
- caption: {
181
- fontSize: theme.fontSizes.sm as number,
182
- color:
183
- theme.colorScheme === 'dark'
184
- ? theme.colors.dark?.[2]
185
- : theme.colors.gray?.[6],
186
- paddingVertical: theme.spacing.xs,
187
- textAlign: 'center',
188
- ...(captionSide === 'bottom' && { order: 1 }),
189
- },
190
- })
191
- );
192
-
193
- const useTableHeadStyles = createStyles((theme) => ({
194
- thead: {
195
- borderBottomWidth: 1,
196
- borderBottomColor:
197
- theme.colorScheme === 'dark'
198
- ? theme.colors.dark?.[4]
199
- : theme.colors.gray?.[3],
200
- },
201
- }));
202
-
203
- const useTableRowStyles = createStyles(
204
- (
205
- theme,
206
- {
207
- striped,
208
- isEven,
209
- }: {
210
- striped: boolean;
211
- highlightOnHover: boolean;
212
- isEven: boolean;
213
- }
214
- ) => ({
215
- tr: {
216
- flexDirection: 'row',
217
- borderBottomWidth: 1,
218
- borderBottomColor:
219
- theme.colorScheme === 'dark'
220
- ? theme.colors.dark?.[4]
221
- : theme.colors.gray?.[3],
222
- ...(striped &&
223
- isEven && {
224
- backgroundColor:
225
- theme.colorScheme === 'dark'
226
- ? theme.colors.dark?.[6]
227
- : theme.colors.gray?.[0],
228
- }),
229
- },
230
- })
231
- );
232
-
233
- const useTableCellStyles = createStyles(
80
+ const useStyles = createStyles(
234
81
  (
235
82
  theme,
236
83
  {
237
- fontSize,
238
- verticalSpacing,
239
84
  horizontalSpacing,
85
+ verticalSpacing,
86
+ fontSize,
87
+ withBorder,
240
88
  withColumnBorders,
241
- isHeader,
242
- width,
89
+ striped,
243
90
  }: {
244
- fontSize: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
245
- verticalSpacing: SpacingValue;
246
- horizontalSpacing: SpacingValue;
91
+ horizontalSpacing: MantineNumberSize;
92
+ verticalSpacing: MantineNumberSize;
93
+ fontSize: MantineNumberSize;
94
+ withBorder: boolean;
247
95
  withColumnBorders: boolean;
248
- isHeader: boolean;
249
- width?: number;
96
+ striped: boolean;
250
97
  }
251
98
  ) => {
252
- const getVerticalPadding = () => {
253
- if (typeof verticalSpacing === 'number') return rem(verticalSpacing);
254
- return theme.spacing[verticalSpacing] || theme.spacing.xs;
99
+ const borderColor =
100
+ theme.colorScheme === 'dark'
101
+ ? (theme.colors.dark || [])[4]
102
+ : (theme.colors.gray || [])[3];
103
+
104
+ const getSpacing = (size: MantineNumberSize) => {
105
+ if (typeof size === 'number') return rem(size);
106
+ return theme.spacing[size] || theme.spacing.xs;
255
107
  };
256
108
 
257
- const getHorizontalPadding = () => {
258
- if (typeof horizontalSpacing === 'number') return rem(horizontalSpacing);
259
- return theme.spacing[horizontalSpacing] || theme.spacing.xs;
109
+ const getFontSize = (size: MantineNumberSize) => {
110
+ if (typeof size === 'number') return size;
111
+ return theme.fontSizes[size] || theme.fontSizes.sm;
260
112
  };
261
113
 
114
+ const hPadding = getSpacing(horizontalSpacing);
115
+ const vPadding = getSpacing(verticalSpacing);
116
+ const cellFontSize = getFontSize(fontSize);
117
+
262
118
  return {
263
- cell: {
264
- // Remove flex: 1 to prevent equal spacing
265
- // Use explicit width when available for column alignment
266
- ...(width && { width }),
267
- paddingVertical: getVerticalPadding() as any,
268
- paddingHorizontal: getHorizontalPadding() as any,
269
- fontSize: fontSizes[fontSize],
270
- color: theme.colorScheme === 'dark' ? theme.white : theme.black,
271
- textAlign: 'left',
272
- ...(withColumnBorders && {
273
- borderRightWidth: 1,
274
- borderRightColor:
275
- theme.colorScheme === 'dark'
276
- ? theme.colors.dark?.[4]
277
- : theme.colors.gray?.[3],
278
- }),
279
- ...(isHeader && {
280
- fontWeight: '600',
281
- }),
119
+ root: {
120
+ width: '100%',
121
+ backgroundColor: 'transparent',
122
+ },
123
+ scrollView: {
124
+ width: '100%',
125
+ },
126
+ container: {
127
+ flexDirection: 'column' as const,
128
+ borderWidth: withBorder ? 1 : 0,
129
+ borderColor: withBorder ? borderColor : 'transparent',
130
+ borderStyle: 'solid' as const,
131
+ },
132
+ caption: {
133
+ paddingHorizontal: hPadding,
134
+ paddingVertical: theme.spacing.xs,
135
+ fontSize: theme.fontSizes.sm,
136
+ color:
137
+ theme.colorScheme === 'dark'
138
+ ? (theme.colors.dark || [])[2]
139
+ : (theme.colors.gray || [])[6],
140
+ textAlign: 'left' as const,
141
+ },
142
+ captionTop: {
143
+ marginBottom: 0,
144
+ },
145
+ captionBottom: {
146
+ marginTop: 0,
147
+ },
148
+ thead: {
149
+ flexDirection: 'column' as const,
150
+ },
151
+ tbody: {
152
+ flexDirection: 'column' as const,
153
+ },
154
+ tfoot: {
155
+ flexDirection: 'column' as const,
156
+ },
157
+ tr: {
158
+ flexDirection: 'row' as const,
282
159
  },
160
+ th: {
161
+ flex: 1,
162
+ paddingHorizontal: hPadding,
163
+ paddingVertical: vPadding,
164
+ borderBottomWidth: 1,
165
+ borderBottomColor: borderColor,
166
+ borderBottomStyle: 'solid' as const,
167
+ borderRightWidth: withColumnBorders ? 1 : 0,
168
+ borderRightColor: withColumnBorders ? borderColor : 'transparent',
169
+ borderRightStyle: 'solid' as const,
170
+ justifyContent: 'center' as const,
171
+ },
172
+ thText: {
173
+ fontWeight: 'bold' as const,
174
+ color:
175
+ theme.colorScheme === 'dark'
176
+ ? (theme.colors.dark || [])[0]
177
+ : (theme.colors.gray || [])[7],
178
+ fontSize: cellFontSize,
179
+ },
180
+ td: {
181
+ flex: 1,
182
+ paddingHorizontal: hPadding,
183
+ paddingVertical: vPadding,
184
+ borderTopWidth: 1,
185
+ borderTopColor: borderColor,
186
+ borderTopStyle: 'solid' as const,
187
+ borderRightWidth: withColumnBorders ? 1 : 0,
188
+ borderRightColor: withColumnBorders ? borderColor : 'transparent',
189
+ borderRightStyle: 'solid' as const,
190
+ justifyContent: 'center' as const,
191
+ },
192
+ tdText: {
193
+ color:
194
+ theme.colorScheme === 'dark'
195
+ ? (theme.colors.dark || [])[0]
196
+ : theme.black,
197
+ fontSize: cellFontSize,
198
+ },
199
+ firstBodyRow: {
200
+ borderTopWidth: 0,
201
+ },
202
+ lastCell: {
203
+ borderRightWidth: 0,
204
+ },
205
+ stripedRow: striped
206
+ ? {
207
+ backgroundColor:
208
+ theme.colorScheme === 'dark'
209
+ ? (theme.colors.dark || [])[6]
210
+ : (theme.colors.gray || [])[0],
211
+ }
212
+ : {},
283
213
  };
284
214
  }
285
215
  );
286
216
 
287
217
  const defaultProps: Partial<TableProps> = {
288
- horizontalSpacing: 'xs',
289
- verticalSpacing: 'xs',
290
- fontSize: 'sm',
291
218
  striped: false,
292
219
  highlightOnHover: false,
220
+ captionSide: 'top',
221
+ horizontalSpacing: 'xs',
222
+ fontSize: 'sm',
223
+ verticalSpacing: 7,
293
224
  withBorder: false,
294
225
  withColumnBorders: false,
295
- captionSide: 'top',
226
+ horizontallyScrollable: false,
296
227
  };
297
228
 
298
- const Table = forwardRef<any, TableProps>((props, ref) => {
299
- const {
300
- children,
301
- horizontalSpacing,
302
- verticalSpacing,
303
- fontSize,
304
- striped,
305
- highlightOnHover: _highlightOnHover,
306
- withBorder,
307
- withColumnBorders,
308
- captionSide,
309
- caption,
310
- flex,
311
- flexGrow,
312
- flexShrink,
313
- flexBasis,
314
- style,
315
- ...others
316
- } = useComponentDefaultProps('Table', defaultProps, props);
229
+ // Context to share table configuration with child components
230
+ interface TableContextValue {
231
+ styles: any;
232
+ sx: any;
233
+ striped: boolean;
234
+ highlightOnHover: boolean;
235
+ }
317
236
 
318
- const { styles, sx } = useTableStyles(
319
- { withBorder, captionSide, flex, flexGrow, flexShrink, flexBasis },
320
- { name: 'Table' }
321
- ) as any;
237
+ const TableContext = React.createContext<TableContextValue | null>(null);
322
238
 
323
- // Track column widths to ensure alignment across rows
324
- const [columnWidths, setColumnWidths] = useState<number[]>([]);
325
-
326
- const onCellLayout = useCallback((columnIndex: number, width: number) => {
327
- setColumnWidths((prevWidths) => {
328
- const newWidths = [...prevWidths];
329
- // Store the maximum width for each column to ensure all cells in that column have the same width
330
- if (!newWidths[columnIndex] || width > newWidths[columnIndex]) {
331
- newWidths[columnIndex] = width;
332
- }
333
- return newWidths;
334
- });
335
- }, []);
239
+ const useTableContext = () => {
240
+ const context = React.useContext(TableContext);
241
+ if (!context) {
242
+ throw new Error('Table compound components must be used within Table');
243
+ }
244
+ return context;
245
+ };
246
+
247
+ // Table Caption Component
248
+ const TableCaption = forwardRef<View, TableCaptionProps>((props, ref) => {
249
+ const { children, style, ...others } = props;
250
+ const { styles, sx } = useTableContext();
336
251
 
337
252
  return (
338
- <TableContext.Provider
339
- value={{
340
- striped: striped!,
341
- highlightOnHover: _highlightOnHover!,
342
- withBorder: withBorder!,
343
- withColumnBorders: withColumnBorders!,
344
- fontSize: fontSize!,
345
- verticalSpacing: verticalSpacing!,
346
- horizontalSpacing: horizontalSpacing!,
347
- columnWidths,
348
- onCellLayout,
349
- }}
350
- >
351
- <ScrollView
352
- horizontal
353
- style={styles.wrapper}
354
- showsHorizontalScrollIndicator
355
- >
356
- <BoxView ref={ref} style={sx(styles.root, style)} {...others}>
357
- {caption && <Text style={styles.caption}>{caption}</Text>}
358
- {children}
359
- </BoxView>
360
- </ScrollView>
361
- </TableContext.Provider>
253
+ <BoxView ref={ref} style={sx(styles.caption, style)} {...others}>
254
+ {typeof children === 'string' ? (
255
+ <Text style={styles.caption}>{children}</Text>
256
+ ) : (
257
+ children
258
+ )}
259
+ </BoxView>
362
260
  );
363
261
  });
364
262
 
365
- const Thead = forwardRef<any, TableTheadProps>((props, ref) => {
263
+ TableCaption.displayName = 'Table.Caption';
264
+
265
+ // Table Head Component
266
+ const THead = forwardRef<View, TableSectionProps>((props, ref) => {
366
267
  const { children, style, ...others } = props;
367
- const { styles, sx } = useTableHeadStyles({}, { name: 'Thead' }) as any;
268
+ const { styles, sx } = useTableContext();
368
269
 
369
270
  return (
370
271
  <BoxView ref={ref} style={sx(styles.thead, style)} {...others}>
@@ -373,177 +274,196 @@ const Thead = forwardRef<any, TableTheadProps>((props, ref) => {
373
274
  );
374
275
  });
375
276
 
376
- const Tbody = forwardRef<any, TableTbodyProps>((props, ref) => {
277
+ THead.displayName = 'Table.THead';
278
+
279
+ // Table Body Component
280
+ const TBody = forwardRef<View, TableSectionProps>((props, ref) => {
377
281
  const { children, style, ...others } = props;
282
+ const { styles, sx, striped } = useTableContext();
378
283
 
379
- const childrenArray = React.Children.toArray(children);
284
+ // Process children to add row styling
285
+ const processedChildren = React.Children.map(children, (child, index) => {
286
+ if (!React.isValidElement(child)) return child;
287
+
288
+ const isOddRow = index % 2 === 1;
289
+ const childProps = child.props as any;
290
+ const rowStyle = [
291
+ childProps.style,
292
+ striped && isOddRow && styles.stripedRow,
293
+ ].filter(Boolean);
294
+
295
+ return React.cloneElement(child as React.ReactElement<any>, {
296
+ 'style': rowStyle.length > 0 ? rowStyle : childProps.style,
297
+ 'data-index': index,
298
+ 'data-first': index === 0,
299
+ });
300
+ });
380
301
 
381
302
  return (
382
- <BoxView ref={ref} style={style} {...others}>
383
- {childrenArray.map((child, index) => {
384
- if (!React.isValidElement(child)) return child;
385
- return React.cloneElement<TableTrProps>(
386
- child as React.ReactElement<TableTrProps>,
387
- {
388
- key: index,
389
- __index: index,
390
- }
391
- );
392
- })}
303
+ <BoxView ref={ref} style={sx(styles.tbody, style)} {...others}>
304
+ {processedChildren}
393
305
  </BoxView>
394
306
  );
395
307
  });
396
308
 
397
- const Tfoot = forwardRef<any, TableTfootProps>((props, ref) => {
309
+ TBody.displayName = 'Table.TBody';
310
+
311
+ // Table Footer Component
312
+ const TFoot = forwardRef<View, TableSectionProps>((props, ref) => {
398
313
  const { children, style, ...others } = props;
314
+ const { styles, sx } = useTableContext();
399
315
 
400
316
  return (
401
- <BoxView ref={ref} style={style} {...others}>
317
+ <BoxView ref={ref} style={sx(styles.tfoot, style)} {...others}>
402
318
  {children}
403
319
  </BoxView>
404
320
  );
405
321
  });
406
322
 
407
- const Tr = forwardRef<any, TableTrProps>((props, ref) => {
408
- const { children, style, __index, ...others } = props;
409
- const context = useTableContext();
323
+ TFoot.displayName = 'Table.TFoot';
410
324
 
411
- const { styles, sx } = useTableRowStyles(
412
- {
413
- striped: context?.striped ?? false,
414
- highlightOnHover: context?.highlightOnHover ?? false,
415
- isEven: (__index ?? 0) % 2 === 0,
416
- },
417
- { name: 'Tr' }
418
- ) as any;
419
-
420
- // Add column indices to children (Th and Td components)
421
- const childrenArray = React.Children.toArray(children);
422
- const childrenWithColumnIndex = childrenArray.map((child, index) => {
423
- if (!React.isValidElement(child)) return child;
424
- return React.cloneElement<TableThProps | TableTdProps>(
425
- child as React.ReactElement<TableThProps | TableTdProps>,
426
- {
427
- __columnIndex: index,
428
- }
429
- );
430
- });
325
+ // Table Row Component
326
+ const Tr = forwardRef<View, TableRowProps>((props, ref) => {
327
+ const { children, style, ...others } = props;
328
+ const { styles, sx } = useTableContext();
431
329
 
432
330
  return (
433
331
  <BoxView ref={ref} style={sx(styles.tr, style)} {...others}>
434
- {childrenWithColumnIndex}
332
+ {children}
435
333
  </BoxView>
436
334
  );
437
335
  });
438
336
 
439
- const Th = forwardRef<any, TableThProps>((props, ref) => {
440
- const { children, style, withTextWrapper: shouldWrapInText = true, __columnIndex, ...others } = props;
441
- const context = useTableContext();
442
-
443
- const columnIndex = __columnIndex ?? 0;
444
- const columnWidth = context?.columnWidths?.[columnIndex];
337
+ Tr.displayName = 'Table.Tr';
445
338
 
446
- const { styles, sx } = useTableCellStyles(
447
- {
448
- fontSize: context?.fontSize ?? 'sm',
449
- verticalSpacing: context?.verticalSpacing ?? 'xs',
450
- horizontalSpacing: context?.horizontalSpacing ?? 'xs',
451
- withColumnBorders: context?.withColumnBorders ?? false,
452
- isHeader: true,
453
- width: columnWidth,
454
- },
455
- { name: 'Th' }
456
- ) as any;
339
+ // Table Header Cell Component
340
+ const Th = forwardRef<View, TableCellProps>((props, ref) => {
341
+ const { children, style, colSpan, ...others } = props;
342
+ const { styles, sx } = useTableContext();
457
343
 
458
- const handleLayout = useCallback(
459
- (event: LayoutChangeEvent) => {
460
- const { width } = event.nativeEvent.layout;
461
- if (context?.onCellLayout && width > 0) {
462
- context.onCellLayout(columnIndex, width);
463
- }
464
- },
465
- [context, columnIndex]
344
+ const cellStyle = [styles.th, colSpan && { flex: colSpan }, style].filter(
345
+ Boolean
466
346
  );
467
347
 
468
348
  return (
469
- <BoxView
470
- ref={ref}
471
- style={sx(styles.cell, style)}
472
- onLayout={handleLayout}
473
- {...others}
474
- >
475
- {withTextWrapper(children, shouldWrapInText, styles.cell)}
349
+ <BoxView ref={ref} style={sx(...cellStyle)} {...others}>
350
+ {typeof children === 'string' ? (
351
+ <Text style={styles.thText}>{children}</Text>
352
+ ) : (
353
+ children
354
+ )}
476
355
  </BoxView>
477
356
  );
478
357
  });
479
358
 
480
- const Td = forwardRef<any, TableTdProps>((props, ref) => {
481
- const { children, style, withTextWrapper: shouldWrapInText = true, __columnIndex, ...others } = props;
482
- const context = useTableContext();
483
-
484
- const columnIndex = __columnIndex ?? 0;
485
- const columnWidth = context?.columnWidths?.[columnIndex];
359
+ Th.displayName = 'Table.Th';
486
360
 
487
- const { styles, sx } = useTableCellStyles(
488
- {
489
- fontSize: context?.fontSize ?? 'sm',
490
- verticalSpacing: context?.verticalSpacing ?? 'xs',
491
- horizontalSpacing: context?.horizontalSpacing ?? 'xs',
492
- withColumnBorders: context?.withColumnBorders ?? false,
493
- isHeader: false,
494
- width: columnWidth,
495
- },
496
- { name: 'Td' }
497
- ) as any;
361
+ // Table Data Cell Component
362
+ const Td = forwardRef<View, TableCellProps>((props, ref) => {
363
+ const { children, style, colSpan, ...others } = props;
364
+ const { styles, sx } = useTableContext();
365
+ const isFirstRow = (others as any)['data-first'];
498
366
 
499
- const handleLayout = useCallback(
500
- (event: LayoutChangeEvent) => {
501
- const { width } = event.nativeEvent.layout;
502
- if (context?.onCellLayout && width > 0) {
503
- context.onCellLayout(columnIndex, width);
504
- }
505
- },
506
- [context, columnIndex]
507
- );
367
+ const cellStyle = [
368
+ styles.td,
369
+ isFirstRow && styles.firstBodyRow,
370
+ colSpan && { flex: colSpan },
371
+ style,
372
+ ].filter(Boolean);
508
373
 
509
374
  return (
510
- <BoxView
511
- ref={ref}
512
- style={sx(styles.cell, style)}
513
- onLayout={handleLayout}
514
- {...others}
515
- >
516
- {withTextWrapper(children, shouldWrapInText, styles.cell)}
375
+ <BoxView ref={ref} style={sx(...cellStyle)} {...others}>
376
+ <Text style={styles.tdText}>{children}</Text>
517
377
  </BoxView>
518
378
  );
519
379
  });
520
380
 
521
- Table.displayName = 'Table';
522
- Thead.displayName = 'Table.Thead';
523
- Tbody.displayName = 'Table.Tbody';
524
- Tfoot.displayName = 'Table.Tfoot';
525
- Tr.displayName = 'Table.Tr';
526
- Th.displayName = 'Table.Th';
527
381
  Td.displayName = 'Table.Td';
528
382
 
529
- // Attach sub-components with proper typing
530
- interface TableComponent extends React.ForwardRefExoticComponent<
531
- TableProps & React.RefAttributes<any>
532
- > {
533
- Thead: typeof Thead;
534
- Tbody: typeof Tbody;
535
- Tfoot: typeof Tfoot;
536
- Tr: typeof Tr;
537
- Th: typeof Th;
538
- Td: typeof Td;
539
- }
383
+ // Main Table Component
384
+ export const _Table = forwardRef<View, TableProps>((props, ref) => {
385
+ const {
386
+ striped,
387
+ highlightOnHover,
388
+ captionSide,
389
+ horizontalSpacing,
390
+ verticalSpacing,
391
+ fontSize,
392
+ withBorder,
393
+ withColumnBorders,
394
+ children,
395
+ style,
396
+ horizontallyScrollable,
397
+ ...others
398
+ } = useComponentDefaultProps('Table', defaultProps, props);
540
399
 
541
- const TableWithSubComponents = Table as TableComponent;
542
- TableWithSubComponents.Thead = Thead;
543
- TableWithSubComponents.Tbody = Tbody;
544
- TableWithSubComponents.Tfoot = Tfoot;
545
- TableWithSubComponents.Tr = Tr;
546
- TableWithSubComponents.Th = Th;
547
- TableWithSubComponents.Td = Td;
400
+ const { styles, sx } = useStyles(
401
+ {
402
+ horizontalSpacing,
403
+ verticalSpacing,
404
+ fontSize,
405
+ withBorder,
406
+ withColumnBorders,
407
+ striped,
408
+ },
409
+ { name: 'Table' }
410
+ ) as any;
548
411
 
549
- export { TableWithSubComponents as Table };
412
+ const contextValue: TableContextValue = {
413
+ styles,
414
+ sx,
415
+ striped: striped || false,
416
+ highlightOnHover: highlightOnHover || false,
417
+ };
418
+
419
+ const tableContent = (
420
+ <BoxView ref={ref} style={sx(styles.container, style)} {...others}>
421
+ {captionSide === 'top' &&
422
+ React.Children.toArray(children).find(
423
+ (child) =>
424
+ React.isValidElement(child) &&
425
+ (child.type as any).displayName === 'Table.Caption'
426
+ )}
427
+ {React.Children.toArray(children).filter(
428
+ (child) =>
429
+ React.isValidElement(child) &&
430
+ (child.type as any).displayName !== 'Table.Caption'
431
+ )}
432
+ {captionSide === 'bottom' &&
433
+ React.Children.toArray(children).find(
434
+ (child) =>
435
+ React.isValidElement(child) &&
436
+ (child.type as any).displayName === 'Table.Caption'
437
+ )}
438
+ </BoxView>
439
+ );
440
+
441
+ return (
442
+ <TableContext.Provider value={contextValue}>
443
+ {horizontallyScrollable ? (
444
+ <ScrollView
445
+ horizontal
446
+ style={styles.scrollView}
447
+ showsHorizontalScrollIndicator={true}
448
+ >
449
+ {tableContent}
450
+ </ScrollView>
451
+ ) : (
452
+ tableContent
453
+ )}
454
+ </TableContext.Provider>
455
+ );
456
+ }) as any;
457
+
458
+ _Table.displayName = 'Table';
459
+
460
+ // Attach compound components
461
+ export const Table = Object.assign(_Table, {
462
+ Caption: TableCaption,
463
+ THead,
464
+ TBody,
465
+ TFoot,
466
+ Tr,
467
+ Th,
468
+ Td,
469
+ });