gbs-add-block 1.0.30 → 1.2.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 (24) hide show
  1. package/README.md +6 -3
  2. package/package.json +1 -1
  3. package/source/components/datagrid/context/GridContext.tsx +7 -5
  4. package/source/components/datagrid/createTemplate.tsx +82 -0
  5. package/source/components/datagrid/hooks/usePagination.ts +11 -1
  6. package/source/components/datagrid/type.ts +1 -1
  7. package/source/components/datagrid/hooks/usePageStatus.ts +0 -13
  8. package/source/components/datagridbeta/context/GridContext.tsx +0 -187
  9. package/source/components/datagridbeta/hooks/index.ts +0 -7
  10. package/source/components/datagridbeta/hooks/useColumns.ts +0 -33
  11. package/source/components/datagridbeta/hooks/useDataSource.ts +0 -54
  12. package/source/components/datagridbeta/hooks/useFiltering.ts +0 -135
  13. package/source/components/datagridbeta/hooks/usePageStatus.ts +0 -13
  14. package/source/components/datagridbeta/hooks/usePagination.ts +0 -125
  15. package/source/components/datagridbeta/hooks/useRowSelection.ts +0 -48
  16. package/source/components/datagridbeta/hooks/useSearch.ts +0 -86
  17. package/source/components/datagridbeta/index.tsx +0 -26
  18. package/source/components/datagridbeta/layout/EditableRow.tsx +0 -85
  19. package/source/components/datagridbeta/layout/FilterPopup.tsx +0 -85
  20. package/source/components/datagridbeta/layout/GridBody.tsx +0 -221
  21. package/source/components/datagridbeta/layout/GridPagination.tsx +0 -118
  22. package/source/components/datagridbeta/layout/GridToolbar.tsx +0 -108
  23. package/source/components/datagridbeta/layout/index.tsx +0 -68
  24. package/source/components/datagridbeta/type.ts +0 -183
@@ -1,125 +0,0 @@
1
- import { useState, useCallback, useEffect } from "react";
2
-
3
- export const usePagination = (
4
- totalPages: number,
5
- lazy: boolean,
6
- dataSource?: any[],
7
- pageSettings?: { pageNumber: number }
8
- ) => {
9
- const [currentPage, setCurrentPage] = useState(0);
10
- const [pageStart, setPageStart] = useState(0);
11
- const [pageEnd, setPageEnd] = useState(10);
12
- const [prevDataLength, setPrevDataLength] = useState(0);
13
-
14
- const updatePageRange = useCallback(
15
- (page: number) => {
16
- const start = Math.floor(page / 10) * 10;
17
- setPageStart(start);
18
- setPageEnd(Math.min(start + 10, totalPages));
19
- },
20
- [totalPages]
21
- );
22
-
23
- useEffect(() => {
24
- if (!lazy) {
25
- setPageEnd(Math.min(10, totalPages));
26
- } else {
27
- setPageEnd(Math.min(pageStart + 10, totalPages));
28
- }
29
- }, [totalPages, lazy, pageStart]);
30
-
31
- // This will handle the case when dataSource changes
32
- // and adjust the current page accordingly
33
- useEffect(() => {
34
- if (dataSource && prevDataLength > 0) {
35
- const currentDataLength = dataSource.length;
36
-
37
- if (currentDataLength > prevDataLength) {
38
- const lastPage = totalPages - 1;
39
- setCurrentPage(lastPage);
40
- updatePageRange(lastPage);
41
- } else if (currentDataLength < prevDataLength) {
42
- const rowsPerPage = lazy ? 1 : pageSettings?.pageNumber || 10;
43
- const startIndex = currentPage * rowsPerPage;
44
-
45
- if (startIndex >= currentDataLength && currentPage > 0) {
46
- const newPage = currentPage - 1;
47
- setCurrentPage(newPage);
48
- updatePageRange(newPage);
49
- }
50
- }
51
- }
52
- setPrevDataLength(dataSource?.length || 0);
53
- }, [
54
- dataSource?.length,
55
- totalPages,
56
- updatePageRange,
57
- prevDataLength,
58
- currentPage,
59
- lazy,
60
- ]);
61
-
62
- const nextPage = useCallback(() => {
63
- setCurrentPage((prevPage) => {
64
- if (prevPage < totalPages - 1) {
65
- const newPage = prevPage + 1;
66
- updatePageRange(newPage);
67
- return newPage;
68
- }
69
- return prevPage;
70
- });
71
- }, [totalPages, updatePageRange]);
72
-
73
- const prevPage = useCallback(() => {
74
- setCurrentPage((prevPage) => {
75
- if (prevPage > 0) {
76
- const newPage = prevPage - 1;
77
- updatePageRange(newPage);
78
- return newPage;
79
- }
80
- return prevPage;
81
- });
82
- }, [updatePageRange]);
83
-
84
- const goToEndPage = useCallback(() => {
85
- const lastPage = totalPages - 1;
86
- setCurrentPage(lastPage);
87
- updatePageRange(lastPage);
88
- }, [totalPages, updatePageRange]);
89
-
90
- const goToFirstPage = useCallback(() => {
91
- setCurrentPage(0);
92
- updatePageRange(0);
93
- }, [updatePageRange]);
94
-
95
- const goToPage = useCallback(
96
- (page: number) => {
97
- setCurrentPage(page);
98
- updatePageRange(page);
99
- },
100
- [updatePageRange]
101
- );
102
-
103
- const resetPage = useCallback((dataSource: any, pageSettings: any) => {
104
- const newTotalPages = Math.ceil(
105
- dataSource.length / pageSettings.pageNumber
106
- );
107
- setCurrentPage(0);
108
- setPageStart(0);
109
- setPageEnd(Math.min(10, newTotalPages));
110
- return newTotalPages;
111
- }, []);
112
-
113
- return {
114
- currentPage,
115
- pageStart,
116
- pageEnd,
117
- nextPage,
118
- prevPage,
119
- goToEndPage,
120
- goToFirstPage,
121
- goToPage,
122
- resetPage,
123
- updatePageRange,
124
- };
125
- };
@@ -1,48 +0,0 @@
1
- import { useState, useCallback } from "react";
2
-
3
- export const useRowSelection = (
4
- workingDataSource: any[],
5
- onSelectRow?: (rows: any[]) => void
6
- ) => {
7
- const [selectedRows, setSelectedRows] = useState<any[]>([]);
8
-
9
- const handleSelectAll = useCallback(
10
- (event: React.ChangeEvent<HTMLInputElement>) => {
11
- const selected = event.target.checked ? workingDataSource : [];
12
- setSelectedRows(selected);
13
- onSelectRow?.(selected);
14
- },
15
- [workingDataSource, onSelectRow]
16
- );
17
-
18
- const handleSelect = useCallback(
19
- (rowData: any) => {
20
- setSelectedRows((prevData) => {
21
- const isSelected = prevData.includes(rowData);
22
- let updatedData;
23
- if (isSelected) {
24
- updatedData = prevData.filter((item) => item !== rowData);
25
- } else {
26
- updatedData = [...prevData, rowData];
27
- }
28
- if (onSelectRow) onSelectRow(updatedData);
29
- return updatedData;
30
- });
31
- },
32
- [onSelectRow]
33
- );
34
-
35
- const isRowSelected = useCallback(
36
- (rowData: any) => {
37
- return selectedRows.includes(rowData);
38
- },
39
- [selectedRows]
40
- );
41
-
42
- return {
43
- selectedRows,
44
- handleSelectAll,
45
- handleSelect,
46
- isRowSelected,
47
- };
48
- };
@@ -1,86 +0,0 @@
1
- import { useState, useCallback } from "react";
2
-
3
- interface UseSearchProps {
4
- workingDataSource: any[];
5
- setWorkingDataSource: (data: any[]) => void;
6
- fallbackSourceData: any[];
7
- dataSource: any;
8
- lazy: boolean;
9
- pageSettings: any;
10
- resetPage: (data: any[], settings: any) => number;
11
- setTotalPages: (pages: number) => void;
12
- searchParamValue?: (value: string) => void;
13
- }
14
-
15
- export const useSearch = ({
16
- workingDataSource,
17
- setWorkingDataSource,
18
- fallbackSourceData,
19
- dataSource,
20
- lazy,
21
- pageSettings,
22
- resetPage,
23
- setTotalPages,
24
- searchParamValue,
25
- }: UseSearchProps) => {
26
- const [searchParam, setSearchParam] = useState("");
27
-
28
- const handleSearchInput = useCallback(
29
- (e: any) => {
30
- const searchValue = e.target.value;
31
- if (searchParamValue) searchParamValue(searchValue);
32
- setSearchParam(searchValue);
33
-
34
- if (searchValue === "") {
35
- if (!lazy) {
36
- const fallback =
37
- fallbackSourceData.length > 0 ? fallbackSourceData : dataSource;
38
- setWorkingDataSource(fallback);
39
- const totalPages = resetPage(fallback, pageSettings);
40
- setTotalPages(totalPages);
41
- }
42
- }
43
- },
44
- [
45
- searchParamValue,
46
- lazy,
47
- fallbackSourceData,
48
- dataSource,
49
- setWorkingDataSource,
50
- resetPage,
51
- pageSettings,
52
- setTotalPages,
53
- ]
54
- );
55
-
56
- const handleSearch = useCallback(
57
- (searchParam: string) => {
58
- if (!lazy) {
59
- const filteredData = workingDataSource.filter((item: any) =>
60
- Object.values(item).some((val: any) => {
61
- const trimmedVal = val.toString().toLowerCase().trim();
62
- const trimmedSearchParam = searchParam.toLowerCase().trim();
63
- return trimmedVal.includes(trimmedSearchParam);
64
- })
65
- );
66
- setWorkingDataSource(filteredData);
67
- const totalPages = resetPage(filteredData, pageSettings);
68
- setTotalPages(totalPages);
69
- }
70
- },
71
- [
72
- lazy,
73
- workingDataSource,
74
- setWorkingDataSource,
75
- resetPage,
76
- pageSettings,
77
- setTotalPages,
78
- ]
79
- );
80
-
81
- return {
82
- searchParam,
83
- handleSearchInput,
84
- handleSearch,
85
- };
86
- };
@@ -1,26 +0,0 @@
1
- /**
2
- * Copyright (c) Grampro Business Services and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- * Here We Will Re-Render Grid as a Memoized Component For Better Performance.
7
- * Extended Documentation for Grid can be found at
8
- * https://psychedelic-step-e70.notion.site/Data-GRID-by-GBS-R-D-20ff97c899d24bc590215a6196435fa3
9
- */
10
-
11
- import { GridMemoised as GridComponent } from "./layout";
12
- import { memo } from "react";
13
-
14
- const DataGrid = memo(GridComponent, (prevProps, nextProps) => {
15
- // Custom comparison function
16
- return (
17
- prevProps.dataSource === nextProps.dataSource &&
18
- prevProps.columns === nextProps.columns &&
19
- prevProps.pageSettings.pageNumber === nextProps.pageSettings.pageNumber &&
20
- prevProps.enableSearch === nextProps.enableSearch &&
21
- prevProps.enablePdfExport === nextProps.enablePdfExport &&
22
- prevProps.enableExcelExport === nextProps.enableExcelExport
23
- );
24
- });
25
-
26
- export { DataGrid };
@@ -1,85 +0,0 @@
1
- import React from "react";
2
-
3
- interface EditableRowProps {
4
- columnType: string | undefined;
5
- cellValue: any;
6
- rowIndex: number;
7
- field: string;
8
- style?: React.CSSProperties;
9
- rowData: any;
10
- }
11
-
12
- export default function EditableRow({
13
- columnType,
14
- cellValue,
15
- rowIndex,
16
- field,
17
- style,
18
- rowData,
19
- }: EditableRowProps) {
20
- // Function to handle cell value change
21
- const handleCellChange = (newValue: any, field: string) => {
22
- if (rowData) {
23
- rowData[field] = newValue;
24
- rowData(rowData);
25
- console.log(rowData);
26
- }
27
- };
28
-
29
- switch (columnType) {
30
- case "text":
31
- return (
32
- <input
33
- key={`${field}-${rowIndex}`}
34
- id={`${field}-${rowIndex}`}
35
- type="text"
36
- defaultValue={cellValue || ""}
37
- onBlur={(e) => handleCellChange(e.target.value, field)}
38
- onKeyDown={(e) => {
39
- if (e.key === "Enter") {
40
- e.currentTarget.blur();
41
- }
42
- }}
43
- className="px-2 py-1 outline-none focus:ring-1 focus:ring-black rounded"
44
- style={style}
45
- />
46
- );
47
-
48
- case "number":
49
- return (
50
- <input
51
- key={`${field}-${rowIndex}`}
52
- id={`${field}-${rowIndex}`}
53
- type="number"
54
- defaultValue={cellValue || ""}
55
- onBlur={(e) => handleCellChange(e.target.value, field)}
56
- onKeyDown={(e) => {
57
- if (e.key === "Enter") {
58
- e.currentTarget.blur();
59
- }
60
- }}
61
- className="px-2 py-1 outline-none focus:ring-1 focus:ring-black rounded"
62
- style={style}
63
- />
64
- );
65
-
66
- default:
67
- return (
68
- <input
69
- type="text"
70
- defaultValue={cellValue || ""}
71
- onBlur={(e) => handleCellChange(e.target.value, field)}
72
- onKeyDown={(e) => {
73
- if (e.key === "Enter") {
74
- e.currentTarget.blur();
75
- }
76
- }}
77
- style={{
78
- width: "100%",
79
- border: "none",
80
- background: "transparent",
81
- }}
82
- />
83
- );
84
- }
85
- }
@@ -1,85 +0,0 @@
1
- import React from "react";
2
- import { useState } from "react";
3
-
4
- export default function FilterPopup({ show, columnHeader, filterAction }: any) {
5
- const [filterValue, setFilterValue] = useState("");
6
- const [filterType, setFilterType] = useState("contains");
7
- const [isFilterActive, setIsFilterActive] = useState(false);
8
-
9
- const handleFilterInput = (e: any) => {
10
- const filterKeyword = e.target.value;
11
- setFilterValue(filterKeyword);
12
- };
13
-
14
- const onCancel = () => {
15
- filterAction({ type: "cancel" });
16
- };
17
-
18
- const applyFilter = () => {
19
- filterAction({
20
- type: "applyFilter",
21
- filterValue,
22
- filterType,
23
- columnHeader,
24
- });
25
- show = false;
26
- setIsFilterActive(true);
27
- };
28
-
29
- const clearFilter = () => {
30
- setIsFilterActive(false);
31
- filterAction({ type: "clearFilter", columnHeader });
32
- };
33
-
34
- return (
35
- show && (
36
- <div
37
- className="absolute bg-gray-100 p-2 text-xs z-50 mt-48 flex flex-col shadow-lg gap-2 rounded-md dark:bg-zinc-700"
38
- role="dialog"
39
- >
40
- <select
41
- name={`${columnHeader}-filter`}
42
- id={`${columnHeader}-filter-id`}
43
- className="w-full p-2 rounded-lg bg-gray-200 outline-none dark:bg-gray-600"
44
- value={filterType}
45
- onChange={(e: any) => {
46
- setFilterType(e.target.value);
47
- }}
48
- >
49
- <option value="contains">Contains</option>
50
- <option value="starts_with">Starts With</option>
51
- <option value="ends_with">Ends With</option>
52
- </select>
53
- <input
54
- type="text"
55
- placeholder="Enter filter value"
56
- className="rounded-lg p-2 text-xs bg-gray-200 outline-none dark:bg-gray-600"
57
- value={filterValue}
58
- onInput={handleFilterInput}
59
- />
60
- <div className="mt-2 flex space-x-1">
61
- <button
62
- className="text-xs bg-red-600 text-white px-2 py-0.5 rounded-lg hover:bg-red-600"
63
- onClick={onCancel}
64
- >
65
- Cancel
66
- </button>
67
- {isFilterActive && (
68
- <button
69
- className="text-xs bg-black text-white px-2 py-0.5 rounded-lg dark:bg-white dark:text-black"
70
- onClick={clearFilter}
71
- >
72
- Clear Filter
73
- </button>
74
- )}
75
- <button
76
- className="text-xs bg-black text-white px-2 py-0.5 rounded-lg dark:bg-white dark:text-black"
77
- onClick={applyFilter}
78
- >
79
- Apply Filter
80
- </button>
81
- </div>
82
- </div>
83
- )
84
- );
85
- }
@@ -1,221 +0,0 @@
1
- import React from "react";
2
- import { useGridContext } from "../context/GridContext";
3
- import FilterPopup from "./FilterPopup";
4
- import Icon from "../../icon/Icon";
5
- import { listFilter, squarePen, trash } from "../../icon/iconPaths";
6
- import { Column } from "../type";
7
- import EditableRow from "./EditableRow";
8
-
9
- const GridBody = () => {
10
- const {
11
- workingDataSource,
12
- workingColumns,
13
- isFetching,
14
- currentPage,
15
- pageSettings,
16
- tableHeaderStyle,
17
- gridColumnStyle,
18
- gridColumnStyleSelectAll,
19
- rowChange,
20
- lazy,
21
- activeFilterArray,
22
- toggleFilterPopup,
23
- handleFilterAction,
24
- selectAll,
25
- handleSelectAll,
26
- handleSelect,
27
- isRowSelected,
28
- } = useGridContext();
29
-
30
- const renderCell = (rowData: any, column: Column, rowIndex: number) => {
31
- const cellValue = rowData[column.field];
32
- const globalRowIndex = rowIndex + currentPage * pageSettings.pageNumber;
33
-
34
- if (column.template && !column.editable) {
35
- const TemplateComponent = column.template;
36
- return (
37
- <TemplateComponent
38
- rowData={rowData}
39
- rowIndex={globalRowIndex}
40
- rowChange={(changes) => rowChange?.(changes)}
41
- />
42
- );
43
- }
44
-
45
- if (column.tooltip && !column.editable) {
46
- return (
47
- <span title={cellValue?.toString()}>
48
- {cellValue && cellValue.length > 10
49
- ? `${cellValue.slice(0, 10)}...`
50
- : cellValue}
51
- </span>
52
- );
53
- }
54
-
55
- if (column.editable && !column.template) {
56
- return (
57
- <EditableRow
58
- columnType={column.type ? column.type : undefined}
59
- cellValue={cellValue}
60
- rowIndex={globalRowIndex}
61
- field={column.field}
62
- style={{ width: column.width ? `${column.width}px` : "auto" }}
63
- rowData={rowData}
64
- />
65
- );
66
- }
67
-
68
- return cellValue;
69
- };
70
-
71
- const displayStart = currentPage * pageSettings.pageNumber;
72
- const displayEnd = displayStart + pageSettings.pageNumber;
73
- const displayData = lazy
74
- ? workingDataSource
75
- : workingDataSource.slice(displayStart, displayEnd);
76
-
77
- const isEditablePresent = workingColumns.some(
78
- (column) => column.editable || column.template
79
- );
80
-
81
- return (
82
- <div className="overflow-x-auto">
83
- <table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
84
- <thead>
85
- <tr>
86
- {selectAll && (
87
- <th
88
- className={tableHeaderStyle}
89
- style={{ width: "2px", paddingLeft: "16px" }}
90
- >
91
- <input
92
- type="checkbox"
93
- onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
94
- handleSelectAll(event);
95
- }}
96
- className="form-checkbox h-5 w-5"
97
- />
98
- </th>
99
- )}
100
- {workingColumns.map((column, colIndex) => (
101
- <th
102
- key={colIndex}
103
- className={tableHeaderStyle}
104
- style={{ width: column.width ? `${column.width}px` : "auto" }}
105
- >
106
- <div className="flex items-center relative">
107
- {column.headerText || column.field}
108
- {column.filter && !column.template && (
109
- <>
110
- <button onClick={() => toggleFilterPopup(colIndex)}>
111
- <Icon
112
- dimensions={{ width: "12", height: "12" }}
113
- elements={listFilter}
114
- svgClass={`ml-2 fill-none ${
115
- activeFilterArray.some(
116
- (filter) => filter.filterColumn === column.field
117
- )
118
- ? "stroke-red-400 dark:stroke-red-400"
119
- : "stroke-black dark:stroke-white"
120
- }`}
121
- />
122
- </button>
123
- <FilterPopup
124
- show={column.showFilterPopup ?? false}
125
- columnHeader={column.field}
126
- filterAction={(action: any) =>
127
- handleFilterAction(action, colIndex)
128
- }
129
- />
130
- </>
131
- )}
132
- </div>
133
- </th>
134
- ))}
135
- {isEditablePresent && <th className={tableHeaderStyle}>Action</th>}
136
- </tr>
137
- </thead>
138
- <tbody>
139
- {isFetching ? (
140
- <tr>
141
- <td colSpan={workingColumns.length + (selectAll ? 1 : 0)}>
142
- Loading...
143
- </td>
144
- </tr>
145
- ) : displayData.length === 0 ? (
146
- <tr>
147
- <td
148
- colSpan={workingColumns.length + (selectAll ? 1 : 0)}
149
- className="text-center py-3"
150
- >
151
- No data found
152
- </td>
153
- </tr>
154
- ) : (
155
- displayData.map((rowData, rowIndex) => (
156
- <tr
157
- key={rowIndex}
158
- className={
159
- isRowSelected(rowData)
160
- ? "bg-blue-100 dark:bg-blue-900"
161
- : rowIndex % 2 === 0
162
- ? "bg-gray-50 dark:bg-zinc-800 cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-700"
163
- : "bg-white dark:bg-zinc-900 cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-700"
164
- }
165
- onClick={() => rowChange(rowData)}
166
- >
167
- {selectAll && (
168
- <td className={gridColumnStyleSelectAll}>
169
- <input
170
- type="checkbox"
171
- checked={isRowSelected(rowData)}
172
- onChange={() => handleSelect(rowData)}
173
- className="form-checkbox h-5 w-5"
174
- />
175
- </td>
176
- )}
177
- {workingColumns.map((column, colIndex) => (
178
- <td
179
- key={colIndex}
180
- className={gridColumnStyle}
181
- style={{
182
- width: column.width ? `${column.width}px` : "auto",
183
- maxWidth: column.width ? `${column.width}px` : "auto",
184
- }}
185
- >
186
- {renderCell(rowData, column, rowIndex)}
187
- </td>
188
- ))}
189
- {isEditablePresent && (
190
- <td style={{ width: "16px", padding: "4px" }}>
191
- <div className="flex justify-start items-start px-2 gap-3">
192
- <button
193
- className="cursor-pointer"
194
- onClick={() => console.log(rowData)}
195
- >
196
- <Icon
197
- dimensions={{ width: "16", height: "16" }}
198
- elements={squarePen}
199
- svgClass="fill-none stroke-black dark:stroke-white"
200
- />
201
- </button>
202
- <button className="cursor-pointer">
203
- <Icon
204
- dimensions={{ width: "16", height: "16" }}
205
- elements={trash}
206
- svgClass="fill-none stroke-red-500 dark:stroke-red-500"
207
- />
208
- </button>
209
- </div>
210
- </td>
211
- )}
212
- </tr>
213
- ))
214
- )}
215
- </tbody>
216
- </table>
217
- </div>
218
- );
219
- };
220
-
221
- export default GridBody;