7onic 0.1.4 → 0.1.6

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 (3) hide show
  1. package/dist/index.js +135 -24
  2. package/llms.txt +6 -5
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1198,7 +1198,7 @@ function installDeps(deps, options) {
1198
1198
  const commands = {
1199
1199
  npm: `npm install${devFlag} ${deps.join(" ")}`,
1200
1200
  pnpm: `pnpm add${devFlag} ${deps.join(" ")}`,
1201
- yarn: `yarn add${devFlag} ${deps.join(" ")}`,
1201
+ yarn: `yarn add --ignore-engines${devFlag} ${deps.join(" ")}`,
1202
1202
  bun: `bun add${devFlag} ${deps.join(" ")}`
1203
1203
  };
1204
1204
  (0, import_node_child_process.execSync)(commands[pm], { cwd, stdio: "pipe" });
@@ -1246,7 +1246,11 @@ var CSS_V3_IMPORTS = `@import '@7onic-ui/tokens/css/variables.css';
1246
1246
  @import '@7onic-ui/tokens/css/themes/light.css';
1247
1247
  @import '@7onic-ui/tokens/css/themes/dark.css';
1248
1248
  `;
1249
- var CSS_V4_IMPORTS = `@import '@7onic-ui/tokens/css/variables.css';
1249
+ var CSS_V4_IMPORTS = `@import "tailwindcss";
1250
+ @import '@7onic-ui/tokens/css/variables.css';
1251
+ @import '@7onic-ui/tokens/tailwind/v4.css';
1252
+ `;
1253
+ var CSS_V4_TOKEN_ONLY = `@import '@7onic-ui/tokens/css/variables.css';
1250
1254
  @import '@7onic-ui/tokens/tailwind/v4.css';
1251
1255
  `;
1252
1256
  async function init(args) {
@@ -1281,15 +1285,37 @@ async function init(args) {
1281
1285
  const tw = detectTailwindVersion(projectRoot);
1282
1286
  const pm = detectPackageManager(projectRoot);
1283
1287
  let hasPathAlias = false;
1284
- try {
1285
- const tsConfigRaw = import_node_fs4.default.readFileSync(import_node_path4.default.join(projectRoot, "tsconfig.json"), "utf-8");
1286
- hasPathAlias = tsConfigRaw.includes('"@/');
1287
- } catch {
1288
+ const TSCONFIG_CANDIDATES = ["tsconfig.json", "tsconfig.app.json"];
1289
+ for (const tc of TSCONFIG_CANDIDATES) {
1290
+ try {
1291
+ const raw = import_node_fs4.default.readFileSync(import_node_path4.default.join(projectRoot, tc), "utf-8");
1292
+ if (raw.includes('"@/')) {
1293
+ hasPathAlias = true;
1294
+ break;
1295
+ }
1296
+ } catch {
1297
+ }
1288
1298
  }
1299
+ const viteConfigPath = import_node_fs4.default.existsSync(import_node_path4.default.join(projectRoot, "vite.config.ts")) ? import_node_path4.default.join(projectRoot, "vite.config.ts") : import_node_fs4.default.existsSync(import_node_path4.default.join(projectRoot, "vite.config.js")) ? import_node_path4.default.join(projectRoot, "vite.config.js") : null;
1300
+ const isViteProject = import_node_fs4.default.existsSync(import_node_path4.default.join(projectRoot, "tsconfig.app.json")) && viteConfigPath !== null;
1301
+ let needsTypesNode = false;
1289
1302
  if (!hasPathAlias) {
1290
- O2.warn(
1291
- "No @/ path alias detected in tsconfig.json.\n Components use @/lib/utils \u2014 make sure your project has path aliases configured.\n Next.js: automatic. Vite: add resolve.alias in vite.config.ts"
1292
- );
1303
+ if (isViteProject) {
1304
+ const tscPatch = patchTsconfigApp(import_node_path4.default.join(projectRoot, "tsconfig.app.json"));
1305
+ const vitePatch = patchViteConfig(viteConfigPath);
1306
+ if (vitePatch) needsTypesNode = true;
1307
+ if (tscPatch || vitePatch) {
1308
+ O2.success("Configured @/ path alias in tsconfig.app.json and vite.config.ts");
1309
+ } else {
1310
+ O2.warn(
1311
+ 'Could not auto-configure @/ path alias. Add manually:\n tsconfig.app.json \u2192 compilerOptions.paths: { "@/*": ["./src/*"] }\n vite.config.ts \u2192 resolve: { alias: { "@": path.resolve(__dirname, "./src") } }'
1312
+ );
1313
+ }
1314
+ } else {
1315
+ O2.warn(
1316
+ "No @/ path alias detected.\n Next.js: automatic (no action needed)\n Other: configure compilerOptions.paths in tsconfig.json"
1317
+ );
1318
+ }
1293
1319
  }
1294
1320
  try {
1295
1321
  const pkgJson = JSON.parse(import_node_fs4.default.readFileSync(import_node_path4.default.join(projectRoot, "package.json"), "utf-8"));
@@ -1353,6 +1379,9 @@ async function init(args) {
1353
1379
  s.start(`Installing dependencies (${pm})...`);
1354
1380
  try {
1355
1381
  installDeps(baseDeps, { cwd: projectRoot, pm });
1382
+ if (needsTypesNode) {
1383
+ installDeps(["@types/node"], { cwd: projectRoot, pm, dev: true });
1384
+ }
1356
1385
  s.stop("Dependencies installed");
1357
1386
  } catch (err) {
1358
1387
  s.stop("Failed to install dependencies");
@@ -1360,18 +1389,30 @@ async function init(args) {
1360
1389
  process.exit(1);
1361
1390
  }
1362
1391
  const cssFullPath = import_node_path4.default.join(projectRoot, config.cssPath);
1363
- const cssImports = tailwindVersion === 3 ? CSS_V3_IMPORTS : CSS_V4_IMPORTS;
1364
1392
  if (!import_node_fs4.default.existsSync(cssFullPath)) {
1365
1393
  const cssDir = import_node_path4.default.dirname(cssFullPath);
1366
1394
  if (!import_node_fs4.default.existsSync(cssDir)) {
1367
1395
  import_node_fs4.default.mkdirSync(cssDir, { recursive: true });
1368
1396
  }
1397
+ const cssImports = tailwindVersion === 3 ? CSS_V3_IMPORTS : CSS_V4_IMPORTS;
1369
1398
  import_node_fs4.default.writeFileSync(cssFullPath, cssImports, "utf-8");
1370
1399
  O2.success(`Created ${config.cssPath} with token imports`);
1371
1400
  } else {
1372
1401
  const cssContent = import_node_fs4.default.readFileSync(cssFullPath, "utf-8");
1373
1402
  if (!cssContent.includes("@7onic-ui/tokens")) {
1374
- import_node_fs4.default.writeFileSync(cssFullPath, cssImports + "\n" + cssContent, "utf-8");
1403
+ const tokenImports = tailwindVersion === 3 ? CSS_V3_IMPORTS : CSS_V4_TOKEN_ONLY;
1404
+ if (tailwindVersion === 4) {
1405
+ const twMatch = cssContent.match(/@import\s+["']tailwindcss["'].*\n/);
1406
+ if (twMatch) {
1407
+ const insertAt = twMatch.index + twMatch[0].length;
1408
+ const updated = cssContent.slice(0, insertAt) + tokenImports + cssContent.slice(insertAt);
1409
+ import_node_fs4.default.writeFileSync(cssFullPath, updated, "utf-8");
1410
+ } else {
1411
+ import_node_fs4.default.writeFileSync(cssFullPath, CSS_V4_IMPORTS + "\n" + cssContent, "utf-8");
1412
+ }
1413
+ } else {
1414
+ import_node_fs4.default.writeFileSync(cssFullPath, tokenImports + "\n" + cssContent, "utf-8");
1415
+ }
1375
1416
  O2.success(`Added token imports to ${config.cssPath}`);
1376
1417
  } else {
1377
1418
  O2.info(`Token imports already present in ${config.cssPath}`);
@@ -1434,6 +1475,48 @@ async function init(args) {
1434
1475
  O2.success("Created 7onic.json");
1435
1476
  gt("Done! Run " + import_picocolors2.default.cyan("npx 7onic add <component>") + " to add components.");
1436
1477
  }
1478
+ function patchTsconfigApp(tsconfigPath) {
1479
+ try {
1480
+ const raw = import_node_fs4.default.readFileSync(tsconfigPath, "utf-8");
1481
+ const clean = raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/,(\s*[}\]])/g, "$1");
1482
+ const tc = JSON.parse(clean);
1483
+ if (!tc.compilerOptions) tc.compilerOptions = {};
1484
+ const existingPaths = tc.compilerOptions.paths ?? {};
1485
+ if (existingPaths["@/*"]) return false;
1486
+ tc.compilerOptions.paths = { "@/*": ["./src/*"], ...existingPaths };
1487
+ import_node_fs4.default.writeFileSync(tsconfigPath, JSON.stringify(tc, null, 2), "utf-8");
1488
+ return true;
1489
+ } catch {
1490
+ return false;
1491
+ }
1492
+ }
1493
+ function patchViteConfig(viteConfigPath) {
1494
+ try {
1495
+ let content = import_node_fs4.default.readFileSync(viteConfigPath, "utf-8");
1496
+ if (content.includes("'@'") || content.includes('"@"') || content.includes("'@/*'") || content.includes('"@/*"') || content.includes("resolve:")) return false;
1497
+ if (!content.includes("import path from 'path'") && !content.includes('import path from "path"')) {
1498
+ const importMatches = [...content.matchAll(/^import .+$/gm)];
1499
+ const lastImport = importMatches.at(-1);
1500
+ if (lastImport?.index !== void 0) {
1501
+ const insertAt = lastImport.index + lastImport[0].length;
1502
+ content = content.slice(0, insertAt) + "\nimport path from 'path'" + content.slice(insertAt);
1503
+ }
1504
+ }
1505
+ const lastClose = content.lastIndexOf("\n})");
1506
+ if (lastClose === -1) return false;
1507
+ const beforeClose = content.slice(0, lastClose).trimEnd();
1508
+ const comma = beforeClose.endsWith(",") ? "" : ",";
1509
+ const resolveBlock = `${comma}
1510
+ resolve: {
1511
+ alias: { '@': path.resolve(__dirname, './src') },
1512
+ },`;
1513
+ content = content.slice(0, lastClose) + resolveBlock + content.slice(lastClose);
1514
+ import_node_fs4.default.writeFileSync(viteConfigPath, content, "utf-8");
1515
+ return true;
1516
+ } catch {
1517
+ return false;
1518
+ }
1519
+ }
1437
1520
  function resolveAliasPath(projectRoot, alias) {
1438
1521
  if (!alias.startsWith("@/")) return null;
1439
1522
  const relative = alias.slice(2);
@@ -3223,12 +3306,6 @@ const CardRoot = React.forwardRef<HTMLDivElement, CardProps>(
3223
3306
  CardRoot.displayName = 'Card'
3224
3307
 
3225
3308
  // \u2500\u2500 Size-based padding map (responsive: mobile \u2192 desktop) \u2500\u2500
3226
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3227
- const sizePaddingMap = {
3228
- sm: 'p-4', // 16px
3229
- default: 'p-4 sm:p-6', // 16px \u2192 24px
3230
- lg: 'p-6 sm:p-8', // 24px \u2192 32px
3231
- } as const
3232
3309
 
3233
3310
  const sizePaddingXMap = {
3234
3311
  sm: 'px-4', // 16px
@@ -8780,8 +8857,9 @@ const PaginationRoot = React.forwardRef<HTMLElement, PaginationProps>(
8780
8857
  color = 'default',
8781
8858
  radius = 'md',
8782
8859
  disabled = false,
8783
- withControls = true, // eslint-disable-line @typescript-eslint/no-unused-vars
8784
- withEdges = false, // eslint-disable-line @typescript-eslint/no-unused-vars
8860
+ // Pre-declared API; conditional auto-rendering is tracked in COMPONENT-IMPROVEMENTS.md.
8861
+ withControls: _withControls = true,
8862
+ withEdges: _withEdges = false,
8785
8863
  loop = false,
8786
8864
  children,
8787
8865
  ...props
@@ -13028,7 +13106,6 @@ const ToastItem = React.memo(function ToastItem({
13028
13106
  }: ToastItemProps) {
13029
13107
  const [isExiting, setIsExiting] = React.useState(false)
13030
13108
  const [isEntered, setIsEntered] = React.useState(false)
13031
- const [isPaused, setIsPaused] = React.useState(false) // eslint-disable-line @typescript-eslint/no-unused-vars
13032
13109
  const timerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)
13033
13110
  const remainingRef = React.useRef<number>(0)
13034
13111
  const startTimeRef = React.useRef<number>(0)
@@ -13095,10 +13172,9 @@ const ToastItem = React.memo(function ToastItem({
13095
13172
  }
13096
13173
  }, [duration, handleAutoClose])
13097
13174
 
13098
- // Pause/resume on hover
13175
+ // Pause/resume on hover (ref-only \u2014 no state update needed, avoids unnecessary re-renders)
13099
13176
  const handleMouseEnter = React.useCallback(() => {
13100
13177
  if (duration <= 0) return
13101
- setIsPaused(true)
13102
13178
  if (timerRef.current) {
13103
13179
  clearTimeout(timerRef.current)
13104
13180
  remainingRef.current -= Date.now() - startTimeRef.current
@@ -13107,7 +13183,6 @@ const ToastItem = React.memo(function ToastItem({
13107
13183
 
13108
13184
  const handleMouseLeave = React.useCallback(() => {
13109
13185
  if (duration <= 0) return
13110
- setIsPaused(false)
13111
13186
  startTimeRef.current = Date.now()
13112
13187
  timerRef.current = setTimeout(handleAutoClose, Math.max(remainingRef.current, TOAST_MIN_RESUME_MS))
13113
13188
  }, [duration, handleAutoClose])
@@ -14255,6 +14330,42 @@ async function add(args) {
14255
14330
  addedCount++;
14256
14331
  logger.success(`${entry.exists ? "Overwrote" : "Added"} ${entry.fileName}`);
14257
14332
  }
14333
+ if (config.tailwind.version === 4 && addedCount > 0) {
14334
+ try {
14335
+ const cssFullPath = import_node_path5.default.join(projectRoot, config.tailwind.css);
14336
+ if (import_node_fs5.default.existsSync(cssFullPath)) {
14337
+ const cssContent = import_node_fs5.default.readFileSync(cssFullPath, "utf-8");
14338
+ const cssDir = import_node_path5.default.dirname(cssFullPath);
14339
+ const relRaw = import_node_path5.default.relative(cssDir, componentsDir).replace(/\\/g, "/");
14340
+ const relSource = relRaw.startsWith(".") ? relRaw : `./${relRaw}`;
14341
+ const sourcePattern = new RegExp(`@source\\s+["']${relSource.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']`);
14342
+ if (!sourcePattern.test(cssContent)) {
14343
+ const marker = "@7onic-ui/tokens";
14344
+ const lastIdx = cssContent.lastIndexOf(marker);
14345
+ if (lastIdx !== -1) {
14346
+ const lineEnd = cssContent.indexOf("\n", lastIdx);
14347
+ const insertAt = lineEnd !== -1 ? lineEnd + 1 : cssContent.length;
14348
+ const updated = cssContent.slice(0, insertAt) + `@source "${relSource}";
14349
+ ` + cssContent.slice(insertAt);
14350
+ import_node_fs5.default.writeFileSync(cssFullPath, updated, "utf-8");
14351
+ O2.success(`Added @source "${relSource}" to ${config.tailwind.css}`);
14352
+ } else {
14353
+ O2.warn(
14354
+ `Could not find @7onic-ui/tokens import in ${config.tailwind.css}.
14355
+ Run ${import_picocolors3.default.cyan("npx 7onic init")} first, or manually add to your CSS:
14356
+
14357
+ @source "${relSource}";`
14358
+ );
14359
+ }
14360
+ }
14361
+ }
14362
+ } catch (err) {
14363
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") {
14364
+ } else {
14365
+ O2.warn(`Failed to inject @source into ${config.tailwind.css}: ${err}`);
14366
+ }
14367
+ }
14368
+ }
14258
14369
  if (depsToInstall.length > 0) {
14259
14370
  const pm = detectPackageManager(projectRoot);
14260
14371
  const s = fe();
@@ -14368,7 +14479,7 @@ function showSetupHints(names) {
14368
14479
 
14369
14480
  // cli/src/index.ts
14370
14481
  var import_picocolors4 = __toESM(require_picocolors());
14371
- var VERSION = "0.1.4";
14482
+ var VERSION = "0.1.6";
14372
14483
  var HELP = `
14373
14484
  ${import_picocolors4.default.bold("7onic")} \u2014 Add 7onic design system components to your project
14374
14485
 
package/llms.txt CHANGED
@@ -25,14 +25,15 @@ npx 7onic init --tailwind v3 --yes # Explicit v3, skip prompts
25
25
  **What it does:**
26
26
  1. Detects Tailwind version (v3: config file exists, v4: no config) — or uses `--tailwind` flag
27
27
  2. Detects package manager (npm/pnpm/yarn/bun)
28
- 3. Installs: `@7onic-ui/tokens`, `clsx`, `tailwind-merge`, `class-variance-authority`
29
- 4. Creates/updates CSS file with token imports
30
- 5. Creates `cn()` utility at configured path
31
- 6. Writes `7onic.json` config
28
+ 3. **Vite projects**: auto-configures `@/` path alias — patches `tsconfig.app.json` (JSONC-safe) and `vite.config.ts` (adds `import path` + `resolve.alias`), installs `@types/node`
29
+ 4. Installs: `@7onic-ui/tokens`, `lucide-react`, `clsx`, `tailwind-merge`, `class-variance-authority`
30
+ 5. Creates/updates CSS file with token imports (v4: auto-injects `@import "tailwindcss"` if missing)
31
+ 6. Creates `cn()` utility at configured path
32
+ 7. Writes `7onic.json` config
32
33
 
33
34
  **Requirements:**
34
35
  - TypeScript project (tsconfig.json required)
35
- - `@/` path alias configured
36
+ - `@/` path alias — auto-configured for Vite; Next.js handles this automatically
36
37
 
37
38
  ### add
38
39
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "7onic",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "CLI for adding 7onic design system components to your project",
5
5
  "bin": {
6
6
  "7onic": "./dist/index.js"