@nikala-ui/cli 0.6.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 (42) hide show
  1. package/README.md +39 -0
  2. package/dist/commands/add.d.ts +9 -0
  3. package/dist/commands/add.js +89 -0
  4. package/dist/commands/diff.d.ts +7 -0
  5. package/dist/commands/diff.js +87 -0
  6. package/dist/commands/init.d.ts +8 -0
  7. package/dist/commands/init.js +116 -0
  8. package/dist/commands/theme.d.ts +5 -0
  9. package/dist/commands/theme.js +64 -0
  10. package/dist/commands/validate.d.ts +5 -0
  11. package/dist/commands/validate.js +38 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +49 -0
  14. package/dist/types/registry.d.ts +23 -0
  15. package/dist/types/registry.js +1 -0
  16. package/dist/utils/add/write-component-files.d.ts +10 -0
  17. package/dist/utils/add/write-component-files.js +31 -0
  18. package/dist/utils/cn.d.ts +5 -0
  19. package/dist/utils/cn.js +18 -0
  20. package/dist/utils/diff/compare-lines.d.ts +12 -0
  21. package/dist/utils/diff/compare-lines.js +31 -0
  22. package/dist/utils/diff/format-diff.d.ts +8 -0
  23. package/dist/utils/diff/format-diff.js +27 -0
  24. package/dist/utils/file.d.ts +4 -0
  25. package/dist/utils/file.js +23 -0
  26. package/dist/utils/init/configure-alias.d.ts +4 -0
  27. package/dist/utils/init/configure-alias.js +51 -0
  28. package/dist/utils/init/setup-css.d.ts +4 -0
  29. package/dist/utils/init/setup-css.js +57 -0
  30. package/dist/utils/pkg.d.ts +15 -0
  31. package/dist/utils/pkg.js +102 -0
  32. package/dist/utils/registry.d.ts +25 -0
  33. package/dist/utils/registry.js +123 -0
  34. package/dist/utils/theme.d.ts +26 -0
  35. package/dist/utils/theme.js +173 -0
  36. package/dist/utils/validate/check-config.d.ts +11 -0
  37. package/dist/utils/validate/check-config.js +47 -0
  38. package/dist/utils/validate/check-css.d.ts +7 -0
  39. package/dist/utils/validate/check-css.js +50 -0
  40. package/dist/utils/validate/check-deps.d.ts +7 -0
  41. package/dist/utils/validate/check-deps.js +52 -0
  42. package/package.json +33 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Compares two text contents line-by-line and returns an array of structured diff entries.
3
+ * Uses a lightweight matching algorithm to identify added, removed, and identical lines.
4
+ *
5
+ * @param oldText - Original local component file content
6
+ * @param newText - Latest registry component file content
7
+ */
8
+ export function compareLines(oldText, newText) {
9
+ const oldLines = oldText.split(/\r?\n/);
10
+ const newLines = newText.split(/\r?\n/);
11
+ const diffs = [];
12
+ let i = 0;
13
+ let j = 0;
14
+ while (i < oldLines.length || j < newLines.length) {
15
+ if (i < oldLines.length && j < newLines.length && oldLines[i] === newLines[j]) {
16
+ diffs.push({ type: "same", value: oldLines[i] });
17
+ i++;
18
+ j++;
19
+ }
20
+ else if (j < newLines.length &&
21
+ (i >= oldLines.length || !oldLines.slice(i).includes(newLines[j]))) {
22
+ diffs.push({ type: "add", value: newLines[j] });
23
+ j++;
24
+ }
25
+ else if (i < oldLines.length) {
26
+ diffs.push({ type: "delete", value: oldLines[i] });
27
+ i++;
28
+ }
29
+ }
30
+ return diffs;
31
+ }
@@ -0,0 +1,8 @@
1
+ import type { DiffLine } from "./compare-lines.js";
2
+ /**
3
+ * Formats and prints color-coded line differences to the terminal using picocolors.
4
+ *
5
+ * @param diffs - Array of diff line entries generated by compareLines
6
+ * @returns Boolean indicating whether any differences were detected
7
+ */
8
+ export declare function printFormattedDiff(diffs: DiffLine[]): boolean;
@@ -0,0 +1,27 @@
1
+ import pc from "picocolors";
2
+ /**
3
+ * Formats and prints color-coded line differences to the terminal using picocolors.
4
+ *
5
+ * @param diffs - Array of diff line entries generated by compareLines
6
+ * @returns Boolean indicating whether any differences were detected
7
+ */
8
+ export function printFormattedDiff(diffs) {
9
+ const hasChanges = diffs.some((d) => d.type !== "same");
10
+ if (!hasChanges) {
11
+ return false;
12
+ }
13
+ console.log("");
14
+ for (const entry of diffs) {
15
+ if (entry.type === "add") {
16
+ console.log(pc.green(`+ ${entry.value}`));
17
+ }
18
+ else if (entry.type === "delete") {
19
+ console.log(pc.red(`- ${entry.value}`));
20
+ }
21
+ else {
22
+ console.log(pc.dim(` ${entry.value}`));
23
+ }
24
+ }
25
+ console.log("");
26
+ return true;
27
+ }
@@ -0,0 +1,4 @@
1
+ export declare function readConfig(cwd: string): Promise<any>;
2
+ export declare function writeConfig(cwd: string, config: unknown): Promise<void>;
3
+ export declare function readTsConfig(cwd: string): Promise<any>;
4
+ export declare function writeTsConfig(cwd: string, config: unknown): Promise<void>;
@@ -0,0 +1,23 @@
1
+ // src/utils/file.ts
2
+ import fs from "fs-extra";
3
+ import path from "path";
4
+ import stripJsonComments from "strip-json-comments";
5
+ export async function readConfig(cwd) {
6
+ const configPath = path.join(cwd, "nikala.config.json");
7
+ if (!(await fs.pathExists(configPath)))
8
+ return null;
9
+ return fs.readJson(configPath);
10
+ }
11
+ export async function writeConfig(cwd, config) {
12
+ await fs.writeFile(path.join(cwd, "nikala.config.json"), JSON.stringify(config, null, 2));
13
+ }
14
+ export async function readTsConfig(cwd) {
15
+ const tsconfigPath = path.join(cwd, "tsconfig.json");
16
+ if (!(await fs.pathExists(tsconfigPath)))
17
+ return null;
18
+ const content = await fs.readFile(tsconfigPath, "utf-8");
19
+ return JSON.parse(stripJsonComments(content));
20
+ }
21
+ export async function writeTsConfig(cwd, config) {
22
+ await fs.writeFile(path.join(cwd, "tsconfig.json"), JSON.stringify(config, null, 2));
23
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Configures Vite / SolidStart config aliases (@) and tsconfig.json path mappings (@/*).
3
+ */
4
+ export declare function configureAliases(cwd: string): Promise<void>;
@@ -0,0 +1,51 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ import pc from "picocolors";
4
+ import { readTsConfig } from "../file.js";
5
+ /**
6
+ * Configures Vite / SolidStart config aliases (@) and tsconfig.json path mappings (@/*).
7
+ */
8
+ export async function configureAliases(cwd) {
9
+ const viteConfigPath = path.join(cwd, "vite.config.ts");
10
+ const appConfigPath = path.join(cwd, "app.config.ts");
11
+ const targetConfigPath = (await fs.pathExists(appConfigPath)) ? appConfigPath : viteConfigPath;
12
+ if (await fs.pathExists(targetConfigPath)) {
13
+ let configContent = await fs.readFile(targetConfigPath, "utf-8");
14
+ let modified = false;
15
+ if (!configContent.includes("@tailwindcss/vite")) {
16
+ configContent = `import tailwindcss from "@tailwindcss/vite";\n${configContent}`;
17
+ if (configContent.includes("plugins: [")) {
18
+ configContent = configContent.replace("plugins: [", "plugins: [\n tailwindcss(), ");
19
+ }
20
+ else if (configContent.includes("defineConfig({")) {
21
+ configContent = configContent.replace("defineConfig({", "defineConfig({\n plugins: [tailwindcss()],");
22
+ }
23
+ modified = true;
24
+ }
25
+ if (!configContent.includes('"@"') && !configContent.includes("'@'")) {
26
+ if (!configContent.includes('import path from "node:path"') && !configContent.includes('import path from "path"')) {
27
+ configContent = `import path from "node:path";\n${configContent}`;
28
+ }
29
+ if (configContent.includes("defineConfig({")) {
30
+ configContent = configContent.replace("defineConfig({", `defineConfig({\n resolve: {\n alias: {\n "@": path.resolve(__dirname, "./src"),\n },\n },`);
31
+ }
32
+ modified = true;
33
+ }
34
+ if (modified) {
35
+ await fs.writeFile(targetConfigPath, configContent, "utf-8");
36
+ console.log(pc.green(`✓ Configured Tailwind CSS v4 plugin and path alias in ${path.basename(targetConfigPath)}`));
37
+ }
38
+ }
39
+ const tsconfigPath = path.join(cwd, "tsconfig.json");
40
+ if (await fs.pathExists(tsconfigPath)) {
41
+ const tsconfig = await readTsConfig(cwd);
42
+ if (tsconfig) {
43
+ tsconfig.compilerOptions = tsconfig.compilerOptions || {};
44
+ tsconfig.compilerOptions.baseUrl = ".";
45
+ tsconfig.compilerOptions.paths = tsconfig.compilerOptions.paths || {};
46
+ tsconfig.compilerOptions.paths["@/*"] = ["src/*"];
47
+ await fs.writeFile(tsconfigPath, JSON.stringify(tsconfig, null, 2), "utf-8");
48
+ console.log(pc.green("✓ Configured path alias (@/*) in tsconfig.json"));
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Resolves target CSS file path (app.css vs index.css), generates theme setup, and injects entry import.
3
+ */
4
+ export declare function setupCssTheme(cwd: string, baseColor: string, primaryColor: string): Promise<string>;
@@ -0,0 +1,57 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ import pc from "picocolors";
4
+ import { generateThemeCss } from "../theme.js";
5
+ /**
6
+ * Resolves target CSS file path (app.css vs index.css), generates theme setup, and injects entry import.
7
+ */
8
+ export async function setupCssTheme(cwd, baseColor, primaryColor) {
9
+ let cssPathRelative = "src/index.css";
10
+ if (await fs.pathExists(path.join(cwd, "src", "app.css"))) {
11
+ cssPathRelative = "src/app.css";
12
+ }
13
+ else if (await fs.pathExists(path.join(cwd, "src", "index.css"))) {
14
+ cssPathRelative = "src/index.css";
15
+ }
16
+ else {
17
+ const isSolidStart = (await fs.pathExists(path.join(cwd, "src", "app.tsx"))) ||
18
+ (await fs.pathExists(path.join(cwd, "app.config.ts")));
19
+ if (isSolidStart) {
20
+ cssPathRelative = "src/app.css";
21
+ }
22
+ }
23
+ const cssPath = path.join(cwd, cssPathRelative);
24
+ const generatedCss = generateThemeCss(baseColor, primaryColor);
25
+ await fs.ensureDir(path.dirname(cssPath));
26
+ await fs.writeFile(cssPath, generatedCss, "utf-8");
27
+ console.log(pc.green(`✓ Generated Tailwind CSS v4 theme setup in ${cssPathRelative}`));
28
+ // Inject CSS import statement into project's main entry point
29
+ const entryCandidates = [
30
+ path.join(cwd, "src", "app.tsx"),
31
+ path.join(cwd, "src", "app.jsx"),
32
+ path.join(cwd, "src", "entry-client.tsx"),
33
+ path.join(cwd, "src", "index.tsx"),
34
+ path.join(cwd, "src", "index.jsx"),
35
+ path.join(cwd, "src", "index.ts"),
36
+ path.join(cwd, "src", "main.tsx"),
37
+ path.join(cwd, "src", "main.ts"),
38
+ ];
39
+ let targetEntryPath = null;
40
+ for (const candidate of entryCandidates) {
41
+ if (await fs.pathExists(candidate)) {
42
+ targetEntryPath = candidate;
43
+ break;
44
+ }
45
+ }
46
+ if (targetEntryPath) {
47
+ let entryContent = await fs.readFile(targetEntryPath, "utf-8");
48
+ const cssFileName = path.basename(cssPathRelative);
49
+ const cssImportStatement = `import "./${cssFileName}";`;
50
+ if (!entryContent.includes(cssFileName)) {
51
+ entryContent = `${cssImportStatement}\n${entryContent}`;
52
+ await fs.writeFile(targetEntryPath, entryContent, "utf-8");
53
+ console.log(pc.green(`✓ Injected ${cssImportStatement} into ${path.relative(cwd, targetEntryPath)}`));
54
+ }
55
+ }
56
+ return cssPathRelative;
57
+ }
@@ -0,0 +1,15 @@
1
+ export type PackageManager = "bun" | "pnpm" | "yarn" | "npm";
2
+ /**
3
+ * Detects the package manager used in the target project workspace by checking lockfiles.
4
+ *
5
+ * @param cwd - Working directory path of the target project
6
+ * @returns The detected package manager name
7
+ */
8
+ export declare function detectPackageManager(cwd?: string): Promise<PackageManager>;
9
+ /**
10
+ * Safely installs missing NPM dependencies while protecting the user's existing package.json from being clobbered.
11
+ *
12
+ * @param dependencies - Array of NPM package names to install
13
+ * @param cwd - Target directory path
14
+ */
15
+ export declare function installDependencies(dependencies: string[], cwd?: string): Promise<void>;
@@ -0,0 +1,102 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ import { execSync } from "node:child_process";
4
+ import pc from "picocolors";
5
+ import stripJsonComments from "strip-json-comments";
6
+ /**
7
+ * Detects the package manager used in the target project workspace by checking lockfiles.
8
+ *
9
+ * @param cwd - Working directory path of the target project
10
+ * @returns The detected package manager name
11
+ */
12
+ export async function detectPackageManager(cwd = process.cwd()) {
13
+ if ((await fs.pathExists(path.join(cwd, "bun.lockb"))) ||
14
+ (await fs.pathExists(path.join(cwd, "bun.lock")))) {
15
+ return "bun";
16
+ }
17
+ if (await fs.pathExists(path.join(cwd, "pnpm-lock.yaml"))) {
18
+ return "pnpm";
19
+ }
20
+ if (await fs.pathExists(path.join(cwd, "yarn.lock"))) {
21
+ return "yarn";
22
+ }
23
+ if (await fs.pathExists(path.join(cwd, "package-lock.json"))) {
24
+ return "npm";
25
+ }
26
+ return "bun";
27
+ }
28
+ /**
29
+ * Safely installs missing NPM dependencies while protecting the user's existing package.json from being clobbered.
30
+ *
31
+ * @param dependencies - Array of NPM package names to install
32
+ * @param cwd - Target directory path
33
+ */
34
+ export async function installDependencies(dependencies, cwd = process.cwd()) {
35
+ if (!dependencies || dependencies.length === 0)
36
+ return;
37
+ const pkgManager = await detectPackageManager(cwd);
38
+ const pkgPath = path.join(cwd, "package.json");
39
+ // 1. Backup original package.json contents before running package manager installation
40
+ let originalPkgJson = null;
41
+ if (await fs.pathExists(pkgPath)) {
42
+ try {
43
+ const rawContent = await fs.readFile(pkgPath, "utf-8");
44
+ originalPkgJson = JSON.parse(stripJsonComments(rawContent));
45
+ }
46
+ catch {
47
+ // Failed to parse original package.json
48
+ }
49
+ }
50
+ const depsString = dependencies.join(" ");
51
+ let command = "";
52
+ switch (pkgManager) {
53
+ case "bun":
54
+ command = `bun add ${depsString}`;
55
+ break;
56
+ case "pnpm":
57
+ command = `pnpm add ${depsString}`;
58
+ break;
59
+ case "yarn":
60
+ command = `yarn add ${depsString}`;
61
+ break;
62
+ case "npm":
63
+ default:
64
+ command = `npm install ${depsString}`;
65
+ break;
66
+ }
67
+ console.log(pc.yellow(`\n📦 Installing required component dependencies (${pkgManager})...`));
68
+ console.log(pc.white(` ${command}\n`));
69
+ try {
70
+ execSync(command, { cwd, stdio: "inherit" });
71
+ // 2. Validate package.json integrity after installation and restore stripped fields if necessary
72
+ if (originalPkgJson && (await fs.pathExists(pkgPath))) {
73
+ try {
74
+ const currentPkg = await fs.readJson(pkgPath);
75
+ // If package manager wiped out essential fields like name or scripts, merge original back
76
+ if (!currentPkg.name && originalPkgJson.name) {
77
+ const mergedPkg = {
78
+ ...originalPkgJson,
79
+ dependencies: {
80
+ ...originalPkgJson.dependencies,
81
+ ...currentPkg.dependencies,
82
+ },
83
+ devDependencies: {
84
+ ...originalPkgJson.devDependencies,
85
+ ...currentPkg.devDependencies,
86
+ },
87
+ };
88
+ await fs.writeFile(pkgPath, JSON.stringify(mergedPkg, null, 2), "utf-8");
89
+ console.log(pc.green(" ✓ Preserved and merged original package.json structure."));
90
+ }
91
+ }
92
+ catch {
93
+ // Ignore merge errors
94
+ }
95
+ }
96
+ console.log(pc.green(" ✓ Dependencies installed successfully."));
97
+ }
98
+ catch (error) {
99
+ console.log(pc.red(`❌ Failed to install dependencies automatically.`));
100
+ console.log(pc.yellow(` Please run manually: ${command}`));
101
+ }
102
+ }
@@ -0,0 +1,25 @@
1
+ import type { RegistryIndex, RegistryItem } from "../types/registry.js";
2
+ /** Official remote registry CDN URL hosted on GitHub main branch */
3
+ export declare const OFFICIAL_REGISTRY_URL = "https://raw.githubusercontent.com/magradze/nikala-ui/main/packages/core/registry";
4
+ /**
5
+ * Reads and parses the central registry index manifest.
6
+ * Bypasses GitHub Raw CDN caching using timestamps and fetches fresh index files.
7
+ *
8
+ * @returns The list of available registry items or null if not found.
9
+ */
10
+ export declare function getRegistryIndex(): Promise<RegistryIndex | null>;
11
+ /**
12
+ * Fetches a component manifest from a remote HTTP(S) URL with cache-busting.
13
+ */
14
+ export declare function fetchRemoteRegistryItem(url: string): Promise<RegistryItem | null>;
15
+ /**
16
+ * Fetches the manifest for a component by name or remote URL.
17
+ * Checks official remote GitHub registry first, then falls back to local package manifest if offline.
18
+ *
19
+ * @param nameOrUrl - Component identifier or full HTTP(S) URL
20
+ */
21
+ export declare function getRegistryItem(nameOrUrl: string): Promise<RegistryItem | null>;
22
+ /**
23
+ * Recursively resolves all required internal registry dependencies for a set of component names or URLs.
24
+ */
25
+ export declare function resolveRegistryDependencies(namesOrUrls: string[]): Promise<string[]>;
@@ -0,0 +1,123 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ /** Official remote registry CDN URL hosted on GitHub main branch */
5
+ export const OFFICIAL_REGISTRY_URL = "https://raw.githubusercontent.com/magradze/nikala-ui/main/packages/core/registry";
6
+ /**
7
+ * Resolves the absolute path to the local fallback registry directory inside the Nikala UI package.
8
+ */
9
+ function getLocalRegistryDirectory() {
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ return path.resolve(__dirname, "../../registry");
13
+ }
14
+ /**
15
+ * Reads and parses the central registry index manifest.
16
+ * Bypasses GitHub Raw CDN caching using timestamps and fetches fresh index files.
17
+ *
18
+ * @returns The list of available registry items or null if not found.
19
+ */
20
+ export async function getRegistryIndex() {
21
+ // 1. Attempt fetching online manifest from GitHub Raw CDN with cache-busting
22
+ try {
23
+ const cacheBuster = Date.now();
24
+ const response = await fetch(`${OFFICIAL_REGISTRY_URL}/index.json?t=${cacheBuster}`, {
25
+ headers: { "Cache-Control": "no-cache, no-store" },
26
+ });
27
+ if (response.ok) {
28
+ const data = (await response.json());
29
+ if (Array.isArray(data))
30
+ return data;
31
+ }
32
+ }
33
+ catch {
34
+ // Fallback to local files if offline or network error occurs
35
+ }
36
+ // 2. Local package fallback
37
+ const localDir = getLocalRegistryDirectory();
38
+ const indexPath = path.join(localDir, "index.json");
39
+ if (await fs.pathExists(indexPath)) {
40
+ try {
41
+ const content = await fs.readFile(indexPath, "utf-8");
42
+ return JSON.parse(content);
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ return null;
49
+ }
50
+ /**
51
+ * Fetches a component manifest from a remote HTTP(S) URL with cache-busting.
52
+ */
53
+ export async function fetchRemoteRegistryItem(url) {
54
+ try {
55
+ const cacheBuster = Date.now();
56
+ const fetchUrl = url.includes("?") ? `${url}&t=${cacheBuster}` : `${url}?t=${cacheBuster}`;
57
+ const response = await fetch(fetchUrl, {
58
+ headers: { "Cache-Control": "no-cache, no-store" },
59
+ });
60
+ if (!response.ok)
61
+ return null;
62
+ const data = (await response.json());
63
+ if (!data.name || !data.files || !Array.isArray(data.files))
64
+ return null;
65
+ return data;
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ /**
72
+ * Fetches the manifest for a component by name or remote URL.
73
+ * Checks official remote GitHub registry first, then falls back to local package manifest if offline.
74
+ *
75
+ * @param nameOrUrl - Component identifier or full HTTP(S) URL
76
+ */
77
+ export async function getRegistryItem(nameOrUrl) {
78
+ if (nameOrUrl.startsWith("http://") || nameOrUrl.startsWith("https://")) {
79
+ return fetchRemoteRegistryItem(nameOrUrl);
80
+ }
81
+ // 1. Attempt fetching online component manifest from official GitHub CDN
82
+ const remoteUrl = `${OFFICIAL_REGISTRY_URL}/${nameOrUrl}.json`;
83
+ const remoteItem = await fetchRemoteRegistryItem(remoteUrl);
84
+ if (remoteItem)
85
+ return remoteItem;
86
+ // 2. Fallback to local package files if offline or unreleased
87
+ const localDir = getLocalRegistryDirectory();
88
+ const itemPath = path.join(localDir, `${nameOrUrl}.json`);
89
+ if (await fs.pathExists(itemPath)) {
90
+ try {
91
+ const content = await fs.readFile(itemPath, "utf-8");
92
+ return JSON.parse(content);
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }
98
+ return null;
99
+ }
100
+ /**
101
+ * Recursively resolves all required internal registry dependencies for a set of component names or URLs.
102
+ */
103
+ export async function resolveRegistryDependencies(namesOrUrls) {
104
+ const resolved = new Set();
105
+ const queue = [...namesOrUrls];
106
+ while (queue.length > 0) {
107
+ const current = queue.shift();
108
+ if (!current || resolved.has(current))
109
+ continue;
110
+ const item = await getRegistryItem(current);
111
+ if (!item)
112
+ continue;
113
+ resolved.add(current);
114
+ if (item.registryDependencies && item.registryDependencies.length > 0) {
115
+ for (const dep of item.registryDependencies) {
116
+ if (!resolved.has(dep)) {
117
+ queue.push(dep);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ return Array.from(resolved);
123
+ }
@@ -0,0 +1,26 @@
1
+ export interface BasePalette {
2
+ lightBg: string;
3
+ lightFg: string;
4
+ darkBg: string;
5
+ darkFg: string;
6
+ lightMuted: string;
7
+ lightMutedFg: string;
8
+ darkMuted: string;
9
+ darkMutedFg: string;
10
+ lightBorder: string;
11
+ darkBorder: string;
12
+ lightRing: string;
13
+ darkRing: string;
14
+ }
15
+ export interface PrimaryColor {
16
+ light: string;
17
+ dark: string;
18
+ lightFg: string;
19
+ darkFg: string;
20
+ }
21
+ export declare const BASE_PALETTES: Record<string, BasePalette>;
22
+ export declare const PRIMARY_COLORS: Record<string, PrimaryColor>;
23
+ /**
24
+ * Generates Tailwind CSS v4 theme variables based on base palette and primary accent color.
25
+ */
26
+ export declare function generateThemeCss(baseColor?: string, primaryColor?: string): string;