@quarklab/rad-ui 0.3.5 → 0.3.7
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/dist/index.js +160 -44
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -78,44 +78,48 @@ async function detectTailwindVersion(cwd, cssPath) {
|
|
|
78
78
|
return "v4";
|
|
79
79
|
}
|
|
80
80
|
async function detectSrcDir(cwd) {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
const
|
|
96
|
-
if (
|
|
81
|
+
const configFiles = ["tsconfig.json", "jsconfig.json"];
|
|
82
|
+
for (const file of configFiles) {
|
|
83
|
+
const configPath = path.resolve(cwd, file);
|
|
84
|
+
if (await fs.pathExists(configPath)) {
|
|
85
|
+
try {
|
|
86
|
+
const raw = await fs.readFile(configPath, "utf-8");
|
|
87
|
+
const cleaned = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
88
|
+
const config = JSON.parse(cleaned);
|
|
89
|
+
const paths = config?.compilerOptions?.paths;
|
|
90
|
+
if (paths) {
|
|
91
|
+
const aliasKey = Object.keys(paths).find(
|
|
92
|
+
(k) => k === "@/*" || k === "~/*"
|
|
93
|
+
);
|
|
94
|
+
if (aliasKey) {
|
|
95
|
+
const aliasTargets = paths[aliasKey];
|
|
96
|
+
if (Array.isArray(aliasTargets) && aliasTargets.length > 0) {
|
|
97
|
+
const target = aliasTargets[0].replace(/^\.\//, "").replace(/\/\*$/, "");
|
|
98
|
+
return target === "" ? "." : target;
|
|
99
|
+
}
|
|
97
100
|
}
|
|
98
101
|
}
|
|
102
|
+
} catch {
|
|
99
103
|
}
|
|
100
|
-
} catch {
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
if (await fs.pathExists(path.resolve(cwd, "src"))) return "src";
|
|
104
107
|
if (await fs.pathExists(path.resolve(cwd, "app"))) return "app";
|
|
105
108
|
return "src";
|
|
106
109
|
}
|
|
107
|
-
function getDefaultCssPath(projectType) {
|
|
110
|
+
function getDefaultCssPath(projectType, srcDir) {
|
|
111
|
+
const prefix = srcDir === "." ? "" : srcDir ? `${srcDir}/` : "src/";
|
|
108
112
|
switch (projectType) {
|
|
109
113
|
case "nextjs":
|
|
110
|
-
return
|
|
114
|
+
return `${prefix}app/globals.css`;
|
|
111
115
|
case "vite":
|
|
112
|
-
return
|
|
116
|
+
return `${prefix}index.css`;
|
|
113
117
|
case "cra":
|
|
114
|
-
return
|
|
118
|
+
return `${prefix}index.css`;
|
|
115
119
|
case "expo":
|
|
116
120
|
return "global.css";
|
|
117
121
|
default:
|
|
118
|
-
return
|
|
122
|
+
return `${prefix}globals.css`;
|
|
119
123
|
}
|
|
120
124
|
}
|
|
121
125
|
function getDefaultTailwindConfig(projectType) {
|
|
@@ -143,19 +147,32 @@ async function readConfig(cwd) {
|
|
|
143
147
|
if (!exists) {
|
|
144
148
|
throw new Error(`Configuration file not found. Run \`rad-ui init\` first.`);
|
|
145
149
|
}
|
|
146
|
-
|
|
150
|
+
const config = await fs2.readJson(configPath);
|
|
151
|
+
if (!config.aliases.hooks) {
|
|
152
|
+
config.aliases.hooks = "@/hooks";
|
|
153
|
+
}
|
|
154
|
+
return config;
|
|
147
155
|
}
|
|
148
156
|
async function writeConfig(cwd, config) {
|
|
149
157
|
const configPath = getConfigPath(cwd);
|
|
150
158
|
await fs2.writeJson(configPath, config, { spaces: 2 });
|
|
151
159
|
}
|
|
152
160
|
function resolveAlias(alias, srcDir) {
|
|
153
|
-
|
|
161
|
+
const prefix = srcDir === "." ? "" : srcDir + "/";
|
|
162
|
+
return alias.replace(/^@\//, prefix).replace(/^~\//, prefix);
|
|
154
163
|
}
|
|
155
164
|
function resolveComponentsDir(cwd, config) {
|
|
156
165
|
const relPath = resolveAlias(config.aliases.components, config.srcDir);
|
|
157
166
|
return path2.resolve(cwd, relPath);
|
|
158
167
|
}
|
|
168
|
+
function resolveUtilsDir(cwd, config) {
|
|
169
|
+
const relPath = resolveAlias(config.aliases.utils, config.srcDir);
|
|
170
|
+
return path2.resolve(cwd, path2.dirname(relPath));
|
|
171
|
+
}
|
|
172
|
+
function resolveHooksDir(cwd, config) {
|
|
173
|
+
const relPath = resolveAlias(config.aliases.hooks, config.srcDir);
|
|
174
|
+
return path2.resolve(cwd, relPath);
|
|
175
|
+
}
|
|
159
176
|
|
|
160
177
|
// src/registry/themes.ts
|
|
161
178
|
var themes = [
|
|
@@ -166,7 +183,7 @@ var themes = [
|
|
|
166
183
|
light: {
|
|
167
184
|
"--background": "40 20% 98%",
|
|
168
185
|
"--foreground": "220 15% 15%",
|
|
169
|
-
"--primary": "
|
|
186
|
+
"--primary": "35 55% 51%",
|
|
170
187
|
"--primary-foreground": "0 0% 100%",
|
|
171
188
|
"--secondary": "40 10% 92%",
|
|
172
189
|
"--secondary-foreground": "220 15% 15%",
|
|
@@ -177,13 +194,13 @@ var themes = [
|
|
|
177
194
|
"--border": "40 10% 88%",
|
|
178
195
|
"--muted": "40 10% 92%",
|
|
179
196
|
"--muted-foreground": "220 10% 40%",
|
|
180
|
-
"--ring": "
|
|
197
|
+
"--ring": "35 55% 51%",
|
|
181
198
|
"--radius": "0.5rem"
|
|
182
199
|
},
|
|
183
200
|
dark: {
|
|
184
201
|
"--background": "222 47% 11%",
|
|
185
202
|
"--foreground": "210 40% 98%",
|
|
186
|
-
"--primary": "
|
|
203
|
+
"--primary": "35 55% 60%",
|
|
187
204
|
"--primary-foreground": "222 47% 11%",
|
|
188
205
|
"--secondary": "217 33% 17%",
|
|
189
206
|
"--secondary-foreground": "210 40% 98%",
|
|
@@ -194,7 +211,7 @@ var themes = [
|
|
|
194
211
|
"--border": "217 33% 20%",
|
|
195
212
|
"--muted": "217 33% 17%",
|
|
196
213
|
"--muted-foreground": "210 20% 70%",
|
|
197
|
-
"--ring": "
|
|
214
|
+
"--ring": "35 55% 60%"
|
|
198
215
|
}
|
|
199
216
|
}
|
|
200
217
|
},
|
|
@@ -462,14 +479,16 @@ async function initCommand(opts) {
|
|
|
462
479
|
const projectType = await detectProjectType(cwd);
|
|
463
480
|
const packageManager = await detectPackageManager(cwd);
|
|
464
481
|
const detectedSrcDir = await detectSrcDir(cwd);
|
|
465
|
-
const defaultCssPath = getDefaultCssPath(projectType);
|
|
482
|
+
const defaultCssPath = getDefaultCssPath(projectType, detectedSrcDir);
|
|
466
483
|
const tailwindVersion = await detectTailwindVersion(cwd, defaultCssPath);
|
|
467
484
|
if (projectType !== "unknown") {
|
|
468
485
|
p.log.info(`Detected project: ${chalk2.cyan(projectType)}`);
|
|
469
486
|
}
|
|
470
487
|
p.log.info(`Package manager: ${chalk2.cyan(packageManager)}`);
|
|
471
488
|
p.log.info(`Tailwind CSS: ${chalk2.cyan(tailwindVersion)}`);
|
|
472
|
-
|
|
489
|
+
const srcDirDisplay = detectedSrcDir === "." ? "project root" : detectedSrcDir + "/";
|
|
490
|
+
p.log.info(`Source directory: ${chalk2.cyan(srcDirDisplay)}`);
|
|
491
|
+
const examplePrefix = detectedSrcDir === "." ? "" : detectedSrcDir + "/";
|
|
473
492
|
const responses = await p.group(
|
|
474
493
|
{
|
|
475
494
|
theme: () => p.select({
|
|
@@ -481,20 +500,25 @@ async function initCommand(opts) {
|
|
|
481
500
|
initialValue: "kahgel"
|
|
482
501
|
}),
|
|
483
502
|
srcDir: () => p.text({
|
|
484
|
-
message: `Base directory that @ resolves to:`,
|
|
503
|
+
message: `Base directory that @ resolves to (use "." for project root):`,
|
|
485
504
|
placeholder: detectedSrcDir,
|
|
486
505
|
defaultValue: detectedSrcDir
|
|
487
506
|
}),
|
|
488
507
|
componentsPath: () => p.text({
|
|
489
|
-
message: `Where to add UI components (e.g. ${
|
|
508
|
+
message: `Where to add UI components (e.g. ${examplePrefix}components/ui):`,
|
|
490
509
|
placeholder: "@/components/ui",
|
|
491
510
|
defaultValue: "@/components/ui"
|
|
492
511
|
}),
|
|
493
512
|
utilsPath: () => p.text({
|
|
494
|
-
message: `Where to create the cn() helper (e.g. ${
|
|
513
|
+
message: `Where to create the cn() helper (e.g. ${examplePrefix}lib/utils.ts):`,
|
|
495
514
|
placeholder: "@/lib/utils",
|
|
496
515
|
defaultValue: "@/lib/utils"
|
|
497
516
|
}),
|
|
517
|
+
hooksPath: () => p.text({
|
|
518
|
+
message: `Where to add hooks (e.g. ${examplePrefix}hooks):`,
|
|
519
|
+
placeholder: "@/hooks",
|
|
520
|
+
defaultValue: "@/hooks"
|
|
521
|
+
}),
|
|
498
522
|
cssPath: () => p.text({
|
|
499
523
|
message: `Path to your global CSS file:`,
|
|
500
524
|
placeholder: defaultCssPath,
|
|
@@ -531,7 +555,8 @@ async function initCommand(opts) {
|
|
|
531
555
|
},
|
|
532
556
|
aliases: {
|
|
533
557
|
components: responses.componentsPath,
|
|
534
|
-
utils: responses.utilsPath
|
|
558
|
+
utils: responses.utilsPath,
|
|
559
|
+
hooks: responses.hooksPath
|
|
535
560
|
}
|
|
536
561
|
};
|
|
537
562
|
await writeConfig(cwd, config);
|
|
@@ -547,8 +572,12 @@ async function initCommand(opts) {
|
|
|
547
572
|
}
|
|
548
573
|
s.stop("Theme configured.");
|
|
549
574
|
s.start("Setting up utilities...");
|
|
575
|
+
const resolveAliasPath = (alias) => {
|
|
576
|
+
const prefix = srcDir === "." ? "" : srcDir + "/";
|
|
577
|
+
return alias.replace(/^@\//, prefix).replace(/^~\//, prefix);
|
|
578
|
+
};
|
|
550
579
|
const utilsAlias = config.aliases.utils;
|
|
551
|
-
const utilsRelPath = utilsAlias
|
|
580
|
+
const utilsRelPath = resolveAliasPath(utilsAlias) + ".ts";
|
|
552
581
|
const utilsDestPath = path3.resolve(cwd, utilsRelPath);
|
|
553
582
|
const utilsDir = path3.dirname(utilsDestPath);
|
|
554
583
|
await fs3.ensureDir(utilsDir);
|
|
@@ -564,7 +593,7 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
564
593
|
if (tailwindVersion === "v3" && config.tailwind.config) {
|
|
565
594
|
s.start("Configuring Tailwind CSS...");
|
|
566
595
|
const tailwindConfigPath = path3.resolve(cwd, config.tailwind.config);
|
|
567
|
-
const componentsRelPath = config.aliases.components
|
|
596
|
+
const componentsRelPath = resolveAliasPath(config.aliases.components);
|
|
568
597
|
if (await fs3.pathExists(tailwindConfigPath)) {
|
|
569
598
|
let tailwindContent = await fs3.readFile(tailwindConfigPath, "utf-8");
|
|
570
599
|
const contentPath = `./${componentsRelPath}/**/*.{ts,tsx}`;
|
|
@@ -712,6 +741,10 @@ module.exports = {
|
|
|
712
741
|
p.log.warn(`Please manually install: ${chalk2.cyan(baseDeps.join(" "))}`);
|
|
713
742
|
}
|
|
714
743
|
logger.break();
|
|
744
|
+
const showResolvedPath = (alias, addExtension) => {
|
|
745
|
+
const resolved = resolveAliasPath(alias);
|
|
746
|
+
return resolved + (addExtension || "");
|
|
747
|
+
};
|
|
715
748
|
p.note(
|
|
716
749
|
[
|
|
717
750
|
`${chalk2.green("Rad UI has been initialized!")}`,
|
|
@@ -721,8 +754,9 @@ module.exports = {
|
|
|
721
754
|
"",
|
|
722
755
|
`Theme: ${chalk2.cyan(selectedTheme?.label || config.theme)}`,
|
|
723
756
|
`Tailwind: ${chalk2.cyan(tailwindVersion)}`,
|
|
724
|
-
`Components: ${chalk2.cyan(config.aliases.components)} \u2192 ${chalk2.dim(
|
|
725
|
-
`Utils: ${chalk2.cyan(config.aliases.utils)} \u2192 ${chalk2.dim(
|
|
757
|
+
`Components: ${chalk2.cyan(config.aliases.components)} \u2192 ${chalk2.dim(showResolvedPath(config.aliases.components))}`,
|
|
758
|
+
`Utils: ${chalk2.cyan(config.aliases.utils)} \u2192 ${chalk2.dim(showResolvedPath(config.aliases.utils, ".ts"))}`,
|
|
759
|
+
`Hooks: ${chalk2.cyan(config.aliases.hooks)} \u2192 ${chalk2.dim(showResolvedPath(config.aliases.hooks))}`
|
|
726
760
|
].join("\n"),
|
|
727
761
|
"Next steps"
|
|
728
762
|
);
|
|
@@ -1035,6 +1069,48 @@ async function fetchRegistryIndex(registryUrl) {
|
|
|
1035
1069
|
}
|
|
1036
1070
|
|
|
1037
1071
|
// src/commands/add.ts
|
|
1072
|
+
function classifyFile(filePath) {
|
|
1073
|
+
const fileName = path4.basename(filePath);
|
|
1074
|
+
const ext = path4.extname(filePath);
|
|
1075
|
+
if (/^use[-_]?[a-zA-Z]/.test(fileName) && ext === ".ts") {
|
|
1076
|
+
return "hook";
|
|
1077
|
+
}
|
|
1078
|
+
if (ext === ".tsx") {
|
|
1079
|
+
return "component";
|
|
1080
|
+
}
|
|
1081
|
+
if (ext === ".ts") {
|
|
1082
|
+
return "util";
|
|
1083
|
+
}
|
|
1084
|
+
return "component";
|
|
1085
|
+
}
|
|
1086
|
+
function transformRelativeImports(content, originalFilePath, componentFiles, config, componentName) {
|
|
1087
|
+
let result = content;
|
|
1088
|
+
const relativeImportRegex = /from\s+["']\.\/([^"']+)["']/g;
|
|
1089
|
+
let match;
|
|
1090
|
+
while ((match = relativeImportRegex.exec(content)) !== null) {
|
|
1091
|
+
const importedModule = match[1];
|
|
1092
|
+
const importedFile = componentFiles.find((f) => {
|
|
1093
|
+
const baseName = path4.basename(f.originalPath, path4.extname(f.originalPath));
|
|
1094
|
+
return baseName === importedModule || f.originalPath.includes(`/${importedModule}.`) || f.originalPath.endsWith(`/${importedModule}.ts`) || f.originalPath.endsWith(`/${importedModule}.tsx`);
|
|
1095
|
+
});
|
|
1096
|
+
if (importedFile && importedFile.fileType !== "component") {
|
|
1097
|
+
let newImportPath;
|
|
1098
|
+
if (importedFile.fileType === "hook") {
|
|
1099
|
+
const hookFileName = path4.basename(importedFile.destPath, ".ts");
|
|
1100
|
+
newImportPath = `${config.aliases.hooks}/${hookFileName}`;
|
|
1101
|
+
} else {
|
|
1102
|
+
const utilFileName = path4.basename(importedFile.destPath, ".ts");
|
|
1103
|
+
const utilsBase = config.aliases.utils.replace(/\/utils$/, "");
|
|
1104
|
+
newImportPath = `${utilsBase}/${componentName}/${utilFileName}`;
|
|
1105
|
+
}
|
|
1106
|
+
result = result.replace(
|
|
1107
|
+
new RegExp(`from\\s+["']\\.\\/${importedModule}["']`, "g"),
|
|
1108
|
+
`from "${newImportPath}"`
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return result;
|
|
1113
|
+
}
|
|
1038
1114
|
async function getComponentContent(name, config) {
|
|
1039
1115
|
if (!config.registry) {
|
|
1040
1116
|
throw new Error(
|
|
@@ -1114,6 +1190,8 @@ async function addCommand(componentNames, opts) {
|
|
|
1114
1190
|
);
|
|
1115
1191
|
}
|
|
1116
1192
|
const componentsDir = opts.path ? path4.resolve(cwd, opts.path) : resolveComponentsDir(cwd, config);
|
|
1193
|
+
const hooksDir = resolveHooksDir(cwd, config);
|
|
1194
|
+
const utilsDir = resolveUtilsDir(cwd, config);
|
|
1117
1195
|
if (!opts.overwrite) {
|
|
1118
1196
|
const existing = [];
|
|
1119
1197
|
for (const name of allNames) {
|
|
@@ -1146,8 +1224,13 @@ async function addCommand(componentNames, opts) {
|
|
|
1146
1224
|
const s = p2.spinner();
|
|
1147
1225
|
s.start("Adding components...");
|
|
1148
1226
|
await fs4.ensureDir(componentsDir);
|
|
1227
|
+
await fs4.ensureDir(hooksDir);
|
|
1228
|
+
await fs4.ensureDir(utilsDir);
|
|
1149
1229
|
let copiedCount = 0;
|
|
1230
|
+
let hooksCount = 0;
|
|
1231
|
+
let utilsCount = 0;
|
|
1150
1232
|
const allDeps = [];
|
|
1233
|
+
const filePlacements = /* @__PURE__ */ new Map();
|
|
1151
1234
|
for (const name of allNames) {
|
|
1152
1235
|
const item = await getComponentContent(name, config);
|
|
1153
1236
|
if (!item || item.files.length === 0) {
|
|
@@ -1157,17 +1240,50 @@ async function addCommand(componentNames, opts) {
|
|
|
1157
1240
|
if (item.dependencies) {
|
|
1158
1241
|
allDeps.push(...item.dependencies);
|
|
1159
1242
|
}
|
|
1243
|
+
const componentFiles = [];
|
|
1160
1244
|
for (const file of item.files) {
|
|
1161
|
-
let content = file.content;
|
|
1162
|
-
content = transformImports(content, config);
|
|
1163
1245
|
const relPath = file.path.replace(/^ui\//, "");
|
|
1164
|
-
const
|
|
1165
|
-
|
|
1166
|
-
|
|
1246
|
+
const fileName = path4.basename(relPath);
|
|
1247
|
+
const fileType = classifyFile(relPath);
|
|
1248
|
+
let destPath;
|
|
1249
|
+
if (fileType === "component") {
|
|
1250
|
+
destPath = path4.resolve(componentsDir, relPath);
|
|
1251
|
+
} else if (fileType === "hook") {
|
|
1252
|
+
destPath = path4.resolve(hooksDir, fileName);
|
|
1253
|
+
hooksCount++;
|
|
1254
|
+
} else {
|
|
1255
|
+
destPath = path4.resolve(utilsDir, name, fileName);
|
|
1256
|
+
utilsCount++;
|
|
1257
|
+
}
|
|
1258
|
+
componentFiles.push({
|
|
1259
|
+
originalPath: relPath,
|
|
1260
|
+
destPath,
|
|
1261
|
+
content: file.content,
|
|
1262
|
+
fileType
|
|
1263
|
+
});
|
|
1264
|
+
filePlacements.set(relPath, { destPath, fileType });
|
|
1265
|
+
}
|
|
1266
|
+
for (const fileInfo of componentFiles) {
|
|
1267
|
+
let content = fileInfo.content;
|
|
1268
|
+
content = transformImports(content, config);
|
|
1269
|
+
if (fileInfo.fileType === "component") {
|
|
1270
|
+
content = transformRelativeImports(
|
|
1271
|
+
content,
|
|
1272
|
+
fileInfo.originalPath,
|
|
1273
|
+
componentFiles,
|
|
1274
|
+
config,
|
|
1275
|
+
name
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1278
|
+
await fs4.ensureDir(path4.dirname(fileInfo.destPath));
|
|
1279
|
+
await fs4.writeFile(fileInfo.destPath, content, "utf-8");
|
|
1167
1280
|
copiedCount++;
|
|
1168
1281
|
}
|
|
1169
1282
|
}
|
|
1170
|
-
|
|
1283
|
+
const summary = [`Added ${copiedCount} file(s)`];
|
|
1284
|
+
if (hooksCount > 0) summary.push(`${hooksCount} hook(s)`);
|
|
1285
|
+
if (utilsCount > 0) summary.push(`${utilsCount} util(s)`);
|
|
1286
|
+
s.stop(summary.join(", ") + ".");
|
|
1171
1287
|
const npmDeps = collectNpmDependencies(allNames);
|
|
1172
1288
|
const depsFromRegistry = [...new Set(allDeps)];
|
|
1173
1289
|
const depsToInstall = Object.entries(npmDeps).map(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quarklab/rad-ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "A CLI for adding Rad UI components to your project. Beautiful Persian-themed React components built on Radix UI and Tailwind CSS.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"type": "git",
|
|
45
45
|
"url": "git+https://github.com/quarklab/rad-ui.git"
|
|
46
46
|
},
|
|
47
|
-
"homepage": "https://
|
|
47
|
+
"homepage": "https://quarklab.dev"
|
|
48
48
|
}
|