ionbit-ui 0.1.7 → 0.1.9
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/base.css +53 -0
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/tailwind.css +13 -0
- package/dist/tokens.css +267 -0
- package/dist/utilities.css +567 -0
- package/package.json +8 -2
package/dist/base.css
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Ionbit UI — Base layer
|
|
3
|
+
*
|
|
4
|
+
* Minimal reset-adjacent defaults + reduced-motion policy.
|
|
5
|
+
* Import once at the application root, after tokens.css.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
@layer base {
|
|
9
|
+
* {
|
|
10
|
+
border-color: var(--border);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
html {
|
|
14
|
+
-webkit-font-smoothing: antialiased;
|
|
15
|
+
-moz-osx-font-smoothing: grayscale;
|
|
16
|
+
text-rendering: optimizeLegibility;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
body {
|
|
20
|
+
background-color: var(--background);
|
|
21
|
+
color: var(--foreground);
|
|
22
|
+
font-family: var(--font-sans);
|
|
23
|
+
line-height: var(--leading-normal);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
:focus-visible {
|
|
27
|
+
outline: 2px solid var(--ring);
|
|
28
|
+
outline-offset: 2px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Reduced-motion policy: disable all animations and transitions by default.
|
|
32
|
+
Components and primitives must opt in via .motion-safe for animations
|
|
33
|
+
that are safe to keep (functional, non-distracting state changes). */
|
|
34
|
+
@media (prefers-reduced-motion: reduce) {
|
|
35
|
+
*,
|
|
36
|
+
*::before,
|
|
37
|
+
*::after {
|
|
38
|
+
animation-duration: 0.001ms !important;
|
|
39
|
+
animation-iteration-count: 1 !important;
|
|
40
|
+
transition-duration: 0.001ms !important;
|
|
41
|
+
scroll-behavior: auto !important;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Opt-in escape hatch for animations that are safe under reduced motion. */
|
|
47
|
+
@media (prefers-reduced-motion: reduce) {
|
|
48
|
+
.motion-safe\:animate,
|
|
49
|
+
.motion-safe\:transition {
|
|
50
|
+
animation-duration: var(--duration-fast) !important;
|
|
51
|
+
transition-duration: var(--duration-fast) !important;
|
|
52
|
+
}
|
|
53
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -294,11 +294,13 @@ function setupCssImports(config, cwd) {
|
|
|
294
294
|
const stylesDir = config.aliases.styles;
|
|
295
295
|
const tokensImport = `@import "./${relativePath(cssPath, resolve(cwd, stylesDir, "tokens.css"))}";`;
|
|
296
296
|
const baseImport = `@import "./${relativePath(cssPath, resolve(cwd, stylesDir, "base.css"))}";`;
|
|
297
|
+
const utilitiesImport = `@import "./${relativePath(cssPath, resolve(cwd, stylesDir, "utilities.css"))}";`;
|
|
297
298
|
if (!existsSync(cssPath)) {
|
|
298
299
|
const content = `@import "tailwindcss";
|
|
299
300
|
|
|
300
301
|
${tokensImport}
|
|
301
302
|
${baseImport}
|
|
303
|
+
${utilitiesImport}
|
|
302
304
|
`;
|
|
303
305
|
writeFileSync(cssPath, content);
|
|
304
306
|
console.log(
|
|
@@ -314,6 +316,9 @@ ${baseImport}
|
|
|
314
316
|
if (!existing.includes("base.css")) {
|
|
315
317
|
lines.push(baseImport);
|
|
316
318
|
}
|
|
319
|
+
if (!existing.includes("utilities.css")) {
|
|
320
|
+
lines.push(utilitiesImport);
|
|
321
|
+
}
|
|
317
322
|
if (lines.length > 0) {
|
|
318
323
|
let updated;
|
|
319
324
|
if (existing.includes('@import "tailwindcss"')) {
|
|
@@ -376,7 +381,7 @@ ${label}`));
|
|
|
376
381
|
const program = new Command();
|
|
377
382
|
program.name("ionbit-ui").description(
|
|
378
383
|
"Ionbit UI CLI — install source-owned components from the Ionbit UI registry."
|
|
379
|
-
).version("0.1.
|
|
384
|
+
).version("0.1.9");
|
|
380
385
|
program.command("init").description(
|
|
381
386
|
"Initialize Ionbit UI in your project. Creates a ionbit-ui.config.json and installs design tokens."
|
|
382
387
|
).option("-y, --yes", "Skip confirmation prompts and use defaults").option("-f, --force", "Force overwrite of existing configuration").option(
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/config.ts","../src/utils/fs.ts","../src/utils/npm.ts","../src/utils/registry.ts","../src/commands/add.ts","../src/commands/init.ts","../src/commands/list.ts","../src/index.ts"],"sourcesContent":["export const REGISTRY_URL =\n \"https://raw.githubusercontent.com/rostislaw9/ionbit-ui/main/registry.json\";\n\nexport const REGISTRY_ITEM_URL =\n \"https://raw.githubusercontent.com/rostislaw9/ionbit-ui/main/registry/items\";\n\nexport interface RegistryItem {\n name: string;\n type: string;\n title: string;\n description: string;\n dependencies?: string[];\n devDependencies?: string[];\n registryDependencies?: string[];\n files: RegistryFile[];\n}\n\nexport interface RegistryFile {\n path: string;\n type: string;\n content: string;\n}\n\nexport interface Registry {\n $schema: string;\n name: string;\n homepage: string;\n items: RegistryItem[];\n}\n\nexport interface Config {\n $schema: string;\n style: string;\n tailwind: {\n css: string;\n cssVariables: boolean;\n };\n aliases: {\n components: string;\n motion: string;\n lib: string;\n styles: string;\n };\n}\n\nexport const DEFAULT_CONFIG: Config = {\n $schema: \"https://ui.shadcn.com/schema/registry.json\",\n style: \"digital\",\n tailwind: {\n css: \"src/index.css\",\n cssVariables: true,\n },\n aliases: {\n components: \"src/components/ui\",\n motion: \"src/components/motion\",\n lib: \"src/lib\",\n styles: \"src/styles\",\n },\n};\n\nexport const CONFIG_FILE = \"ionbit-ui.config.json\";\n","import type { Config } from \"../config\";\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\n\nimport { CONFIG_FILE } from \"../config\";\n\nexport function loadConfig(cwd = process.cwd()): Config | null {\n const configPath = resolve(cwd, CONFIG_FILE);\n if (!existsSync(configPath)) return null;\n return JSON.parse(readFileSync(configPath, \"utf-8\")) as Config;\n}\n\nexport function saveConfig(config: Config, cwd = process.cwd()): void {\n const configPath = resolve(cwd, CONFIG_FILE);\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\nexport function ensureDir(filePath: string): void {\n const dir = dirname(filePath);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nexport function writeFile(filePath: string, content: string): void {\n ensureDir(filePath);\n writeFileSync(filePath, content);\n}\n\nexport function resolveTargetPath(\n target: string,\n config: Config,\n cwd = process.cwd(),\n): string {\n // Map registry target paths to the user's configured aliases.\n // e.g. \"components/ui/button.tsx\" -> \"{cwd}/components/ui/button.tsx\"\n // \"components/motion/spotlight.tsx\" -> \"{cwd}/components/motion/spotlight.tsx\"\n // \"lib/utils.ts\" -> \"{cwd}/lib/utils.ts\"\n // \"styles/tokens.css\" -> \"{cwd}/styles/tokens.css\"\n let resolved = target;\n\n if (target.startsWith(\"components/ui/\")) {\n resolved = target.replace(\n \"components/ui/\",\n config.aliases.components + \"/\",\n );\n } else if (target.startsWith(\"components/motion/\")) {\n resolved = target.replace(\n \"components/motion/\",\n config.aliases.motion + \"/\",\n );\n } else if (target.startsWith(\"lib/\")) {\n resolved = target.replace(\"lib/\", config.aliases.lib + \"/\");\n } else if (target.startsWith(\"styles/\")) {\n resolved = target.replace(\"styles/\", config.aliases.styles + \"/\");\n }\n\n return resolve(cwd, resolved);\n}\n","import { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nexport function detectPackageManager(cwd: string): PackageManager {\n if (existsSync(resolve(cwd, \"bun.lockb\"))) return \"bun\";\n if (existsSync(resolve(cwd, \"bun.lock\"))) return \"bun\";\n if (existsSync(resolve(cwd, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(resolve(cwd, \"yarn.lock\"))) return \"yarn\";\n return \"npm\";\n}\n\nexport function installNpmDeps(deps: string[], cwd: string): void {\n if (deps.length === 0) return;\n const pm = detectPackageManager(cwd);\n const cmd =\n pm === \"pnpm\"\n ? `pnpm add ${deps.join(\" \")}`\n : pm === \"yarn\"\n ? `yarn add ${deps.join(\" \")}`\n : pm === \"bun\"\n ? `bun add ${deps.join(\" \")}`\n : `npm install ${deps.join(\" \")}`;\n execSync(cmd, { cwd, stdio: \"inherit\" });\n}\n","import type { Registry, RegistryItem } from \"../config\";\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { REGISTRY_ITEM_URL, REGISTRY_URL } from \"../config\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Find the registry.json — checks local paths first, then falls back to the\n * remote GitHub URL. This allows development/testing without pushing to GitHub.\n */\nfunction findLocalRegistry(): string | null {\n const candidates = [\n // Relative to cwd (user's project)\n resolve(process.cwd(), \"registry.json\"),\n // Relative to CLI dist (packages/cli/dist -> ../../../registry.json)\n resolve(__dirname, \"../../../registry.json\"),\n // Relative to CLI src/utils (packages/cli/src/utils -> ../../../../registry.json)\n resolve(__dirname, \"../../../../registry.json\"),\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nfunction findLocalRegistryItem(name: string): string | null {\n const candidates = [\n resolve(process.cwd(), \"registry/items\", `${name}.json`),\n resolve(__dirname, \"../../../registry/items\", `${name}.json`),\n resolve(__dirname, \"../../../../registry/items\", `${name}.json`),\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nexport async function fetchRegistry(): Promise<Registry> {\n const localPath = findLocalRegistry();\n if (localPath) {\n return JSON.parse(readFileSync(localPath, \"utf-8\")) as Registry;\n }\n\n const res = await fetch(REGISTRY_URL);\n if (!res.ok) {\n throw new Error(\n `Failed to fetch registry: ${res.status} ${res.statusText}`,\n );\n }\n return (await res.json()) as Registry;\n}\n\nexport async function fetchRegistryItem(name: string): Promise<RegistryItem> {\n const localPath = findLocalRegistryItem(name);\n if (localPath) {\n return JSON.parse(readFileSync(localPath, \"utf-8\")) as RegistryItem;\n }\n\n const res = await fetch(`${REGISTRY_ITEM_URL}/${name}.json`);\n if (!res.ok) {\n throw new Error(\n `Failed to fetch registry item \"${name}\": ${res.status} ${res.statusText}`,\n );\n }\n return (await res.json()) as RegistryItem;\n}\n\nexport async function fetchRegistryItems(\n names: string[],\n): Promise<RegistryItem[]> {\n return Promise.all(names.map(fetchRegistryItem));\n}\n","import type { Config, RegistryItem } from \"../config\";\n\nimport chalk from \"chalk\";\nimport { existsSync } from \"node:fs\";\n\nimport { loadConfig, resolveTargetPath, writeFile } from \"../utils/fs\";\nimport { installNpmDeps } from \"../utils/npm\";\nimport { fetchRegistry, fetchRegistryItems } from \"../utils/registry\";\n\nexport async function add(\n components: string[],\n options: { overwrite?: boolean },\n): Promise<void> {\n const cwd = process.cwd();\n const config = loadConfig(cwd);\n\n if (!config) {\n console.log(\n chalk.red(\"No ionbit-ui.config.json found. Run `ionbit-ui init` first.\"),\n );\n process.exit(1);\n }\n\n // Fetch the full registry to resolve names and dependencies\n const registry = await fetchRegistry();\n const allNames = new Set(registry.items.map((i) => i.name));\n\n // Validate requested components\n for (const name of components) {\n if (!allNames.has(name)) {\n console.log(\n chalk.red(\n `Component \"${name}\" not found in registry. Run \\`ionbit-ui list\\` to see available components.`,\n ),\n );\n process.exit(1);\n }\n }\n\n // Resolve transitive registry dependencies\n const toInstall = resolveDependencies(components, registry.items);\n\n console.log(chalk.dim(`Installing ${toInstall.length} item(s)...`));\n console.log(\"\");\n\n // Fetch all items with embedded content\n const items = await fetchRegistryItems(toInstall);\n\n for (const item of items) {\n await installItem(item, config, cwd, options.overwrite ?? false);\n }\n\n // Collect and install npm dependencies\n const npmDeps = new Set<string>();\n for (const item of items) {\n for (const dep of item.dependencies ?? []) {\n npmDeps.add(dep);\n }\n }\n\n if (npmDeps.size > 0) {\n console.log(\"\");\n installNpmDeps([...npmDeps], cwd);\n }\n\n console.log(\"\");\n console.log(chalk.green(`✓ Added ${items.length} component(s).`));\n}\n\nfunction resolveDependencies(\n names: string[],\n allItems: { name: string; registryDependencies?: string[] }[],\n): string[] {\n const resolved = new Set<string>();\n const queue = [...names];\n\n while (queue.length > 0) {\n const name = queue.shift()!;\n if (resolved.has(name)) continue;\n resolved.add(name);\n\n const item = allItems.find((i) => i.name === name);\n if (item?.registryDependencies) {\n for (const dep of item.registryDependencies) {\n if (!resolved.has(dep)) queue.push(dep);\n }\n }\n }\n\n return [...resolved];\n}\n\nasync function installItem(\n item: RegistryItem,\n config: Config,\n cwd: string,\n overwrite: boolean,\n): Promise<void> {\n for (const file of item.files) {\n const targetPath = resolveTargetPath(file.path, config, cwd);\n\n if (existsSync(targetPath) && !overwrite) {\n console.log(\n chalk.yellow(\n ` ⚠ ${file.path} already exists — skipping (use --overwrite)`,\n ),\n );\n continue;\n }\n\n writeFile(targetPath, file.content);\n console.log(chalk.green(` ✓ ${file.path}`));\n }\n}\n","import type { Config, RegistryItem } from \"../config\";\n\nimport chalk from \"chalk\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { relative, resolve } from \"node:path\";\n\nimport { CONFIG_FILE, DEFAULT_CONFIG } from \"../config\";\nimport { resolveTargetPath, saveConfig, writeFile } from \"../utils/fs\";\nimport { installNpmDeps } from \"../utils/npm\";\nimport { fetchRegistryItems } from \"../utils/registry\";\n\nconst CURSOR_CSS = `@layer base {\n button:not(:disabled),\n [role=\"button\"]:not(:disabled) {\n cursor: pointer;\n }\n}`;\n\n/** Items that every project needs — installed automatically during init. */\nconst BASE_ITEMS = [\"cn\", \"tokens\"];\n\nexport async function init(options: {\n yes?: boolean;\n force?: boolean;\n pointer?: boolean;\n}): Promise<void> {\n const cwd = process.cwd();\n const configPath = resolve(cwd, CONFIG_FILE);\n\n if (existsSync(configPath) && !options.force) {\n console.log(\n chalk.yellow(\n `${CONFIG_FILE} already exists. Use --force to reinitialize.`,\n ),\n );\n return;\n }\n\n const config: Config = { ...DEFAULT_CONFIG };\n\n saveConfig(config, cwd);\n console.log(chalk.green(`✓ Created ${CONFIG_FILE}`));\n\n // Create directory structure\n const dirs = [\n config.aliases.components,\n config.aliases.motion,\n config.aliases.lib,\n config.aliases.styles,\n ];\n\n for (const dir of dirs) {\n const dirPath = resolve(cwd, dir);\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n console.log(chalk.dim(` Created ${dir}/`));\n }\n }\n\n // Install base items (cn utility + design tokens)\n console.log(chalk.dim(\"Installing base items (cn, tokens)...\"));\n const items = await fetchRegistryItems(BASE_ITEMS);\n for (const item of items) {\n installBaseItem(item, config, cwd);\n }\n\n // Add token CSS imports to the user's stylesheet\n setupCssImports(config, cwd);\n\n // Collect and install npm dependencies for base items\n const npmDeps = new Set<string>();\n for (const item of items) {\n for (const dep of item.dependencies ?? []) {\n npmDeps.add(dep);\n }\n }\n installNpmDeps([...npmDeps], cwd);\n\n // Optionally add cursor: pointer CSS\n if (options.pointer) {\n const cssPath = resolve(cwd, config.tailwind.css);\n if (existsSync(cssPath)) {\n const existing = readFileSync(cssPath, \"utf-8\");\n if (!existing.includes(\"cursor: pointer\")) {\n writeFileSync(cssPath, existing + \"\\n\" + CURSOR_CSS);\n console.log(\n chalk.green(`✓ Added cursor: pointer to ${config.tailwind.css}`),\n );\n } else {\n console.log(\n chalk.dim(\n ` ${config.tailwind.css} already has cursor: pointer — skipping`,\n ),\n );\n }\n } else {\n writeFileSync(cssPath, CURSOR_CSS);\n console.log(\n chalk.green(`✓ Created ${config.tailwind.css} with cursor: pointer`),\n );\n }\n }\n\n console.log(\"\");\n console.log(chalk.bold(\"Ionbit UI initialized!\"));\n console.log(\"\");\n console.log(chalk.dim(\"Next steps:\"));\n console.log(` ${chalk.cyan(\"ionbit-ui add button\")} — add a component`);\n console.log(\n ` ${chalk.cyan(\"ionbit-ui list\")} — browse available components`,\n );\n console.log(\"\");\n}\n\nfunction installBaseItem(\n item: RegistryItem,\n config: Config,\n cwd: string,\n): void {\n for (const file of item.files) {\n const targetPath = resolveTargetPath(file.path, config, cwd);\n if (existsSync(targetPath)) {\n console.log(chalk.dim(` ⚠ ${file.path} already exists — skipping`));\n continue;\n }\n writeFile(targetPath, file.content);\n console.log(chalk.green(` ✓ ${file.path}`));\n }\n}\n\nfunction setupCssImports(config: Config, cwd: string): void {\n const cssPath = resolve(cwd, config.tailwind.css);\n const stylesDir = config.aliases.styles;\n\n // Build the import lines relative to the CSS file's directory\n const tokensImport = `@import \"./${relativePath(cssPath, resolve(cwd, stylesDir, \"tokens.css\"))}\";`;\n const baseImport = `@import \"./${relativePath(cssPath, resolve(cwd, stylesDir, \"base.css\"))}\";`;\n\n if (!existsSync(cssPath)) {\n // Create the CSS file with token imports\n const content = `@import \"tailwindcss\";\\n\\n${tokensImport}\\n${baseImport}\\n`;\n writeFileSync(cssPath, content);\n console.log(\n chalk.green(`✓ Created ${config.tailwind.css} with token imports`),\n );\n return;\n }\n\n const existing = readFileSync(cssPath, \"utf-8\");\n const lines: string[] = [];\n\n if (!existing.includes(\"tokens.css\")) {\n lines.push(tokensImport);\n }\n if (!existing.includes(\"base.css\")) {\n lines.push(baseImport);\n }\n\n if (lines.length > 0) {\n // Add imports after @import \"tailwindcss\" if present, otherwise at the top\n let updated: string;\n if (existing.includes('@import \"tailwindcss\"')) {\n updated = existing.replace(\n /(@import\\s+\"tailwindcss\"[^\\n]*)/,\n `$1\\n${lines.join(\"\\n\")}`,\n );\n } else {\n updated = lines.join(\"\\n\") + \"\\n\" + existing;\n }\n writeFileSync(cssPath, updated);\n console.log(chalk.green(`✓ Added token imports to ${config.tailwind.css}`));\n } else {\n console.log(\n chalk.dim(\n ` ${config.tailwind.css} already has token imports — skipping`,\n ),\n );\n }\n}\n\nfunction relativePath(from: string, to: string): string {\n let rel = relative(from, to).replace(/\\\\/g, \"/\");\n // Remove the leading \"../\" if the CSS file is in the same or parent directory\n if (rel.startsWith(\"../\")) rel = rel.slice(3);\n return rel;\n}\n","import chalk from \"chalk\";\n\nimport { fetchRegistry } from \"../utils/registry\";\n\nexport async function list(): Promise<void> {\n const registry = await fetchRegistry();\n\n const groups: Record<string, typeof registry.items> = {};\n\n for (const item of registry.items) {\n const category = item.type.replace(\"registry:\", \"\");\n if (!groups[category]) groups[category] = [];\n groups[category].push(item);\n }\n\n const categoryOrder = [\"lib\", \"base\", \"ui\"];\n const sortedCategories = Object.keys(groups).sort((a, b) => {\n const ai = categoryOrder.indexOf(a);\n const bi = categoryOrder.indexOf(b);\n if (ai !== -1 && bi !== -1) return ai - bi;\n if (ai !== -1) return -1;\n if (bi !== -1) return 1;\n return a.localeCompare(b);\n });\n\n for (const category of sortedCategories) {\n const items = groups[category];\n if (!items) continue;\n const label =\n category === \"lib\"\n ? \"Libraries\"\n : category === \"base\"\n ? \"Foundation\"\n : \"Components\";\n\n console.log(chalk.bold(`\\n${label}`));\n\n for (const item of items) {\n const deps = item.dependencies?.length\n ? chalk.dim(` (${item.dependencies.length} deps)`)\n : \"\";\n console.log(` ${chalk.cyan(item.name.padEnd(18))} ${item.title}${deps}`);\n }\n }\n\n console.log(\"\");\n console.log(chalk.dim(`Total: ${registry.items.length} items`));\n console.log(chalk.dim(`Install with: ionbit-ui add <name>`));\n console.log(\"\");\n}\n","import { Command } from \"commander\";\n\nimport { add } from \"./commands/add\";\nimport { init } from \"./commands/init\";\nimport { list } from \"./commands/list\";\n\nconst program = new Command();\n\nprogram\n .name(\"ionbit-ui\")\n .description(\n \"Ionbit UI CLI — install source-owned components from the Ionbit UI registry.\",\n )\n .version(\"0.1.7\");\n\nprogram\n .command(\"init\")\n .description(\n \"Initialize Ionbit UI in your project. Creates a ionbit-ui.config.json and installs design tokens.\",\n )\n .option(\"-y, --yes\", \"Skip confirmation prompts and use defaults\")\n .option(\"-f, --force\", \"Force overwrite of existing configuration\")\n .option(\n \"--pointer\",\n \"Add cursor: pointer CSS for buttons (Tailwind v4 defaults to cursor: default)\",\n )\n .action(init);\n\nprogram\n .command(\"add <components...>\")\n .description(\n \"Add components to your project. e.g. ionbit-ui add button card accordion\",\n )\n .option(\"-o, --overwrite\", \"Overwrite existing files\")\n .action(add);\n\nprogram\n .command(\"list\")\n .description(\"List all available components in the registry.\")\n .action(list);\n\nprogram.parse();\n"],"names":["__dirname"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/config.ts","../src/utils/fs.ts","../src/utils/npm.ts","../src/utils/registry.ts","../src/commands/add.ts","../src/commands/init.ts","../src/commands/list.ts","../src/index.ts"],"sourcesContent":["export const REGISTRY_URL =\n \"https://raw.githubusercontent.com/rostislaw9/ionbit-ui/main/registry.json\";\n\nexport const REGISTRY_ITEM_URL =\n \"https://raw.githubusercontent.com/rostislaw9/ionbit-ui/main/registry/items\";\n\nexport interface RegistryItem {\n name: string;\n type: string;\n title: string;\n description: string;\n dependencies?: string[];\n devDependencies?: string[];\n registryDependencies?: string[];\n files: RegistryFile[];\n}\n\nexport interface RegistryFile {\n path: string;\n type: string;\n content: string;\n}\n\nexport interface Registry {\n $schema: string;\n name: string;\n homepage: string;\n items: RegistryItem[];\n}\n\nexport interface Config {\n $schema: string;\n style: string;\n tailwind: {\n css: string;\n cssVariables: boolean;\n };\n aliases: {\n components: string;\n motion: string;\n lib: string;\n styles: string;\n };\n}\n\nexport const DEFAULT_CONFIG: Config = {\n $schema: \"https://ui.shadcn.com/schema/registry.json\",\n style: \"digital\",\n tailwind: {\n css: \"src/index.css\",\n cssVariables: true,\n },\n aliases: {\n components: \"src/components/ui\",\n motion: \"src/components/motion\",\n lib: \"src/lib\",\n styles: \"src/styles\",\n },\n};\n\nexport const CONFIG_FILE = \"ionbit-ui.config.json\";\n","import type { Config } from \"../config\";\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\n\nimport { CONFIG_FILE } from \"../config\";\n\nexport function loadConfig(cwd = process.cwd()): Config | null {\n const configPath = resolve(cwd, CONFIG_FILE);\n if (!existsSync(configPath)) return null;\n return JSON.parse(readFileSync(configPath, \"utf-8\")) as Config;\n}\n\nexport function saveConfig(config: Config, cwd = process.cwd()): void {\n const configPath = resolve(cwd, CONFIG_FILE);\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\nexport function ensureDir(filePath: string): void {\n const dir = dirname(filePath);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nexport function writeFile(filePath: string, content: string): void {\n ensureDir(filePath);\n writeFileSync(filePath, content);\n}\n\nexport function resolveTargetPath(\n target: string,\n config: Config,\n cwd = process.cwd(),\n): string {\n // Map registry target paths to the user's configured aliases.\n // e.g. \"components/ui/button.tsx\" -> \"{cwd}/components/ui/button.tsx\"\n // \"components/motion/spotlight.tsx\" -> \"{cwd}/components/motion/spotlight.tsx\"\n // \"lib/utils.ts\" -> \"{cwd}/lib/utils.ts\"\n // \"styles/tokens.css\" -> \"{cwd}/styles/tokens.css\"\n let resolved = target;\n\n if (target.startsWith(\"components/ui/\")) {\n resolved = target.replace(\n \"components/ui/\",\n config.aliases.components + \"/\",\n );\n } else if (target.startsWith(\"components/motion/\")) {\n resolved = target.replace(\n \"components/motion/\",\n config.aliases.motion + \"/\",\n );\n } else if (target.startsWith(\"lib/\")) {\n resolved = target.replace(\"lib/\", config.aliases.lib + \"/\");\n } else if (target.startsWith(\"styles/\")) {\n resolved = target.replace(\"styles/\", config.aliases.styles + \"/\");\n }\n\n return resolve(cwd, resolved);\n}\n","import { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nexport function detectPackageManager(cwd: string): PackageManager {\n if (existsSync(resolve(cwd, \"bun.lockb\"))) return \"bun\";\n if (existsSync(resolve(cwd, \"bun.lock\"))) return \"bun\";\n if (existsSync(resolve(cwd, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(resolve(cwd, \"yarn.lock\"))) return \"yarn\";\n return \"npm\";\n}\n\nexport function installNpmDeps(deps: string[], cwd: string): void {\n if (deps.length === 0) return;\n const pm = detectPackageManager(cwd);\n const cmd =\n pm === \"pnpm\"\n ? `pnpm add ${deps.join(\" \")}`\n : pm === \"yarn\"\n ? `yarn add ${deps.join(\" \")}`\n : pm === \"bun\"\n ? `bun add ${deps.join(\" \")}`\n : `npm install ${deps.join(\" \")}`;\n execSync(cmd, { cwd, stdio: \"inherit\" });\n}\n","import type { Registry, RegistryItem } from \"../config\";\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { REGISTRY_ITEM_URL, REGISTRY_URL } from \"../config\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Find the registry.json — checks local paths first, then falls back to the\n * remote GitHub URL. This allows development/testing without pushing to GitHub.\n */\nfunction findLocalRegistry(): string | null {\n const candidates = [\n // Relative to cwd (user's project)\n resolve(process.cwd(), \"registry.json\"),\n // Relative to CLI dist (packages/cli/dist -> ../../../registry.json)\n resolve(__dirname, \"../../../registry.json\"),\n // Relative to CLI src/utils (packages/cli/src/utils -> ../../../../registry.json)\n resolve(__dirname, \"../../../../registry.json\"),\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nfunction findLocalRegistryItem(name: string): string | null {\n const candidates = [\n resolve(process.cwd(), \"registry/items\", `${name}.json`),\n resolve(__dirname, \"../../../registry/items\", `${name}.json`),\n resolve(__dirname, \"../../../../registry/items\", `${name}.json`),\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nexport async function fetchRegistry(): Promise<Registry> {\n const localPath = findLocalRegistry();\n if (localPath) {\n return JSON.parse(readFileSync(localPath, \"utf-8\")) as Registry;\n }\n\n const res = await fetch(REGISTRY_URL);\n if (!res.ok) {\n throw new Error(\n `Failed to fetch registry: ${res.status} ${res.statusText}`,\n );\n }\n return (await res.json()) as Registry;\n}\n\nexport async function fetchRegistryItem(name: string): Promise<RegistryItem> {\n const localPath = findLocalRegistryItem(name);\n if (localPath) {\n return JSON.parse(readFileSync(localPath, \"utf-8\")) as RegistryItem;\n }\n\n const res = await fetch(`${REGISTRY_ITEM_URL}/${name}.json`);\n if (!res.ok) {\n throw new Error(\n `Failed to fetch registry item \"${name}\": ${res.status} ${res.statusText}`,\n );\n }\n return (await res.json()) as RegistryItem;\n}\n\nexport async function fetchRegistryItems(\n names: string[],\n): Promise<RegistryItem[]> {\n return Promise.all(names.map(fetchRegistryItem));\n}\n","import type { Config, RegistryItem } from \"../config\";\n\nimport chalk from \"chalk\";\nimport { existsSync } from \"node:fs\";\n\nimport { loadConfig, resolveTargetPath, writeFile } from \"../utils/fs\";\nimport { installNpmDeps } from \"../utils/npm\";\nimport { fetchRegistry, fetchRegistryItems } from \"../utils/registry\";\n\nexport async function add(\n components: string[],\n options: { overwrite?: boolean },\n): Promise<void> {\n const cwd = process.cwd();\n const config = loadConfig(cwd);\n\n if (!config) {\n console.log(\n chalk.red(\"No ionbit-ui.config.json found. Run `ionbit-ui init` first.\"),\n );\n process.exit(1);\n }\n\n // Fetch the full registry to resolve names and dependencies\n const registry = await fetchRegistry();\n const allNames = new Set(registry.items.map((i) => i.name));\n\n // Validate requested components\n for (const name of components) {\n if (!allNames.has(name)) {\n console.log(\n chalk.red(\n `Component \"${name}\" not found in registry. Run \\`ionbit-ui list\\` to see available components.`,\n ),\n );\n process.exit(1);\n }\n }\n\n // Resolve transitive registry dependencies\n const toInstall = resolveDependencies(components, registry.items);\n\n console.log(chalk.dim(`Installing ${toInstall.length} item(s)...`));\n console.log(\"\");\n\n // Fetch all items with embedded content\n const items = await fetchRegistryItems(toInstall);\n\n for (const item of items) {\n await installItem(item, config, cwd, options.overwrite ?? false);\n }\n\n // Collect and install npm dependencies\n const npmDeps = new Set<string>();\n for (const item of items) {\n for (const dep of item.dependencies ?? []) {\n npmDeps.add(dep);\n }\n }\n\n if (npmDeps.size > 0) {\n console.log(\"\");\n installNpmDeps([...npmDeps], cwd);\n }\n\n console.log(\"\");\n console.log(chalk.green(`✓ Added ${items.length} component(s).`));\n}\n\nfunction resolveDependencies(\n names: string[],\n allItems: { name: string; registryDependencies?: string[] }[],\n): string[] {\n const resolved = new Set<string>();\n const queue = [...names];\n\n while (queue.length > 0) {\n const name = queue.shift()!;\n if (resolved.has(name)) continue;\n resolved.add(name);\n\n const item = allItems.find((i) => i.name === name);\n if (item?.registryDependencies) {\n for (const dep of item.registryDependencies) {\n if (!resolved.has(dep)) queue.push(dep);\n }\n }\n }\n\n return [...resolved];\n}\n\nasync function installItem(\n item: RegistryItem,\n config: Config,\n cwd: string,\n overwrite: boolean,\n): Promise<void> {\n for (const file of item.files) {\n const targetPath = resolveTargetPath(file.path, config, cwd);\n\n if (existsSync(targetPath) && !overwrite) {\n console.log(\n chalk.yellow(\n ` ⚠ ${file.path} already exists — skipping (use --overwrite)`,\n ),\n );\n continue;\n }\n\n writeFile(targetPath, file.content);\n console.log(chalk.green(` ✓ ${file.path}`));\n }\n}\n","import type { Config, RegistryItem } from \"../config\";\n\nimport chalk from \"chalk\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { relative, resolve } from \"node:path\";\n\nimport { CONFIG_FILE, DEFAULT_CONFIG } from \"../config\";\nimport { resolveTargetPath, saveConfig, writeFile } from \"../utils/fs\";\nimport { installNpmDeps } from \"../utils/npm\";\nimport { fetchRegistryItems } from \"../utils/registry\";\n\nconst CURSOR_CSS = `@layer base {\n button:not(:disabled),\n [role=\"button\"]:not(:disabled) {\n cursor: pointer;\n }\n}`;\n\n/** Items that every project needs — installed automatically during init. */\nconst BASE_ITEMS = [\"cn\", \"tokens\"];\n\nexport async function init(options: {\n yes?: boolean;\n force?: boolean;\n pointer?: boolean;\n}): Promise<void> {\n const cwd = process.cwd();\n const configPath = resolve(cwd, CONFIG_FILE);\n\n if (existsSync(configPath) && !options.force) {\n console.log(\n chalk.yellow(\n `${CONFIG_FILE} already exists. Use --force to reinitialize.`,\n ),\n );\n return;\n }\n\n const config: Config = { ...DEFAULT_CONFIG };\n\n saveConfig(config, cwd);\n console.log(chalk.green(`✓ Created ${CONFIG_FILE}`));\n\n // Create directory structure\n const dirs = [\n config.aliases.components,\n config.aliases.motion,\n config.aliases.lib,\n config.aliases.styles,\n ];\n\n for (const dir of dirs) {\n const dirPath = resolve(cwd, dir);\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n console.log(chalk.dim(` Created ${dir}/`));\n }\n }\n\n // Install base items (cn utility + design tokens)\n console.log(chalk.dim(\"Installing base items (cn, tokens)...\"));\n const items = await fetchRegistryItems(BASE_ITEMS);\n for (const item of items) {\n installBaseItem(item, config, cwd);\n }\n\n // Add token CSS imports to the user's stylesheet\n setupCssImports(config, cwd);\n\n // Collect and install npm dependencies for base items\n const npmDeps = new Set<string>();\n for (const item of items) {\n for (const dep of item.dependencies ?? []) {\n npmDeps.add(dep);\n }\n }\n installNpmDeps([...npmDeps], cwd);\n\n // Optionally add cursor: pointer CSS\n if (options.pointer) {\n const cssPath = resolve(cwd, config.tailwind.css);\n if (existsSync(cssPath)) {\n const existing = readFileSync(cssPath, \"utf-8\");\n if (!existing.includes(\"cursor: pointer\")) {\n writeFileSync(cssPath, existing + \"\\n\" + CURSOR_CSS);\n console.log(\n chalk.green(`✓ Added cursor: pointer to ${config.tailwind.css}`),\n );\n } else {\n console.log(\n chalk.dim(\n ` ${config.tailwind.css} already has cursor: pointer — skipping`,\n ),\n );\n }\n } else {\n writeFileSync(cssPath, CURSOR_CSS);\n console.log(\n chalk.green(`✓ Created ${config.tailwind.css} with cursor: pointer`),\n );\n }\n }\n\n console.log(\"\");\n console.log(chalk.bold(\"Ionbit UI initialized!\"));\n console.log(\"\");\n console.log(chalk.dim(\"Next steps:\"));\n console.log(` ${chalk.cyan(\"ionbit-ui add button\")} — add a component`);\n console.log(\n ` ${chalk.cyan(\"ionbit-ui list\")} — browse available components`,\n );\n console.log(\"\");\n}\n\nfunction installBaseItem(\n item: RegistryItem,\n config: Config,\n cwd: string,\n): void {\n for (const file of item.files) {\n const targetPath = resolveTargetPath(file.path, config, cwd);\n if (existsSync(targetPath)) {\n console.log(chalk.dim(` ⚠ ${file.path} already exists — skipping`));\n continue;\n }\n writeFile(targetPath, file.content);\n console.log(chalk.green(` ✓ ${file.path}`));\n }\n}\n\nfunction setupCssImports(config: Config, cwd: string): void {\n const cssPath = resolve(cwd, config.tailwind.css);\n const stylesDir = config.aliases.styles;\n\n // Build the import lines relative to the CSS file's directory\n const tokensImport = `@import \"./${relativePath(cssPath, resolve(cwd, stylesDir, \"tokens.css\"))}\";`;\n const baseImport = `@import \"./${relativePath(cssPath, resolve(cwd, stylesDir, \"base.css\"))}\";`;\n const utilitiesImport = `@import \"./${relativePath(cssPath, resolve(cwd, stylesDir, \"utilities.css\"))}\";`;\n\n if (!existsSync(cssPath)) {\n // Create the CSS file with token imports\n const content = `@import \"tailwindcss\";\\n\\n${tokensImport}\\n${baseImport}\\n${utilitiesImport}\\n`;\n writeFileSync(cssPath, content);\n console.log(\n chalk.green(`✓ Created ${config.tailwind.css} with token imports`),\n );\n return;\n }\n\n const existing = readFileSync(cssPath, \"utf-8\");\n const lines: string[] = [];\n\n if (!existing.includes(\"tokens.css\")) {\n lines.push(tokensImport);\n }\n if (!existing.includes(\"base.css\")) {\n lines.push(baseImport);\n }\n if (!existing.includes(\"utilities.css\")) {\n lines.push(utilitiesImport);\n }\n\n if (lines.length > 0) {\n // Add imports after @import \"tailwindcss\" if present, otherwise at the top\n let updated: string;\n if (existing.includes('@import \"tailwindcss\"')) {\n updated = existing.replace(\n /(@import\\s+\"tailwindcss\"[^\\n]*)/,\n `$1\\n${lines.join(\"\\n\")}`,\n );\n } else {\n updated = lines.join(\"\\n\") + \"\\n\" + existing;\n }\n writeFileSync(cssPath, updated);\n console.log(chalk.green(`✓ Added token imports to ${config.tailwind.css}`));\n } else {\n console.log(\n chalk.dim(\n ` ${config.tailwind.css} already has token imports — skipping`,\n ),\n );\n }\n}\n\nfunction relativePath(from: string, to: string): string {\n let rel = relative(from, to).replace(/\\\\/g, \"/\");\n // Remove the leading \"../\" if the CSS file is in the same or parent directory\n if (rel.startsWith(\"../\")) rel = rel.slice(3);\n return rel;\n}\n","import chalk from \"chalk\";\n\nimport { fetchRegistry } from \"../utils/registry\";\n\nexport async function list(): Promise<void> {\n const registry = await fetchRegistry();\n\n const groups: Record<string, typeof registry.items> = {};\n\n for (const item of registry.items) {\n const category = item.type.replace(\"registry:\", \"\");\n if (!groups[category]) groups[category] = [];\n groups[category].push(item);\n }\n\n const categoryOrder = [\"lib\", \"base\", \"ui\"];\n const sortedCategories = Object.keys(groups).sort((a, b) => {\n const ai = categoryOrder.indexOf(a);\n const bi = categoryOrder.indexOf(b);\n if (ai !== -1 && bi !== -1) return ai - bi;\n if (ai !== -1) return -1;\n if (bi !== -1) return 1;\n return a.localeCompare(b);\n });\n\n for (const category of sortedCategories) {\n const items = groups[category];\n if (!items) continue;\n const label =\n category === \"lib\"\n ? \"Libraries\"\n : category === \"base\"\n ? \"Foundation\"\n : \"Components\";\n\n console.log(chalk.bold(`\\n${label}`));\n\n for (const item of items) {\n const deps = item.dependencies?.length\n ? chalk.dim(` (${item.dependencies.length} deps)`)\n : \"\";\n console.log(` ${chalk.cyan(item.name.padEnd(18))} ${item.title}${deps}`);\n }\n }\n\n console.log(\"\");\n console.log(chalk.dim(`Total: ${registry.items.length} items`));\n console.log(chalk.dim(`Install with: ionbit-ui add <name>`));\n console.log(\"\");\n}\n","import { Command } from \"commander\";\n\nimport { add } from \"./commands/add\";\nimport { init } from \"./commands/init\";\nimport { list } from \"./commands/list\";\n\nconst program = new Command();\n\nprogram\n .name(\"ionbit-ui\")\n .description(\n \"Ionbit UI CLI — install source-owned components from the Ionbit UI registry.\",\n )\n .version(\"0.1.9\");\n\nprogram\n .command(\"init\")\n .description(\n \"Initialize Ionbit UI in your project. Creates a ionbit-ui.config.json and installs design tokens.\",\n )\n .option(\"-y, --yes\", \"Skip confirmation prompts and use defaults\")\n .option(\"-f, --force\", \"Force overwrite of existing configuration\")\n .option(\n \"--pointer\",\n \"Add cursor: pointer CSS for buttons (Tailwind v4 defaults to cursor: default)\",\n )\n .action(init);\n\nprogram\n .command(\"add <components...>\")\n .description(\n \"Add components to your project. e.g. ionbit-ui add button card accordion\",\n )\n .option(\"-o, --overwrite\", \"Overwrite existing files\")\n .action(add);\n\nprogram\n .command(\"list\")\n .description(\"List all available components in the registry.\")\n .action(list);\n\nprogram.parse();\n"],"names":["__dirname"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Ionbit UI — Tailwind CSS entry point
|
|
3
|
+
*
|
|
4
|
+
* Import this in your global CSS file:
|
|
5
|
+
* @import "tailwindcss";
|
|
6
|
+
* @import "ionbit-ui/tailwind.css";
|
|
7
|
+
*
|
|
8
|
+
* It bundles design tokens, base styles, and CSS utilities
|
|
9
|
+
* (scroll-fade, shimmer) in a single import.
|
|
10
|
+
*/
|
|
11
|
+
@import "./tokens.css";
|
|
12
|
+
@import "./base.css";
|
|
13
|
+
@import "./utilities.css";
|
package/dist/tokens.css
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Ionbit UI — Design Tokens
|
|
3
|
+
*
|
|
4
|
+
* Layered as:
|
|
5
|
+
* 1. :root / .dark — raw semantic variable values (themeable by consumers)
|
|
6
|
+
* 2. @theme inline — Tailwind v4 theme mapping (utilities resolve to the
|
|
7
|
+
* variables above)
|
|
8
|
+
*
|
|
9
|
+
* Components reference semantic utilities only (bg-surface, text-foreground,
|
|
10
|
+
* border-border, etc.). Retheming = overriding the variables in :root / .dark.
|
|
11
|
+
*
|
|
12
|
+
* The default theme is dark, technical, and restrained. Not neon cyberpunk.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/* ---------------------------------------------------------------------------
|
|
16
|
+
* 1. Raw semantic token values
|
|
17
|
+
* --------------------------------------------------------------------------- */
|
|
18
|
+
|
|
19
|
+
:root {
|
|
20
|
+
/* The default theme is dark. These values ARE the dark theme. */
|
|
21
|
+
color-scheme: dark;
|
|
22
|
+
|
|
23
|
+
/* Surfaces — subtle brightness steps, not flat black. */
|
|
24
|
+
--background: oklch(0.16 0.012 250); /* deep neutral, faintly cool */
|
|
25
|
+
--surface: oklch(0.19 0.013 250);
|
|
26
|
+
--surface-elevated: oklch(0.22 0.014 250);
|
|
27
|
+
--surface-hover: oklch(0.235 0.015 250);
|
|
28
|
+
|
|
29
|
+
/* Foreground — high but not pure-white contrast. */
|
|
30
|
+
--foreground: oklch(0.96 0.005 250);
|
|
31
|
+
--foreground-muted: oklch(0.68 0.012 250);
|
|
32
|
+
--foreground-subtle: oklch(0.52 0.012 250);
|
|
33
|
+
|
|
34
|
+
/* Borders — barely visible at rest, stronger on interaction. */
|
|
35
|
+
--border: oklch(1 0 0 / 0.08);
|
|
36
|
+
--border-strong: oklch(1 0 0 / 0.14);
|
|
37
|
+
--border-accent: oklch(0.78 0.16 238 / 0.5);
|
|
38
|
+
--border-error: oklch(0.62 0.24 5 / 0.5);
|
|
39
|
+
|
|
40
|
+
/* Accent — electric cyan/blue family. Configurable. */
|
|
41
|
+
--accent: oklch(0.78 0.17 238);
|
|
42
|
+
--accent-hover: oklch(0.82 0.18 238);
|
|
43
|
+
--accent-muted: oklch(0.78 0.17 238 / 0.16);
|
|
44
|
+
--accent-foreground: oklch(0.1 0.02 238);
|
|
45
|
+
|
|
46
|
+
/* Semantic status — restrained, not neon. */
|
|
47
|
+
--success: oklch(0.78 0.15 155);
|
|
48
|
+
--warning: oklch(0.82 0.15 80);
|
|
49
|
+
--error: oklch(0.62 0.24 5);
|
|
50
|
+
--error-foreground: oklch(0.1 0.04 5);
|
|
51
|
+
--info: oklch(0.82 0.14 230);
|
|
52
|
+
|
|
53
|
+
/* Focus ring — accent-tinted, visible but not loud. */
|
|
54
|
+
--ring: oklch(0.82 0.16 238 / 0.55);
|
|
55
|
+
|
|
56
|
+
/* Typography */
|
|
57
|
+
--font-sans:
|
|
58
|
+
ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
|
|
59
|
+
"Helvetica Neue", Arial, sans-serif;
|
|
60
|
+
--font-mono:
|
|
61
|
+
ui-monospace, "SF Mono", "JetBrains Mono", "Fira Code", Menlo, Consolas,
|
|
62
|
+
monospace;
|
|
63
|
+
|
|
64
|
+
--text-xs: 0.75rem;
|
|
65
|
+
--text-sm: 0.875rem;
|
|
66
|
+
--text-base: 1rem;
|
|
67
|
+
--text-lg: 1.125rem;
|
|
68
|
+
--text-xl: 1.25rem;
|
|
69
|
+
--text-2xl: 1.5rem;
|
|
70
|
+
--text-3xl: 1.875rem;
|
|
71
|
+
|
|
72
|
+
--leading-tight: 1.2;
|
|
73
|
+
--leading-normal: 1.5;
|
|
74
|
+
--leading-relaxed: 1.65;
|
|
75
|
+
|
|
76
|
+
--tracking-tight: -0.01em;
|
|
77
|
+
--tracking-normal: 0;
|
|
78
|
+
--tracking-wide: 0.02em;
|
|
79
|
+
|
|
80
|
+
--weight-normal: 400;
|
|
81
|
+
--weight-medium: 500;
|
|
82
|
+
--weight-semibold: 600;
|
|
83
|
+
--weight-bold: 700;
|
|
84
|
+
|
|
85
|
+
/* Spacing scale — 4px base. */
|
|
86
|
+
--space-1: 0.25rem;
|
|
87
|
+
--space-2: 0.5rem;
|
|
88
|
+
--space-3: 0.75rem;
|
|
89
|
+
--space-4: 1rem;
|
|
90
|
+
--space-5: 1.25rem;
|
|
91
|
+
--space-6: 1.5rem;
|
|
92
|
+
--space-8: 2rem;
|
|
93
|
+
--space-10: 2.5rem;
|
|
94
|
+
--space-12: 3rem;
|
|
95
|
+
--space-16: 4rem;
|
|
96
|
+
|
|
97
|
+
/* Radius — controlled, not bubbly. */
|
|
98
|
+
--radius-sm: 0.375rem;
|
|
99
|
+
--radius-md: 0.5rem;
|
|
100
|
+
--radius-lg: 0.75rem;
|
|
101
|
+
--radius-xl: 1rem;
|
|
102
|
+
--radius-full: 9999px;
|
|
103
|
+
|
|
104
|
+
/* Shadows — subtle, used for depth, not drama. */
|
|
105
|
+
--shadow-xs: 0 1px 2px 0 oklch(0 0 0 / 0.2);
|
|
106
|
+
--shadow-sm:
|
|
107
|
+
0 2px 4px -1px oklch(0 0 0 / 0.25), 0 1px 2px -1px oklch(0 0 0 / 0.2);
|
|
108
|
+
--shadow-md:
|
|
109
|
+
0 4px 8px -2px oklch(0 0 0 / 0.3), 0 2px 4px -2px oklch(0 0 0 / 0.25);
|
|
110
|
+
--shadow-lg:
|
|
111
|
+
0 12px 24px -8px oklch(0 0 0 / 0.4), 0 4px 8px -4px oklch(0 0 0 / 0.3);
|
|
112
|
+
--shadow-glow:
|
|
113
|
+
0 0 0 1px var(--border-accent),
|
|
114
|
+
0 0 16px -4px color-mix(in oklab, var(--accent) 40%, transparent);
|
|
115
|
+
--shadow-glow-error:
|
|
116
|
+
0 0 0 1px var(--border-error),
|
|
117
|
+
0 0 16px -4px color-mix(in oklab, var(--error) 40%, transparent);
|
|
118
|
+
--shadow-focus: 0 0 0 2px var(--ring), 0 0 16px -4px var(--accent);
|
|
119
|
+
--shadow-focus-error: 0 0 0 2px var(--error), 0 0 16px -4px var(--error);
|
|
120
|
+
|
|
121
|
+
/* Motion — durations (ms) and easings. */
|
|
122
|
+
--duration-fast: 140ms;
|
|
123
|
+
--duration-normal: 220ms;
|
|
124
|
+
--duration-slow: 420ms;
|
|
125
|
+
--ease-standard: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
126
|
+
--ease-emphasized: cubic-bezier(0.3, 0, 0, 1);
|
|
127
|
+
--ease-exit: cubic-bezier(0.4, 0, 1, 1);
|
|
128
|
+
|
|
129
|
+
/* Effect intensities — 0..1 multipliers. */
|
|
130
|
+
--spotlight-intensity: 0.4;
|
|
131
|
+
--magnetic-intensity: 0.25;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* ---------------------------------------------------------------------------
|
|
135
|
+
* Light theme override — architecture supports it; not the priority.
|
|
136
|
+
* --------------------------------------------------------------------------- */
|
|
137
|
+
|
|
138
|
+
.light {
|
|
139
|
+
color-scheme: light;
|
|
140
|
+
|
|
141
|
+
--background: oklch(0.99 0.002 250);
|
|
142
|
+
--surface: oklch(0.98 0.003 250);
|
|
143
|
+
--surface-elevated: oklch(1 0 0);
|
|
144
|
+
--surface-hover: oklch(0.96 0.004 250);
|
|
145
|
+
|
|
146
|
+
--foreground: oklch(0.2 0.012 250);
|
|
147
|
+
--foreground-muted: oklch(0.45 0.012 250);
|
|
148
|
+
--foreground-subtle: oklch(0.6 0.012 250);
|
|
149
|
+
|
|
150
|
+
--border: oklch(0 0 0 / 0.08);
|
|
151
|
+
--border-strong: oklch(0 0 0 / 0.14);
|
|
152
|
+
--border-accent: oklch(0.62 0.18 238 / 0.5);
|
|
153
|
+
--border-error: oklch(0.52 0.24 5 / 0.5);
|
|
154
|
+
|
|
155
|
+
--accent: oklch(0.58 0.2 238);
|
|
156
|
+
--accent-hover: oklch(0.52 0.21 238);
|
|
157
|
+
--accent-muted: oklch(0.58 0.2 238 / 0.12);
|
|
158
|
+
--accent-foreground: oklch(0.99 0 0);
|
|
159
|
+
|
|
160
|
+
--success: oklch(0.58 0.16 155);
|
|
161
|
+
--warning: oklch(0.62 0.17 80);
|
|
162
|
+
--error: oklch(0.52 0.24 5);
|
|
163
|
+
--error-foreground: oklch(0.99 0 0);
|
|
164
|
+
--info: oklch(0.58 0.16 238);
|
|
165
|
+
|
|
166
|
+
--ring: oklch(0.62 0.18 238 / 0.5);
|
|
167
|
+
|
|
168
|
+
--shadow-xs: 0 1px 2px 0 oklch(0 0 0 / 0.06);
|
|
169
|
+
--shadow-sm:
|
|
170
|
+
0 2px 4px -1px oklch(0 0 0 / 0.08), 0 1px 2px -1px oklch(0 0 0 / 0.06);
|
|
171
|
+
--shadow-md:
|
|
172
|
+
0 4px 8px -2px oklch(0 0 0 / 0.1), 0 2px 4px -2px oklch(0 0 0 / 0.08);
|
|
173
|
+
--shadow-lg:
|
|
174
|
+
0 12px 24px -8px oklch(0 0 0 / 0.12), 0 4px 8px -4px oklch(0 0 0 / 0.1);
|
|
175
|
+
--shadow-glow:
|
|
176
|
+
0 0 0 1px var(--border-accent),
|
|
177
|
+
0 0 16px -4px color-mix(in oklab, var(--accent) 40%, transparent);
|
|
178
|
+
--shadow-glow-error:
|
|
179
|
+
0 0 0 1px var(--border-error),
|
|
180
|
+
0 0 16px -4px color-mix(in oklab, var(--error) 40%, transparent);
|
|
181
|
+
--shadow-focus: 0 0 0 2px var(--ring), 0 0 16px -4px var(--accent);
|
|
182
|
+
--shadow-focus-error: 0 0 0 2px var(--error), 0 0 16px -4px var(--error);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* ---------------------------------------------------------------------------
|
|
186
|
+
* 2. Tailwind v4 theme mapping
|
|
187
|
+
* Utilities like bg-surface, text-foreground, border-border resolve to
|
|
188
|
+
* the variables above. Consumers override the variables, not the utilities.
|
|
189
|
+
* --------------------------------------------------------------------------- */
|
|
190
|
+
|
|
191
|
+
@theme inline {
|
|
192
|
+
/* Colors */
|
|
193
|
+
--color-background: var(--background);
|
|
194
|
+
--color-surface: var(--surface);
|
|
195
|
+
--color-surface-elevated: var(--surface-elevated);
|
|
196
|
+
--color-surface-hover: var(--surface-hover);
|
|
197
|
+
--color-foreground: var(--foreground);
|
|
198
|
+
--color-foreground-muted: var(--foreground-muted);
|
|
199
|
+
--color-foreground-subtle: var(--foreground-subtle);
|
|
200
|
+
--color-border: var(--border);
|
|
201
|
+
--color-border-strong: var(--border-strong);
|
|
202
|
+
--color-border-accent: var(--border-accent);
|
|
203
|
+
--color-border-error: var(--border-error);
|
|
204
|
+
--color-accent: var(--accent);
|
|
205
|
+
--color-accent-hover: var(--accent-hover);
|
|
206
|
+
--color-accent-muted: var(--accent-muted);
|
|
207
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
208
|
+
--color-success: var(--success);
|
|
209
|
+
--color-warning: var(--warning);
|
|
210
|
+
--color-error: var(--error);
|
|
211
|
+
--color-error-foreground: var(--error-foreground);
|
|
212
|
+
--color-info: var(--info);
|
|
213
|
+
--color-ring: var(--ring);
|
|
214
|
+
|
|
215
|
+
/* Fonts */
|
|
216
|
+
--font-sans: var(--font-sans);
|
|
217
|
+
--font-mono: var(--font-mono);
|
|
218
|
+
|
|
219
|
+
/* Radius */
|
|
220
|
+
--radius-sm: var(--radius-sm);
|
|
221
|
+
--radius-md: var(--radius-md);
|
|
222
|
+
--radius-lg: var(--radius-lg);
|
|
223
|
+
--radius-xl: var(--radius-xl);
|
|
224
|
+
--radius-full: var(--radius-full);
|
|
225
|
+
|
|
226
|
+
/* Shadows */
|
|
227
|
+
--shadow-xs: var(--shadow-xs);
|
|
228
|
+
--shadow-sm: var(--shadow-sm);
|
|
229
|
+
--shadow-md: var(--shadow-md);
|
|
230
|
+
--shadow-lg: var(--shadow-lg);
|
|
231
|
+
--shadow-glow: var(--shadow-glow);
|
|
232
|
+
--shadow-glow-error: var(--shadow-glow-error);
|
|
233
|
+
--shadow-focus: var(--shadow-focus);
|
|
234
|
+
--shadow-focus-error: var(--shadow-focus-error);
|
|
235
|
+
|
|
236
|
+
/* Motion durations + easings (Tailwind v4 exposes them as utilities) */
|
|
237
|
+
--duration-fast: var(--duration-fast);
|
|
238
|
+
--duration-normal: var(--duration-normal);
|
|
239
|
+
--duration-slow: var(--duration-slow);
|
|
240
|
+
--ease-standard: var(--ease-standard);
|
|
241
|
+
--ease-emphasized: var(--ease-emphasized);
|
|
242
|
+
--ease-exit: var(--ease-exit);
|
|
243
|
+
|
|
244
|
+
/* Accordion expand/collapse — syncs with Radix's --radix-accordion-content-height */
|
|
245
|
+
--animate-accordion-down: accordion-down var(--duration-normal)
|
|
246
|
+
var(--ease-standard);
|
|
247
|
+
--animate-accordion-up: accordion-up var(--duration-normal)
|
|
248
|
+
var(--ease-standard);
|
|
249
|
+
|
|
250
|
+
@keyframes accordion-down {
|
|
251
|
+
from {
|
|
252
|
+
height: 0;
|
|
253
|
+
}
|
|
254
|
+
to {
|
|
255
|
+
height: var(--radix-accordion-content-height);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
@keyframes accordion-up {
|
|
260
|
+
from {
|
|
261
|
+
height: var(--radix-accordion-content-height);
|
|
262
|
+
}
|
|
263
|
+
to {
|
|
264
|
+
height: 0;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Ionbit UI — CSS Utilities
|
|
3
|
+
*
|
|
4
|
+
* Scroll-fade and shimmer utilities, inspired by shadcn.
|
|
5
|
+
* Import in your global CSS after Tailwind:
|
|
6
|
+
* @import "tailwindcss";
|
|
7
|
+
* @import "ionbit-ui/tailwind.css";
|
|
8
|
+
*
|
|
9
|
+
* These use Tailwind v4 at-rules (@utility, @theme inline, @variant)
|
|
10
|
+
* and must be processed by the Tailwind engine, not lightningcss.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/* no-scrollbar */
|
|
14
|
+
@utility no-scrollbar {
|
|
15
|
+
-ms-overflow-style: none;
|
|
16
|
+
scrollbar-width: none;
|
|
17
|
+
|
|
18
|
+
&::-webkit-scrollbar {
|
|
19
|
+
display: none;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* ─── scroll-fade ─── */
|
|
24
|
+
@property --scroll-fade-t {
|
|
25
|
+
syntax: "<length-percentage>";
|
|
26
|
+
inherits: false;
|
|
27
|
+
initial-value: 0px;
|
|
28
|
+
}
|
|
29
|
+
@property --scroll-fade-b {
|
|
30
|
+
syntax: "<length-percentage>";
|
|
31
|
+
inherits: false;
|
|
32
|
+
initial-value: 0px;
|
|
33
|
+
}
|
|
34
|
+
@property --scroll-fade-s {
|
|
35
|
+
syntax: "<length-percentage>";
|
|
36
|
+
inherits: false;
|
|
37
|
+
initial-value: 0px;
|
|
38
|
+
}
|
|
39
|
+
@property --scroll-fade-e {
|
|
40
|
+
syntax: "<length-percentage>";
|
|
41
|
+
inherits: false;
|
|
42
|
+
initial-value: 0px;
|
|
43
|
+
}
|
|
44
|
+
@property --scroll-fade-mask {
|
|
45
|
+
syntax: "*";
|
|
46
|
+
inherits: false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@theme inline {
|
|
50
|
+
@keyframes scroll-fade-reveal-t {
|
|
51
|
+
from {
|
|
52
|
+
--scroll-fade-t: 0px;
|
|
53
|
+
}
|
|
54
|
+
to {
|
|
55
|
+
--scroll-fade-t: var(
|
|
56
|
+
--_scroll-fade-size-t,
|
|
57
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
@keyframes scroll-fade-reveal-b {
|
|
62
|
+
from {
|
|
63
|
+
--scroll-fade-b: var(
|
|
64
|
+
--_scroll-fade-size-b,
|
|
65
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
to {
|
|
69
|
+
--scroll-fade-b: 0px;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
@keyframes scroll-fade-reveal-s {
|
|
73
|
+
from {
|
|
74
|
+
--scroll-fade-s: 0px;
|
|
75
|
+
}
|
|
76
|
+
to {
|
|
77
|
+
--scroll-fade-s: var(
|
|
78
|
+
--_scroll-fade-size-s,
|
|
79
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
@keyframes scroll-fade-reveal-e {
|
|
84
|
+
from {
|
|
85
|
+
--scroll-fade-e: var(
|
|
86
|
+
--_scroll-fade-size-e,
|
|
87
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
to {
|
|
91
|
+
--scroll-fade-e: 0px;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@utility scroll-fade {
|
|
97
|
+
--_scroll-fade-size-t: var(
|
|
98
|
+
--scroll-fade-t-size,
|
|
99
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
100
|
+
);
|
|
101
|
+
--_scroll-fade-size-b: var(
|
|
102
|
+
--scroll-fade-b-size,
|
|
103
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
104
|
+
);
|
|
105
|
+
--scroll-fade-block: linear-gradient(
|
|
106
|
+
to bottom,
|
|
107
|
+
transparent 0,
|
|
108
|
+
#000 var(--scroll-fade-t, 0px),
|
|
109
|
+
#000 calc(100% - var(--scroll-fade-b, 0px)),
|
|
110
|
+
transparent 100%
|
|
111
|
+
);
|
|
112
|
+
-webkit-mask-image: var(--scroll-fade-mask, var(--scroll-fade-block));
|
|
113
|
+
mask-image: var(--scroll-fade-mask, var(--scroll-fade-block));
|
|
114
|
+
-webkit-mask-composite: source-in;
|
|
115
|
+
mask-composite: intersect;
|
|
116
|
+
-webkit-mask-repeat: no-repeat;
|
|
117
|
+
mask-repeat: no-repeat;
|
|
118
|
+
|
|
119
|
+
@supports (animation-timeline: scroll()) {
|
|
120
|
+
animation:
|
|
121
|
+
scroll-fade-reveal-t 1ms ease-in-out,
|
|
122
|
+
scroll-fade-reveal-b 1ms ease-in-out;
|
|
123
|
+
animation-timeline: scroll(self y), scroll(self y);
|
|
124
|
+
animation-range:
|
|
125
|
+
0 var(--scroll-fade-reveal, calc(var(--spacing) * 24)),
|
|
126
|
+
calc(100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))) 100%;
|
|
127
|
+
animation-fill-mode: both;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@supports not (animation-timeline: scroll()) {
|
|
131
|
+
--scroll-fade-t: var(--_scroll-fade-size-t);
|
|
132
|
+
--scroll-fade-b: var(--_scroll-fade-size-b);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@utility scroll-fade-y {
|
|
137
|
+
--_scroll-fade-size-t: var(
|
|
138
|
+
--scroll-fade-t-size,
|
|
139
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
140
|
+
);
|
|
141
|
+
--_scroll-fade-size-b: var(
|
|
142
|
+
--scroll-fade-b-size,
|
|
143
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
144
|
+
);
|
|
145
|
+
--scroll-fade-block: linear-gradient(
|
|
146
|
+
to bottom,
|
|
147
|
+
transparent 0,
|
|
148
|
+
#000 var(--scroll-fade-t, 0px),
|
|
149
|
+
#000 calc(100% - var(--scroll-fade-b, 0px)),
|
|
150
|
+
transparent 100%
|
|
151
|
+
);
|
|
152
|
+
-webkit-mask-image: var(--scroll-fade-mask, var(--scroll-fade-block));
|
|
153
|
+
mask-image: var(--scroll-fade-mask, var(--scroll-fade-block));
|
|
154
|
+
-webkit-mask-composite: source-in;
|
|
155
|
+
mask-composite: intersect;
|
|
156
|
+
-webkit-mask-repeat: no-repeat;
|
|
157
|
+
mask-repeat: no-repeat;
|
|
158
|
+
|
|
159
|
+
@supports (animation-timeline: scroll()) {
|
|
160
|
+
animation:
|
|
161
|
+
scroll-fade-reveal-t 1ms ease-in-out,
|
|
162
|
+
scroll-fade-reveal-b 1ms ease-in-out;
|
|
163
|
+
animation-timeline: scroll(self y), scroll(self y);
|
|
164
|
+
animation-range:
|
|
165
|
+
0 var(--scroll-fade-reveal, calc(var(--spacing) * 24)),
|
|
166
|
+
calc(100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))) 100%;
|
|
167
|
+
animation-fill-mode: both;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@supports not (animation-timeline: scroll()) {
|
|
171
|
+
--scroll-fade-t: var(--_scroll-fade-size-t);
|
|
172
|
+
--scroll-fade-b: var(--_scroll-fade-size-b);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@utility scroll-fade-x {
|
|
177
|
+
--_scroll-fade-size-s: var(
|
|
178
|
+
--scroll-fade-s-size,
|
|
179
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
180
|
+
);
|
|
181
|
+
--_scroll-fade-size-e: var(
|
|
182
|
+
--scroll-fade-e-size,
|
|
183
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
184
|
+
);
|
|
185
|
+
--scroll-fade-inline: linear-gradient(
|
|
186
|
+
to right,
|
|
187
|
+
transparent 0,
|
|
188
|
+
#000 var(--scroll-fade-s, 0px),
|
|
189
|
+
#000 calc(100% - var(--scroll-fade-e, 0px)),
|
|
190
|
+
transparent 100%
|
|
191
|
+
);
|
|
192
|
+
&:where([dir="rtl"], [dir="rtl"] *) {
|
|
193
|
+
--scroll-fade-inline: linear-gradient(
|
|
194
|
+
to left,
|
|
195
|
+
transparent 0,
|
|
196
|
+
#000 var(--scroll-fade-s, 0px),
|
|
197
|
+
#000 calc(100% - var(--scroll-fade-e, 0px)),
|
|
198
|
+
transparent 100%
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
-webkit-mask-image: var(--scroll-fade-mask, var(--scroll-fade-inline));
|
|
202
|
+
mask-image: var(--scroll-fade-mask, var(--scroll-fade-inline));
|
|
203
|
+
-webkit-mask-composite: source-in;
|
|
204
|
+
mask-composite: intersect;
|
|
205
|
+
-webkit-mask-repeat: no-repeat;
|
|
206
|
+
mask-repeat: no-repeat;
|
|
207
|
+
|
|
208
|
+
@supports (animation-timeline: scroll()) {
|
|
209
|
+
animation:
|
|
210
|
+
scroll-fade-reveal-s 1ms ease-in-out,
|
|
211
|
+
scroll-fade-reveal-e 1ms ease-in-out;
|
|
212
|
+
animation-timeline: scroll(self inline), scroll(self inline);
|
|
213
|
+
animation-range:
|
|
214
|
+
0 var(--scroll-fade-reveal, calc(var(--spacing) * 24)),
|
|
215
|
+
calc(100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))) 100%;
|
|
216
|
+
animation-fill-mode: both;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@supports not (animation-timeline: scroll()) {
|
|
220
|
+
--scroll-fade-s: var(--_scroll-fade-size-s);
|
|
221
|
+
--scroll-fade-e: var(--_scroll-fade-size-e);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@utility scroll-fade-t {
|
|
226
|
+
--_scroll-fade-size-t: var(
|
|
227
|
+
--scroll-fade-t-size,
|
|
228
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
229
|
+
);
|
|
230
|
+
--scroll-fade-mask: linear-gradient(
|
|
231
|
+
to bottom,
|
|
232
|
+
transparent 0,
|
|
233
|
+
#000 var(--scroll-fade-t, 0px),
|
|
234
|
+
#000 100%
|
|
235
|
+
);
|
|
236
|
+
-webkit-mask-image: var(--scroll-fade-mask);
|
|
237
|
+
mask-image: var(--scroll-fade-mask);
|
|
238
|
+
-webkit-mask-composite: source-in;
|
|
239
|
+
mask-composite: intersect;
|
|
240
|
+
-webkit-mask-repeat: no-repeat;
|
|
241
|
+
mask-repeat: no-repeat;
|
|
242
|
+
|
|
243
|
+
@supports (animation-timeline: scroll()) {
|
|
244
|
+
animation: scroll-fade-reveal-t 1ms ease-in-out;
|
|
245
|
+
animation-timeline: scroll(self y);
|
|
246
|
+
animation-range: 0 var(--scroll-fade-reveal, calc(var(--spacing) * 24));
|
|
247
|
+
animation-fill-mode: both;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
@supports not (animation-timeline: scroll()) {
|
|
251
|
+
--scroll-fade-t: var(--_scroll-fade-size-t);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@utility scroll-fade-b {
|
|
256
|
+
--_scroll-fade-size-b: var(
|
|
257
|
+
--scroll-fade-b-size,
|
|
258
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
259
|
+
);
|
|
260
|
+
--scroll-fade-mask: linear-gradient(
|
|
261
|
+
to bottom,
|
|
262
|
+
#000 0,
|
|
263
|
+
#000 calc(100% - var(--scroll-fade-b, 0px)),
|
|
264
|
+
transparent 100%
|
|
265
|
+
);
|
|
266
|
+
-webkit-mask-image: var(--scroll-fade-mask);
|
|
267
|
+
mask-image: var(--scroll-fade-mask);
|
|
268
|
+
-webkit-mask-composite: source-in;
|
|
269
|
+
mask-composite: intersect;
|
|
270
|
+
-webkit-mask-repeat: no-repeat;
|
|
271
|
+
mask-repeat: no-repeat;
|
|
272
|
+
|
|
273
|
+
@supports (animation-timeline: scroll()) {
|
|
274
|
+
animation: scroll-fade-reveal-b 1ms ease-in-out;
|
|
275
|
+
animation-timeline: scroll(self y);
|
|
276
|
+
animation-range: calc(
|
|
277
|
+
100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))
|
|
278
|
+
)
|
|
279
|
+
100%;
|
|
280
|
+
animation-fill-mode: both;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
@supports not (animation-timeline: scroll()) {
|
|
284
|
+
--scroll-fade-b: var(--_scroll-fade-size-b);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
@utility scroll-fade-l {
|
|
289
|
+
--_scroll-fade-size-s: var(
|
|
290
|
+
--scroll-fade-s-size,
|
|
291
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
292
|
+
);
|
|
293
|
+
--scroll-fade-mask: linear-gradient(
|
|
294
|
+
to right,
|
|
295
|
+
transparent 0,
|
|
296
|
+
#000 var(--scroll-fade-s, 0px),
|
|
297
|
+
#000 100%
|
|
298
|
+
);
|
|
299
|
+
-webkit-mask-image: var(--scroll-fade-mask);
|
|
300
|
+
mask-image: var(--scroll-fade-mask);
|
|
301
|
+
-webkit-mask-composite: source-in;
|
|
302
|
+
mask-composite: intersect;
|
|
303
|
+
-webkit-mask-repeat: no-repeat;
|
|
304
|
+
mask-repeat: no-repeat;
|
|
305
|
+
|
|
306
|
+
@supports (animation-timeline: scroll()) {
|
|
307
|
+
animation: scroll-fade-reveal-s 1ms ease-in-out;
|
|
308
|
+
animation-timeline: scroll(self x);
|
|
309
|
+
animation-range: 0 var(--scroll-fade-reveal, calc(var(--spacing) * 24));
|
|
310
|
+
animation-fill-mode: both;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
@supports not (animation-timeline: scroll()) {
|
|
314
|
+
--scroll-fade-s: var(--_scroll-fade-size-s);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
@utility scroll-fade-r {
|
|
319
|
+
--_scroll-fade-size-e: var(
|
|
320
|
+
--scroll-fade-e-size,
|
|
321
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
322
|
+
);
|
|
323
|
+
--scroll-fade-mask: linear-gradient(
|
|
324
|
+
to right,
|
|
325
|
+
#000 0,
|
|
326
|
+
#000 calc(100% - var(--scroll-fade-e, 0px)),
|
|
327
|
+
transparent 100%
|
|
328
|
+
);
|
|
329
|
+
-webkit-mask-image: var(--scroll-fade-mask);
|
|
330
|
+
mask-image: var(--scroll-fade-mask);
|
|
331
|
+
-webkit-mask-composite: source-in;
|
|
332
|
+
mask-composite: intersect;
|
|
333
|
+
-webkit-mask-repeat: no-repeat;
|
|
334
|
+
mask-repeat: no-repeat;
|
|
335
|
+
|
|
336
|
+
@supports (animation-timeline: scroll()) {
|
|
337
|
+
animation: scroll-fade-reveal-e 1ms ease-in-out;
|
|
338
|
+
animation-timeline: scroll(self x);
|
|
339
|
+
animation-range: calc(
|
|
340
|
+
100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))
|
|
341
|
+
)
|
|
342
|
+
100%;
|
|
343
|
+
animation-fill-mode: both;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
@supports not (animation-timeline: scroll()) {
|
|
347
|
+
--scroll-fade-e: var(--_scroll-fade-size-e);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
@utility scroll-fade-s {
|
|
352
|
+
--_scroll-fade-size-s: var(
|
|
353
|
+
--scroll-fade-s-size,
|
|
354
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
355
|
+
);
|
|
356
|
+
--scroll-fade-mask: linear-gradient(
|
|
357
|
+
to right,
|
|
358
|
+
transparent 0,
|
|
359
|
+
#000 var(--scroll-fade-s, 0px),
|
|
360
|
+
#000 100%
|
|
361
|
+
);
|
|
362
|
+
&:where([dir="rtl"], [dir="rtl"] *) {
|
|
363
|
+
--scroll-fade-mask: linear-gradient(
|
|
364
|
+
to left,
|
|
365
|
+
transparent 0,
|
|
366
|
+
#000 var(--scroll-fade-s, 0px),
|
|
367
|
+
#000 100%
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
-webkit-mask-image: var(--scroll-fade-mask);
|
|
371
|
+
mask-image: var(--scroll-fade-mask);
|
|
372
|
+
-webkit-mask-composite: source-in;
|
|
373
|
+
mask-composite: intersect;
|
|
374
|
+
-webkit-mask-repeat: no-repeat;
|
|
375
|
+
mask-repeat: no-repeat;
|
|
376
|
+
|
|
377
|
+
@supports (animation-timeline: scroll()) {
|
|
378
|
+
animation: scroll-fade-reveal-s 1ms ease-in-out;
|
|
379
|
+
animation-timeline: scroll(self inline);
|
|
380
|
+
animation-range: 0 var(--scroll-fade-reveal, calc(var(--spacing) * 24));
|
|
381
|
+
animation-fill-mode: both;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
@supports not (animation-timeline: scroll()) {
|
|
385
|
+
--scroll-fade-s: var(--_scroll-fade-size-s);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
@utility scroll-fade-e {
|
|
390
|
+
--_scroll-fade-size-e: var(
|
|
391
|
+
--scroll-fade-e-size,
|
|
392
|
+
var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
|
|
393
|
+
);
|
|
394
|
+
--scroll-fade-mask: linear-gradient(
|
|
395
|
+
to right,
|
|
396
|
+
#000 0,
|
|
397
|
+
#000 calc(100% - var(--scroll-fade-e, 0px)),
|
|
398
|
+
transparent 100%
|
|
399
|
+
);
|
|
400
|
+
&:where([dir="rtl"], [dir="rtl"] *) {
|
|
401
|
+
--scroll-fade-mask: linear-gradient(
|
|
402
|
+
to left,
|
|
403
|
+
#000 0,
|
|
404
|
+
#000 calc(100% - var(--scroll-fade-e, 0px)),
|
|
405
|
+
transparent 100%
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
-webkit-mask-image: var(--scroll-fade-mask);
|
|
409
|
+
mask-image: var(--scroll-fade-mask);
|
|
410
|
+
-webkit-mask-composite: source-in;
|
|
411
|
+
mask-composite: intersect;
|
|
412
|
+
-webkit-mask-repeat: no-repeat;
|
|
413
|
+
mask-repeat: no-repeat;
|
|
414
|
+
|
|
415
|
+
@supports (animation-timeline: scroll()) {
|
|
416
|
+
animation: scroll-fade-reveal-e 1ms ease-in-out;
|
|
417
|
+
animation-timeline: scroll(self inline);
|
|
418
|
+
animation-range: calc(
|
|
419
|
+
100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))
|
|
420
|
+
)
|
|
421
|
+
100%;
|
|
422
|
+
animation-fill-mode: both;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
@supports not (animation-timeline: scroll()) {
|
|
426
|
+
--scroll-fade-e: var(--_scroll-fade-size-e);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
@utility scroll-fade-* {
|
|
431
|
+
--scroll-fade-size: calc(var(--spacing) * --value(integer));
|
|
432
|
+
--scroll-fade-size: --value([length], [percentage]);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
@utility scroll-fade-t-* {
|
|
436
|
+
--scroll-fade-t-size: calc(var(--spacing) * --value(integer));
|
|
437
|
+
--scroll-fade-t-size: --value([length], [percentage]);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
@utility scroll-fade-b-* {
|
|
441
|
+
--scroll-fade-b-size: calc(var(--spacing) * --value(integer));
|
|
442
|
+
--scroll-fade-b-size: --value([length], [percentage]);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
@utility scroll-fade-s-* {
|
|
446
|
+
--scroll-fade-s-size: calc(var(--spacing) * --value(integer));
|
|
447
|
+
--scroll-fade-s-size: --value([length], [percentage]);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
@utility scroll-fade-e-* {
|
|
451
|
+
--scroll-fade-e-size: calc(var(--spacing) * --value(integer));
|
|
452
|
+
--scroll-fade-e-size: --value([length], [percentage]);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
@utility scroll-fade-none {
|
|
456
|
+
--scroll-fade-mask: none;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* ─── shimmer ─── */
|
|
460
|
+
@property --shimmer-angle {
|
|
461
|
+
syntax: "<angle>";
|
|
462
|
+
inherits: true;
|
|
463
|
+
initial-value: 20deg;
|
|
464
|
+
}
|
|
465
|
+
@property --shimmer-image {
|
|
466
|
+
syntax: "*";
|
|
467
|
+
inherits: false;
|
|
468
|
+
}
|
|
469
|
+
@property --shimmer-text-fill {
|
|
470
|
+
syntax: "*";
|
|
471
|
+
inherits: false;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
@theme inline {
|
|
475
|
+
@keyframes tw-shimmer {
|
|
476
|
+
from {
|
|
477
|
+
background-position: 100% 0;
|
|
478
|
+
}
|
|
479
|
+
to {
|
|
480
|
+
background-position: 0 0;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
@utility shimmer {
|
|
486
|
+
--_spread: var(--shimmer-spread, calc(3ch + 40px));
|
|
487
|
+
--_base: currentColor;
|
|
488
|
+
--_highlight: var(
|
|
489
|
+
--shimmer-color,
|
|
490
|
+
oklch(from currentColor l c h / calc(alpha* 0.2))
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
background-image: var(
|
|
494
|
+
--shimmer-image,
|
|
495
|
+
linear-gradient(
|
|
496
|
+
calc(90deg + var(--shimmer-angle)),
|
|
497
|
+
var(--_base) calc(50% - var(--_spread)),
|
|
498
|
+
color-mix(in oklch, var(--_highlight), var(--_base) 50%)
|
|
499
|
+
calc(50% - var(--_spread) * 0.5),
|
|
500
|
+
var(--_highlight) 50%,
|
|
501
|
+
color-mix(in oklch, var(--_highlight), var(--_base) 50%)
|
|
502
|
+
calc(50% + var(--_spread) * 0.5),
|
|
503
|
+
var(--_base) calc(50% + var(--_spread))
|
|
504
|
+
)
|
|
505
|
+
);
|
|
506
|
+
background-repeat: no-repeat;
|
|
507
|
+
background-size: calc(200% + var(--_spread) * 2) 100%;
|
|
508
|
+
background-position: 0 0;
|
|
509
|
+
background-clip: text;
|
|
510
|
+
-webkit-background-clip: text;
|
|
511
|
+
-webkit-text-fill-color: var(--shimmer-text-fill, transparent);
|
|
512
|
+
animation: tw-shimmer var(--shimmer-duration, 2s) linear infinite;
|
|
513
|
+
|
|
514
|
+
@variant dark {
|
|
515
|
+
--_highlight: var(
|
|
516
|
+
--shimmer-color,
|
|
517
|
+
oklch(from currentColor max(0.8, calc(l + 0.4)) c h / calc(alpha + 0.4))
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
&:where([dir="rtl"], [dir="rtl"] *) {
|
|
522
|
+
animation-direction: reverse;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
@utility shimmer-once {
|
|
527
|
+
animation-iteration-count: 1;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
@utility shimmer-reverse {
|
|
531
|
+
animation-direction: reverse;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
@utility shimmer-none {
|
|
535
|
+
--shimmer-image: none;
|
|
536
|
+
--shimmer-text-fill: currentColor;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
@utility shimmer-color-* {
|
|
540
|
+
--shimmer-color: --value(--color, [color]);
|
|
541
|
+
--shimmer-color: color-mix(
|
|
542
|
+
in oklch,
|
|
543
|
+
--value(--color, [color]) calc(--modifier(integer) * 1%),
|
|
544
|
+
transparent
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
@utility shimmer-duration-* {
|
|
549
|
+
--shimmer-duration: calc(--value(integer) * 1ms);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
@utility shimmer-spread-* {
|
|
553
|
+
--shimmer-spread: calc(var(--spacing) * --value(integer));
|
|
554
|
+
--shimmer-spread: --value([length], [percentage]);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
@utility shimmer-angle-* {
|
|
558
|
+
--shimmer-angle: calc(--value(integer) * 1deg);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
@media (prefers-reduced-motion: reduce) {
|
|
562
|
+
.shimmer {
|
|
563
|
+
animation: none;
|
|
564
|
+
background-image: none;
|
|
565
|
+
-webkit-text-fill-color: currentColor;
|
|
566
|
+
}
|
|
567
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ionbit-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Ionbit UI CLI — install source-owned components from the Ionbit UI registry.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,6 +24,12 @@
|
|
|
24
24
|
"scaffold"
|
|
25
25
|
],
|
|
26
26
|
"bin": "dist/index.js",
|
|
27
|
+
"exports": {
|
|
28
|
+
"./tailwind.css": "./dist/tailwind.css",
|
|
29
|
+
"./tokens.css": "./dist/tokens.css",
|
|
30
|
+
"./base.css": "./dist/base.css",
|
|
31
|
+
"./utilities.css": "./dist/utilities.css"
|
|
32
|
+
},
|
|
27
33
|
"files": [
|
|
28
34
|
"dist",
|
|
29
35
|
"README.md"
|
|
@@ -32,7 +38,7 @@
|
|
|
32
38
|
"access": "public"
|
|
33
39
|
},
|
|
34
40
|
"scripts": {
|
|
35
|
-
"build": "vite build",
|
|
41
|
+
"build": "vite build && node scripts/copy-css.mjs",
|
|
36
42
|
"typecheck": "tsc --noEmit",
|
|
37
43
|
"dev": "vite build --watch"
|
|
38
44
|
},
|