pixelize-design-library 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 (116) hide show
  1. package/. prettierrc +14 -0
  2. package/.eslintcache +1 -0
  3. package/.husky/pre-commit +4 -0
  4. package/.storybook/main.ts +19 -0
  5. package/.storybook/preview.ts +14 -0
  6. package/README.md +48 -0
  7. package/build/favicon.ico +0 -0
  8. package/build/logo192.png +0 -0
  9. package/build/logo512.png +0 -0
  10. package/build/manifest.json +25 -0
  11. package/build/robots.txt +3 -0
  12. package/eslint.config.mjs +20 -0
  13. package/exposedComponents.json +26 -0
  14. package/package.json +105 -0
  15. package/public/favicon.ico +0 -0
  16. package/public/index.html +43 -0
  17. package/public/logo192.png +0 -0
  18. package/public/logo512.png +0 -0
  19. package/public/manifest.json +25 -0
  20. package/public/robots.txt +3 -0
  21. package/rsbuild.config.ts +49 -0
  22. package/src/App.tsx +10 -0
  23. package/src/Components/Apexcharts/ApexBarChart/ApexBarChart.stories.tsx +39 -0
  24. package/src/Components/Apexcharts/ApexBarChart/ApexBarChart.tsx +80 -0
  25. package/src/Components/Apexcharts/ApexBarChart/ApexBarChartProps.tsx +20 -0
  26. package/src/Components/Apexcharts/ApexPieChart/ApexPieChart.stories.tsx +33 -0
  27. package/src/Components/Apexcharts/ApexPieChart/ApexPieChart.tsx +42 -0
  28. package/src/Components/Apexcharts/ApexPieChart/ApexPieChartProps.tsx +17 -0
  29. package/src/Components/Breadcrumbs/Breadcrumbs.stories.tsx +26 -0
  30. package/src/Components/Breadcrumbs/Breadcrumbs.tsx +25 -0
  31. package/src/Components/Breadcrumbs/BreadcrumbsProps.tsx +12 -0
  32. package/src/Components/Button/Button.stories.tsx +32 -0
  33. package/src/Components/Button/Button.tsx +26 -0
  34. package/src/Components/Button/ButtonProps.tsx +10 -0
  35. package/src/Components/ButtonGroupIcon/ButtonGoupIconProps.tsx +14 -0
  36. package/src/Components/ButtonGroupIcon/ButtonGroupIcon.stories.tsx +37 -0
  37. package/src/Components/ButtonGroupIcon/ButtonGroupIcon.tsx +25 -0
  38. package/src/Components/Checkbox/Checkbox.stories.tsx +45 -0
  39. package/src/Components/Checkbox/Checkbox.tsx +29 -0
  40. package/src/Components/Checkbox/CheckboxProps.tsx +9 -0
  41. package/src/Components/Input/TextInput.stories.tsx +44 -0
  42. package/src/Components/Input/TextInput.tsx +70 -0
  43. package/src/Components/Input/TextInputProps.tsx +27 -0
  44. package/src/Components/InputTextArea/InputTextArea.stories.tsx +48 -0
  45. package/src/Components/InputTextArea/InputTextArea.tsx +36 -0
  46. package/src/Components/InputTextArea/InputTextAreaProps.tsx +11 -0
  47. package/src/Components/Loading/Loading.stories.tsx +25 -0
  48. package/src/Components/Loading/Loading.tsx +37 -0
  49. package/src/Components/Loading/LoadingProps.tsx +1 -0
  50. package/src/Components/Modal/Modal.stories.tsx +106 -0
  51. package/src/Components/Modal/Modal.tsx +44 -0
  52. package/src/Components/Modal/ModalProps.tsx +12 -0
  53. package/src/Components/NavigationBar/NavBar.stories.tsx +26 -0
  54. package/src/Components/NavigationBar/NavigationBar.tsx +55 -0
  55. package/src/Components/NavigationBar/NavigationBarProps.tsx +13 -0
  56. package/src/Components/NumberInput/NumberInput.stories.tsx +31 -0
  57. package/src/Components/NumberInput/NumberInput.tsx +55 -0
  58. package/src/Components/NumberInput/NumberInputProps.tsx +28 -0
  59. package/src/Components/PinInput/PinInput.stories.tsx +40 -0
  60. package/src/Components/PinInput/PinInput.tsx +48 -0
  61. package/src/Components/PinInput/PinInputProps.tsx +33 -0
  62. package/src/Components/ProfileCard/ProfileCard.stories.tsx +30 -0
  63. package/src/Components/ProfileCard/ProfileCard.tsx +58 -0
  64. package/src/Components/ProfileCard/ProfileCardProps.tsx +41 -0
  65. package/src/Components/ProfilePhotoViewer/ProfilePhotoViewer.stories.tsx +25 -0
  66. package/src/Components/ProfilePhotoViewer/ProfilePhotoViewer.tsx +68 -0
  67. package/src/Components/ProfilePhotoViewer/ProfilePhotoViewerProps.tsx +14 -0
  68. package/src/Components/ProgressBar/ProgressBar.stories.tsx +46 -0
  69. package/src/Components/ProgressBar/ProgressBar.tsx +32 -0
  70. package/src/Components/ProgressBar/ProgressBarProps.tsx +7 -0
  71. package/src/Components/RadioButton/RadioButton.stories.tsx +46 -0
  72. package/src/Components/RadioButton/RadioButton.tsx +63 -0
  73. package/src/Components/RadioButton/RadioButtonProps.tsx +10 -0
  74. package/src/Components/Select/Select.stories.tsx +56 -0
  75. package/src/Components/Select/Select.tsx +45 -0
  76. package/src/Components/Select/SelectProps.tsx +15 -0
  77. package/src/Components/SideBar/SideBar.tsx +143 -0
  78. package/src/Components/SideBar/SideBarProps.tsx +18 -0
  79. package/src/Components/SideBar/Sidebar.stories.tsx +80 -0
  80. package/src/Components/Skeletons/Skeleton.stories.tsx +63 -0
  81. package/src/Components/Skeletons/SkeletonProps.tsx +23 -0
  82. package/src/Components/Skeletons/Skeletons.tsx +51 -0
  83. package/src/Components/Table/Table.stories.tsx +47 -0
  84. package/src/Components/Table/Table.tsx +516 -0
  85. package/src/Components/Table/TableProps.tsx +36 -0
  86. package/src/Components/Toaster/Toaster.stories.tsx +58 -0
  87. package/src/Components/Toaster/Toaster.tsx +34 -0
  88. package/src/Components/Toaster/ToasterProps.tsx +15 -0
  89. package/src/Components/ToolTip/ToolTip.stories.tsx +39 -0
  90. package/src/Components/ToolTip/ToolTip.tsx +61 -0
  91. package/src/Components/ToolTip/ToolTipProps.tsx +45 -0
  92. package/src/Layout.tsx +499 -0
  93. package/src/Theme/Dark/theme.ts +278 -0
  94. package/src/Theme/Default/theme.ts +301 -0
  95. package/src/Theme/index.ts +4 -0
  96. package/src/bootstrap.tsx +13 -0
  97. package/src/index.tsx +22 -0
  98. package/src/stories/Configure.mdx +364 -0
  99. package/src/stories/assets/accessibility.png +0 -0
  100. package/src/stories/assets/accessibility.svg +5 -0
  101. package/src/stories/assets/addon-library.png +0 -0
  102. package/src/stories/assets/assets.png +0 -0
  103. package/src/stories/assets/avif-test-image.avif +0 -0
  104. package/src/stories/assets/context.png +0 -0
  105. package/src/stories/assets/discord.svg +15 -0
  106. package/src/stories/assets/docs.png +0 -0
  107. package/src/stories/assets/figma-plugin.png +0 -0
  108. package/src/stories/assets/github.svg +3 -0
  109. package/src/stories/assets/share.png +0 -0
  110. package/src/stories/assets/styling.png +0 -0
  111. package/src/stories/assets/testing.png +0 -0
  112. package/src/stories/assets/theming.png +0 -0
  113. package/src/stories/assets/tutorials.svg +12 -0
  114. package/src/stories/assets/youtube.svg +4 -0
  115. package/src/stories/header.css +32 -0
  116. package/tsconfig.json +20 -0
@@ -0,0 +1,516 @@
1
+ import {
2
+ Box,
3
+ Button,
4
+ ChakraProvider,
5
+ Checkbox,
6
+ Flex,
7
+ Input,
8
+ Menu,
9
+ MenuButton,
10
+ MenuItem,
11
+ MenuList,
12
+ Popover,
13
+ PopoverBody,
14
+ PopoverContent,
15
+ PopoverTrigger,
16
+ Select,
17
+ Spinner,
18
+ TableContainer,
19
+ Text,
20
+ } from "@chakra-ui/react";
21
+ import {
22
+ Table as ChakraTable,
23
+ Tbody,
24
+ Td,
25
+ Th,
26
+ Thead,
27
+ Tr,
28
+ } from "@chakra-ui/react";
29
+
30
+ import { TableProps } from "./TableProps";
31
+ import { useState } from "react";
32
+ import {
33
+ ArrowDownIcon,
34
+ ArrowUpIcon,
35
+ ChevronDownIcon,
36
+ HamburgerIcon,
37
+ } from "@chakra-ui/icons";
38
+
39
+ export default function Table({
40
+ data,
41
+ headers,
42
+ tableHeaderBgColor = "#3182ce",
43
+ tableHeaderColor = "white",
44
+ handleExportChange,
45
+ exportOptions,
46
+ exportLabel,
47
+ isLoading,
48
+ loadingContaxt,
49
+ loadingBoxStyle,
50
+ }: TableProps) {
51
+ const [currentPage, setCurrentPage] = useState(0);
52
+ const [rowsPerPage, setRowsPerPage] = useState(5);
53
+ const [sortField, setSortField] = useState<string | null>(null);
54
+ const [sortDirection, setSortDirection] = useState<"asc" | "desc" | null>(
55
+ null
56
+ );
57
+ const [isPopoverOpen, setPopoverOpen] = useState(false);
58
+ const [activeHeader, setActiveHeader] = useState<string | null>(null);
59
+ const [searchTerms, setSearchTerms] = useState<Record<string, string>>({});
60
+ const [searchOperation, setSearchOperation] = useState<
61
+ Record<string, string>
62
+ >({});
63
+ const [betweenValues, setBetweenValues] = useState<
64
+ Record<string, { min: string; max: string }>
65
+ >({});
66
+ const [hoveredHeaderIndex, setHoveredHeaderIndex] = useState<number | null>(
67
+ null
68
+ );
69
+ const [visibleColumns, setVisibleColumns] = useState<Record<string, boolean>>(
70
+ headers.reduce((acc, curr) => ({ ...acc, [curr.label]: true }), {})
71
+ );
72
+ if (isLoading) {
73
+ return (
74
+ <ChakraProvider>
75
+ <Box width="full" overflowX="auto" style={loadingBoxStyle}>
76
+ {loadingContaxt ? loadingContaxt :
77
+ <Spinner thickness='4px' speed='0.65s' emptyColor='gray.200' color='blue.500' size='xl' />
78
+ }
79
+ </Box>
80
+ </ChakraProvider>
81
+ );
82
+ }
83
+
84
+ const handlePageSizeChange = (
85
+ event: React.ChangeEvent<HTMLSelectElement>
86
+ ) => {
87
+ setRowsPerPage(Number(event.target.value));
88
+ setCurrentPage(0);
89
+ };
90
+ const pageSizeOptions = [5, 10, 20, 50, 100].filter(
91
+ (size) => size <= data.length
92
+ );
93
+
94
+ const sortedData = [...data].sort((a, b) => {
95
+ if (!sortField) return 0;
96
+ if (a[sortField] < b[sortField]) return sortDirection === "asc" ? -1 : 1;
97
+ if (a[sortField] > b[sortField]) return sortDirection === "asc" ? 1 : -1;
98
+ return 0;
99
+ });
100
+
101
+ const handleSort = (field: string) => {
102
+ setSortField(field);
103
+ setSortDirection(sortDirection === "asc" ? "desc" : "asc");
104
+ };
105
+ const handleSearchOperation = (header: string, operation: string) => {
106
+ setSearchOperation((prev) => ({ ...prev, [header]: operation }));
107
+ };
108
+
109
+ const handleSearch = (field: string, term: string) => {
110
+ if (searchOperation[field] === "between") {
111
+ setBetweenValues((prev) => ({
112
+ ...prev,
113
+ [field]: { min: term.split("-")[0], max: term.split("-")[1] },
114
+ }));
115
+ } else {
116
+ setSearchTerms((prev) => ({ ...prev, [field]: term }));
117
+ }
118
+ };
119
+
120
+ const handleHeaderClick = (header: string) => {
121
+ setActiveHeader(header);
122
+ setPopoverOpen(true);
123
+ };
124
+ const closePopover = () => {
125
+ setPopoverOpen(false);
126
+ };
127
+
128
+ const filteredData = sortedData.filter((item) => {
129
+ return Object.keys(searchTerms).every((key) => {
130
+ const term = searchTerms[key].toLowerCase();
131
+ const value = String(item[key]).toLowerCase();
132
+ const operation = searchOperation[key] || "contains";
133
+
134
+ switch (operation) {
135
+ case "contains":
136
+ return value.includes(term);
137
+ case "notContains":
138
+ return !value.includes(term);
139
+ case "equals":
140
+ return value === term;
141
+ case "notEquals":
142
+ return value !== term;
143
+ case "beginsWith":
144
+ return value.startsWith(term);
145
+ case "endsWith":
146
+ return value.endsWith(term);
147
+ case "greaterThan":
148
+ return Number(value) > Number(term);
149
+ case "greaterThanOrEqual":
150
+ return Number(value) >= Number(term);
151
+ case "lessThan":
152
+ return Number(value) < Number(term);
153
+ case "lessThanOrEqual":
154
+ return Number(value) <= Number(term);
155
+ case "between":
156
+ const { min, max } = betweenValues[key] || {};
157
+ return Number(value) >= Number(min) && Number(value) <= Number(max);
158
+ case "blank":
159
+ return value === "";
160
+ case "notBlank":
161
+ return value !== "";
162
+ default:
163
+ return true;
164
+ }
165
+ });
166
+ });
167
+
168
+ const pages = Math.ceil(filteredData.length / rowsPerPage);
169
+ const startRow = currentPage * rowsPerPage;
170
+ const endRow = startRow + rowsPerPage;
171
+
172
+ const getFieldType = (header: string) => {
173
+ for (const row of data) {
174
+ if (row[header] !== null) {
175
+ return typeof row[header];
176
+ }
177
+ }
178
+ return "string";
179
+ };
180
+ const searchFeatures = (header: string) => {
181
+ const fieldType = getFieldType(header);
182
+ return (
183
+ <>
184
+ <Select
185
+ value={searchOperation[header] || "notBlank"}
186
+ onChange={(e) => handleSearchOperation(header, e.target.value)}
187
+ style={{ background: "#3182ce", color: "white" }}
188
+ >
189
+ {fieldType === "number" ? (
190
+ <>
191
+ <option value="equals">Equals</option>
192
+ <option value="notEquals">Does not equal</option>
193
+ <option value="greaterThan">Greater than</option>
194
+ <option value="greaterThanOrEqual">
195
+ Greater than or equal to
196
+ </option>
197
+ <option value="lessThan">Less than</option>
198
+ <option value="lessThanOrEqual">Less than or equal to</option>
199
+ <option value="between">Between</option>
200
+ <option value="blank">Blank</option>
201
+ <option value="notBlank">Not blank</option>
202
+ </>
203
+ ) : (
204
+ <>
205
+ <option value="contains">Contains</option>
206
+ <option value="notContains">Does not contain</option>
207
+ <option value="equals">Equals</option>
208
+ <option value="notEquals">Does not equal</option>
209
+ <option value="beginsWith">Begins with</option>
210
+ <option value="endsWith">Ends with</option>
211
+ <option value="blank">Blank</option>
212
+ <option value="notBlank">Not blank</option>
213
+ </>
214
+ )}
215
+ </Select>
216
+ <br />
217
+ {searchOperation[header] === "between" && fieldType === "number" ? (
218
+ <>
219
+ <Input
220
+ value={betweenValues[header]?.min || ""}
221
+ onChange={(e) =>
222
+ setBetweenValues((prev) => ({
223
+ ...prev,
224
+ [header]: { ...prev[header], min: e.target.value },
225
+ }))
226
+ }
227
+ placeholder="Min..."
228
+ background="white"
229
+ color="black"
230
+ />
231
+ <br />
232
+ <br />
233
+ <Input
234
+ value={betweenValues[header]?.max || ""}
235
+ onChange={(e) =>
236
+ setBetweenValues((prev) => ({
237
+ ...prev,
238
+ [header]: { ...prev[header], max: e.target.value },
239
+ }))
240
+ }
241
+ placeholder="Max..."
242
+ background="white"
243
+ color="black"
244
+ />
245
+ </>
246
+ ) : (
247
+ <Input
248
+ value={searchTerms[header] || ""}
249
+ onChange={(e) => handleSearch(header, e.target.value)}
250
+ placeholder="Search..."
251
+ background="white"
252
+ color="black"
253
+ />
254
+ )}
255
+ </>
256
+ );
257
+ };
258
+
259
+
260
+ const handleColumnVisibilityChange = (header: string) => {
261
+ setVisibleColumns((prev) => ({ ...prev, [header]: !prev[header] }));
262
+ };
263
+
264
+ function calculateLeftOffset(headers: any, currentIndex: number) {
265
+ let offset = 0;
266
+ for (let i = 0; i < currentIndex; i++) {
267
+ if (headers[i].columnFreeze) {
268
+ offset += 100;
269
+ }
270
+ }
271
+ return offset;
272
+ }
273
+
274
+ const handleMouseEnter = (index: number) => setHoveredHeaderIndex(index);
275
+ const handleMouseLeave = () => {
276
+ setHoveredHeaderIndex(null);
277
+ closePopover();
278
+ };
279
+
280
+ return (
281
+ <ChakraProvider>
282
+ <div style={{ width: "97%" }}>
283
+ <Box display="flex" justifyContent="flex-end">
284
+ {exportOptions && exportOptions.length > 0 && (
285
+ <Select
286
+ placeholder="Exports"
287
+ width={160}
288
+ onChange={(e) => {
289
+ handleExportChange && handleExportChange(e.target.value);
290
+ }}
291
+ value={exportLabel}
292
+ >
293
+ {exportOptions.map((option) => (
294
+ <option key={option.value} value={option.value}>
295
+ {option.label}
296
+ </option>
297
+ ))}
298
+ </Select>
299
+ )}
300
+ </Box>
301
+ <br />
302
+ <TableContainer>
303
+ <ChakraTable
304
+ variant="simple"
305
+ colorScheme="teal"
306
+ size={"md"}
307
+ overflowX={"scroll"}
308
+ >
309
+ <Thead background={tableHeaderBgColor}>
310
+ <Tr>
311
+ {headers.map((header, index) => {
312
+ const isFrozen = header.columnFreeze;
313
+ const leftOffset = calculateLeftOffset(headers, index);
314
+ return (
315
+ visibleColumns[header.label] && (
316
+ <Th
317
+ key={index}
318
+ style={{
319
+ textTransform: "capitalize",
320
+ color: tableHeaderColor,
321
+ fontSize: "medium",
322
+ fontWeight: 600,
323
+ position: isFrozen ? "sticky" : undefined,
324
+ left: isFrozen
325
+ ? `${leftOffset === 0 ? leftOffset : leftOffset - 4}px`
326
+ : undefined,
327
+ zIndex: isFrozen ? 2 : 1,
328
+ background: tableHeaderBgColor,
329
+ textAlign: "center",
330
+ }}
331
+ onMouseEnter={() => handleMouseEnter(index)}
332
+ onMouseLeave={handleMouseLeave}
333
+ >
334
+ {header.sort ? (
335
+ <Button
336
+ onClick={() => handleSort(header.label)}
337
+ style={{
338
+ textTransform: "capitalize",
339
+ color: "white",
340
+ background: "none",
341
+ }}
342
+ >
343
+ {header.label}
344
+ {sortField === header.label &&
345
+ (sortDirection === "asc" ? (
346
+ <ArrowUpIcon w={15} h={15} />
347
+ ) : (
348
+ <ArrowDownIcon w={15} h={15} />
349
+ ))}
350
+ </Button>
351
+ ) : (
352
+ <span>{header.label}</span>
353
+ )}
354
+ {header.search && (
355
+ <Popover
356
+ isOpen={
357
+ activeHeader === header.label && isPopoverOpen
358
+ }
359
+ onClose={closePopover}
360
+ placement="bottom-start"
361
+ closeOnBlur={false}
362
+ >
363
+ <PopoverTrigger>
364
+ <HamburgerIcon
365
+ w={15}
366
+ h={15}
367
+ onClick={() => handleHeaderClick(header.label)}
368
+ style={{
369
+ cursor: "pointer",
370
+ display:
371
+ hoveredHeaderIndex === index
372
+ ? "inline"
373
+ : "none",
374
+ }}
375
+ />
376
+ </PopoverTrigger>
377
+ <PopoverContent width={200} zIndex={3}>
378
+ <PopoverBody background={"#deeefd"}>
379
+ {searchFeatures(header.label)}
380
+ </PopoverBody>
381
+ </PopoverContent>
382
+ </Popover>
383
+ )}
384
+ </Th>
385
+ )
386
+ );
387
+ })}
388
+ </Tr>
389
+ </Thead>
390
+ <Tbody>
391
+ {filteredData.slice(startRow, endRow).map((row, index) => (
392
+ <Tr
393
+ key={index}
394
+ style={{
395
+ backgroundColor: index % 2 === 0 ? "#f7f7f7" : "white",
396
+ }}
397
+ border={"none"}
398
+ >
399
+ {headers.map((header, headerIndex) => {
400
+ const isFrozen = header.columnFreeze;
401
+ const leftOffset = calculateLeftOffset(
402
+ headers,
403
+ headerIndex
404
+ );
405
+ return (
406
+ visibleColumns[header.label] && (
407
+ <Td
408
+ key={headerIndex}
409
+ style={{
410
+ border: "none",
411
+ textAlign: "center",
412
+ position: isFrozen ? "sticky" : undefined,
413
+ left: isFrozen
414
+ ? `${leftOffset === 0 ? leftOffset : leftOffset - 4}px`
415
+ : undefined,
416
+ zIndex: isFrozen ? 1 : 0,
417
+ backgroundColor:
418
+ index % 2 === 0 ? "#f7f7f7" : "white",
419
+ }}
420
+ // onClick={() => handleCellClick(row, header)}
421
+ >
422
+ {typeof header.accessor_function === "function" &&
423
+ header.accessor_key in row
424
+ ? header.accessor_function(row[header.accessor_key])
425
+ : row[header.accessor_key]}
426
+ </Td>
427
+ )
428
+ );
429
+ })}
430
+ </Tr>
431
+ ))}
432
+ </Tbody>
433
+ </ChakraTable>
434
+ </TableContainer>
435
+ <Flex justify="flex-end" align="center" mt={4}>
436
+ <Flex mr={4}>
437
+ <Menu>
438
+ <MenuButton
439
+ as={Button}
440
+ rightIcon={<ChevronDownIcon />}
441
+ colorScheme={"blue"}
442
+ variant="outline"
443
+ >
444
+ Visiblity
445
+ </MenuButton>
446
+ <MenuList height={150} overflow={"scroll"} zIndex={"2"}>
447
+ {headers.map((header, index) => (
448
+ <MenuItem key={index}>
449
+ <Checkbox
450
+ isChecked={visibleColumns[header.label]}
451
+ onChange={() =>
452
+ handleColumnVisibilityChange(header.label)
453
+ }
454
+ >
455
+ {header.label}
456
+ </Checkbox>
457
+ </MenuItem>
458
+ ))}
459
+ </MenuList>
460
+ </Menu>
461
+ </Flex>
462
+ <Text mr={4}>
463
+ {startRow + 1} to {endRow} of {filteredData.length}
464
+ </Text>
465
+ <Select
466
+ onChange={handlePageSizeChange}
467
+ value={rowsPerPage}
468
+ mr={4}
469
+ width={20}
470
+ >
471
+ {pageSizeOptions.map((size, index) => (
472
+ <option key={index} value={size}>
473
+ {size}
474
+ </option>
475
+ ))}
476
+ </Select>
477
+ <Flex>
478
+ <Button
479
+ mx={1}
480
+ disabled={currentPage === 0}
481
+ onClick={() => setCurrentPage(0)}
482
+ >
483
+ {"<<"}
484
+ </Button>
485
+ <Button
486
+ mx={1}
487
+ disabled={currentPage === 0}
488
+ onClick={() => currentPage > 0 && setCurrentPage(currentPage - 1)}
489
+ >
490
+ {"<"}
491
+ </Button>
492
+ <Text mx={1} mt={2}>
493
+ Page {currentPage + 1} of {pages}
494
+ </Text>
495
+ <Button
496
+ mx={1}
497
+ disabled={currentPage > pages}
498
+ onClick={() =>
499
+ currentPage < pages - 1 && setCurrentPage(currentPage + 1)
500
+ }
501
+ >
502
+ {">"}
503
+ </Button>
504
+ <Button
505
+ mx={1}
506
+ disabled={currentPage >= pages - 1}
507
+ onClick={() => setCurrentPage(pages - 1)}
508
+ >
509
+ {">>"}
510
+ </Button>
511
+ </Flex>
512
+ </Flex>
513
+ </div>
514
+ </ChakraProvider>
515
+ );
516
+ }
@@ -0,0 +1,36 @@
1
+ import { ReactNode } from "react";
2
+
3
+ export type TableProps = {
4
+ data: DataObject[];
5
+ headers: TableHeader[];
6
+ // handleCellClick?: (row: any, header: any) => void;
7
+ tableHeaderBgColor?: string;
8
+ tableHeaderColor?: string;
9
+ handleExportChange?: (value: string) => void | undefined;
10
+ exportOptions?: ExportOption[];
11
+ exportLabel?: string;
12
+ isLoading?: boolean;
13
+ loadingType?: 'skeleton' | 'spinner';
14
+ loadingContaxt?: ReactNode;
15
+ loadingBoxStyle?: React.CSSProperties;
16
+
17
+ };
18
+ export type DataObject = {
19
+ id: number;
20
+ name: string;
21
+ email: string;
22
+ role: string;
23
+ [key: string]: string | number;
24
+ }
25
+ export type TableHeader = {
26
+ label: string;
27
+ accessor_key: string;
28
+ sort?: boolean;
29
+ search?: boolean;
30
+ columnFreeze?: boolean;
31
+ accessor_function?: (data: string | number) => JSX.Element | string | number;
32
+ }
33
+ export type ExportOption = {
34
+ label: string;
35
+ value: string;
36
+ }
@@ -0,0 +1,58 @@
1
+ // Toaster.stories.tsx
2
+ import React from 'react';
3
+ import { Meta, StoryFn } from '@storybook/react';
4
+ import ToasterProvider, { useToaster } from './Toaster';
5
+ import { Button, ChakraProvider } from '@chakra-ui/react';
6
+ import { ToasterToastProps } from './ToasterProps';
7
+
8
+ export default {
9
+ title: 'Components/Toaster/ToasterProvider',
10
+ component: ToasterProvider,
11
+ argTypes: {
12
+ title: {
13
+ control: 'text',
14
+ defaultValue: 'Test',
15
+ },
16
+ status: {
17
+ control: 'select',
18
+ options: ['info', 'warning', 'success', 'error'],
19
+ defaultValue: 'info',
20
+ },
21
+ position: {
22
+ control: 'select',
23
+ options: ['top', 'top-right', 'top-left', 'bottom', 'bottom-right', 'bottom-left'],
24
+ defaultValue: 'bottom-right',
25
+ },
26
+ },
27
+ } as Meta;
28
+
29
+ interface StoryProps {
30
+ title: string;
31
+ status: 'info' | 'warning' | 'success' | 'error';
32
+ position: 'top' | 'top-right' | 'top-left' | 'bottom' | 'bottom-right' | 'bottom-left';
33
+ }
34
+
35
+ const Template: StoryFn<StoryProps> = ({ title, status, position }) => {
36
+ const ShowToastButton = () => {
37
+ const { showToast } = useToaster();
38
+ return (
39
+ <Button onClick={() => showToast({
40
+ title,
41
+ description: 'This is a test toast',
42
+ status,
43
+ position,
44
+ })}>
45
+ Show Toast
46
+ </Button>
47
+ );
48
+ };
49
+ return (
50
+ <ToasterProvider>
51
+ <ChakraProvider>
52
+ <ShowToastButton />
53
+ </ChakraProvider>
54
+ </ToasterProvider>
55
+ );
56
+ };
57
+
58
+ export const Default = Template.bind({});
@@ -0,0 +1,34 @@
1
+
2
+ import React, { createContext, useContext } from 'react'
3
+ import { useToast } from '@chakra-ui/react'
4
+ import { ToasterChildren, ToasterContextType, ToasterToastProps } from './ToasterProps'
5
+
6
+ const ToasterContext = createContext<ToasterContextType | undefined>(undefined);
7
+
8
+ export default function ToasterProvider({ children }: ToasterChildren) {
9
+ const toast = useToast();
10
+ const showToast: ToasterContextType["showToast"] = ({ title, description, status, duration = 5000, isClosable = true, position, onClose }: ToasterToastProps) => {
11
+ toast({
12
+ title: title,
13
+ description: description,
14
+ status: status,
15
+ duration: duration,
16
+ isClosable: isClosable,
17
+ position: position,
18
+ onCloseComplete: onClose
19
+ })
20
+ }
21
+ return (
22
+ <ToasterContext.Provider value={{ showToast }}>
23
+ {children}
24
+ </ToasterContext.Provider>
25
+ )
26
+ }
27
+
28
+ export const useToaster = () => {
29
+ const context = useContext(ToasterContext);
30
+ if (!context) {
31
+ throw new Error("useToaster must be used within a ToasterProvider")
32
+ }
33
+ return context;
34
+ }
@@ -0,0 +1,15 @@
1
+ import { ToastProps } from "@chakra-ui/react";
2
+ import React, { ReactNode } from "react";
3
+
4
+ export type ToasterToastProps = Pick<ToastProps, 'description' | 'title' | 'isClosable' | 'duration' | 'children' | 'onClose'> & {
5
+ position?: "top" | "bottom" | "top-right" | "top-left" | "bottom-right" | "bottom-left"
6
+ status?: "success" | "error" | "warning" | "info" | "loading"
7
+ }
8
+
9
+ export interface ToasterContextType {
10
+ showToast: (children: ToasterToastProps) => void
11
+ }
12
+
13
+ export interface ToasterChildren {
14
+ children: ReactNode;
15
+ }