myoperator-ui 0.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.
- package/README.md +71 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +333 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# myOperator UI
|
|
2
|
+
|
|
3
|
+
CLI for adding myOperator UI components to your React project.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx myoperator-ui init
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Initialize your project
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx myoperator-ui init
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This will:
|
|
20
|
+
- Create a `components.json` configuration file
|
|
21
|
+
- Set up the utils file with the `cn` helper
|
|
22
|
+
- Create the components directory
|
|
23
|
+
|
|
24
|
+
### Add components
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Add a specific component
|
|
28
|
+
npx myoperator-ui add button
|
|
29
|
+
|
|
30
|
+
# Add multiple components
|
|
31
|
+
npx myoperator-ui add button input card
|
|
32
|
+
|
|
33
|
+
# Interactive selection
|
|
34
|
+
npx myoperator-ui add
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Options
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Skip confirmation
|
|
41
|
+
npx myoperator-ui add button -y
|
|
42
|
+
|
|
43
|
+
# Overwrite existing files
|
|
44
|
+
npx myoperator-ui add button --overwrite
|
|
45
|
+
|
|
46
|
+
# Custom path
|
|
47
|
+
npx myoperator-ui add button -p src/ui
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Available Components
|
|
51
|
+
|
|
52
|
+
- `button` - A customizable button with variants, sizes, icons, and loading state
|
|
53
|
+
|
|
54
|
+
## Requirements
|
|
55
|
+
|
|
56
|
+
- React 18+
|
|
57
|
+
- Tailwind CSS
|
|
58
|
+
- TypeScript (recommended)
|
|
59
|
+
|
|
60
|
+
## Dependencies
|
|
61
|
+
|
|
62
|
+
Components use these packages (installed automatically):
|
|
63
|
+
- `@radix-ui/react-slot`
|
|
64
|
+
- `class-variance-authority`
|
|
65
|
+
- `clsx`
|
|
66
|
+
- `tailwind-merge`
|
|
67
|
+
- `lucide-react`
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
|
|
71
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/add.ts
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import fs from "fs-extra";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import prompts from "prompts";
|
|
11
|
+
import ora from "ora";
|
|
12
|
+
|
|
13
|
+
// src/utils/registry.ts
|
|
14
|
+
async function getRegistry() {
|
|
15
|
+
return {
|
|
16
|
+
button: {
|
|
17
|
+
name: "button",
|
|
18
|
+
description: "A customizable button component with variants, sizes, and icons",
|
|
19
|
+
dependencies: [
|
|
20
|
+
"@radix-ui/react-slot",
|
|
21
|
+
"class-variance-authority",
|
|
22
|
+
"clsx",
|
|
23
|
+
"tailwind-merge",
|
|
24
|
+
"lucide-react"
|
|
25
|
+
],
|
|
26
|
+
files: [
|
|
27
|
+
{
|
|
28
|
+
name: "button.tsx",
|
|
29
|
+
content: `import * as React from "react"
|
|
30
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
31
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
32
|
+
import { Loader2 } from "lucide-react"
|
|
33
|
+
|
|
34
|
+
import { cn } from "@/lib/utils"
|
|
35
|
+
|
|
36
|
+
const buttonVariants = cva(
|
|
37
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
38
|
+
{
|
|
39
|
+
variants: {
|
|
40
|
+
variant: {
|
|
41
|
+
default: "bg-[#343E55] text-white hover:bg-[#343E55]/90",
|
|
42
|
+
destructive:
|
|
43
|
+
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
44
|
+
outline:
|
|
45
|
+
"border border-[#343E55] bg-transparent text-[#343E55] hover:bg-[#343E55] hover:text-white",
|
|
46
|
+
secondary:
|
|
47
|
+
"bg-[#343E55]/20 text-[#343E55] hover:bg-[#343E55]/30",
|
|
48
|
+
ghost: "hover:bg-[#343E55]/10 hover:text-[#343E55]",
|
|
49
|
+
link: "text-[#343E55] underline-offset-4 hover:underline",
|
|
50
|
+
},
|
|
51
|
+
size: {
|
|
52
|
+
default: "py-2.5 px-4",
|
|
53
|
+
sm: "py-2 px-3 text-xs",
|
|
54
|
+
lg: "py-3 px-6",
|
|
55
|
+
icon: "p-2.5",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
defaultVariants: {
|
|
59
|
+
variant: "default",
|
|
60
|
+
size: "default",
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
export interface ButtonProps
|
|
66
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
67
|
+
VariantProps<typeof buttonVariants> {
|
|
68
|
+
asChild?: boolean
|
|
69
|
+
leftIcon?: React.ReactNode
|
|
70
|
+
rightIcon?: React.ReactNode
|
|
71
|
+
loading?: boolean
|
|
72
|
+
loadingText?: string
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
76
|
+
({
|
|
77
|
+
className,
|
|
78
|
+
variant,
|
|
79
|
+
size,
|
|
80
|
+
asChild = false,
|
|
81
|
+
leftIcon,
|
|
82
|
+
rightIcon,
|
|
83
|
+
loading = false,
|
|
84
|
+
loadingText,
|
|
85
|
+
children,
|
|
86
|
+
disabled,
|
|
87
|
+
...props
|
|
88
|
+
}, ref) => {
|
|
89
|
+
const Comp = asChild ? Slot : "button"
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Comp
|
|
93
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
94
|
+
ref={ref}
|
|
95
|
+
disabled={disabled || loading}
|
|
96
|
+
{...props}
|
|
97
|
+
>
|
|
98
|
+
{loading ? (
|
|
99
|
+
<>
|
|
100
|
+
<Loader2 className="animate-spin" />
|
|
101
|
+
{loadingText || children}
|
|
102
|
+
</>
|
|
103
|
+
) : (
|
|
104
|
+
<>
|
|
105
|
+
{leftIcon}
|
|
106
|
+
{children}
|
|
107
|
+
{rightIcon}
|
|
108
|
+
</>
|
|
109
|
+
)}
|
|
110
|
+
</Comp>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
Button.displayName = "Button"
|
|
115
|
+
|
|
116
|
+
export { Button, buttonVariants }
|
|
117
|
+
`
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/commands/add.ts
|
|
125
|
+
async function add(components, options) {
|
|
126
|
+
const cwd = process.cwd();
|
|
127
|
+
const configPath = path.join(cwd, "components.json");
|
|
128
|
+
if (!await fs.pathExists(configPath)) {
|
|
129
|
+
console.log(chalk.red("\n Error: Project not initialized."));
|
|
130
|
+
console.log(chalk.yellow(" Run `npx myoperator-ui init` first.\n"));
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
const registry = await getRegistry();
|
|
134
|
+
const availableComponents = Object.keys(registry);
|
|
135
|
+
if (!components || components.length === 0) {
|
|
136
|
+
const { selectedComponents } = await prompts({
|
|
137
|
+
type: "multiselect",
|
|
138
|
+
name: "selectedComponents",
|
|
139
|
+
message: "Which components would you like to add?",
|
|
140
|
+
choices: availableComponents.map((name) => ({
|
|
141
|
+
title: name,
|
|
142
|
+
value: name,
|
|
143
|
+
description: registry[name].description
|
|
144
|
+
})),
|
|
145
|
+
min: 1
|
|
146
|
+
});
|
|
147
|
+
if (!selectedComponents || selectedComponents.length === 0) {
|
|
148
|
+
console.log(chalk.yellow("\n No components selected.\n"));
|
|
149
|
+
process.exit(0);
|
|
150
|
+
}
|
|
151
|
+
components = selectedComponents;
|
|
152
|
+
}
|
|
153
|
+
const invalidComponents = components.filter((c) => !availableComponents.includes(c));
|
|
154
|
+
if (invalidComponents.length > 0) {
|
|
155
|
+
console.log(chalk.red(`
|
|
156
|
+
Error: Unknown components: ${invalidComponents.join(", ")}`));
|
|
157
|
+
console.log(chalk.yellow(` Available: ${availableComponents.join(", ")}
|
|
158
|
+
`));
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
const config = await fs.readJson(configPath);
|
|
162
|
+
const componentsDir = path.join(cwd, options.path);
|
|
163
|
+
if (!options.yes) {
|
|
164
|
+
const { confirm } = await prompts({
|
|
165
|
+
type: "confirm",
|
|
166
|
+
name: "confirm",
|
|
167
|
+
message: `Add ${components.length} component(s) to ${options.path}?`,
|
|
168
|
+
initial: true
|
|
169
|
+
});
|
|
170
|
+
if (!confirm) {
|
|
171
|
+
console.log(chalk.yellow("\n Installation cancelled.\n"));
|
|
172
|
+
process.exit(0);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
console.log("");
|
|
176
|
+
const spinner = ora("Installing components...").start();
|
|
177
|
+
try {
|
|
178
|
+
const installed = [];
|
|
179
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
180
|
+
for (const componentName of components) {
|
|
181
|
+
const component = registry[componentName];
|
|
182
|
+
for (const file of component.files) {
|
|
183
|
+
const filePath = path.join(componentsDir, file.name);
|
|
184
|
+
if (await fs.pathExists(filePath)) {
|
|
185
|
+
if (!options.overwrite) {
|
|
186
|
+
spinner.warn(`${file.name} already exists. Use --overwrite to replace.`);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
191
|
+
await fs.writeFile(filePath, file.content);
|
|
192
|
+
installed.push(file.name);
|
|
193
|
+
}
|
|
194
|
+
if (component.dependencies) {
|
|
195
|
+
component.dependencies.forEach((dep) => dependencies.add(dep));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
spinner.succeed("Components installed successfully!");
|
|
199
|
+
if (installed.length > 0) {
|
|
200
|
+
console.log(chalk.green("\n Installed files:"));
|
|
201
|
+
installed.forEach((file) => {
|
|
202
|
+
console.log(chalk.green(` \u2713 ${options.path}/${file}`));
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (dependencies.size > 0) {
|
|
206
|
+
console.log(chalk.yellow("\n Required dependencies:"));
|
|
207
|
+
console.log(chalk.cyan(` npm install ${Array.from(dependencies).join(" ")}`));
|
|
208
|
+
}
|
|
209
|
+
console.log("");
|
|
210
|
+
} catch (error) {
|
|
211
|
+
spinner.fail("Failed to install components");
|
|
212
|
+
console.error(error);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/commands/init.ts
|
|
218
|
+
import chalk2 from "chalk";
|
|
219
|
+
import fs2 from "fs-extra";
|
|
220
|
+
import path2 from "path";
|
|
221
|
+
import prompts2 from "prompts";
|
|
222
|
+
import ora2 from "ora";
|
|
223
|
+
var DEFAULT_CONFIG = {
|
|
224
|
+
$schema: "https://myoperator.com/schema.json",
|
|
225
|
+
style: "default",
|
|
226
|
+
tailwind: {
|
|
227
|
+
config: "tailwind.config.js",
|
|
228
|
+
css: "src/index.css",
|
|
229
|
+
baseColor: "slate",
|
|
230
|
+
cssVariables: true
|
|
231
|
+
},
|
|
232
|
+
aliases: {
|
|
233
|
+
components: "@/components",
|
|
234
|
+
utils: "@/lib/utils",
|
|
235
|
+
ui: "@/components/ui"
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
async function init() {
|
|
239
|
+
console.log(chalk2.bold("\n Welcome to myOperator UI!\n"));
|
|
240
|
+
const cwd = process.cwd();
|
|
241
|
+
const configPath = path2.join(cwd, "components.json");
|
|
242
|
+
if (await fs2.pathExists(configPath)) {
|
|
243
|
+
const { overwrite } = await prompts2({
|
|
244
|
+
type: "confirm",
|
|
245
|
+
name: "overwrite",
|
|
246
|
+
message: "components.json already exists. Overwrite?",
|
|
247
|
+
initial: false
|
|
248
|
+
});
|
|
249
|
+
if (!overwrite) {
|
|
250
|
+
console.log(chalk2.yellow(" Initialization cancelled.\n"));
|
|
251
|
+
process.exit(0);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const response = await prompts2([
|
|
255
|
+
{
|
|
256
|
+
type: "text",
|
|
257
|
+
name: "componentsPath",
|
|
258
|
+
message: "Where would you like to install components?",
|
|
259
|
+
initial: "src/components/ui"
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
type: "text",
|
|
263
|
+
name: "utilsPath",
|
|
264
|
+
message: "Where is your utils file?",
|
|
265
|
+
initial: "src/lib/utils.ts"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
type: "text",
|
|
269
|
+
name: "tailwindConfig",
|
|
270
|
+
message: "Where is your tailwind.config.js?",
|
|
271
|
+
initial: "tailwind.config.js"
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
type: "text",
|
|
275
|
+
name: "globalCss",
|
|
276
|
+
message: "Where is your global CSS file?",
|
|
277
|
+
initial: "src/index.css"
|
|
278
|
+
}
|
|
279
|
+
]);
|
|
280
|
+
const spinner = ora2("Initializing project...").start();
|
|
281
|
+
try {
|
|
282
|
+
const config = {
|
|
283
|
+
...DEFAULT_CONFIG,
|
|
284
|
+
tailwind: {
|
|
285
|
+
...DEFAULT_CONFIG.tailwind,
|
|
286
|
+
config: response.tailwindConfig,
|
|
287
|
+
css: response.globalCss
|
|
288
|
+
},
|
|
289
|
+
aliases: {
|
|
290
|
+
...DEFAULT_CONFIG.aliases,
|
|
291
|
+
ui: `@/${response.componentsPath.replace("src/", "")}`
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
await fs2.writeJson(configPath, config, { spaces: 2 });
|
|
295
|
+
const utilsPath = path2.join(cwd, response.utilsPath);
|
|
296
|
+
if (!await fs2.pathExists(utilsPath)) {
|
|
297
|
+
await fs2.ensureDir(path2.dirname(utilsPath));
|
|
298
|
+
await fs2.writeFile(
|
|
299
|
+
utilsPath,
|
|
300
|
+
`import { type ClassValue, clsx } from "clsx"
|
|
301
|
+
import { twMerge } from "tailwind-merge"
|
|
302
|
+
|
|
303
|
+
export function cn(...inputs: ClassValue[]) {
|
|
304
|
+
return twMerge(clsx(inputs))
|
|
305
|
+
}
|
|
306
|
+
`
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
const componentsPath = path2.join(cwd, response.componentsPath);
|
|
310
|
+
await fs2.ensureDir(componentsPath);
|
|
311
|
+
spinner.succeed("Project initialized successfully!");
|
|
312
|
+
console.log(chalk2.green("\n \u2713 Created components.json"));
|
|
313
|
+
console.log(chalk2.green(` \u2713 Created ${response.utilsPath}`));
|
|
314
|
+
console.log(chalk2.green(` \u2713 Created ${response.componentsPath}
|
|
315
|
+
`));
|
|
316
|
+
console.log(chalk2.bold(" Next steps:\n"));
|
|
317
|
+
console.log(" 1. Install dependencies:");
|
|
318
|
+
console.log(chalk2.cyan(" npm install clsx tailwind-merge class-variance-authority\n"));
|
|
319
|
+
console.log(" 2. Add your first component:");
|
|
320
|
+
console.log(chalk2.cyan(" npx myoperator-ui add button\n"));
|
|
321
|
+
} catch (error) {
|
|
322
|
+
spinner.fail("Failed to initialize project");
|
|
323
|
+
console.error(error);
|
|
324
|
+
process.exit(1);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// src/index.ts
|
|
329
|
+
var program = new Command();
|
|
330
|
+
program.name("myoperator-ui").description("CLI for adding myOperator UI components to your project").version("0.0.1");
|
|
331
|
+
program.command("init").description("Initialize your project with myOperator UI").action(init);
|
|
332
|
+
program.command("add").description("Add a component to your project").argument("[components...]", "Components to add").option("-y, --yes", "Skip confirmation prompt", false).option("-o, --overwrite", "Overwrite existing files", false).option("-p, --path <path>", "Path to add components to", "src/components/ui").action(add);
|
|
333
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "myoperator-ui",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "CLI for adding myOperator UI components to your project",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"myoperator-ui": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
15
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
16
|
+
"typecheck": "tsc --noEmit"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"chalk": "^5.3.0",
|
|
20
|
+
"commander": "^12.1.0",
|
|
21
|
+
"fs-extra": "^11.2.0",
|
|
22
|
+
"ora": "^8.0.1",
|
|
23
|
+
"prompts": "^2.4.2"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/fs-extra": "^11.0.4",
|
|
27
|
+
"@types/node": "^20.11.0",
|
|
28
|
+
"@types/prompts": "^2.4.9",
|
|
29
|
+
"tsup": "^8.0.1",
|
|
30
|
+
"typescript": "^5.3.3"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"myoperator",
|
|
34
|
+
"ui",
|
|
35
|
+
"components",
|
|
36
|
+
"cli",
|
|
37
|
+
"react"
|
|
38
|
+
],
|
|
39
|
+
"author": "",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/Ankish8/storybook-npm.git"
|
|
44
|
+
}
|
|
45
|
+
}
|