gbs-add-block 0.0.51 → 0.0.52-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/index.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require("fs-extra");
|
|
4
4
|
const path = require("path");
|
|
5
|
-
const
|
|
5
|
+
const yargs = require("yargs/yargs");
|
|
6
|
+
const { hideBin } = require("yargs/helpers");
|
|
6
7
|
|
|
7
8
|
// Configuration
|
|
8
9
|
const CONFIG = {
|
|
@@ -21,7 +22,8 @@ const CONFIG = {
|
|
|
21
22
|
"Toast",
|
|
22
23
|
"Uploader",
|
|
23
24
|
"FormRenderer",
|
|
24
|
-
"
|
|
25
|
+
"MaterialInput",
|
|
26
|
+
"ContextMenu",
|
|
25
27
|
],
|
|
26
28
|
frameworks: {
|
|
27
29
|
next: {
|
|
@@ -37,23 +39,6 @@ const CONFIG = {
|
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
const SOURCE_PATH = path.join(__dirname, "source", "components");
|
|
40
|
-
let isFirstCopy = true;
|
|
41
|
-
|
|
42
|
-
const rl = createInterface({
|
|
43
|
-
input: process.stdin,
|
|
44
|
-
output: process.stdout,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
const prompt = (question) =>
|
|
48
|
-
new Promise((resolve) => {
|
|
49
|
-
rl.question(question, resolve);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const displayOptions = (options, title) => {
|
|
53
|
-
console.log(`\n${title}:\n`);
|
|
54
|
-
options.forEach((option, index) => console.log(`${index + 1}. ${option}`));
|
|
55
|
-
console.log("");
|
|
56
|
-
};
|
|
57
42
|
|
|
58
43
|
const copyCommonFiles = async (destPath) => {
|
|
59
44
|
const commonFiles = [
|
|
@@ -66,7 +51,7 @@ const copyCommonFiles = async (destPath) => {
|
|
|
66
51
|
const src = path.join(SOURCE_PATH, ...file.src);
|
|
67
52
|
const dest = path.join(destPath, file.dest);
|
|
68
53
|
await fs.copy(src, dest, { overwrite: true });
|
|
69
|
-
console.log(
|
|
54
|
+
console.log(`✓ ${file.dest} copied successfully`);
|
|
70
55
|
}
|
|
71
56
|
};
|
|
72
57
|
|
|
@@ -80,80 +65,103 @@ const copyComponent = async (component, destPath) => {
|
|
|
80
65
|
}
|
|
81
66
|
|
|
82
67
|
await fs.copy(componentSrc, componentDest, { overwrite: true });
|
|
83
|
-
console.log(
|
|
84
|
-
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
if (isFirstCopy) {
|
|
88
|
-
await copyCommonFiles(destPath);
|
|
89
|
-
isFirstCopy = false;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
console.log(`\nFor Props and Usage Guides Visit: ${CONFIG.docs}\n`);
|
|
68
|
+
console.log(`✓ Component ${component} installed successfully`);
|
|
69
|
+
console.log(`\nFor documentation visit: ${CONFIG.docs}`);
|
|
93
70
|
} catch (error) {
|
|
94
|
-
console.error(`Error
|
|
71
|
+
console.error(`Error installing component ${component}:`, error.message);
|
|
72
|
+
process.exit(1);
|
|
95
73
|
}
|
|
96
74
|
};
|
|
97
75
|
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
const answer = await prompt("Select your framework (enter the number): ");
|
|
105
|
-
const index = parseInt(answer) - 1;
|
|
106
|
-
const frameworks = Object.keys(CONFIG.frameworks);
|
|
107
|
-
|
|
108
|
-
if (isNaN(index) || index < 0 || index >= frameworks.length) {
|
|
109
|
-
throw new Error("Invalid framework selection");
|
|
76
|
+
const detectFramework = () => {
|
|
77
|
+
// Check for Next.js
|
|
78
|
+
if (fs.existsSync(path.join(process.cwd(), "next.config.js"))) {
|
|
79
|
+
return "next";
|
|
110
80
|
}
|
|
111
|
-
|
|
112
|
-
|
|
81
|
+
// Check for Vite
|
|
82
|
+
if (
|
|
83
|
+
fs.existsSync(path.join(process.cwd(), "vite.config.js")) ||
|
|
84
|
+
fs.existsSync(path.join(process.cwd(), "vite.config.ts"))
|
|
85
|
+
) {
|
|
86
|
+
return "vite";
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
113
89
|
};
|
|
114
90
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
91
|
+
const main = async () => {
|
|
92
|
+
const argv = yargs(hideBin(process.argv))
|
|
93
|
+
.option("add", {
|
|
94
|
+
alias: "a",
|
|
95
|
+
describe: "Component to install",
|
|
96
|
+
type: "string",
|
|
97
|
+
})
|
|
98
|
+
.option("framework", {
|
|
99
|
+
alias: "f",
|
|
100
|
+
describe: "Framework to use (next or vite)",
|
|
101
|
+
type: "string",
|
|
102
|
+
})
|
|
103
|
+
.option("list", {
|
|
104
|
+
alias: "l",
|
|
105
|
+
describe: "List available components",
|
|
106
|
+
type: "boolean",
|
|
107
|
+
})
|
|
108
|
+
.help().argv;
|
|
109
|
+
|
|
110
|
+
// List components if requested
|
|
111
|
+
if (argv.list) {
|
|
112
|
+
console.log("\nAvailable components:");
|
|
113
|
+
CONFIG.components.forEach((comp) => console.log(`- ${comp}`));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
118
116
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
);
|
|
117
|
+
if (!argv.add) {
|
|
118
|
+
console.error("Please specify a component to install using -a or --add");
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
122
121
|
|
|
123
|
-
|
|
122
|
+
// Validate component name
|
|
123
|
+
const component = argv.add;
|
|
124
|
+
if (!CONFIG.components.includes(component)) {
|
|
125
|
+
console.error(`Invalid component: ${component}`);
|
|
126
|
+
console.log("\nAvailable components:");
|
|
127
|
+
CONFIG.components.forEach((comp) => console.log(`- ${comp}`));
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
124
130
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
// Detect or get framework
|
|
132
|
+
let framework = argv.framework;
|
|
133
|
+
if (!framework) {
|
|
134
|
+
framework = detectFramework();
|
|
135
|
+
if (!framework) {
|
|
136
|
+
console.error(
|
|
137
|
+
"Could not detect framework. Please specify using -f or --framework"
|
|
138
|
+
);
|
|
139
|
+
process.exit(1);
|
|
129
140
|
}
|
|
130
|
-
|
|
131
|
-
await copyComponent(CONFIG.components[index], destPath);
|
|
132
|
-
|
|
133
|
-
const continueAnswer = await prompt(
|
|
134
|
-
"Do you want to copy another component? (y/n): "
|
|
135
|
-
);
|
|
136
|
-
if (continueAnswer.toLowerCase() !== "y") break;
|
|
137
141
|
}
|
|
138
|
-
};
|
|
139
142
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const framework = await selectFramework();
|
|
143
|
-
const destPath = path.join(
|
|
144
|
-
process.cwd(),
|
|
145
|
-
...CONFIG.frameworks[framework].path
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
await fs.ensureDir(destPath);
|
|
149
|
-
await handleComponentSelection(destPath);
|
|
150
|
-
} catch (error) {
|
|
151
|
-
console.error("Error:", error.message);
|
|
143
|
+
if (!CONFIG.frameworks[framework]) {
|
|
144
|
+
console.error(`Unsupported framework: ${framework}`);
|
|
152
145
|
process.exit(1);
|
|
153
|
-
} finally {
|
|
154
|
-
rl.close();
|
|
155
146
|
}
|
|
147
|
+
|
|
148
|
+
// Create destination directory
|
|
149
|
+
const destPath = path.join(
|
|
150
|
+
process.cwd(),
|
|
151
|
+
...CONFIG.frameworks[framework].path
|
|
152
|
+
);
|
|
153
|
+
await fs.ensureDir(destPath);
|
|
154
|
+
|
|
155
|
+
// Copy common files if they don't exist
|
|
156
|
+
if (!fs.existsSync(path.join(destPath, "utils.ts"))) {
|
|
157
|
+
await copyCommonFiles(destPath);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Copy the requested component
|
|
161
|
+
await copyComponent(component, destPath);
|
|
156
162
|
};
|
|
157
163
|
|
|
158
|
-
|
|
159
|
-
|
|
164
|
+
main().catch((error) => {
|
|
165
|
+
console.error("Error:", error.message);
|
|
166
|
+
process.exit(1);
|
|
167
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gbs-add-block",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.52-beta",
|
|
4
4
|
"description": "React Component Library",
|
|
5
5
|
"files": [
|
|
6
6
|
"index.js",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"license": "ISC",
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"fs-extra": "^11.2.0",
|
|
23
|
-
"path": "^0.12.7"
|
|
23
|
+
"path": "^0.12.7",
|
|
24
|
+
"yargs": "^17.7.2"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
27
|
"@types/fs-extra": "^11.0.4"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ContextMenuItemProps } from "./types";
|
|
2
|
+
|
|
3
|
+
export const ContextMenuItem: React.FC<ContextMenuItemProps> = ({
|
|
4
|
+
onClick,
|
|
5
|
+
icon,
|
|
6
|
+
children,
|
|
7
|
+
disabled = false,
|
|
8
|
+
}) => (
|
|
9
|
+
<button
|
|
10
|
+
onClick={(e: React.MouseEvent) => {
|
|
11
|
+
e.stopPropagation();
|
|
12
|
+
if (!disabled) {
|
|
13
|
+
onClick?.();
|
|
14
|
+
}
|
|
15
|
+
}}
|
|
16
|
+
disabled={disabled}
|
|
17
|
+
className={`w-full px-4 py-2 text-left flex items-center gap-2 ${
|
|
18
|
+
disabled
|
|
19
|
+
? "text-gray-400 cursor-not-allowed"
|
|
20
|
+
: "hover:bg-gray-100 cursor-pointer"
|
|
21
|
+
}`}
|
|
22
|
+
>
|
|
23
|
+
{icon && <span className="w-4 h-4">{icon}</span>}
|
|
24
|
+
{children}
|
|
25
|
+
</button>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export const ContextMenuDivider: React.FC = () => (
|
|
29
|
+
<div className="my-1 border-t border-gray-200" />
|
|
30
|
+
);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React, { useState, useEffect, useCallback, MouseEvent } from "react";
|
|
2
|
+
import { ContextMenuProps, Position } from "./types";
|
|
3
|
+
|
|
4
|
+
export const ContextMenu: React.FC<ContextMenuProps> = ({ children }) => {
|
|
5
|
+
const [isVisible, setIsVisible] = useState<boolean>(false);
|
|
6
|
+
const [position, setPosition] = useState<Position>({ x: 0, y: 0 });
|
|
7
|
+
|
|
8
|
+
const handleContextMenu = useCallback(
|
|
9
|
+
(event: MouseEvent | globalThis.MouseEvent) => {
|
|
10
|
+
event.preventDefault();
|
|
11
|
+
setIsVisible(true);
|
|
12
|
+
setPosition({
|
|
13
|
+
x: event.pageX,
|
|
14
|
+
y: event.pageY,
|
|
15
|
+
});
|
|
16
|
+
},
|
|
17
|
+
[]
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const handleClick = useCallback(() => {
|
|
21
|
+
if (isVisible) setIsVisible(false);
|
|
22
|
+
}, [isVisible]);
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
document.addEventListener("click", handleClick);
|
|
26
|
+
document.addEventListener("contextmenu", handleContextMenu);
|
|
27
|
+
|
|
28
|
+
return () => {
|
|
29
|
+
document.removeEventListener("click", handleClick);
|
|
30
|
+
document.removeEventListener("contextmenu", handleContextMenu);
|
|
31
|
+
};
|
|
32
|
+
}, [handleClick, handleContextMenu]);
|
|
33
|
+
|
|
34
|
+
// Ensure menu stays within viewport bounds
|
|
35
|
+
const adjustedPosition = useCallback((position: Position): Position => {
|
|
36
|
+
const menuWidth = 160; // min-width from CSS
|
|
37
|
+
const menuHeight = 200; // approximate max height
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
x: Math.min(position.x, window.innerWidth - menuWidth),
|
|
41
|
+
y: Math.min(position.y, window.innerHeight - menuHeight),
|
|
42
|
+
};
|
|
43
|
+
}, []);
|
|
44
|
+
|
|
45
|
+
const finalPosition = adjustedPosition(position);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<>
|
|
49
|
+
{isVisible && (
|
|
50
|
+
<div
|
|
51
|
+
className="fixed bg-white rounded-lg shadow-lg border border-gray-200 py-2 min-w-[160px]"
|
|
52
|
+
style={{
|
|
53
|
+
top: finalPosition.y,
|
|
54
|
+
left: finalPosition.x,
|
|
55
|
+
zIndex: 1000,
|
|
56
|
+
}}
|
|
57
|
+
>
|
|
58
|
+
{children}
|
|
59
|
+
</div>
|
|
60
|
+
)}
|
|
61
|
+
</>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
interface Position {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface ContextMenuProps {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface ContextMenuItemProps {
|
|
13
|
+
onClick?: () => void;
|
|
14
|
+
icon?: ReactNode;
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type { Position, ContextMenuProps, ContextMenuItemProps };
|