@tokiui/cli 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 (2) hide show
  1. package/dist/index.js +273 -0
  2. package/package.json +47 -0
package/dist/index.js ADDED
@@ -0,0 +1,273 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/index.ts
27
+ var import_commander4 = require("commander");
28
+
29
+ // src/commands/init.ts
30
+ var import_commander = require("commander");
31
+ var import_path2 = __toESM(require("path"));
32
+ var import_fs_extra2 = __toESM(require("fs-extra"));
33
+ var import_prompts = __toESM(require("prompts"));
34
+ var import_kleur = __toESM(require("kleur"));
35
+ var import_ora = __toESM(require("ora"));
36
+
37
+ // src/utils/config.ts
38
+ var import_path = __toESM(require("path"));
39
+ var import_fs_extra = __toESM(require("fs-extra"));
40
+ var CONFIG_FILE = "tokiui.json";
41
+ function getConfig(cwd) {
42
+ const configPath = import_path.default.join(cwd, CONFIG_FILE);
43
+ if (!import_fs_extra.default.existsSync(configPath)) return null;
44
+ return import_fs_extra.default.readJsonSync(configPath);
45
+ }
46
+ function writeConfig(cwd, config) {
47
+ const configPath = import_path.default.join(cwd, CONFIG_FILE);
48
+ import_fs_extra.default.writeJsonSync(configPath, config, { spaces: 2 });
49
+ }
50
+ function detectPackageManager(cwd) {
51
+ if (import_fs_extra.default.existsSync(import_path.default.join(cwd, "bun.lockb"))) return "bun";
52
+ if (import_fs_extra.default.existsSync(import_path.default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
53
+ if (import_fs_extra.default.existsSync(import_path.default.join(cwd, "yarn.lock"))) return "yarn";
54
+ return "npm";
55
+ }
56
+
57
+ // src/commands/init.ts
58
+ var initCommand = new import_commander.Command("init").description("Initialize tokiui in your project").action(async () => {
59
+ const cwd = process.cwd();
60
+ console.log(import_kleur.default.bold("\nInitializing tokiui...\n"));
61
+ const answers = await (0, import_prompts.default)([
62
+ {
63
+ type: "text",
64
+ name: "componentsDir",
65
+ message: "Where should components be installed?",
66
+ initial: "src/components/ui"
67
+ },
68
+ {
69
+ type: "text",
70
+ name: "libDir",
71
+ message: "Where should utility files be placed?",
72
+ initial: "src/lib"
73
+ }
74
+ ]);
75
+ if (!answers.componentsDir) {
76
+ console.log(import_kleur.default.red("Aborted."));
77
+ process.exit(0);
78
+ }
79
+ const spinner = (0, import_ora.default)("Setting up project...").start();
80
+ await import_fs_extra2.default.ensureDir(import_path2.default.join(cwd, answers.componentsDir));
81
+ await import_fs_extra2.default.ensureDir(import_path2.default.join(cwd, answers.libDir));
82
+ const cnPath = import_path2.default.join(cwd, answers.libDir, "utils.ts");
83
+ if (!import_fs_extra2.default.existsSync(cnPath)) {
84
+ await import_fs_extra2.default.writeFile(
85
+ cnPath,
86
+ `import { clsx, type ClassValue } from 'clsx'
87
+ import { twMerge } from 'tailwind-merge'
88
+
89
+ export function cn(...inputs: ClassValue[]) {
90
+ return twMerge(clsx(inputs))
91
+ }
92
+ `
93
+ );
94
+ }
95
+ writeConfig(cwd, {
96
+ componentsDir: answers.componentsDir,
97
+ libDir: answers.libDir,
98
+ style: "default"
99
+ });
100
+ spinner.succeed("Project initialized");
101
+ console.log(import_kleur.default.green("\n\u2713 tokiui initialized successfully"));
102
+ console.log(import_kleur.default.dim("\nNext: run `npx tokiui add <component>` to add components\n"));
103
+ });
104
+
105
+ // src/commands/add.ts
106
+ var import_commander2 = require("commander");
107
+ var import_path3 = __toESM(require("path"));
108
+ var import_fs_extra3 = __toESM(require("fs-extra"));
109
+ var import_prompts2 = __toESM(require("prompts"));
110
+ var import_kleur2 = __toESM(require("kleur"));
111
+ var import_ora2 = __toESM(require("ora"));
112
+ var import_execa = require("execa");
113
+
114
+ // src/utils/registry.ts
115
+ var REGISTRY_BASE = "https://raw.githubusercontent.com/TopherGacad/tokiui/main/packages/registry";
116
+ async function fetchRegistryIndex() {
117
+ const res = await fetch(`${REGISTRY_BASE}/index.json`);
118
+ if (!res.ok) throw new Error(`Failed to fetch registry index: ${res.statusText}`);
119
+ return res.json();
120
+ }
121
+ async function fetchComponent(name) {
122
+ const res = await fetch(`${REGISTRY_BASE}/components/${name}.json`);
123
+ if (!res.ok) throw new Error(`Component "${name}" not found in registry`);
124
+ return res.json();
125
+ }
126
+ async function fetchComponentSource(name, file) {
127
+ const res = await fetch(
128
+ `https://raw.githubusercontent.com/TopherGacad/tokiui/main/packages/ui/src/${file}`
129
+ );
130
+ if (!res.ok) throw new Error(`Failed to fetch source for ${name}/${file}`);
131
+ return res.text();
132
+ }
133
+
134
+ // src/utils/transforms.ts
135
+ function transformImports(source, libDir) {
136
+ return source.replace(/from ['"]\.\.\/lib\/utils['"]/g, `from '${libDir}/utils'`);
137
+ }
138
+
139
+ // src/commands/add.ts
140
+ var addCommand = new import_commander2.Command("add").description("Add a component to your project").argument("[component]", "Component name to add").action(async (componentArg) => {
141
+ const cwd = process.cwd();
142
+ const config = getConfig(cwd);
143
+ if (!config) {
144
+ console.log(
145
+ import_kleur2.default.red("No tokiui.json found. Run `npx tokiui init` first.")
146
+ );
147
+ process.exit(1);
148
+ }
149
+ let componentName = componentArg;
150
+ if (!componentName) {
151
+ const spinner = (0, import_ora2.default)("Fetching component list...").start();
152
+ const index = await fetchRegistryIndex().catch(() => {
153
+ spinner.fail("Failed to fetch registry");
154
+ process.exit(1);
155
+ });
156
+ spinner.stop();
157
+ const answer = await (0, import_prompts2.default)({
158
+ type: "multiselect",
159
+ name: "components",
160
+ message: "Which components would you like to add?",
161
+ choices: index.components.map((c) => ({ title: c.label, value: c.name })),
162
+ min: 1
163
+ });
164
+ if (!answer.components?.length) {
165
+ console.log(import_kleur2.default.red("Aborted."));
166
+ process.exit(0);
167
+ }
168
+ for (const name of answer.components) {
169
+ await installComponent(name, cwd, config.componentsDir, config.libDir);
170
+ }
171
+ return;
172
+ }
173
+ await installComponent(componentName, cwd, config.componentsDir, config.libDir);
174
+ });
175
+ async function installComponent(name, cwd, componentsDir, libDir) {
176
+ const spinner = (0, import_ora2.default)(`Adding ${name}...`).start();
177
+ const meta = await fetchComponent(name).catch(() => {
178
+ spinner.fail(`Component "${name}" not found`);
179
+ process.exit(1);
180
+ });
181
+ for (const dep of meta.registryDependencies) {
182
+ await installComponent(dep, cwd, componentsDir, libDir);
183
+ }
184
+ for (const file of meta.files) {
185
+ const source = await fetchComponentSource(name, file);
186
+ const transformed = transformImports(source, `@/${libDir}`);
187
+ const destPath = import_path3.default.join(cwd, componentsDir, import_path3.default.basename(file));
188
+ if (import_fs_extra3.default.existsSync(destPath)) {
189
+ spinner.stop();
190
+ const { overwrite } = await (0, import_prompts2.default)({
191
+ type: "confirm",
192
+ name: "overwrite",
193
+ message: `${import_path3.default.basename(file)} already exists. Overwrite?`,
194
+ initial: false
195
+ });
196
+ if (!overwrite) {
197
+ console.log(import_kleur2.default.dim(`Skipped ${import_path3.default.basename(file)}`));
198
+ continue;
199
+ }
200
+ spinner.start(`Adding ${name}...`);
201
+ }
202
+ await import_fs_extra3.default.ensureDir(import_path3.default.dirname(destPath));
203
+ await import_fs_extra3.default.writeFile(destPath, transformed);
204
+ }
205
+ if (meta.dependencies.length > 0) {
206
+ const pm = detectPackageManager(cwd);
207
+ const installCmd = pm === "npm" ? "install" : "add";
208
+ await (0, import_execa.execa)(pm, [installCmd, ...meta.dependencies], { cwd });
209
+ }
210
+ spinner.succeed(`Added ${import_kleur2.default.bold(name)}`);
211
+ }
212
+
213
+ // src/commands/theme.ts
214
+ var import_commander3 = require("commander");
215
+ var import_path4 = __toESM(require("path"));
216
+ var import_fs_extra4 = __toESM(require("fs-extra"));
217
+ var import_kleur3 = __toESM(require("kleur"));
218
+ var themeApplyCommand = new import_commander3.Command("apply").description("Apply a shared theme URL string to your globals.css").argument("<encoded>", "Encoded theme string from the tokiui playground").action(async (encoded) => {
219
+ const cwd = process.cwd();
220
+ const config = getConfig(cwd);
221
+ let tokens;
222
+ try {
223
+ tokens = JSON.parse(Buffer.from(encoded, "base64").toString("utf-8"));
224
+ } catch {
225
+ console.log(import_kleur3.default.red("Invalid theme string. Copy it from the tokiui playground."));
226
+ process.exit(1);
227
+ }
228
+ const candidates = [
229
+ "src/app/globals.css",
230
+ "src/styles/globals.css",
231
+ "styles/globals.css",
232
+ "app/globals.css"
233
+ ];
234
+ let globalsPath = null;
235
+ for (const candidate of candidates) {
236
+ if (import_fs_extra4.default.existsSync(import_path4.default.join(cwd, candidate))) {
237
+ globalsPath = import_path4.default.join(cwd, candidate);
238
+ break;
239
+ }
240
+ }
241
+ if (!globalsPath) {
242
+ console.log(
243
+ import_kleur3.default.red(
244
+ "Could not find globals.css. Specify the path manually or create it first."
245
+ )
246
+ );
247
+ process.exit(1);
248
+ }
249
+ let css = await import_fs_extra4.default.readFile(globalsPath, "utf-8");
250
+ for (const [key, value] of Object.entries(tokens)) {
251
+ const cssVar = `--${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
252
+ if (cssVar === "--radius") {
253
+ css = css.replace(/(--radius:\s*)([^;]+)(;)/g, `$1${value}$3`);
254
+ } else {
255
+ const regex = new RegExp(`(${cssVar}:\\s*)([^;]+)(;)`, "g");
256
+ css = css.replace(regex, `$1${value}$3`);
257
+ }
258
+ }
259
+ await import_fs_extra4.default.writeFile(globalsPath, css);
260
+ console.log(import_kleur3.default.green(`\u2713 Theme applied to ${import_path4.default.relative(cwd, globalsPath)}`));
261
+ if (config) {
262
+ console.log(import_kleur3.default.dim("Restart your dev server to see changes."));
263
+ }
264
+ });
265
+ var themeCommand = new import_commander3.Command("theme").description("Manage themes").addCommand(themeApplyCommand);
266
+
267
+ // src/index.ts
268
+ var program = new import_commander4.Command();
269
+ program.name("tokiui").description("Add tokiui components to your project").version("0.0.1");
270
+ program.addCommand(initCommand);
271
+ program.addCommand(addCommand);
272
+ program.addCommand(themeCommand);
273
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@tokiui/cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI for adding tokiui components to your project",
5
+ "license": "MIT",
6
+ "author": "Topher Gacad",
7
+ "homepage": "https://github.com/TopherGacad/tokiui#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/TopherGacad/tokiui.git",
11
+ "directory": "packages/cli"
12
+ },
13
+ "keywords": [
14
+ "cli",
15
+ "tokiui",
16
+ "components",
17
+ "react",
18
+ "tailwind"
19
+ ],
20
+ "main": "./dist/index.js",
21
+ "bin": {
22
+ "tokiui": "./dist/index.js"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "dependencies": {
28
+ "commander": "^12.1.0",
29
+ "execa": "^9.3.0",
30
+ "fs-extra": "^11.2.0",
31
+ "kleur": "^4.1.5",
32
+ "ora": "^8.0.1",
33
+ "prompts": "^2.4.2"
34
+ },
35
+ "devDependencies": {
36
+ "@types/fs-extra": "^11.0.4",
37
+ "@types/node": "^20.14.0",
38
+ "@types/prompts": "^2.4.9",
39
+ "tsup": "^8.2.4",
40
+ "typescript": "^5.5.4"
41
+ },
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "dev": "tsup --watch",
45
+ "lint": "tsc --noEmit"
46
+ }
47
+ }