jp-composter 0.1.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 (194) hide show
  1. package/dist/index.d.mts +997 -0
  2. package/dist/index.d.ts +997 -0
  3. package/dist/index.js +36837 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.mjs +36778 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/package.json +66 -0
  8. package/src/SliceUI/IconMoon.tsx +33 -0
  9. package/src/SliceUI/assets/Anatomy diagram copy.svg +19 -0
  10. package/src/SliceUI/assets/Anatomy diagram.svg +19 -0
  11. package/src/SliceUI/assets/Anatomycheck.svg +15 -0
  12. package/src/SliceUI/assets/Anatomyinput.svg +32 -0
  13. package/src/SliceUI/assets/Checkbox.jpg +0 -0
  14. package/src/SliceUI/assets/Diagram copy.svg +15 -0
  15. package/src/SliceUI/assets/Diagram.jpg +0 -0
  16. package/src/SliceUI/assets/Diagram.svg +15 -0
  17. package/src/SliceUI/assets/Frame 5 copy.png +0 -0
  18. package/src/SliceUI/assets/Frame 5.png +0 -0
  19. package/src/SliceUI/assets/Frame 65.png +0 -0
  20. package/src/SliceUI/assets/Frame_65.png +0 -0
  21. package/src/SliceUI/assets/Icon copy.svg +3 -0
  22. package/src/SliceUI/assets/Icon.svg +3 -0
  23. package/src/SliceUI/assets/Icon_Bridging copy.svg +39 -0
  24. package/src/SliceUI/assets/Icon_Bridging.svg +39 -0
  25. package/src/SliceUI/assets/Icon_Consistent copy.svg +39 -0
  26. package/src/SliceUI/assets/Icon_Consistent.svg +39 -0
  27. package/src/SliceUI/assets/Icon_Plug copy.svg +38 -0
  28. package/src/SliceUI/assets/Icon_Plug.svg +38 -0
  29. package/src/SliceUI/assets/Icon_Reusable copy.svg +39 -0
  30. package/src/SliceUI/assets/Icon_Reusable.svg +39 -0
  31. package/src/SliceUI/assets/Layer_1.png +0 -0
  32. package/src/SliceUI/assets/accessibility.png +0 -0
  33. package/src/SliceUI/assets/accessibility.svg +1 -0
  34. package/src/SliceUI/assets/addon-library.png +0 -0
  35. package/src/SliceUI/assets/assets.png +0 -0
  36. package/src/SliceUI/assets/avif-test-image.avif +0 -0
  37. package/src/SliceUI/assets/bridging.svg +13 -0
  38. package/src/SliceUI/assets/consistent.svg +11 -0
  39. package/src/SliceUI/assets/context.png +0 -0
  40. package/src/SliceUI/assets/discord.svg +1 -0
  41. package/src/SliceUI/assets/docs.png +0 -0
  42. package/src/SliceUI/assets/figma-plugin.png +0 -0
  43. package/src/SliceUI/assets/github.svg +1 -0
  44. package/src/SliceUI/assets/resources/Anatomy diagram.svg +19 -0
  45. package/src/SliceUI/assets/resources/Anatomycheck.svg +15 -0
  46. package/src/SliceUI/assets/resources/Anatomyinput.svg +32 -0
  47. package/src/SliceUI/assets/resources/Diagram.svg +15 -0
  48. package/src/SliceUI/assets/resources/Frame 5.png +0 -0
  49. package/src/SliceUI/assets/resources/Frame 65.png +0 -0
  50. package/src/SliceUI/assets/resources/Icon.svg +3 -0
  51. package/src/SliceUI/assets/resources/Icon_Bridging.svg +39 -0
  52. package/src/SliceUI/assets/resources/Icon_Consistent.svg +39 -0
  53. package/src/SliceUI/assets/resources/Icon_Plug.svg +38 -0
  54. package/src/SliceUI/assets/resources/Icon_Reusable.svg +39 -0
  55. package/src/SliceUI/assets/resources/fonts/FontIcon.json +150 -0
  56. package/src/SliceUI/assets/resources/fonts/Lato-Black.ttf +0 -0
  57. package/src/SliceUI/assets/resources/fonts/Lato-Bold.ttf +0 -0
  58. package/src/SliceUI/assets/resources/fonts/Lato-Heavy.ttf +0 -0
  59. package/src/SliceUI/assets/resources/fonts/Lato-Medium.ttf +0 -0
  60. package/src/SliceUI/assets/resources/fonts/Lato-Regular.ttf +0 -0
  61. package/src/SliceUI/assets/resources/fonts/Lato.woff2 +0 -0
  62. package/src/SliceUI/assets/resources/fonts/icomoon.eot +0 -0
  63. package/src/SliceUI/assets/resources/fonts/icomoon.svg +601 -0
  64. package/src/SliceUI/assets/resources/fonts/icomoon.ttf +0 -0
  65. package/src/SliceUI/assets/resources/fonts/icomoon.woff +0 -0
  66. package/src/SliceUI/assets/resources/fonts/selection.json +1 -0
  67. package/src/SliceUI/assets/share.png +0 -0
  68. package/src/SliceUI/assets/styling.png +0 -0
  69. package/src/SliceUI/assets/testing.png +0 -0
  70. package/src/SliceUI/assets/theming.png +0 -0
  71. package/src/SliceUI/assets/tutorials.svg +1 -0
  72. package/src/SliceUI/assets/youtube.svg +1 -0
  73. package/src/SliceUI/automation/helper.ts +29 -0
  74. package/src/SliceUI/avatar/Avatar.tsx +237 -0
  75. package/src/SliceUI/avatar/Token.ts +116 -0
  76. package/src/SliceUI/avatar/Type.ts +36 -0
  77. package/src/SliceUI/avatar/helper.ts +53 -0
  78. package/src/SliceUI/badge/Badge.tsx +308 -0
  79. package/src/SliceUI/badge/Token.ts +202 -0
  80. package/src/SliceUI/badge/Type.ts +46 -0
  81. package/src/SliceUI/badge/helper.ts +39 -0
  82. package/src/SliceUI/button/Button.tsx +243 -0
  83. package/src/SliceUI/button/Token.ts +138 -0
  84. package/src/SliceUI/button/Type.ts +34 -0
  85. package/src/SliceUI/button/helper.ts +125 -0
  86. package/src/SliceUI/checkbox/Checkbox.tsx +176 -0
  87. package/src/SliceUI/checkbox/Token.ts +128 -0
  88. package/src/SliceUI/checkbox/Type.ts +35 -0
  89. package/src/SliceUI/chip/Chip.tsx +290 -0
  90. package/src/SliceUI/chip/Token.ts +151 -0
  91. package/src/SliceUI/chip/Type.ts +43 -0
  92. package/src/SliceUI/chip/helper.ts +40 -0
  93. package/src/SliceUI/colors/Pallete.ts +151 -0
  94. package/src/SliceUI/colors/Token.ts +110 -0
  95. package/src/SliceUI/colors/Type.ts +56 -0
  96. package/src/SliceUI/contextProvider/context.tsx +108 -0
  97. package/src/SliceUI/divider/Divider.tsx +109 -0
  98. package/src/SliceUI/divider/Token.ts +18 -0
  99. package/src/SliceUI/divider/Type.ts +26 -0
  100. package/src/SliceUI/icon/CustomIcon.ts +4 -0
  101. package/src/SliceUI/icon/IcoMoonIcon.tsx +11 -0
  102. package/src/SliceUI/icon/Icon.tsx +38 -0
  103. package/src/SliceUI/icon/Token.ts +14 -0
  104. package/src/SliceUI/icon/Type.ts +13 -0
  105. package/src/SliceUI/icon/selection.json +1 -0
  106. package/src/SliceUI/input/Input.tsx +573 -0
  107. package/src/SliceUI/input/ToDo.md +99 -0
  108. package/src/SliceUI/input/Token.ts +372 -0
  109. package/src/SliceUI/input/Type.ts +109 -0
  110. package/src/SliceUI/input/components/InputPortal.tsx +211 -0
  111. package/src/SliceUI/input/components/NativeBottomSheet.tsx +296 -0
  112. package/src/SliceUI/input/components/SelectChip.tsx +185 -0
  113. package/src/SliceUI/input/components/SelectList.tsx +173 -0
  114. package/src/SliceUI/input/components/SelectListItem.tsx +377 -0
  115. package/src/SliceUI/input/components/SelectScrollbarStyle.ts +44 -0
  116. package/src/SliceUI/input/hooks/useCustomScrollbar.ts +17 -0
  117. package/src/SliceUI/input/hooks/useInputState.ts +41 -0
  118. package/src/SliceUI/input/hooks/useLabelAnimation.ts +132 -0
  119. package/src/SliceUI/input/hooks/useOutsideClick.ts +38 -0
  120. package/src/SliceUI/input/hooks/useSelectLogic.ts +338 -0
  121. package/src/SliceUI/input/utils/inputUtils.ts +120 -0
  122. package/src/SliceUI/input/utils/selectUtils.ts +85 -0
  123. package/src/SliceUI/input/utils/styleUtils.ts +50 -0
  124. package/src/SliceUI/input/variants/CurrencyInput/CurrencyInput.tsx +16 -0
  125. package/src/SliceUI/input/variants/CurrencyInput/NativeCurrencyInput.tsx +181 -0
  126. package/src/SliceUI/input/variants/CurrencyInput/WebCurrencyInput.tsx +163 -0
  127. package/src/SliceUI/input/variants/CurrencyInput/types.ts +17 -0
  128. package/src/SliceUI/input/variants/PhoneInput/NativePhoneInput.tsx +189 -0
  129. package/src/SliceUI/input/variants/PhoneInput/PhoneInput.tsx +16 -0
  130. package/src/SliceUI/input/variants/PhoneInput/WebPhoneInput.tsx +291 -0
  131. package/src/SliceUI/input/variants/PhoneInput/types.ts +22 -0
  132. package/src/SliceUI/input/variants/SelectInput/SelectInput.tsx +407 -0
  133. package/src/SliceUI/input/variants/SelectInput/types.ts +34 -0
  134. package/src/SliceUI/input/variants/TextInput.tsx +68 -0
  135. package/src/SliceUI/layout/Box.tsx +38 -0
  136. package/src/SliceUI/layout/Center.tsx +38 -0
  137. package/src/SliceUI/layout/Divider.tsx +37 -0
  138. package/src/SliceUI/layout/Grid.tsx +75 -0
  139. package/src/SliceUI/layout/PageContainer.tsx +60 -0
  140. package/src/SliceUI/layout/ScrollContainer.tsx +72 -0
  141. package/src/SliceUI/layout/Spacer.tsx +54 -0
  142. package/src/SliceUI/layout/Stack.tsx +97 -0
  143. package/src/SliceUI/layout/StickyHeader.tsx +71 -0
  144. package/src/SliceUI/radio/RadioButton.tsx +130 -0
  145. package/src/SliceUI/radio/Token.ts +197 -0
  146. package/src/SliceUI/radio/Type.ts +35 -0
  147. package/src/SliceUI/react-native.config.js +3 -0
  148. package/src/SliceUI/responsive/Type.ts +7 -0
  149. package/src/SliceUI/responsive/helper.ts +53 -0
  150. package/src/SliceUI/switch/Switch.tsx +119 -0
  151. package/src/SliceUI/switch/Token.ts +205 -0
  152. package/src/SliceUI/switch/Type.ts +26 -0
  153. package/src/SliceUI/tab/TabItem.tsx +204 -0
  154. package/src/SliceUI/tab/Tabs.tsx +110 -0
  155. package/src/SliceUI/tab/Token.ts +282 -0
  156. package/src/SliceUI/tab/Type.ts +66 -0
  157. package/src/SliceUI/tab/helper.ts +53 -0
  158. package/src/SliceUI/table/Table.tsx +388 -0
  159. package/src/SliceUI/table/TableCell.tsx +158 -0
  160. package/src/SliceUI/table/TableFooter.tsx +353 -0
  161. package/src/SliceUI/table/TableHeader.tsx +247 -0
  162. package/src/SliceUI/table/TableRow.tsx +218 -0
  163. package/src/SliceUI/table/Token.ts +252 -0
  164. package/src/SliceUI/table/Type.ts +213 -0
  165. package/src/SliceUI/table/helper.ts +376 -0
  166. package/src/SliceUI/table/index.ts +53 -0
  167. package/src/SliceUI/theme/dummyColors.tsx +7 -0
  168. package/src/SliceUI/theme/theme.ts +107 -0
  169. package/src/SliceUI/typography/BaseTypographyToken.ts +62 -0
  170. package/src/SliceUI/typography/FoundationToken.ts +48 -0
  171. package/src/SliceUI/typography/Token.ts +228 -0
  172. package/src/SliceUI/typography/Type.ts +20 -0
  173. package/src/SliceUI/typography/Typography.tsx +99 -0
  174. package/src/SliceUI/values/BorderRadius.ts +17 -0
  175. package/src/SliceUI/values/BorderWidth.ts +7 -0
  176. package/src/SliceUI/values/Dimension.ts +35 -0
  177. package/src/SliceUI/values/IconSizes.ts +13 -0
  178. package/src/SliceUI/values/Spacing.ts +22 -0
  179. package/src/declarations.d.ts +8 -0
  180. package/src/index.tsx +119 -0
  181. package/src/stories/Colors.mdx +1418 -0
  182. package/src/stories/Dimensions.mdx +60 -0
  183. package/src/stories/GetStarted.mdx +90 -0
  184. package/src/stories/Introduction.mdx +136 -0
  185. package/src/stories/Shape.mdx +126 -0
  186. package/src/stories/Spacing.mdx +104 -0
  187. package/src/stories/Typography.mdx +454 -0
  188. package/src/stories/Utils.mdx +277 -0
  189. package/src/stories/story-components/AddIcon.js +13 -0
  190. package/src/stories/story-components/RectangleWithBox.jsx +51 -0
  191. package/src/stories/story-components/RoundedRectangle.jsx +18 -0
  192. package/src/stories/story-components/RoundedWithWhiteInside.jsx +33 -0
  193. package/src/stories/story-components/WhiteRoundedRectangle.jsx +107 -0
  194. package/src/stories/story-components/svgPaths.js +126 -0
@@ -0,0 +1,388 @@
1
+ import React, {useMemo, useState, useCallback, useEffect} from 'react';
2
+ import {
3
+ View,
4
+ StyleSheet,
5
+ ScrollView,
6
+ ActivityIndicator,
7
+ type ViewStyle,
8
+ } from 'react-native';
9
+ import {useSliceTheme} from '../contextProvider/context';
10
+ import {setTestId} from '../automation/helper';
11
+ import {
12
+ sortData,
13
+ filterData,
14
+ paginateData,
15
+ getRowKey,
16
+ isAllRowsSelected,
17
+ isSomeRowsSelected,
18
+ toggleAllRowsSelection,
19
+ getTableBackgroundColor,
20
+ getTableBorderColor,
21
+ } from './helper';
22
+ import type {
23
+ TableProps,
24
+ TableRowData,
25
+ TableSortState,
26
+ SortDirection,
27
+ } from './Type';
28
+ import type {ExtendedTheme} from '../colors/Type';
29
+ import Typography from '../typography/Typography';
30
+ import TableHeader from './TableHeader';
31
+ import TableRow from './TableRow';
32
+ import TableFooter from './TableFooter';
33
+
34
+ const Table = <T extends TableRowData>({
35
+ screenName = 'default',
36
+ id = 'default',
37
+ columns,
38
+ dataSource,
39
+ size = 'medium',
40
+ variant = 'default',
41
+ loading = false,
42
+ pagination = false,
43
+ rowSelection,
44
+ scroll,
45
+ bordered = false,
46
+ showHeader = true,
47
+ title,
48
+ footer,
49
+ expandable,
50
+ rowKey,
51
+ onRow,
52
+ onHeaderRow,
53
+ sortDirections = ['asc', 'desc'],
54
+ defaultSortOrder,
55
+ showSorterTooltip = true,
56
+ tableStyle,
57
+ headerStyle,
58
+ bodyStyle,
59
+ footerStyle,
60
+ rowStyle,
61
+ cellStyle,
62
+ emptyText,
63
+ locale,
64
+ }: TableProps<T>) => {
65
+ const {theme} = useSliceTheme();
66
+ const {isDebugBuildType, automationBaseid} = theme;
67
+
68
+ // State management
69
+ const [sortedInfo, setSortedInfo] = useState<TableSortState>({
70
+ columnKey: undefined,
71
+ order: defaultSortOrder,
72
+ });
73
+ const [selectedRowKeys, setSelectedRowKeys] = useState<(string | number)[]>(
74
+ rowSelection?.selectedRowKeys || [],
75
+ );
76
+ const [expandedRowKeys, setExpandedRowKeys] = useState<(string | number)[]>(
77
+ expandable?.expandedRowKeys || expandable?.defaultExpandedRowKeys || [],
78
+ );
79
+
80
+ // Update selected rows when prop changes
81
+ useEffect(() => {
82
+ if (rowSelection?.selectedRowKeys) {
83
+ setSelectedRowKeys(rowSelection.selectedRowKeys);
84
+ }
85
+ }, [rowSelection?.selectedRowKeys]);
86
+
87
+ // Update expanded rows when prop changes
88
+ useEffect(() => {
89
+ if (expandable?.expandedRowKeys) {
90
+ setExpandedRowKeys(expandable.expandedRowKeys);
91
+ }
92
+ }, [expandable?.expandedRowKeys]);
93
+
94
+ // Process data
95
+ const processedData = useMemo(() => {
96
+ let result = [...dataSource];
97
+
98
+ // Apply sorting
99
+ result = sortData(result, sortedInfo, columns);
100
+
101
+ return result;
102
+ }, [dataSource, sortedInfo, columns]);
103
+
104
+ // Apply pagination
105
+ const paginatedResult = useMemo(() => {
106
+ return paginateData(processedData, pagination);
107
+ }, [processedData, pagination]);
108
+
109
+ const {paginatedData, totalPages, startIndex, endIndex} = paginatedResult;
110
+
111
+ // Selection logic
112
+ const allSelected = useMemo(
113
+ () => isAllRowsSelected(paginatedData, selectedRowKeys, rowKey),
114
+ [paginatedData, selectedRowKeys, rowKey],
115
+ );
116
+
117
+ const indeterminate = useMemo(
118
+ () => isSomeRowsSelected(paginatedData, selectedRowKeys, rowKey),
119
+ [paginatedData, selectedRowKeys, rowKey],
120
+ );
121
+
122
+ const selectedRows = useMemo(
123
+ () =>
124
+ processedData.filter((record, index) => {
125
+ const key = getRowKey(record, index, rowKey);
126
+ return selectedRowKeys.includes(key);
127
+ }),
128
+ [processedData, selectedRowKeys, rowKey],
129
+ );
130
+
131
+ // Event handlers
132
+ const handleSort = useCallback(
133
+ (columnKey: string, direction: SortDirection) => {
134
+ setSortedInfo({columnKey, order: direction});
135
+ },
136
+ [],
137
+ );
138
+
139
+ const handleSelectAll = useCallback(
140
+ (selected: boolean) => {
141
+ const result = toggleAllRowsSelection(
142
+ paginatedData,
143
+ selectedRowKeys,
144
+ rowKey,
145
+ );
146
+
147
+ setSelectedRowKeys(result.selectedRowKeys);
148
+
149
+ if (rowSelection?.onChange) {
150
+ rowSelection.onChange(result.selectedRowKeys, result.selectedRows);
151
+ }
152
+
153
+ if (rowSelection?.onSelectAll) {
154
+ rowSelection.onSelectAll(selected, result.selectedRows, paginatedData);
155
+ }
156
+ },
157
+ [paginatedData, selectedRowKeys, rowKey, rowSelection],
158
+ );
159
+
160
+ const handleRowSelect = useCallback(
161
+ (record: T, index: number, selected: boolean) => {
162
+ const key = getRowKey(record, index, rowKey);
163
+ let newSelectedKeys: (string | number)[];
164
+
165
+ if (rowSelection?.type === 'radio') {
166
+ newSelectedKeys = selected ? [key] : [];
167
+ } else {
168
+ newSelectedKeys = selected
169
+ ? [...selectedRowKeys, key]
170
+ : selectedRowKeys.filter(k => k !== key);
171
+ }
172
+
173
+ setSelectedRowKeys(newSelectedKeys);
174
+
175
+ const newSelectedRows = processedData.filter((r, i) => {
176
+ const rKey = getRowKey(r, i, rowKey);
177
+ return newSelectedKeys.includes(rKey);
178
+ });
179
+
180
+ if (rowSelection?.onChange) {
181
+ rowSelection.onChange(newSelectedKeys, newSelectedRows);
182
+ }
183
+
184
+ if (rowSelection?.onSelect) {
185
+ rowSelection.onSelect(record, selected, newSelectedRows, {} as any);
186
+ }
187
+ },
188
+ [selectedRowKeys, rowKey, rowSelection, processedData],
189
+ );
190
+
191
+ // Styles
192
+ const containerStyle = useMemo((): ViewStyle => {
193
+ const backgroundColor = theme.colors?.colorBackgroundPrimary || '#ffffff';
194
+ const borderColor = theme.colors?.colorBorderSubtle || '#e0e0e0';
195
+
196
+ return {
197
+ backgroundColor,
198
+ borderRadius: 8,
199
+ overflow: 'hidden',
200
+ borderWidth: 1,
201
+ borderColor,
202
+ width: '100%',
203
+ minWidth: 800, // Ensure minimum width for proper column display
204
+ };
205
+ }, [theme, bordered]);
206
+
207
+ const scrollViewStyle = useMemo((): ViewStyle => {
208
+ const style: ViewStyle = {
209
+ flex: 1,
210
+ };
211
+
212
+ if (scroll?.y) {
213
+ style.maxHeight = typeof scroll.y === 'number' ? scroll.y : undefined;
214
+ }
215
+
216
+ return style;
217
+ }, [scroll]);
218
+
219
+ // Render methods
220
+ const renderTitle = () => {
221
+ if (!title) return null;
222
+
223
+ return <View style={styles.titleContainer}>{title()}</View>;
224
+ };
225
+
226
+ const renderHeader = () => {
227
+ if (!showHeader) return null;
228
+
229
+ return (
230
+ <TableHeader
231
+ columns={columns}
232
+ selection={rowSelection}
233
+ sortedInfo={sortedInfo}
234
+ onSort={handleSort}
235
+ onSelectAll={handleSelectAll}
236
+ allSelected={allSelected}
237
+ indeterminate={indeterminate}
238
+ style={headerStyle}
239
+ />
240
+ );
241
+ };
242
+
243
+ const renderBody = () => {
244
+ if (loading) {
245
+ return (
246
+ <View style={styles.loadingContainer}>
247
+ <ActivityIndicator
248
+ size="large"
249
+ color={theme.colors?.colorForegroundAccent}
250
+ />
251
+ <Typography
252
+ variant="body2"
253
+ style={StyleSheet.flatten([
254
+ styles.loadingText,
255
+ {color: theme.colors?.colorForegroundSecondary},
256
+ ])}>
257
+ Loading...
258
+ </Typography>
259
+ </View>
260
+ );
261
+ }
262
+
263
+ if (paginatedData.length === 0) {
264
+ return (
265
+ <View style={styles.emptyContainer}>
266
+ {emptyText || (
267
+ <Typography
268
+ variant="body1"
269
+ style={StyleSheet.flatten([
270
+ styles.emptyText,
271
+ {color: theme.colors?.colorForegroundTertiary},
272
+ ])}>
273
+ {locale?.emptyText || 'No data'}
274
+ </Typography>
275
+ )}
276
+ </View>
277
+ );
278
+ }
279
+
280
+ return (
281
+ <View style={[styles.bodyContainer, bodyStyle]}>
282
+ {paginatedData.map((record, index) => {
283
+ const key = getRowKey(record, index, rowKey);
284
+ const selected = selectedRowKeys.includes(key);
285
+
286
+ return (
287
+ <TableRow
288
+ key={key}
289
+ record={record}
290
+ index={index}
291
+ columns={columns}
292
+ selection={rowSelection}
293
+ selected={selected}
294
+ onSelect={sel => handleRowSelect(record, index, sel)}
295
+ onRow={onRow}
296
+ style={rowStyle}
297
+ hover={true}
298
+ striped={variant === 'striped'}
299
+ />
300
+ );
301
+ })}
302
+ </View>
303
+ );
304
+ };
305
+
306
+ const renderFooter = () => {
307
+ const footerContent = (
308
+ <>
309
+ {pagination && (
310
+ <TableFooter pagination={pagination} style={footerStyle} />
311
+ )}
312
+ {footer && <View style={styles.customFooter}>{footer()}</View>}
313
+ </>
314
+ );
315
+
316
+ return footerContent;
317
+ };
318
+
319
+ const combinedTableStyle = useMemo(
320
+ () => StyleSheet.flatten([containerStyle, tableStyle]),
321
+ [containerStyle, tableStyle],
322
+ );
323
+
324
+ return (
325
+ <View
326
+ style={combinedTableStyle}
327
+ {...(isDebugBuildType && automationBaseid
328
+ ? setTestId(automationBaseid, screenName, id)
329
+ : {})}>
330
+ {renderTitle()}
331
+
332
+ <View style={styles.tableContent}>
333
+ {renderHeader()}
334
+
335
+ <ScrollView
336
+ style={scrollViewStyle}
337
+ horizontal={!!scroll?.x}
338
+ showsHorizontalScrollIndicator={!!scroll?.x}
339
+ showsVerticalScrollIndicator={!!scroll?.y}>
340
+ {renderBody()}
341
+ </ScrollView>
342
+ </View>
343
+
344
+ {renderFooter()}
345
+ </View>
346
+ );
347
+ };
348
+
349
+ const styles = StyleSheet.create({
350
+ titleContainer: {
351
+ padding: 16,
352
+ borderBottomWidth: 1,
353
+ borderBottomColor: '#f0f0f0',
354
+ },
355
+ tableContent: {
356
+ flex: 1,
357
+ },
358
+ bodyContainer: {
359
+ flex: 1,
360
+ },
361
+ loadingContainer: {
362
+ flex: 1,
363
+ alignItems: 'center',
364
+ justifyContent: 'center',
365
+ paddingVertical: 60,
366
+ },
367
+ loadingText: {
368
+ marginTop: 12,
369
+ },
370
+ emptyContainer: {
371
+ flex: 1,
372
+ alignItems: 'center',
373
+ justifyContent: 'center',
374
+ paddingVertical: 60,
375
+ },
376
+ emptyText: {
377
+ textAlign: 'center',
378
+ },
379
+ customFooter: {
380
+ padding: 16,
381
+ borderTopWidth: 1,
382
+ borderTopColor: '#f0f0f0',
383
+ },
384
+ });
385
+
386
+ export default React.memo(Table) as <T extends TableRowData>(
387
+ props: TableProps<T>,
388
+ ) => React.ReactElement;
@@ -0,0 +1,158 @@
1
+ import React, {useMemo} from 'react';
2
+ import {
3
+ View,
4
+ StyleSheet,
5
+ Pressable,
6
+ Platform,
7
+ type ViewStyle,
8
+ type TextStyle,
9
+ } from 'react-native';
10
+ import {useSliceTheme} from '../contextProvider/context';
11
+ import {setTestId} from '../automation/helper';
12
+ import {getJustifyContent, getTextAlign} from './helper';
13
+ import type {TableCellProps} from './Type';
14
+ import Typography from '../typography/Typography';
15
+
16
+ const isWeb = Platform.OS === 'web';
17
+
18
+ const TableCell: React.FC<TableCellProps> = ({
19
+ children,
20
+ align = 'left',
21
+ style,
22
+ textStyle,
23
+ width,
24
+ minWidth,
25
+ maxWidth,
26
+ fixed,
27
+ ellipsis = false,
28
+ onPress,
29
+ }) => {
30
+ const {theme} = useSliceTheme();
31
+ const {isDebugBuildType, automationBaseid} = theme;
32
+
33
+ const cellStyle = useMemo((): ViewStyle => {
34
+ const baseStyle: ViewStyle = {
35
+ flex: width ? 0 : 1,
36
+ flexDirection: 'row',
37
+ alignItems: 'center',
38
+ justifyContent: getJustifyContent(align),
39
+ paddingHorizontal: 8,
40
+ paddingVertical: 0,
41
+ };
42
+
43
+ if (width) {
44
+ if (typeof width === 'number') {
45
+ baseStyle.width = width;
46
+ } else if (typeof width === 'string') {
47
+ if (width.endsWith('%')) {
48
+ baseStyle.flexBasis = width as any;
49
+ } else {
50
+ baseStyle.width = parseInt(width, 10) || undefined;
51
+ }
52
+ }
53
+ }
54
+
55
+ if (minWidth) {
56
+ baseStyle.minWidth = minWidth;
57
+ }
58
+
59
+ if (maxWidth) {
60
+ baseStyle.maxWidth = maxWidth;
61
+ }
62
+
63
+ if (fixed) {
64
+ baseStyle.position = 'absolute';
65
+ if (fixed === 'left') {
66
+ baseStyle.left = 0;
67
+ baseStyle.zIndex = 10;
68
+ } else if (fixed === 'right') {
69
+ baseStyle.right = 0;
70
+ baseStyle.zIndex = 10;
71
+ }
72
+ }
73
+
74
+ return baseStyle;
75
+ }, [align, width, minWidth, maxWidth, fixed, theme.spacing]);
76
+
77
+ const contentStyle = useMemo((): TextStyle => {
78
+ const baseStyle: TextStyle = {
79
+ flex: 1,
80
+ textAlign: getTextAlign(align),
81
+ };
82
+
83
+ if (ellipsis && isWeb) {
84
+ // Web-only CSS properties - cast as any since RN types don't include them
85
+ (baseStyle as any).overflow = 'hidden';
86
+ (baseStyle as any).textOverflow = 'ellipsis';
87
+ (baseStyle as any).whiteSpace = 'nowrap';
88
+ }
89
+
90
+ return baseStyle;
91
+ }, [align, ellipsis]);
92
+
93
+ const combinedCellStyle = useMemo(
94
+ () => StyleSheet.flatten([styles.baseCell, cellStyle, style]),
95
+ [cellStyle, style],
96
+ );
97
+
98
+ const combinedTextStyle = useMemo(
99
+ () => StyleSheet.flatten([contentStyle, textStyle]),
100
+ [contentStyle, textStyle],
101
+ );
102
+
103
+ const renderContent = () => {
104
+ if (React.isValidElement(children)) {
105
+ return children;
106
+ }
107
+
108
+ if (typeof children === 'string' || typeof children === 'number') {
109
+ return (
110
+ <Typography
111
+ variant="body2"
112
+ style={combinedTextStyle}
113
+ extraProps={{
114
+ numberOfLines: ellipsis ? 1 : undefined,
115
+ ellipsizeMode: ellipsis ? 'tail' : undefined,
116
+ }}>
117
+ {String(children)}
118
+ </Typography>
119
+ );
120
+ }
121
+
122
+ return children;
123
+ };
124
+
125
+ if (onPress) {
126
+ return (
127
+ <Pressable
128
+ onPress={onPress}
129
+ style={({pressed}) => [combinedCellStyle, pressed && styles.pressed]}
130
+ {...(isDebugBuildType && automationBaseid
131
+ ? setTestId(automationBaseid, 'table', 'cell')
132
+ : {})}>
133
+ {renderContent()}
134
+ </Pressable>
135
+ );
136
+ }
137
+
138
+ return (
139
+ <View
140
+ style={combinedCellStyle}
141
+ {...(isDebugBuildType && automationBaseid
142
+ ? setTestId(automationBaseid, 'table', 'cell')
143
+ : {})}>
144
+ {renderContent()}
145
+ </View>
146
+ );
147
+ };
148
+
149
+ const styles = StyleSheet.create({
150
+ baseCell: {
151
+ borderRightWidth: 0, // Will be handled by parent row
152
+ },
153
+ pressed: {
154
+ opacity: 0.7,
155
+ },
156
+ });
157
+
158
+ export default React.memo(TableCell);