gbs-add-block 1.0.13 → 1.0.15-beta

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.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # GBS Building Blocks 2.0 (v1.0.13)
1
+ # GBS Building Blocks 2.0 (v1.0.14)
2
2
 
3
3
  Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
4
4
 
@@ -6,10 +6,11 @@ Latest and upgraded version of GBS building blocks with headless UI and removed
6
6
 
7
7
  For detailed documentation on usage and props, Please visit: [Building Block Documentation v2.0](https://blackmax-designs.gitbook.io/building-block-v2.0)
8
8
 
9
- ## What's New 🎉 (Ver 1.0.13)
9
+ ## What's New 🎉 (Ver 1.0.14)
10
10
 
11
11
  - Data Grid Enhancement
12
12
  - End of Support for Grid Component
13
+ - Select Enhancement
13
14
 
14
15
  ## Authors
15
16
 
package/index.cjs CHANGED
@@ -4,6 +4,7 @@ const fs = require("fs-extra");
4
4
  const path = require("path");
5
5
  const yargs = require("yargs/yargs");
6
6
  const { hideBin } = require("yargs/helpers");
7
+ const readline = require("readline");
7
8
 
8
9
  // Configuration
9
10
  const CONFIG = {
@@ -31,7 +32,8 @@ const CONFIG = {
31
32
  "BreadCrumb",
32
33
  "Bargraph",
33
34
  "UsePaginatedData",
34
- "UseUploader"
35
+ "UseUploader",
36
+ "DataGridBeta"
35
37
  ],
36
38
  // Define component dependencies
37
39
  dependencies: {
@@ -118,18 +120,182 @@ const installComponentWithDependencies = async (component, destPath) => {
118
120
  console.log(`\nFor documentation visit: ${CONFIG.docs}`);
119
121
  };
120
122
 
123
+ const installMultipleComponents = async (components, destPath) => {
124
+ const allComponentsToInstall = new Set();
125
+
126
+ // Collect all components and their dependencies
127
+ components.forEach((component) => {
128
+ const dependencies = CONFIG.dependencies[component] || [];
129
+ allComponentsToInstall.add(component);
130
+ dependencies.forEach((dep) => allComponentsToInstall.add(dep));
131
+ });
132
+
133
+ // Filter out already installed components
134
+ const pendingInstalls = Array.from(allComponentsToInstall).filter(
135
+ (comp) => !checkComponentExists(comp, destPath)
136
+ );
137
+
138
+ if (pendingInstalls.length === 0) {
139
+ console.log(
140
+ "✓ All selected components and their dependencies are already installed."
141
+ );
142
+ return;
143
+ }
144
+
145
+ console.log(`\nInstalling ${pendingInstalls.length} components...`);
146
+
147
+ // Install all pending components
148
+ for (const comp of pendingInstalls) {
149
+ await copyComponent(comp, destPath);
150
+ }
151
+
152
+ // Show dependency information
153
+ const allDependencies = new Set();
154
+ components.forEach((component) => {
155
+ const dependencies = CONFIG.dependencies[component] || [];
156
+ dependencies.forEach((dep) => allDependencies.add(dep));
157
+ });
158
+
159
+ if (allDependencies.size > 0) {
160
+ console.log(`\nDependencies installed:`);
161
+ Array.from(allDependencies).forEach((dep) => {
162
+ console.log(`- ${dep}`);
163
+ });
164
+ }
165
+
166
+ console.log(`\nFor documentation visit: ${CONFIG.docs}`);
167
+ };
168
+
169
+ const interactiveComponentSelector = async () => {
170
+ return new Promise((resolve) => {
171
+ const rl = readline.createInterface({
172
+ input: process.stdin,
173
+ output: process.stdout,
174
+ });
175
+
176
+ let selectedComponents = new Set();
177
+ let currentIndex = 0;
178
+
179
+ const renderMenu = () => {
180
+ console.clear();
181
+ console.log("🚀 Component Installer - Interactive Mode");
182
+ console.log(
183
+ "Use ↑/↓ arrow keys to navigate, SPACE to select/deselect, ENTER to install\n"
184
+ );
185
+
186
+ CONFIG.components.forEach((component, index) => {
187
+ const isSelected = selectedComponents.has(component);
188
+ const isCurrentIndex = index === currentIndex;
189
+ const deps = CONFIG.dependencies[component]
190
+ ? ` (requires: ${CONFIG.dependencies[component].join(", ")})`
191
+ : "";
192
+
193
+ const prefix = isCurrentIndex ? ">" : " ";
194
+ const checkbox = isSelected ? "☑" : "☐";
195
+ const line = `${prefix} ${checkbox} ${component}${deps}`;
196
+
197
+ if (isCurrentIndex) {
198
+ console.log(`\x1b[36m${line}\x1b[0m`); // Cyan highlight
199
+ } else {
200
+ console.log(line);
201
+ }
202
+ });
203
+
204
+ console.log(`\nSelected: ${selectedComponents.size} components`);
205
+ console.log("Press ENTER to install selected components, or 'q' to quit");
206
+ };
207
+
208
+ const handleKeyPress = (key) => {
209
+ switch (key) {
210
+ case "\u001b[A": // Up arrow
211
+ currentIndex = Math.max(0, currentIndex - 1);
212
+ renderMenu();
213
+ break;
214
+ case "\u001b[B": // Down arrow
215
+ currentIndex = Math.min(
216
+ CONFIG.components.length - 1,
217
+ currentIndex + 1
218
+ );
219
+ renderMenu();
220
+ break;
221
+ case " ": // Space bar
222
+ const component = CONFIG.components[currentIndex];
223
+ if (selectedComponents.has(component)) {
224
+ selectedComponents.delete(component);
225
+ } else {
226
+ selectedComponents.add(component);
227
+ }
228
+ renderMenu();
229
+ break;
230
+ case "\r": // Enter
231
+ if (selectedComponents.size > 0) {
232
+ rl.close();
233
+ resolve(Array.from(selectedComponents));
234
+ }
235
+ break;
236
+ case "q":
237
+ rl.close();
238
+ resolve([]);
239
+ break;
240
+ }
241
+ };
242
+
243
+ // Enable raw mode to capture arrow keys
244
+ process.stdin.setRawMode(true);
245
+ process.stdin.resume();
246
+ process.stdin.setEncoding("utf8");
247
+ process.stdin.on("data", handleKeyPress);
248
+
249
+ renderMenu();
250
+
251
+ rl.on("close", () => {
252
+ process.stdin.setRawMode(false);
253
+ process.stdin.pause();
254
+ });
255
+ });
256
+ };
257
+
258
+ const parseMultipleComponents = (componentString) => {
259
+ return componentString
260
+ .split(",")
261
+ .map((comp) => comp.trim())
262
+ .filter((comp) => comp.length > 0);
263
+ };
264
+
265
+ const validateComponents = (components) => {
266
+ const invalidComponents = components.filter(
267
+ (comp) => !CONFIG.components.includes(comp)
268
+ );
269
+ if (invalidComponents.length > 0) {
270
+ console.error(`Invalid components: ${invalidComponents.join(", ")}`);
271
+ console.log("\nAvailable components:");
272
+ CONFIG.components.forEach((comp) => console.log(`- ${comp}`));
273
+ return false;
274
+ }
275
+ return true;
276
+ };
277
+
121
278
  const main = async () => {
122
279
  const argv = yargs(hideBin(process.argv))
123
280
  .option("add", {
124
281
  alias: "a",
125
- describe: "Component to install",
282
+ describe:
283
+ "Component to install (single component or comma-separated list)",
126
284
  type: "string",
127
285
  })
286
+ .option("interactive", {
287
+ alias: "i",
288
+ describe: "Interactive component selection mode",
289
+ type: "boolean",
290
+ })
128
291
  .option("list", {
129
292
  alias: "l",
130
293
  describe: "List available components",
131
294
  type: "boolean",
132
295
  })
296
+ .example("$0 -a Button", "Install a single component")
297
+ .example("$0 -a Button,Card,Modal", "Install multiple components")
298
+ .example("$0 -i", "Interactive selection mode")
133
299
  .help().argv;
134
300
 
135
301
  // List components if requested
@@ -144,17 +310,43 @@ const main = async () => {
144
310
  return;
145
311
  }
146
312
 
313
+ // Interactive mode
314
+ if (argv.interactive) {
315
+ console.log("Starting interactive component selector...\n");
316
+ const selectedComponents = await interactiveComponentSelector();
317
+
318
+ if (selectedComponents.length === 0) {
319
+ console.log("No components selected. Exiting...");
320
+ return;
321
+ }
322
+
323
+ // Create destination directory in project root
324
+ const destPath = DEFAULT_DEST_PATH;
325
+ await fs.ensureDir(destPath);
326
+
327
+ // Copy common files if they don't exist
328
+ if (!fs.existsSync(path.join(destPath, "utils.ts"))) {
329
+ await copyCommonFiles(destPath);
330
+ }
331
+
332
+ // Install selected components
333
+ await installMultipleComponents(selectedComponents, destPath);
334
+ return;
335
+ }
336
+
147
337
  if (!argv.add) {
148
- console.error("Please specify a component to install using -a or --add");
338
+ console.error(
339
+ "Please specify a component to install using -a/--add, use -i/--interactive for interactive mode, or -l/--list to see available components"
340
+ );
149
341
  process.exit(1);
150
342
  }
151
343
 
152
- // Validate component name
153
- const component = argv.add;
154
- if (!CONFIG.components.includes(component)) {
155
- console.error(`Invalid component: ${component}`);
156
- console.log("\nAvailable components:");
157
- CONFIG.components.forEach((comp) => console.log(`- ${comp}`));
344
+ // Parse components (single or multiple)
345
+ const componentInput = argv.add;
346
+ const components = parseMultipleComponents(componentInput);
347
+
348
+ // Validate all components
349
+ if (!validateComponents(components)) {
158
350
  process.exit(1);
159
351
  }
160
352
 
@@ -167,8 +359,14 @@ const main = async () => {
167
359
  await copyCommonFiles(destPath);
168
360
  }
169
361
 
170
- // Install component and its dependencies
171
- await installComponentWithDependencies(component, destPath);
362
+ // Install components
363
+ if (components.length === 1) {
364
+ // Single component installation (existing behavior)
365
+ await installComponentWithDependencies(components[0], destPath);
366
+ } else {
367
+ // Multiple components installation
368
+ await installMultipleComponents(components, destPath);
369
+ }
172
370
  };
173
371
 
174
372
  main().catch((error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gbs-add-block",
3
- "version": "1.0.13",
3
+ "version": "1.0.15-beta",
4
4
  "description": "React Component Library",
5
5
  "type": "module",
6
6
  "files": [
@@ -0,0 +1,187 @@
1
+ import React, { createContext, useContext } from "react";
2
+ import type { GridContextType, GridProps } from "../type";
3
+ import {
4
+ useDataSource,
5
+ useColumns,
6
+ usePagination,
7
+ useSearch,
8
+ useFiltering,
9
+ useRowSelection,
10
+ usePageStatus,
11
+ } from "../hooks";
12
+
13
+ const GridContext = createContext<GridContextType | undefined>(undefined);
14
+
15
+ export const GridProvider: React.FC<{
16
+ children: React.ReactNode;
17
+ props: GridProps;
18
+ }> = ({ children, props }) => {
19
+ const {
20
+ dataSource,
21
+ columns = [],
22
+ pageSettings,
23
+ enableSearch = false,
24
+ lazy = false,
25
+ enableExcelExport = false,
26
+ excelName = "data",
27
+ enablePdfExport = false,
28
+ pdfName = "data",
29
+ pdfOptions = {},
30
+ gridButtonClass = "px-1 py-2 text-xs rounded bg-zinc-200 dark:bg-zinc-700 cursor-pointer",
31
+ selectAll = false,
32
+ onSelectRow,
33
+ isFetching,
34
+ tableHeaderStyle = "text-left px-2 py-4 bg-zinc-200 dark:bg-zinc-800",
35
+ gridContainerClass = "flex flex-col rounded-md overflow-hidden",
36
+ gridColumnStyleSelectAll = "px-4 text-xs",
37
+ gridColumnStyle = "p-2 text-xs",
38
+ rowChange = () => {},
39
+ pageStatus = () => {},
40
+ activeFilterArrayValue = [],
41
+ searchParamValue = () => {},
42
+ showTotalPages = false,
43
+ onSearch = () => {},
44
+ onToolbarButtonClick = () => {},
45
+ } = props;
46
+
47
+ // Data source management
48
+ const {
49
+ workingDataSource,
50
+ setWorkingDataSource,
51
+ fallbackSourceData,
52
+ totalPages,
53
+ setTotalPages,
54
+ } = useDataSource(dataSource, pageSettings, lazy);
55
+
56
+ // Column management
57
+ const { workingColumns, setWorkingColumns } = useColumns(
58
+ columns,
59
+ workingDataSource
60
+ );
61
+
62
+ // Pagination management
63
+ const {
64
+ currentPage,
65
+ pageStart,
66
+ pageEnd,
67
+ nextPage,
68
+ prevPage,
69
+ goToEndPage,
70
+ goToFirstPage,
71
+ goToPage,
72
+ resetPage,
73
+ } = usePagination(totalPages, lazy, workingDataSource, pageSettings);
74
+
75
+ // Search functionality
76
+ const { searchParam, handleSearchInput, handleSearch } = useSearch({
77
+ workingDataSource,
78
+ setWorkingDataSource,
79
+ fallbackSourceData,
80
+ dataSource,
81
+ lazy,
82
+ pageSettings,
83
+ resetPage,
84
+ setTotalPages,
85
+ searchParamValue,
86
+ });
87
+
88
+ // Filtering functionality
89
+ const {
90
+ activeFilterArray,
91
+ toggleFilterPopup,
92
+ handleApplyFilter,
93
+ clearFilter,
94
+ handleFilterAction,
95
+ } = useFiltering({
96
+ columns,
97
+ workingColumns,
98
+ setWorkingColumns,
99
+ workingDataSource,
100
+ setWorkingDataSource,
101
+ dataSource,
102
+ fallbackSourceData,
103
+ resetPage,
104
+ setTotalPages,
105
+ pageSettings,
106
+ activeFilterArrayValue,
107
+ });
108
+
109
+ // Row selection functionality
110
+ const { selectedRows, handleSelectAll, handleSelect, isRowSelected } =
111
+ useRowSelection(workingDataSource, onSelectRow);
112
+
113
+ // Page status reporting
114
+ usePageStatus(currentPage, totalPages, pageStatus);
115
+
116
+ // Context value
117
+ const contextValue: GridContextType = {
118
+ // State
119
+ workingDataSource,
120
+ fallbackSourceData,
121
+ workingColumns,
122
+ currentPage,
123
+ pageStart,
124
+ pageEnd,
125
+ totalPages,
126
+ searchParam,
127
+ activeFilterArray,
128
+ selectedRows,
129
+ isFetching,
130
+
131
+ // Navigation methods
132
+ nextPage,
133
+ prevPage,
134
+ goToEndPage,
135
+ goToFirstPage,
136
+ goToPage,
137
+ lazy,
138
+
139
+ // Search methods
140
+ handleSearchInput,
141
+ handleSearch,
142
+
143
+ // Filter methods
144
+ toggleFilterPopup,
145
+ handleApplyFilter,
146
+ clearFilter,
147
+ handleFilterAction,
148
+
149
+ // Row selection methods
150
+ handleSelectAll,
151
+ handleSelect,
152
+ isRowSelected,
153
+
154
+ // Grid settings
155
+ columns,
156
+ pageSettings,
157
+ enableSearch,
158
+ enableExcelExport,
159
+ enablePdfExport,
160
+ excelName,
161
+ pdfName,
162
+ pdfOptions,
163
+ gridButtonClass,
164
+ selectAll,
165
+ tableHeaderStyle,
166
+ gridContainerClass,
167
+ gridColumnStyleSelectAll,
168
+ gridColumnStyle,
169
+ rowChange,
170
+ showTotalPages,
171
+ onSearch,
172
+ onToolbarButtonClick,
173
+ };
174
+
175
+ return (
176
+ <GridContext.Provider value={contextValue}>{children}</GridContext.Provider>
177
+ );
178
+ };
179
+
180
+ // Base context hook
181
+ export const useGridContext = () => {
182
+ const context = useContext(GridContext);
183
+ if (context === undefined) {
184
+ throw new Error("useGridContext must be used within a GridProvider");
185
+ }
186
+ return context;
187
+ };
@@ -0,0 +1,7 @@
1
+ export { useDataSource } from "./useDataSource";
2
+ export { useColumns } from "./useColumns";
3
+ export { usePagination } from "./usePagination";
4
+ export { useSearch } from "./useSearch";
5
+ export { useFiltering } from "./useFiltering";
6
+ export { useRowSelection } from "./useRowSelection";
7
+ export { usePageStatus } from "./usePageStatus";
@@ -0,0 +1,33 @@
1
+ import { useState, useEffect } from "react";
2
+
3
+ export const useColumns = (columns: any[], workingDataSource: any[]) => {
4
+ const [workingColumns, setWorkingColumns] = useState<any>([]);
5
+
6
+ useEffect(() => {
7
+ if (columns && columns.length > 0) {
8
+ const filteredColumns = columns.map((column) => ({
9
+ ...column,
10
+ showFilterPopup: false,
11
+ isFilterActive: false,
12
+ }));
13
+ setWorkingColumns(filteredColumns);
14
+ } else if (
15
+ workingDataSource.length > 0 &&
16
+ Object.keys(workingDataSource[0]).length > 0
17
+ ) {
18
+ const inferredColumns = Object.keys(workingDataSource[0]).map((key) => ({
19
+ field: key,
20
+ headerText: key.charAt(0).toUpperCase() + key.slice(1),
21
+ width: 150,
22
+ }));
23
+ setWorkingColumns((prevColumns: any) => {
24
+ if (JSON.stringify(prevColumns) !== JSON.stringify(inferredColumns)) {
25
+ return inferredColumns;
26
+ }
27
+ return prevColumns;
28
+ });
29
+ }
30
+ }, [columns, workingDataSource]);
31
+
32
+ return { workingColumns, setWorkingColumns };
33
+ };
@@ -0,0 +1,54 @@
1
+ import { useState, useCallback, useEffect } from "react";
2
+ import { getSourceData } from "../../utils";
3
+
4
+ export const useDataSource = (
5
+ dataSource: any,
6
+ pageSettings: any,
7
+ lazy: boolean
8
+ ) => {
9
+ const [workingDataSource, setWorkingDataSource] = useState<any>([]);
10
+ const [fallbackSourceData, setFallbackSourceData] = useState([]);
11
+ const [totalPages, setTotalPages] = useState(0);
12
+
13
+ const getGridData = useCallback(async () => {
14
+ try {
15
+ const sourceData = await getSourceData(dataSource);
16
+ const gridData = sourceData.sourcedata;
17
+ setFallbackSourceData(gridData);
18
+ setWorkingDataSource(gridData);
19
+ const totalPages = Math.ceil(gridData.length / pageSettings.pageNumber);
20
+ setTotalPages(totalPages);
21
+ return totalPages;
22
+ } catch (error) {
23
+ console.error("Error fetching grid source data:", error);
24
+ return 0;
25
+ }
26
+ }, [dataSource, pageSettings.pageNumber]);
27
+
28
+ useEffect(() => {
29
+ const handleDataSource = async () => {
30
+ if (Array.isArray(dataSource)) {
31
+ setWorkingDataSource(dataSource);
32
+
33
+ const totalPages =
34
+ lazy && pageSettings.totalCount
35
+ ? Math.ceil(pageSettings.totalCount / pageSettings.pageNumber)
36
+ : Math.ceil(dataSource.length / pageSettings.pageNumber);
37
+
38
+ setTotalPages(totalPages);
39
+ } else if (typeof dataSource === "string") {
40
+ await getGridData();
41
+ }
42
+ };
43
+
44
+ handleDataSource();
45
+ }, [dataSource, pageSettings, lazy, getGridData]);
46
+
47
+ return {
48
+ workingDataSource,
49
+ setWorkingDataSource,
50
+ fallbackSourceData,
51
+ totalPages,
52
+ setTotalPages,
53
+ };
54
+ };