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,353 @@
1
+ import React, {useMemo} from 'react';
2
+ import {
3
+ View,
4
+ StyleSheet,
5
+ Pressable,
6
+ Platform,
7
+ type ViewStyle,
8
+ } from 'react-native';
9
+ import {useSliceTheme} from '../contextProvider/context';
10
+ import {setTestId} from '../automation/helper';
11
+ import {
12
+ getTableBackgroundColor,
13
+ getTableBorderColor,
14
+ getTableTextColor,
15
+ generatePageNumbers,
16
+ formatPaginationText,
17
+ } from './helper';
18
+ import type {TableFooterProps} from './Type';
19
+ import type {ExtendedTheme} from '../colors/Type';
20
+ import Typography from '../typography/Typography';
21
+ import Button from '../button/Button';
22
+ import IconMoon from '../IconMoon';
23
+ import FontIcon from '../assets/resources/fonts/FontIcon.json';
24
+
25
+ const isWeb = Platform.OS === 'web';
26
+
27
+ const TableFooter: React.FC<TableFooterProps> = ({pagination, style}) => {
28
+ const {theme} = useSliceTheme();
29
+ const {isDebugBuildType, automationBaseid} = theme;
30
+
31
+ if (!pagination) return null;
32
+
33
+ const {
34
+ current = 1,
35
+ pageSize = 10,
36
+ total = 0,
37
+ showSizeChanger = false,
38
+ pageSizeOptions = ['10', '20', '50', '100'],
39
+ showQuickJumper = false,
40
+ showTotal,
41
+ onChange,
42
+ onShowSizeChange,
43
+ position = 'bottomRight',
44
+ size = 'default',
45
+ } = pagination;
46
+
47
+ const getJustifyContent = (pos: string): ViewStyle['justifyContent'] => {
48
+ if (pos.includes('Left')) return 'flex-start';
49
+ if (pos.includes('Center')) return 'center';
50
+ return 'flex-end';
51
+ };
52
+
53
+ const footerStyle = useMemo((): ViewStyle => {
54
+ const backgroundColor = theme.colors?.colorBackgroundPrimary || '#ffffff';
55
+ const borderColor = theme.colors?.colorBorderSubtle || '#e0e0e0';
56
+
57
+ return {
58
+ flexDirection: 'row',
59
+ alignItems: 'center',
60
+ justifyContent: getJustifyContent(position),
61
+ backgroundColor,
62
+ borderTopWidth: 1,
63
+ borderTopColor: borderColor,
64
+ paddingHorizontal: 16,
65
+ paddingVertical: 12,
66
+ minHeight: 56,
67
+ };
68
+ }, [theme, position]);
69
+
70
+ const textColor = theme.colors?.colorForegroundPrimary || '#333333';
71
+
72
+ const totalPages = Math.ceil(total / pageSize);
73
+ const pageNumbers = generatePageNumbers(current, totalPages);
74
+ const paginationText = formatPaginationText(current, pageSize, total);
75
+
76
+ const handlePageChange = (page: number) => {
77
+ if (page !== current && onChange) {
78
+ onChange(page, pageSize);
79
+ }
80
+ };
81
+
82
+ const handlePageSizeChange = (newPageSize: number) => {
83
+ if (newPageSize !== pageSize && onShowSizeChange) {
84
+ onShowSizeChange(current, newPageSize);
85
+ }
86
+ };
87
+
88
+ const renderPageButton = (page: number | string, index: number) => {
89
+ if (page === '...') {
90
+ return (
91
+ <View key={`ellipsis-${index}`} style={styles.ellipsis}>
92
+ <Typography variant="body2" style={{color: textColor}}>
93
+ ...
94
+ </Typography>
95
+ </View>
96
+ );
97
+ }
98
+
99
+ const pageNumber = page as number;
100
+ const isActive = pageNumber === current;
101
+
102
+ return (
103
+ <Pressable
104
+ key={pageNumber}
105
+ onPress={() => handlePageChange(pageNumber)}
106
+ style={[
107
+ styles.pageButton,
108
+ isActive && styles.activePageButton,
109
+ {
110
+ backgroundColor: isActive
111
+ ? theme.colors?.colorBackgroundAccent
112
+ : 'transparent',
113
+ },
114
+ ]}>
115
+ <Typography
116
+ variant="body2"
117
+ style={{
118
+ color: isActive
119
+ ? theme.colors?.colorForegroundInvariable || '#fff'
120
+ : textColor,
121
+ fontWeight: isActive ? '600' : '400',
122
+ }}>
123
+ {String(pageNumber)}
124
+ </Typography>
125
+ </Pressable>
126
+ );
127
+ };
128
+
129
+ const renderPaginationInfo = () => {
130
+ if (showTotal) {
131
+ return showTotal(total, paginationText.range);
132
+ }
133
+
134
+ return (
135
+ <Typography
136
+ variant="body2"
137
+ style={StyleSheet.flatten([styles.paginationInfo, {color: textColor}])}>
138
+ {paginationText.text}
139
+ </Typography>
140
+ );
141
+ };
142
+
143
+ const renderPageSizeChanger = () => {
144
+ if (!showSizeChanger) return null;
145
+
146
+ return (
147
+ <View style={styles.pageSizeChanger}>
148
+ <Typography
149
+ variant="body2"
150
+ style={StyleSheet.flatten([
151
+ styles.pageSizeLabel,
152
+ {color: textColor},
153
+ ])}>
154
+ Show
155
+ </Typography>
156
+ {/* Note: In a real implementation, this would be a dropdown/select component */}
157
+ <View style={styles.pageSizeSelect}>
158
+ <Typography variant="body2" style={{color: textColor}}>
159
+ {String(pageSize)}
160
+ </Typography>
161
+ <IconMoon icon={FontIcon.ARROW_DOWN} size={12} color={textColor} />
162
+ </View>
163
+ <Typography
164
+ variant="body2"
165
+ style={StyleSheet.flatten([
166
+ styles.pageSizeLabel,
167
+ {color: textColor},
168
+ ])}>
169
+ per page
170
+ </Typography>
171
+ </View>
172
+ );
173
+ };
174
+
175
+ const renderQuickJumper = () => {
176
+ if (!showQuickJumper) return null;
177
+
178
+ return (
179
+ <View style={styles.quickJumper}>
180
+ <Typography
181
+ variant="body2"
182
+ style={StyleSheet.flatten([
183
+ styles.quickJumperLabel,
184
+ {color: textColor},
185
+ ])}>
186
+ Go to
187
+ </Typography>
188
+ {/* Note: In a real implementation, this would be a text input */}
189
+ <View style={styles.quickJumperInput}>
190
+ <Typography variant="body2" style={{color: textColor}}>
191
+ {String(current)}
192
+ </Typography>
193
+ </View>
194
+ </View>
195
+ );
196
+ };
197
+
198
+ const renderPaginationControls = () => {
199
+ return (
200
+ <View style={styles.paginationControls}>
201
+ <Pressable
202
+ onPress={() => handlePageChange(current - 1)}
203
+ disabled={current <= 1}
204
+ style={[styles.navButton, current <= 1 && styles.disabledNavButton]}>
205
+ <IconMoon
206
+ icon={FontIcon.LEFT_ARROW}
207
+ size={16}
208
+ color={
209
+ current <= 1
210
+ ? theme.colors?.colorForegroundTertiary || textColor
211
+ : textColor
212
+ }
213
+ />
214
+ </Pressable>
215
+
216
+ <View style={styles.pageNumbers}>
217
+ {pageNumbers.map(renderPageButton)}
218
+ </View>
219
+
220
+ <Pressable
221
+ onPress={() => handlePageChange(current + 1)}
222
+ disabled={current >= totalPages}
223
+ style={[
224
+ styles.navButton,
225
+ current >= totalPages && styles.disabledNavButton,
226
+ ]}>
227
+ <IconMoon
228
+ icon={FontIcon.ARROW_RIGHT_SMALL}
229
+ size={16}
230
+ color={
231
+ current >= totalPages
232
+ ? theme.colors?.colorForegroundTertiary || textColor
233
+ : textColor
234
+ }
235
+ />
236
+ </Pressable>
237
+ </View>
238
+ );
239
+ };
240
+
241
+ const combinedFooterStyle = useMemo(
242
+ () => StyleSheet.flatten([footerStyle, style]),
243
+ [footerStyle, style],
244
+ );
245
+
246
+ return (
247
+ <View
248
+ style={combinedFooterStyle}
249
+ {...(isDebugBuildType && automationBaseid
250
+ ? setTestId(automationBaseid, 'table', 'footer')
251
+ : {})}>
252
+ <View style={styles.footerContent}>
253
+ {renderPaginationInfo()}
254
+
255
+ <View style={styles.footerControls}>
256
+ {renderPageSizeChanger()}
257
+ {renderQuickJumper()}
258
+ {renderPaginationControls()}
259
+ </View>
260
+ </View>
261
+ </View>
262
+ );
263
+ };
264
+
265
+ const styles = StyleSheet.create({
266
+ footerContent: {
267
+ flex: 1,
268
+ flexDirection: 'row',
269
+ alignItems: 'center',
270
+ justifyContent: 'space-between',
271
+ },
272
+ footerControls: {
273
+ flexDirection: 'row',
274
+ alignItems: 'center',
275
+ gap: 16,
276
+ },
277
+ paginationInfo: {
278
+ fontSize: 14,
279
+ },
280
+ pageSizeChanger: {
281
+ flexDirection: 'row',
282
+ alignItems: 'center',
283
+ gap: 8,
284
+ },
285
+ pageSizeLabel: {
286
+ fontSize: 14,
287
+ },
288
+ pageSizeSelect: {
289
+ flexDirection: 'row',
290
+ alignItems: 'center',
291
+ paddingHorizontal: 8,
292
+ paddingVertical: 4,
293
+ borderWidth: 1,
294
+ borderRadius: 4,
295
+ borderColor: '#d9d9d9',
296
+ gap: 4,
297
+ },
298
+ quickJumper: {
299
+ flexDirection: 'row',
300
+ alignItems: 'center',
301
+ gap: 8,
302
+ },
303
+ quickJumperLabel: {
304
+ fontSize: 14,
305
+ },
306
+ quickJumperInput: {
307
+ paddingHorizontal: 8,
308
+ paddingVertical: 4,
309
+ borderWidth: 1,
310
+ borderRadius: 4,
311
+ borderColor: '#d9d9d9',
312
+ minWidth: 40,
313
+ alignItems: 'center',
314
+ },
315
+ paginationControls: {
316
+ flexDirection: 'row',
317
+ alignItems: 'center',
318
+ gap: 4,
319
+ },
320
+ navButton: {
321
+ padding: 8,
322
+ borderRadius: 4,
323
+ alignItems: 'center',
324
+ justifyContent: 'center',
325
+ },
326
+ disabledNavButton: {
327
+ opacity: 0.5,
328
+ },
329
+ pageNumbers: {
330
+ flexDirection: 'row',
331
+ alignItems: 'center',
332
+ gap: 2,
333
+ },
334
+ pageButton: {
335
+ paddingHorizontal: 8,
336
+ paddingVertical: 4,
337
+ borderRadius: 4,
338
+ minWidth: 32,
339
+ alignItems: 'center',
340
+ justifyContent: 'center',
341
+ },
342
+ activePageButton: {
343
+ // backgroundColor will be set dynamically
344
+ },
345
+ ellipsis: {
346
+ paddingHorizontal: 8,
347
+ paddingVertical: 4,
348
+ alignItems: 'center',
349
+ justifyContent: 'center',
350
+ },
351
+ });
352
+
353
+ export default React.memo(TableFooter);
@@ -0,0 +1,247 @@
1
+ import React, {useMemo, useState} from 'react';
2
+ import {
3
+ View,
4
+ StyleSheet,
5
+ Pressable,
6
+ Platform,
7
+ type ViewStyle,
8
+ } from 'react-native';
9
+ import {useSliceTheme} from '../contextProvider/context';
10
+ import {setTestId} from '../automation/helper';
11
+ import {
12
+ getTableBackgroundColor,
13
+ getTableBorderColor,
14
+ getTableTextColor,
15
+ } from './helper';
16
+ import type {TableHeaderProps, SortDirection} from './Type';
17
+ import type {ExtendedTheme} from '../colors/Type';
18
+ import Typography from '../typography/Typography';
19
+ import TableCell from './TableCell';
20
+ import Checkbox from '../checkbox/Checkbox';
21
+ import IconMoon from '../IconMoon';
22
+ import FontIcon from '../assets/resources/fonts/FontIcon.json';
23
+
24
+ const isWeb = Platform.OS === 'web';
25
+
26
+ const TableHeader: React.FC<TableHeaderProps> = ({
27
+ columns,
28
+ selection,
29
+ sortedInfo,
30
+ onSort,
31
+ onSelectAll,
32
+ allSelected = false,
33
+ indeterminate = false,
34
+ style,
35
+ }) => {
36
+ const {theme} = useSliceTheme();
37
+ const {isDebugBuildType, automationBaseid} = theme;
38
+ const [hoveredColumn, setHoveredColumn] = useState<string | null>(null);
39
+
40
+ const headerStyle = useMemo((): ViewStyle => {
41
+ const backgroundColor = theme.colors?.colorBackgroundSecondary || '#f5f5f5';
42
+ const borderColor = theme.colors?.colorBorderSubtle || '#e0e0e0';
43
+
44
+ return {
45
+ flexDirection: 'row',
46
+ alignItems: 'center',
47
+ backgroundColor,
48
+ borderBottomWidth: 1,
49
+ borderBottomColor: borderColor,
50
+ minHeight: 60,
51
+ paddingHorizontal: 16,
52
+ paddingVertical: 16,
53
+ };
54
+ }, [theme]);
55
+
56
+ const textColor = theme.colors?.colorForegroundPrimary || '#333333';
57
+
58
+ const handleSort = (columnKey: string, currentOrder?: SortDirection) => {
59
+ if (!onSort) return;
60
+
61
+ let newOrder: SortDirection = 'asc';
62
+ if (currentOrder === 'asc') {
63
+ newOrder = 'desc';
64
+ } else if (currentOrder === 'desc') {
65
+ newOrder = null;
66
+ }
67
+
68
+ onSort(columnKey, newOrder);
69
+ };
70
+
71
+ const handleSelectAll = () => {
72
+ if (onSelectAll) {
73
+ onSelectAll(!allSelected);
74
+ }
75
+ };
76
+
77
+ const renderSortIcon = (columnKey: string, sortable?: boolean) => {
78
+ if (!sortable) return null;
79
+
80
+ const isActive = sortedInfo?.columnKey === columnKey;
81
+ const order = isActive ? sortedInfo?.order : null;
82
+ const isHovered = hoveredColumn === columnKey;
83
+
84
+ return (
85
+ <View style={styles.sortIconContainer}>
86
+ <IconMoon
87
+ icon={
88
+ order === 'asc'
89
+ ? FontIcon.ARROW_UP
90
+ : order === 'desc'
91
+ ? FontIcon.ARROW_DOWN
92
+ : FontIcon.ARROW_DOWN
93
+ }
94
+ size={12}
95
+ color={
96
+ isActive || isHovered
97
+ ? theme.colors?.colorForegroundAccent || textColor
98
+ : theme.colors?.colorForegroundTertiary || textColor
99
+ }
100
+ />
101
+ </View>
102
+ );
103
+ };
104
+
105
+ const renderSelectionColumn = () => {
106
+ if (!selection) return null;
107
+
108
+ return (
109
+ <View style={[styles.selectionCell, {width: 48, minWidth: 48}]}>
110
+ {selection.type !== 'radio' && !selection.hideSelectAll && (
111
+ <Checkbox
112
+ checked={allSelected}
113
+ onChange={handleSelectAll}
114
+ size="medium"
115
+ style={styles.checkbox}
116
+ />
117
+ )}
118
+ </View>
119
+ );
120
+ };
121
+
122
+ const renderHeaderCell = (column: any, index: number) => {
123
+ const isActive = sortedInfo?.columnKey === column.key;
124
+ const order = isActive ? sortedInfo?.order : null;
125
+
126
+ const cellContent = (
127
+ <View style={styles.headerCellContent}>
128
+ <View style={styles.headerTextContainer}>
129
+ {column.headerRender ? (
130
+ column.headerRender()
131
+ ) : (
132
+ <Typography
133
+ variant="body2Bold"
134
+ style={StyleSheet.flatten([
135
+ styles.headerText,
136
+ {color: textColor},
137
+ ])}
138
+ extraProps={{
139
+ numberOfLines: 1,
140
+ ellipsizeMode: 'tail',
141
+ }}>
142
+ {column.title}
143
+ </Typography>
144
+ )}
145
+ </View>
146
+ {renderSortIcon(column.key, column.sortable)}
147
+ </View>
148
+ );
149
+
150
+ if (column.sortable) {
151
+ return (
152
+ <Pressable
153
+ key={column.key}
154
+ onPress={() => handleSort(column.key, order)}
155
+ style={[
156
+ styles.headerCell,
157
+ {
158
+ width: column.width || 'auto',
159
+ minWidth: column.minWidth || 100,
160
+ flex: column.width ? 0 : 1,
161
+ },
162
+ ]}
163
+ {...(isWeb && {
164
+ onMouseEnter: () => setHoveredColumn(column.key),
165
+ onMouseLeave: () => setHoveredColumn(null),
166
+ })}>
167
+ {cellContent}
168
+ </Pressable>
169
+ );
170
+ }
171
+
172
+ return (
173
+ <View
174
+ key={column.key}
175
+ style={[
176
+ styles.headerCell,
177
+ {
178
+ width: column.width || 'auto',
179
+ minWidth: column.minWidth || 100,
180
+ flex: column.width ? 0 : 1,
181
+ },
182
+ ]}>
183
+ {cellContent}
184
+ </View>
185
+ );
186
+ };
187
+
188
+ const combinedHeaderStyle = useMemo(
189
+ () => StyleSheet.flatten([headerStyle, style]),
190
+ [headerStyle, style],
191
+ );
192
+
193
+ return (
194
+ <View
195
+ style={combinedHeaderStyle}
196
+ {...(isDebugBuildType && automationBaseid
197
+ ? setTestId(automationBaseid, 'table', 'header')
198
+ : {})}>
199
+ {renderSelectionColumn()}
200
+ {columns.map(renderHeaderCell)}
201
+ </View>
202
+ );
203
+ };
204
+
205
+ const styles = StyleSheet.create({
206
+ selectionCell: {
207
+ justifyContent: 'center',
208
+ alignItems: 'center',
209
+ paddingHorizontal: 8,
210
+ },
211
+ checkbox: {
212
+ margin: 0,
213
+ },
214
+ headerCell: {
215
+ paddingHorizontal: 8,
216
+ paddingVertical: 0,
217
+ justifyContent: 'flex-start',
218
+ alignItems: 'center',
219
+ minHeight: 60,
220
+ },
221
+ headerCellContent: {
222
+ flex: 1,
223
+ flexDirection: 'row',
224
+ alignItems: 'center',
225
+ justifyContent: 'space-between',
226
+ },
227
+ headerTextContainer: {
228
+ flex: 1,
229
+ marginRight: 4,
230
+ },
231
+ headerText: {
232
+ fontWeight: '600',
233
+ },
234
+ sortIconContainer: {
235
+ marginLeft: 4,
236
+ justifyContent: 'center',
237
+ alignItems: 'center',
238
+ },
239
+ sortableHeader: {
240
+ flex: 1,
241
+ },
242
+ pressedHeader: {
243
+ opacity: 0.7,
244
+ },
245
+ });
246
+
247
+ export default React.memo(TableHeader);