ctms-common-components 1.0.1

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 (61) hide show
  1. package/.babelrc +3 -0
  2. package/.czrc +3 -0
  3. package/.github/CODEOWNERS +1 -0
  4. package/.github/workflows/cd.yml +38 -0
  5. package/.github/workflows/ci.yml +29 -0
  6. package/.storybook/main.js +22 -0
  7. package/.storybook/preview.js +14 -0
  8. package/CHANGELOG.md +11 -0
  9. package/README.md +1 -0
  10. package/dist/index.js.LICENSE.txt +50 -0
  11. package/package.json +58 -0
  12. package/public/fonts/lato-latin.woff2 +0 -0
  13. package/public/index.html +17 -0
  14. package/src/assets/components/index.css +3 -0
  15. package/src/assets/components/index.jsx +607 -0
  16. package/src/assets/pngs/background-logo.png +0 -0
  17. package/src/assets/pngs/logo.png +0 -0
  18. package/src/assets/styles/tailwind.css +3 -0
  19. package/src/assets/svgs/edit-icon.svg +12 -0
  20. package/src/assets/svgs/overflow-icon.svg +20 -0
  21. package/src/assets/svgs/tick-mark.svg +3 -0
  22. package/src/components/Button.jsx +50 -0
  23. package/src/components/Pagination/PaginationStyles.js +49 -0
  24. package/src/components/Pagination/index.jsx +85 -0
  25. package/src/components/PoojaCard/index.jsx +216 -0
  26. package/src/components/StatusCard/index.jsx +102 -0
  27. package/src/components/TokenCard/index.jsx +205 -0
  28. package/src/components/button.css +50 -0
  29. package/src/components/custom-Table/AdvancedTableBody.jsx +186 -0
  30. package/src/components/custom-Table/AdvancedTableHead.jsx +315 -0
  31. package/src/components/custom-Table/EllipsisCell.jsx +137 -0
  32. package/src/components/custom-Table/Loader.jsx +24 -0
  33. package/src/components/custom-Table/index.jsx +340 -0
  34. package/src/components/index.js +7 -0
  35. package/src/components/more-actions/MenuStyles.js +54 -0
  36. package/src/components/more-actions/index.jsx +50 -0
  37. package/src/index.jsx +11 -0
  38. package/src/lib.js +133 -0
  39. package/src/stories/AdvancedTable.stories.jsx +108 -0
  40. package/src/stories/Button.stories.js +45 -0
  41. package/src/stories/PoojaCard.stories.jsx +108 -0
  42. package/src/stories/StatusCard.stories.jsx +51 -0
  43. package/src/stories/TokenCard.stories.jsx +75 -0
  44. package/src/theme/README.md +23 -0
  45. package/src/theme/components/button.js +42 -0
  46. package/src/theme/components/checkbox.js +20 -0
  47. package/src/theme/components/index.js +27 -0
  48. package/src/theme/foundations/blur.js +12 -0
  49. package/src/theme/foundations/borders.js +9 -0
  50. package/src/theme/foundations/breakpoints.js +10 -0
  51. package/src/theme/foundations/colors.js +196 -0
  52. package/src/theme/foundations/index.js +27 -0
  53. package/src/theme/foundations/radius.js +13 -0
  54. package/src/theme/foundations/shadows.js +16 -0
  55. package/src/theme/foundations/sizes.js +60 -0
  56. package/src/theme/foundations/spacing.js +37 -0
  57. package/src/theme/foundations/transition.js +25 -0
  58. package/src/theme/foundations/typography.js +55 -0
  59. package/src/theme/foundations/z-index.js +17 -0
  60. package/src/theme/index.js +20 -0
  61. package/webpack.config.js +34 -0
@@ -0,0 +1,50 @@
1
+ .storybook-button {
2
+ font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
3
+ font-weight: 700;
4
+ border-radius: 4em;
5
+ cursor: pointer;
6
+ display: inline-block;
7
+ line-height: 1;
8
+ transition: all 0.3s ease;
9
+ }
10
+
11
+ /* GOLD FILLED */
12
+ .storybook-button--primary {
13
+ color: #6b0f1a; /* Maroon text */
14
+ background-color: #d4af37; /* Gold */
15
+ border: 2px solid #d4af37;
16
+ }
17
+
18
+ /* GOLD OUTLINE */
19
+ .storybook-button--secondary {
20
+ color: #6b0f1a; /* Maroon text */
21
+ background-color: transparent;
22
+ border: 2px solid #d4af37; /* Gold border */
23
+ }
24
+
25
+ /* Hover Effects */
26
+ .storybook-button--primary:hover {
27
+ background-color: #c19b2e;
28
+ border-color: #c19b2e;
29
+ }
30
+
31
+ .storybook-button--secondary:hover {
32
+ background-color: #d4af37;
33
+ color: #6b0f1a;
34
+ }
35
+
36
+ /* Sizes */
37
+ .storybook-button--small {
38
+ font-size: 12px;
39
+ padding: 10px 16px;
40
+ }
41
+
42
+ .storybook-button--medium {
43
+ font-size: 14px;
44
+ padding: 11px 20px;
45
+ }
46
+
47
+ .storybook-button--large {
48
+ font-size: 16px;
49
+ padding: 12px 24px;
50
+ }
@@ -0,0 +1,186 @@
1
+ /* eslint-disable no-nested-ternary */
2
+ /* eslint-disable react/no-array-index-key */
3
+ import React from 'react';
4
+ import {
5
+
6
+ TableRow as Tr,
7
+
8
+ TableCell as Td,
9
+
10
+ Typography as Text,
11
+
12
+ Checkbox,
13
+
14
+ Radio,
15
+
16
+ TableBody as Tbody,
17
+
18
+ Button
19
+
20
+ } from '@mui/material';
21
+ import AddIcon from '@mui/icons-material/Add';
22
+
23
+ import RemoveIcon from '@mui/icons-material/Remove';
24
+ import EllipsisCell from './EllipsisCell';
25
+ import MoreActions from '../more-actions';
26
+
27
+ const AdvancedTableBody = ({
28
+ paginatedData = [],
29
+ columns = [],
30
+ checkedItems = [],
31
+ handleIndividualCheck = () => {},
32
+ handleRadioSelect = () => {},
33
+ radioSelected = () => false,
34
+ rowDisabled = [],
35
+ rowDisabledOptionKey = '',
36
+ rowValues = () => {},
37
+ onRowClick = () => {},
38
+ columnWidths = {},
39
+ expandedRows = [],
40
+ setExpandedRows = () => {}
41
+ }) => {
42
+ const toggleRow = (id) => {
43
+ if (expandedRows.includes(id)) {
44
+ setExpandedRows(expandedRows.filter((rowId) => rowId !== id));
45
+ } else {
46
+ setExpandedRows([...expandedRows, id]);
47
+ }
48
+ };
49
+ return (
50
+ <Tbody>
51
+ {paginatedData.length === 0 ? (
52
+ <Tr>
53
+ <Td colSpan={columns.length}>
54
+ <Text align="center" py={4}>No Data Found</Text>
55
+ </Td>
56
+ </Tr>
57
+ ) : (
58
+ paginatedData.map((row, index) => (
59
+ <Tr
60
+ key={row.id || `row-${index}`}
61
+ onClick={() => onRowClick({ row, index })}
62
+ hover={!!onRowClick}
63
+ sx={{
64
+ cursor: onRowClick ? 'pointer' : 'default',
65
+ backgroundColor: checkedItems[index]
66
+ ? '#E8F5E9'
67
+ : index % 2 === 0
68
+ ? '#F9FAFB'
69
+ : '#FFFFFF',
70
+
71
+ '& td': {
72
+ borderBottom: '1px solid #E5E7EB'
73
+ }
74
+ }}
75
+ >
76
+ {columns.map((col, columnIndex) => {
77
+ const value = row[col.field];
78
+ const columnKey = `${index}-${columnIndex}`;
79
+
80
+ if (col.type === 'multi-select' || col.type === 'select') {
81
+ const isDisabled = rowDisabled.some(
82
+ (item) => item[rowDisabledOptionKey] === row[rowDisabledOptionKey]
83
+ ) && checkedItems[index];
84
+ return (
85
+ <Td
86
+ key={columnKey}
87
+ align={col.alignment || 'center'}
88
+ sx={{
89
+ py: 1.5,
90
+ px: 2
91
+ }}
92
+ >
93
+ <Checkbox
94
+ checked={checkedItems[index]}
95
+ onChange={(e) => handleIndividualCheck(e, index, row)}
96
+ disabled={isDisabled}
97
+ size="small"
98
+ />
99
+ </Td>
100
+ );
101
+ }
102
+
103
+ if (col.type === 'radio') {
104
+ return (
105
+ <Td
106
+ key={columnKey}
107
+ align={col.alignment || 'center'}
108
+ sx={{
109
+ py: 1.5,
110
+ px: 2
111
+ }}
112
+ >
113
+ <Radio
114
+ value={index}
115
+ checked={radioSelected(row)}
116
+ onClick={() => handleRadioSelect(row)}
117
+ size="small"
118
+ />
119
+ </Td>
120
+ );
121
+ }
122
+
123
+ if (col.type === 'actions') {
124
+ return (
125
+ <Td
126
+ key={columnKey}
127
+ align={col.alignment}
128
+ onClick={(e) => rowValues(e, row)}
129
+ >
130
+ <MoreActions actionData={col.actions} rowData={row} />
131
+ </Td>
132
+ );
133
+ }
134
+ if (col.type === 'isExpandable') {
135
+ return (
136
+ <Td
137
+ key={columnKey}
138
+ align={col.alignment}
139
+ onClick={(e) => rowValues(e, row)}
140
+ >
141
+ <Button
142
+ variant="text"
143
+
144
+ size="small"
145
+
146
+ onClick={() => toggleRow(row.id)}
147
+
148
+ sx={{
149
+
150
+ minWidth: 'auto',
151
+
152
+ p: 0.5
153
+
154
+ }}
155
+ >
156
+ {expandedRows.includes(row.id) ? (
157
+ <RemoveIcon variant="ghost" />
158
+ ) : (
159
+ <AddIcon color="pink.500" />
160
+ )}
161
+ </Button>
162
+ </Td>
163
+ );
164
+ }
165
+
166
+ return (
167
+ <EllipsisCell
168
+ columnKey={columnKey}
169
+ col={col}
170
+ value={value}
171
+ row={row}
172
+ rowIndex={index}
173
+ columnIndex={columnIndex}
174
+ maxWidth={columnWidths[col.field] || 160}
175
+ expandedRows={expandedRows}
176
+ />
177
+ );
178
+ })}
179
+ </Tr>
180
+ ))
181
+ )}
182
+ </Tbody>
183
+ );
184
+ };
185
+
186
+ export default AdvancedTableBody;
@@ -0,0 +1,315 @@
1
+ /* eslint-disable no-return-assign */
2
+ /* eslint-disable no-param-reassign */
3
+
4
+ import React from 'react';
5
+
6
+ import {
7
+ Table,
8
+ TableHead,
9
+ TableRow,
10
+ TableCell,
11
+ Checkbox,
12
+ Typography,
13
+ Box,
14
+ InputBase,
15
+ IconButton
16
+ } from '@mui/material';
17
+
18
+
19
+ const AdvancedTableHead = ({
20
+ tableSize,
21
+ columns,
22
+ columnWidths,
23
+ checkedItems,
24
+ handleAllCheck,
25
+ sortConfig,
26
+ handleSort,
27
+ filterValues,
28
+ setFilterValues,
29
+ onFilterInput,
30
+ headerRefs
31
+ }) => {
32
+ return (
33
+
34
+ <TableHead>
35
+ <TableRow>
36
+ {columns.map((col) => {
37
+ const isSortedAsc =
38
+ sortConfig.field === col.field &&
39
+ sortConfig.direction === 'asc';
40
+
41
+ const isSortedDesc =
42
+ sortConfig.field === col.field &&
43
+ sortConfig.direction === 'desc';
44
+
45
+ return (
46
+ <TableCell
47
+ key={col.field}
48
+ ref={(el) => (headerRefs.current[col.field] = el)}
49
+ align={col.alignment || 'center'}
50
+ sx={{
51
+ backgroundColor: '#edeef0',
52
+ color: '#fff',
53
+ px: 2,
54
+ py: 1.5,
55
+ borderBottom: 'none',
56
+
57
+ maxWidth: columnWidths[col.field] || col.width ,
58
+ '&:first-of-type': {
59
+ borderTopLeftRadius: 10
60
+ },
61
+ '&:last-child': {
62
+ borderTopRightRadius: 10
63
+ }
64
+ }}
65
+ >
66
+ <Box
67
+ display="flex"
68
+ flexDirection="column"
69
+ alignItems="center"
70
+ gap={1}
71
+ width="100%"
72
+ >
73
+ {/* Header */}
74
+ <Box
75
+ display="flex"
76
+ alignItems="center"
77
+ justifyContent={
78
+ col.alignment === 'right'
79
+ ? 'flex-end'
80
+ : col.alignment === 'left'
81
+ ? 'flex-start'
82
+ : 'center'
83
+ }
84
+ gap={0.5}
85
+ width="100%"
86
+ >
87
+ {col.type === 'multi-select' ? (
88
+ <Checkbox
89
+ checked={
90
+ checkedItems.length > 0 &&
91
+ checkedItems.every(Boolean)
92
+ }
93
+ indeterminate={
94
+ checkedItems.some(Boolean) &&
95
+ !checkedItems.every(Boolean)
96
+ }
97
+ onChange={handleAllCheck}
98
+ size="small"
99
+ sx={{
100
+ color: '#404040',
101
+ p: 0.5,
102
+ '&.Mui-checked': {
103
+ color: '#FFD54F'
104
+ },
105
+ '&.MuiCheckbox-indeterminate': {
106
+ color: '#FFD54F'
107
+ }
108
+ }}
109
+ />
110
+ ) : (
111
+ <Typography
112
+ variant="subtitle2"
113
+ noWrap
114
+ sx={{
115
+ fontWeight: 400,
116
+ color: '#404040',
117
+
118
+ }}
119
+ >
120
+ {col.header}
121
+ </Typography>
122
+ )}
123
+
124
+ {/* Sort */}
125
+ {/* {col.sort && (
126
+ <Box
127
+ onClick={() => handleSort(col.field)}
128
+ sx={{
129
+ display: 'flex',
130
+ flexDirection: 'column',
131
+ cursor: 'pointer',
132
+ ml: 0.5
133
+ }}
134
+ >
135
+ <KeyboardArrowUpRoundedIcon
136
+ sx={{
137
+ fontSize: 16,
138
+ color: isSortedAsc
139
+ ? '#FFD54F'
140
+ : 'rgba(255,255,255,0.7)',
141
+ mb: -0.8
142
+ }}
143
+ />
144
+
145
+ <KeyboardArrowDownRoundedIcon
146
+ sx={{
147
+ fontSize: 16,
148
+ color: isSortedDesc
149
+ ? '#FFD54F'
150
+ : 'rgba(255,255,255,0.7)'
151
+ }}
152
+ />
153
+ </Box>
154
+ )} */}
155
+ </Box>
156
+
157
+ {/* Filter */}
158
+ <Box width="100%">
159
+ {!filterValues[col.field]?.visible ? (
160
+ <Box display="flex" justifyContent="center">
161
+ <IconButton
162
+ size="small"
163
+ onClick={() =>
164
+ setFilterValues((prev) => ({
165
+ ...prev,
166
+ [col.field]: {
167
+ type: col.filterType || 'text',
168
+ value: '',
169
+ visible: true
170
+ }
171
+ }))
172
+ }
173
+ sx={{
174
+ color: 'rgba(255,255,255,0.85)',
175
+ p: 0.5,
176
+ '&:hover': {
177
+ backgroundColor: 'rgba(255,255,255,0.12)'
178
+ }
179
+ }}
180
+ >
181
+ {/* {col.filterType === 'date' ? (
182
+ <CalendarTodayOutlinedIcon fontSize="small" />
183
+ ) : col.filterType === 'select' ? (
184
+ <KeyboardArrowDownRoundedIcon fontSize="small" />
185
+ ) : (
186
+ <SearchRoundedIcon fontSize="small" />
187
+ )} */}
188
+ </IconButton>
189
+ </Box>
190
+ ) : (
191
+ <>
192
+ {/* Text Filter */}
193
+ {(!col.filterType ||
194
+ col.filterType === 'text') && (
195
+ <InputBase
196
+ fullWidth
197
+ value={
198
+ filterValues[col.field]?.value || ''
199
+ }
200
+ onChange={(e) =>
201
+ onFilterInput(
202
+ col.field,
203
+ 'text',
204
+ e.target.value
205
+ )
206
+ }
207
+ placeholder="Search..."
208
+ sx={{
209
+ px: 1,
210
+ py: 0.5,
211
+ fontSize: 13,
212
+ color: '#404040',
213
+ borderRadius: 1,
214
+ backgroundColor:
215
+ 'rgba(255,255,255,0.12)',
216
+ border:
217
+ '1px solid rgba(255,255,255,0.18)',
218
+
219
+ '& input::placeholder': {
220
+ color: 'rgba(255,255,255,0.7)',
221
+ opacity: 1
222
+ },
223
+
224
+ '&:hover': {
225
+ backgroundColor:
226
+ 'rgba(255,255,255,0.16)'
227
+ },
228
+
229
+ '&.Mui-focused': {
230
+ border:
231
+ '1px solid rgba(255,255,255,0.35)'
232
+ }
233
+ }}
234
+ />
235
+ )}
236
+
237
+ {/* Date Filter */}
238
+ {col.filterType === 'date' && (
239
+ <InputBase
240
+ type="date"
241
+ fullWidth
242
+ value={
243
+ filterValues[col.field]?.value || ''
244
+ }
245
+ onChange={(e) =>
246
+ onFilterInput(
247
+ col.field,
248
+ 'date',
249
+ e.target.value
250
+ )
251
+ }
252
+ sx={{
253
+ px: 1,
254
+ py: 0.5,
255
+ fontSize: 13,
256
+ color: '#fff',
257
+ borderRadius: 1,
258
+ backgroundColor:
259
+ 'rgba(255,255,255,0.12)',
260
+ border:
261
+ '1px solid rgba(255,255,255,0.18)',
262
+
263
+ '& input': {
264
+ color: '#fff'
265
+ },
266
+
267
+ '&::-webkit-calendar-picker-indicator': {
268
+ filter: 'invert(1)'
269
+ }
270
+ }}
271
+ />
272
+ )}
273
+
274
+ {/* Select Filter */}
275
+ {col.filterType === 'select' && (
276
+ <InputBase
277
+ select
278
+ fullWidth
279
+ value={
280
+ filterValues[col.field]?.value || ''
281
+ }
282
+ onChange={(e) =>
283
+ onFilterInput(
284
+ col.field,
285
+ 'select',
286
+ e.target.value
287
+ )
288
+ }
289
+ sx={{
290
+ px: 1,
291
+ py: 0.5,
292
+ fontSize: 13,
293
+ color: '#fff',
294
+ borderRadius: 1,
295
+ backgroundColor:
296
+ 'rgba(255,255,255,0.12)',
297
+ border:
298
+ '1px solid rgba(255,255,255,0.18)'
299
+ }}
300
+ />
301
+ )}
302
+ </>
303
+ )}
304
+ </Box>
305
+ </Box>
306
+ </TableCell>
307
+ );
308
+ })}
309
+ </TableRow>
310
+ </TableHead>
311
+
312
+ );
313
+ };
314
+
315
+ export default AdvancedTableHead;
@@ -0,0 +1,137 @@
1
+ /* eslint-disable no-nested-ternary */
2
+ /* eslint-disable react/no-array-index-key */
3
+
4
+ import React, { useRef, useEffect, useState } from 'react';
5
+
6
+ import {
7
+ TableCell,
8
+ Tooltip,
9
+ Box,
10
+ List,
11
+ ListItem,
12
+ Typography
13
+ } from '@mui/material';
14
+
15
+ const EllipsisCell = ({
16
+ value,
17
+ row,
18
+ columnIndex,
19
+ rowIndex,
20
+ col,
21
+ expandedRows,
22
+ maxWidth = 200
23
+ }) => {
24
+ const boxRef = useRef(null);
25
+
26
+ const [isOverflowed, setIsOverflowed] = useState(false);
27
+
28
+ useEffect(() => {
29
+ const box = boxRef.current;
30
+
31
+ if (box) {
32
+ setIsOverflowed(box.scrollWidth > box.clientWidth);
33
+ }
34
+ }, [value, maxWidth]);
35
+
36
+ const isExpanded = expandedRows.includes(row.id);
37
+
38
+ const items = Array.isArray(value) ? value : [];
39
+
40
+ const renderExpandableList = () => (
41
+ <List
42
+ dense
43
+ sx={{
44
+ pl: 2,
45
+ py: 0,
46
+ width: '100%'
47
+ }}
48
+ >
49
+ {items.map((item, i) => {
50
+ const shouldShow = i === 0 || isExpanded;
51
+
52
+ if (!shouldShow) return null;
53
+
54
+ return (
55
+ <ListItem
56
+ key={i}
57
+ sx={{
58
+ display: 'list-item',
59
+ listStyleType: 'disc',
60
+ py: 0.25,
61
+ px: 0,
62
+ whiteSpace: 'nowrap',
63
+ overflow: 'hidden',
64
+ textOverflow: 'ellipsis'
65
+ }}
66
+ >
67
+ <Typography variant="body2">
68
+ {item}
69
+ </Typography>
70
+ </ListItem>
71
+ );
72
+ })}
73
+ </List>
74
+ );
75
+
76
+ const content = col?.isExpandable
77
+ ? renderExpandableList()
78
+ : col?.cell
79
+ ? col.cell({
80
+ field: value,
81
+ row,
82
+ rowIndex,
83
+ columnIndex
84
+ })
85
+ : value;
86
+
87
+ const columnKey =
88
+ col?.id || col?.accessor || columnIndex;
89
+
90
+ const ellipsisStyles = {
91
+ whiteSpace: 'nowrap',
92
+ overflow: 'hidden',
93
+ textOverflow: 'ellipsis',
94
+ width: '100%'
95
+ };
96
+
97
+ return (
98
+ <TableCell
99
+ key={columnKey}
100
+ align={col.alignment || 'left'}
101
+ sx={{
102
+ width: `${maxWidth}px`,
103
+ minWidth: `${maxWidth}px`,
104
+ maxWidth: `${maxWidth}px`,
105
+ py: 1.5,
106
+ px: 2,
107
+ borderBottom: '1px solid #E5E7EB'
108
+ }}
109
+ >
110
+ {col?.type === 'isExpandable' ? (
111
+ content
112
+ ) : isOverflowed ? (
113
+ <Tooltip
114
+ title={String(value || '')}
115
+ arrow
116
+ placement="top"
117
+ >
118
+ <Box
119
+ ref={boxRef}
120
+ sx={ellipsisStyles}
121
+ >
122
+ {content}
123
+ </Box>
124
+ </Tooltip>
125
+ ) : (
126
+ <Box
127
+ ref={boxRef}
128
+ sx={ellipsisStyles}
129
+ >
130
+ {content}
131
+ </Box>
132
+ )}
133
+ </TableCell>
134
+ );
135
+ };
136
+
137
+ export default EllipsisCell;
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import {
3
+ Modal,
4
+ Box,
5
+ CircularProgress
6
+ } from '@mui/material';
7
+
8
+ const Loader = ({ isLoading = false }) => {
9
+ return (
10
+ <Modal open={isLoading}>
11
+ <Box
12
+ display="flex"
13
+ justifyContent="center"
14
+ alignItems="center"
15
+ height="100vh"
16
+ bgcolor="rgba(0,0,0,0.3)"
17
+ >
18
+ <CircularProgress />
19
+ </Box>
20
+ </Modal>
21
+ );
22
+ };
23
+
24
+ export default Loader;