@babelize/elements 1.0.8 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -11
- package/bin.js +2 -0
- package/dist/cli/index.js +169 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.cjs +956 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +118 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.js +930 -0
- package/dist/index.js.map +1 -0
- package/package.json +35 -16
- package/dist/lib/utils.d.ts +0 -3
- package/dist/lib/utils.d.ts.map +0 -1
- package/dist/lib/utils.js +0 -6
- package/dist/lib/utils.js.map +0 -1
- package/dist/registry/components/index.d.ts +0 -3
- package/dist/registry/components/index.d.ts.map +0 -1
- package/dist/registry/components/index.js +0 -2
- package/dist/registry/components/index.js.map +0 -1
- package/dist/registry/components/language-switcher.d.ts +0 -83
- package/dist/registry/components/language-switcher.d.ts.map +0 -1
- package/dist/registry/components/language-switcher.js +0 -194
- package/dist/registry/components/language-switcher.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="
|
|
2
|
+
<img src="https://raw.githubusercontent.com/babelize/babelize-elements/main/public/elements_logo.svg" width="341" height="64" alt="Babelize Elements logo" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">Babelize Elements</h1>
|
|
@@ -19,40 +19,135 @@
|
|
|
19
19
|
</p>
|
|
20
20
|
|
|
21
21
|
<p align="center">
|
|
22
|
-
<a href="https://
|
|
23
|
-
<a href="https://
|
|
22
|
+
<a href="https://www.npmjs.com/package/@babelize/elements"><img src="https://img.shields.io/npm/v/@babelize/elements.svg" alt="npm version" /></a>
|
|
23
|
+
<a href="https://www.npmjs.com/package/@babelize/elements"><img src="https://img.shields.io/npm/dm/@babelize/elements.svg" alt="npm downloads" /></a>
|
|
24
|
+
<a href="https://github.com/babelize/babelize-elements/actions/workflows/ci.yml"><img src="https://github.com/babelize/babelize-elements/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
|
|
25
|
+
<a href="https://github.com/babelize/babelize-elements/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@babelize/elements.svg" alt="License: MIT" /></a>
|
|
24
26
|
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs welcome" />
|
|
25
|
-
<a href="https://github.com/babelize/babelize-elements/discussions"><img src="https://img.shields.io/badge/discussions-Join%20us-blue.svg" alt="Discussions" /></a>
|
|
26
27
|
</p>
|
|
27
28
|
|
|
28
29
|
## What is Babelize Elements?
|
|
29
30
|
|
|
30
31
|
**Babelize Elements** is a community-built library of **Localization UI components** for React and Tailwind CSS. Every localized app needs a language switcher, a locale picker, RTL-aware layouts, and pluralization UI — Elements turns that repetitive work into a shared, open-source toolbox.
|
|
31
32
|
|
|
32
|
-
- **Easy to install** — `npm install @babelize/elements`
|
|
33
|
+
- **Easy to install** — `npm install @babelize/elements` for the full library, or add components one at a time with `npx shadcn@latest add @elements/<component>`.
|
|
34
|
+
- **No framework lock-in** — plain React and Tailwind. No Next.js, no router, no theme provider required.
|
|
33
35
|
- **Localization-first** — pluralization, RTL, and locale data built into every component.
|
|
34
36
|
- **Accessible** — keyboard support, ARIA labels, and WCAG-aware markup.
|
|
35
37
|
- **Open source** — MIT-licensed, free forever, built by contributors like you.
|
|
36
38
|
|
|
37
39
|
## Installation
|
|
38
40
|
|
|
41
|
+
### Full library
|
|
42
|
+
|
|
39
43
|
```bash
|
|
40
44
|
npm install @babelize/elements
|
|
41
45
|
```
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
### Individual components
|
|
48
|
+
|
|
49
|
+
Install a component with the shadcn CLI (register the registry once):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx shadcn@latest registry add @elements=https://elements.babelize.co/r/{name}.json
|
|
53
|
+
npx shadcn@latest add @elements/language-switcher
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or with the CLI bundled in `@babelize/elements`:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx @babelize/elements add language-switcher
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Usage
|
|
63
|
+
|
|
64
|
+
Every component works uncontrolled (pass `defaultValue`) or controlled (pass `value`
|
|
65
|
+
and `onValueChange`).
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { LanguageSwitcher, PhoneInput, NavBar } from "@babelize/elements";
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### LanguageSwitcher
|
|
44
72
|
|
|
45
|
-
|
|
73
|
+
```tsx
|
|
74
|
+
<LanguageSwitcher
|
|
75
|
+
locales={[{ code: "en" }, { code: "fr" }, { code: "ar" }]}
|
|
76
|
+
defaultValue="en"
|
|
77
|
+
showFlags
|
|
78
|
+
onValueChange={(code) => router.push(`/${code}`)}
|
|
79
|
+
/>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
| Prop | Type | Default | Description |
|
|
83
|
+
| --------------- | ------------------------ | ------------ | ------------------------------------------------------------------------------------- |
|
|
84
|
+
| `locales` | `Locale[]` | — | Available locales. Only `code` is required; labels, flags, and RTL are auto-detected. |
|
|
85
|
+
| `value` | `string` | — | Selected locale code. Pass this to control the component. |
|
|
86
|
+
| `defaultValue` | `string` | first locale | Initial locale code when uncontrolled. |
|
|
87
|
+
| `onValueChange` | `(code: string) => void` | — | Fired once per selection. |
|
|
88
|
+
| `showFlags` | `boolean` | `false` | Show flag emojis beside locale names. |
|
|
89
|
+
| `label` | `"native" \| "english"` | `"english"` | Render locale names natively or in English. |
|
|
90
|
+
|
|
91
|
+
### PhoneInput
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
<PhoneInput
|
|
95
|
+
defaultCountry="IN"
|
|
96
|
+
name="phone"
|
|
97
|
+
onValueChange={(phone, country) => console.log(country.dialCode + phone)}
|
|
98
|
+
/>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
| Prop | Type | Default | Description |
|
|
102
|
+
| ---------------- | ------------------------------------------- | ------- | ------------------------------------------------- |
|
|
103
|
+
| `value` | `string` | — | Phone number. Pass this to control the component. |
|
|
104
|
+
| `defaultValue` | `string` | `""` | Initial number when uncontrolled. |
|
|
105
|
+
| `onValueChange` | `(phone: string, country: Country) => void` | — | Fired on typing and on country change. |
|
|
106
|
+
| `defaultCountry` | `string` | `"US"` | ISO 3166-1 alpha-2 code of the initial country. |
|
|
107
|
+
| `showFlags` | `boolean` | `true` | Show the flag emoji beside the dial code. |
|
|
108
|
+
|
|
109
|
+
The ref points at the underlying `<input>`, and `name`, `required`, and other input
|
|
110
|
+
attributes pass straight through — so it works in a plain HTML form.
|
|
111
|
+
|
|
112
|
+
### NavBar
|
|
113
|
+
|
|
114
|
+
`NavBar` renders plain `<a>` elements by default. Pass `linkComponent` to get
|
|
115
|
+
client-side navigation from your router:
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
import Link from "next/link";
|
|
119
|
+
|
|
120
|
+
<NavBar
|
|
121
|
+
logo={<Logo />}
|
|
122
|
+
links={[{ label: "Docs", href: "/docs" }]}
|
|
123
|
+
locales={[{ code: "en" }, { code: "fr" }]}
|
|
124
|
+
value={locale}
|
|
125
|
+
onValueChange={setLocale}
|
|
126
|
+
linkComponent={Link}
|
|
127
|
+
cta={{ label: "Get started", href: "/docs" }}
|
|
128
|
+
/>;
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Full props for every component are documented at
|
|
132
|
+
[elements.babelize.co](https://elements.babelize.co).
|
|
46
133
|
|
|
47
|
-
##
|
|
134
|
+
## Documentation
|
|
48
135
|
|
|
49
|
-
|
|
136
|
+
Full documentation, guides, and live component demos live at
|
|
137
|
+
[elements.babelize.co](https://elements.babelize.co), built with Next.js and
|
|
138
|
+
[Fumadocs](https://fumadocs.dev) from this same repo.
|
|
50
139
|
|
|
51
|
-
|
|
140
|
+
## Local development
|
|
52
141
|
|
|
53
142
|
```bash
|
|
54
143
|
bun install
|
|
55
|
-
bun run dev
|
|
144
|
+
bun run dev # docs site at http://localhost:3000
|
|
145
|
+
|
|
146
|
+
bun run test # component tests
|
|
147
|
+
bun run typecheck
|
|
148
|
+
bun run lint
|
|
149
|
+
bun run build:lib # build the publishable library into dist/
|
|
150
|
+
bun run test:pack # install the packed tarball into a scratch project
|
|
56
151
|
```
|
|
57
152
|
|
|
58
153
|
## Contributing a component
|
|
@@ -80,6 +175,20 @@ Great component candidates:
|
|
|
80
175
|
- [Security Policy](https://github.com/babelize/babelize-elements/blob/main/SECURITY.md)
|
|
81
176
|
- [Contributing](https://github.com/babelize/babelize-elements/blob/main/CONTRIBUTING.md)
|
|
82
177
|
|
|
178
|
+
## Contributors
|
|
179
|
+
|
|
180
|
+
<p align="center">
|
|
181
|
+
Babelize Elements is built by an amazing community of designers,
|
|
182
|
+
developers, and translators. A huge thank-you to everyone who contributes
|
|
183
|
+
code, reviews, docs, or ideas.
|
|
184
|
+
</p>
|
|
185
|
+
|
|
186
|
+
<p align="center">
|
|
187
|
+
<a href="https://github.com/babelize/babelize-elements/graphs/contributors">
|
|
188
|
+
<img src="https://contrib.rocks/image?repo=babelize/babelize-elements" alt="All Babelize Elements contributors" />
|
|
189
|
+
</a>
|
|
190
|
+
</p>
|
|
191
|
+
|
|
83
192
|
## License
|
|
84
193
|
|
|
85
194
|
[MIT](https://github.com/babelize/babelize-elements/blob/main/LICENSE) © [Babelize](https://babelize.co)
|
package/bin.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// src/cli/index.ts
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
|
+
import { basename, dirname, join } from "path";
|
|
4
|
+
import { spawnSync } from "child_process";
|
|
5
|
+
var REGISTRY_URL = process.env.BABELIZE_REGISTRY ?? "https://elements.babelize.co/r";
|
|
6
|
+
var BASE_URL = REGISTRY_URL.replace(/\/r\/?$/, "");
|
|
7
|
+
var DEFAULT_ALIASES = {
|
|
8
|
+
components: "@/components",
|
|
9
|
+
ui: "@/components/ui",
|
|
10
|
+
lib: "@/lib",
|
|
11
|
+
utils: "@/lib/utils",
|
|
12
|
+
hooks: "@/hooks"
|
|
13
|
+
};
|
|
14
|
+
var GREEN = "\x1B[32m";
|
|
15
|
+
var RED = "\x1B[31m";
|
|
16
|
+
var CYAN = "\x1B[36m";
|
|
17
|
+
var BOLD = "\x1B[1m";
|
|
18
|
+
var RESET = "\x1B[0m";
|
|
19
|
+
var projectRoot = process.cwd();
|
|
20
|
+
function log(message = "") {
|
|
21
|
+
process.stdout.write(`${message}
|
|
22
|
+
`);
|
|
23
|
+
}
|
|
24
|
+
function error(message) {
|
|
25
|
+
process.stderr.write(`${RED}${message}${RESET}
|
|
26
|
+
`);
|
|
27
|
+
}
|
|
28
|
+
function readComponentsJson() {
|
|
29
|
+
try {
|
|
30
|
+
return JSON.parse(readFileSync(join(projectRoot, "components.json"), "utf8"));
|
|
31
|
+
} catch {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function resolveAliases() {
|
|
36
|
+
const user = readComponentsJson().aliases ?? {};
|
|
37
|
+
return { ...DEFAULT_ALIASES, ...user };
|
|
38
|
+
}
|
|
39
|
+
function aliasToDir(alias) {
|
|
40
|
+
return alias.replace(/^@\//, "");
|
|
41
|
+
}
|
|
42
|
+
async function fetchItem(name) {
|
|
43
|
+
const url = `${REGISTRY_URL}/${name}.json`;
|
|
44
|
+
const res = await fetch(url);
|
|
45
|
+
if (!res.ok) {
|
|
46
|
+
throw new Error(`Failed to fetch "${name}" from ${url} (HTTP ${res.status}).`);
|
|
47
|
+
}
|
|
48
|
+
return await res.json();
|
|
49
|
+
}
|
|
50
|
+
function detectPackageManager() {
|
|
51
|
+
if (existsSync(join(projectRoot, "bun.lock")) || existsSync(join(projectRoot, "bun.lockb"))) {
|
|
52
|
+
return "bun";
|
|
53
|
+
}
|
|
54
|
+
if (existsSync(join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
55
|
+
if (existsSync(join(projectRoot, "yarn.lock"))) return "yarn";
|
|
56
|
+
return "npm";
|
|
57
|
+
}
|
|
58
|
+
function installDependencies(pm, deps) {
|
|
59
|
+
const args = pm === "npm" ? ["install", ...deps] : ["add", ...deps];
|
|
60
|
+
log(`
|
|
61
|
+
${CYAN}Installing dependencies with ${pm}${RESET}`);
|
|
62
|
+
const result = spawnSync(pm, args, { cwd: projectRoot, stdio: "inherit" });
|
|
63
|
+
if (result.status !== 0) process.exit(result.status ?? 1);
|
|
64
|
+
}
|
|
65
|
+
function resolveDestination(file, aliases) {
|
|
66
|
+
const dir = file.type === "registry:lib" ? aliasToDir(aliases.lib) : aliasToDir(aliases.components);
|
|
67
|
+
const pathInDir = file.path.replace(/^(components|lib|ui|hooks)\//, "");
|
|
68
|
+
return join(projectRoot, dir, pathInDir);
|
|
69
|
+
}
|
|
70
|
+
function rewriteImports(content, aliases) {
|
|
71
|
+
return content.replaceAll("@/lib/use-controllable-state", `${aliases.lib}/use-controllable-state`).replaceAll("@/lib/utils", aliases.utils);
|
|
72
|
+
}
|
|
73
|
+
function writeItem(item, aliases, written) {
|
|
74
|
+
for (const file of item.files ?? []) {
|
|
75
|
+
if (!file.content) continue;
|
|
76
|
+
const dest = resolveDestination(file, aliases);
|
|
77
|
+
if (written.has(dest)) continue;
|
|
78
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
79
|
+
writeFileSync(dest, rewriteImports(file.content, aliases), "utf8");
|
|
80
|
+
written.add(dest);
|
|
81
|
+
log(` ${GREEN}\u2713${RESET} ${basename(dest)}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function addComponents(names, aliases) {
|
|
85
|
+
const visited = /* @__PURE__ */ new Set();
|
|
86
|
+
const written = /* @__PURE__ */ new Set();
|
|
87
|
+
const deps = /* @__PURE__ */ new Set();
|
|
88
|
+
async function addItem(name) {
|
|
89
|
+
if (visited.has(name)) return;
|
|
90
|
+
visited.add(name);
|
|
91
|
+
const item = await fetchItem(name);
|
|
92
|
+
log(`
|
|
93
|
+
${BOLD}${item.title ?? item.name}${RESET}`);
|
|
94
|
+
if (item.description) log(` ${item.description}`);
|
|
95
|
+
for (const dep of item.dependencies ?? []) deps.add(dep);
|
|
96
|
+
writeItem(item, aliases, written);
|
|
97
|
+
for (const dep of item.registryDependencies ?? []) {
|
|
98
|
+
await addItem(dep);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
for (const name of names) {
|
|
102
|
+
await addItem(name);
|
|
103
|
+
}
|
|
104
|
+
if (deps.size > 0) {
|
|
105
|
+
installDependencies(detectPackageManager(), [...deps]);
|
|
106
|
+
}
|
|
107
|
+
log(`
|
|
108
|
+
${GREEN}${BOLD}Done.${RESET} Components written to ${aliases.components}.`);
|
|
109
|
+
}
|
|
110
|
+
async function listComponents() {
|
|
111
|
+
const res = await fetch(`${BASE_URL}/registry.json`);
|
|
112
|
+
if (!res.ok) {
|
|
113
|
+
throw new Error(`Failed to fetch registry index (HTTP ${res.status}).`);
|
|
114
|
+
}
|
|
115
|
+
const index = await res.json();
|
|
116
|
+
log(`${BOLD}${index.name}${RESET} registry
|
|
117
|
+
`);
|
|
118
|
+
for (const item of index.items) {
|
|
119
|
+
const title = item.title ?? item.name;
|
|
120
|
+
log(` ${CYAN}${item.name}${RESET} \u2014 ${item.description ?? title}`);
|
|
121
|
+
}
|
|
122
|
+
log(`
|
|
123
|
+
Install a component:
|
|
124
|
+
npx shadcn@latest add @elements/<component>`);
|
|
125
|
+
log(` npx @babelize/elements add <component>`);
|
|
126
|
+
}
|
|
127
|
+
function printUsage() {
|
|
128
|
+
log(`${BOLD}Babelize Elements CLI${RESET}`);
|
|
129
|
+
log(`
|
|
130
|
+
Usage:
|
|
131
|
+
babelize add <component...> Install components into your project`);
|
|
132
|
+
log(` babelize list List available components
|
|
133
|
+
`);
|
|
134
|
+
log(`Options:
|
|
135
|
+
--help Show this help
|
|
136
|
+
`);
|
|
137
|
+
log(`Registry:
|
|
138
|
+
Set BABELIZE_REGISTRY to override the registry URL (default ${REGISTRY_URL}).`);
|
|
139
|
+
}
|
|
140
|
+
async function main() {
|
|
141
|
+
const args = process.argv.slice(2);
|
|
142
|
+
const command = args[0];
|
|
143
|
+
if (command === "--help" || command === "-h" || !command) {
|
|
144
|
+
printUsage();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const aliases = resolveAliases();
|
|
148
|
+
try {
|
|
149
|
+
if (command === "add") {
|
|
150
|
+
const names = args.slice(1);
|
|
151
|
+
if (names.length === 0) {
|
|
152
|
+
error("No components specified. Usage: babelize add <component...>");
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
await addComponents(names, aliases);
|
|
156
|
+
} else if (command === "list") {
|
|
157
|
+
await listComponents();
|
|
158
|
+
} else {
|
|
159
|
+
error(`Unknown command: ${command}`);
|
|
160
|
+
printUsage();
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
} catch (err) {
|
|
164
|
+
error(err instanceof Error ? err.message : String(err));
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
main();
|
|
169
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\n\nconst REGISTRY_URL = process.env.BABELIZE_REGISTRY ?? \"https://elements.babelize.co/r\";\nconst BASE_URL = REGISTRY_URL.replace(/\\/r\\/?$/, \"\");\n\nconst DEFAULT_ALIASES = {\n components: \"@/components\",\n ui: \"@/components/ui\",\n lib: \"@/lib\",\n utils: \"@/lib/utils\",\n hooks: \"@/hooks\",\n};\n\nconst GREEN = \"\\u001b[32m\";\nconst RED = \"\\u001b[31m\";\nconst CYAN = \"\\u001b[36m\";\nconst BOLD = \"\\u001b[1m\";\nconst RESET = \"\\u001b[0m\";\n\ninterface RegistryFile {\n path: string;\n type: string;\n content?: string;\n}\n\ninterface RegistryItem {\n $schema?: string;\n name: string;\n type: string;\n title?: string;\n description?: string;\n dependencies?: string[];\n registryDependencies?: string[];\n files?: RegistryFile[];\n}\n\nconst projectRoot = process.cwd();\n\nfunction log(message = \"\"): void {\n process.stdout.write(`${message}\\n`);\n}\n\nfunction error(message: string): void {\n process.stderr.write(`${RED}${message}${RESET}\\n`);\n}\n\nfunction readComponentsJson(): { aliases?: Record<string, string> } {\n try {\n return JSON.parse(readFileSync(join(projectRoot, \"components.json\"), \"utf8\"));\n } catch {\n return {};\n }\n}\n\nfunction resolveAliases(): Record<string, string> {\n const user = readComponentsJson().aliases ?? {};\n return { ...DEFAULT_ALIASES, ...user };\n}\n\nfunction aliasToDir(alias: string): string {\n return alias.replace(/^@\\//, \"\");\n}\n\nasync function fetchItem(name: string): Promise<RegistryItem> {\n const url = `${REGISTRY_URL}/${name}.json`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Failed to fetch \"${name}\" from ${url} (HTTP ${res.status}).`);\n }\n return (await res.json()) as RegistryItem;\n}\n\nfunction detectPackageManager(): string {\n if (existsSync(join(projectRoot, \"bun.lock\")) || existsSync(join(projectRoot, \"bun.lockb\"))) {\n return \"bun\";\n }\n if (existsSync(join(projectRoot, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(join(projectRoot, \"yarn.lock\"))) return \"yarn\";\n return \"npm\";\n}\n\nfunction installDependencies(pm: string, deps: string[]): void {\n const args = pm === \"npm\" ? [\"install\", ...deps] : [\"add\", ...deps];\n log(`\\n${CYAN}Installing dependencies with ${pm}${RESET}`);\n const result = spawnSync(pm, args, { cwd: projectRoot, stdio: \"inherit\" });\n if (result.status !== 0) process.exit(result.status ?? 1);\n}\n\nfunction resolveDestination(file: RegistryFile, aliases: Record<string, string>): string {\n const dir =\n file.type === \"registry:lib\" ? aliasToDir(aliases.lib) : aliasToDir(aliases.components);\n const pathInDir = file.path.replace(/^(components|lib|ui|hooks)\\//, \"\");\n return join(projectRoot, dir, pathInDir);\n}\n\nfunction rewriteImports(content: string, aliases: Record<string, string>): string {\n // Longest specifier first: \"@/lib/utils\" is a prefix of nothing here, but the\n // hook path must not be partially rewritten by a shorter rule later.\n return content\n .replaceAll(\"@/lib/use-controllable-state\", `${aliases.lib}/use-controllable-state`)\n .replaceAll(\"@/lib/utils\", aliases.utils);\n}\n\nfunction writeItem(\n item: RegistryItem,\n aliases: Record<string, string>,\n written: Set<string>,\n): void {\n for (const file of item.files ?? []) {\n if (!file.content) continue;\n const dest = resolveDestination(file, aliases);\n if (written.has(dest)) continue;\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, rewriteImports(file.content, aliases), \"utf8\");\n written.add(dest);\n log(` ${GREEN}✓${RESET} ${basename(dest)}`);\n }\n}\n\nasync function addComponents(names: string[], aliases: Record<string, string>): Promise<void> {\n const visited = new Set<string>();\n const written = new Set<string>();\n const deps = new Set<string>();\n\n async function addItem(name: string): Promise<void> {\n if (visited.has(name)) return;\n visited.add(name);\n\n const item = await fetchItem(name);\n log(`\\n${BOLD}${item.title ?? item.name}${RESET}`);\n if (item.description) log(` ${item.description}`);\n\n for (const dep of item.dependencies ?? []) deps.add(dep);\n writeItem(item, aliases, written);\n\n for (const dep of item.registryDependencies ?? []) {\n await addItem(dep);\n }\n }\n\n for (const name of names) {\n await addItem(name);\n }\n\n if (deps.size > 0) {\n installDependencies(detectPackageManager(), [...deps]);\n }\n\n log(`\\n${GREEN}${BOLD}Done.${RESET} Components written to ${aliases.components}.`);\n}\n\nasync function listComponents(): Promise<void> {\n const res = await fetch(`${BASE_URL}/registry.json`);\n if (!res.ok) {\n throw new Error(`Failed to fetch registry index (HTTP ${res.status}).`);\n }\n const index = (await res.json()) as { name: string; items: RegistryItem[] };\n log(`${BOLD}${index.name}${RESET} registry\\n`);\n for (const item of index.items) {\n const title = item.title ?? item.name;\n log(` ${CYAN}${item.name}${RESET} — ${item.description ?? title}`);\n }\n log(`\\nInstall a component:\\n npx shadcn@latest add @elements/<component>`);\n log(` npx @babelize/elements add <component>`);\n}\n\nfunction printUsage(): void {\n log(`${BOLD}Babelize Elements CLI${RESET}`);\n log(`\\nUsage:\\n babelize add <component...> Install components into your project`);\n log(` babelize list List available components\\n`);\n log(`Options:\\n --help Show this help\\n`);\n log(`Registry:\\n Set BABELIZE_REGISTRY to override the registry URL (default ${REGISTRY_URL}).`);\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const command = args[0];\n\n if (command === \"--help\" || command === \"-h\" || !command) {\n printUsage();\n return;\n }\n\n const aliases = resolveAliases();\n\n try {\n if (command === \"add\") {\n const names = args.slice(1);\n if (names.length === 0) {\n error(\"No components specified. Usage: babelize add <component...>\");\n process.exit(1);\n }\n await addComponents(names, aliases);\n } else if (command === \"list\") {\n await listComponents();\n } else {\n error(`Unknown command: ${command}`);\n printUsage();\n process.exit(1);\n }\n } catch (err) {\n error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":";AAAA,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,UAAU,SAAS,YAAY;AACxC,SAAS,iBAAiB;AAE1B,IAAM,eAAe,QAAQ,IAAI,qBAAqB;AACtD,IAAM,WAAW,aAAa,QAAQ,WAAW,EAAE;AAEnD,IAAM,kBAAkB;AAAA,EACtB,YAAY;AAAA,EACZ,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,OAAO;AAAA,EACP,OAAO;AACT;AAEA,IAAM,QAAQ;AACd,IAAM,MAAM;AACZ,IAAM,OAAO;AACb,IAAM,OAAO;AACb,IAAM,QAAQ;AAmBd,IAAM,cAAc,QAAQ,IAAI;AAEhC,SAAS,IAAI,UAAU,IAAU;AAC/B,UAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AACrC;AAEA,SAAS,MAAM,SAAuB;AACpC,UAAQ,OAAO,MAAM,GAAG,GAAG,GAAG,OAAO,GAAG,KAAK;AAAA,CAAI;AACnD;AAEA,SAAS,qBAA2D;AAClE,MAAI;AACF,WAAO,KAAK,MAAM,aAAa,KAAK,aAAa,iBAAiB,GAAG,MAAM,CAAC;AAAA,EAC9E,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,iBAAyC;AAChD,QAAM,OAAO,mBAAmB,EAAE,WAAW,CAAC;AAC9C,SAAO,EAAE,GAAG,iBAAiB,GAAG,KAAK;AACvC;AAEA,SAAS,WAAW,OAAuB;AACzC,SAAO,MAAM,QAAQ,QAAQ,EAAE;AACjC;AAEA,eAAe,UAAU,MAAqC;AAC5D,QAAM,MAAM,GAAG,YAAY,IAAI,IAAI;AACnC,QAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,MAAM,oBAAoB,IAAI,UAAU,GAAG,UAAU,IAAI,MAAM,IAAI;AAAA,EAC/E;AACA,SAAQ,MAAM,IAAI,KAAK;AACzB;AAEA,SAAS,uBAA+B;AACtC,MAAI,WAAW,KAAK,aAAa,UAAU,CAAC,KAAK,WAAW,KAAK,aAAa,WAAW,CAAC,GAAG;AAC3F,WAAO;AAAA,EACT;AACA,MAAI,WAAW,KAAK,aAAa,gBAAgB,CAAC,EAAG,QAAO;AAC5D,MAAI,WAAW,KAAK,aAAa,WAAW,CAAC,EAAG,QAAO;AACvD,SAAO;AACT;AAEA,SAAS,oBAAoB,IAAY,MAAsB;AAC7D,QAAM,OAAO,OAAO,QAAQ,CAAC,WAAW,GAAG,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI;AAClE,MAAI;AAAA,EAAK,IAAI,gCAAgC,EAAE,GAAG,KAAK,EAAE;AACzD,QAAM,SAAS,UAAU,IAAI,MAAM,EAAE,KAAK,aAAa,OAAO,UAAU,CAAC;AACzE,MAAI,OAAO,WAAW,EAAG,SAAQ,KAAK,OAAO,UAAU,CAAC;AAC1D;AAEA,SAAS,mBAAmB,MAAoB,SAAyC;AACvF,QAAM,MACJ,KAAK,SAAS,iBAAiB,WAAW,QAAQ,GAAG,IAAI,WAAW,QAAQ,UAAU;AACxF,QAAM,YAAY,KAAK,KAAK,QAAQ,gCAAgC,EAAE;AACtE,SAAO,KAAK,aAAa,KAAK,SAAS;AACzC;AAEA,SAAS,eAAe,SAAiB,SAAyC;AAGhF,SAAO,QACJ,WAAW,gCAAgC,GAAG,QAAQ,GAAG,yBAAyB,EAClF,WAAW,eAAe,QAAQ,KAAK;AAC5C;AAEA,SAAS,UACP,MACA,SACA,SACM;AACN,aAAW,QAAQ,KAAK,SAAS,CAAC,GAAG;AACnC,QAAI,CAAC,KAAK,QAAS;AACnB,UAAM,OAAO,mBAAmB,MAAM,OAAO;AAC7C,QAAI,QAAQ,IAAI,IAAI,EAAG;AACvB,cAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,kBAAc,MAAM,eAAe,KAAK,SAAS,OAAO,GAAG,MAAM;AACjE,YAAQ,IAAI,IAAI;AAChB,QAAI,KAAK,KAAK,SAAI,KAAK,IAAI,SAAS,IAAI,CAAC,EAAE;AAAA,EAC7C;AACF;AAEA,eAAe,cAAc,OAAiB,SAAgD;AAC5F,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,OAAO,oBAAI,IAAY;AAE7B,iBAAe,QAAQ,MAA6B;AAClD,QAAI,QAAQ,IAAI,IAAI,EAAG;AACvB,YAAQ,IAAI,IAAI;AAEhB,UAAM,OAAO,MAAM,UAAU,IAAI;AACjC,QAAI;AAAA,EAAK,IAAI,GAAG,KAAK,SAAS,KAAK,IAAI,GAAG,KAAK,EAAE;AACjD,QAAI,KAAK,YAAa,KAAI,KAAK,KAAK,WAAW,EAAE;AAEjD,eAAW,OAAO,KAAK,gBAAgB,CAAC,EAAG,MAAK,IAAI,GAAG;AACvD,cAAU,MAAM,SAAS,OAAO;AAEhC,eAAW,OAAO,KAAK,wBAAwB,CAAC,GAAG;AACjD,YAAM,QAAQ,GAAG;AAAA,IACnB;AAAA,EACF;AAEA,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,IAAI;AAAA,EACpB;AAEA,MAAI,KAAK,OAAO,GAAG;AACjB,wBAAoB,qBAAqB,GAAG,CAAC,GAAG,IAAI,CAAC;AAAA,EACvD;AAEA,MAAI;AAAA,EAAK,KAAK,GAAG,IAAI,QAAQ,KAAK,0BAA0B,QAAQ,UAAU,GAAG;AACnF;AAEA,eAAe,iBAAgC;AAC7C,QAAM,MAAM,MAAM,MAAM,GAAG,QAAQ,gBAAgB;AACnD,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,MAAM,wCAAwC,IAAI,MAAM,IAAI;AAAA,EACxE;AACA,QAAM,QAAS,MAAM,IAAI,KAAK;AAC9B,MAAI,GAAG,IAAI,GAAG,MAAM,IAAI,GAAG,KAAK;AAAA,CAAa;AAC7C,aAAW,QAAQ,MAAM,OAAO;AAC9B,UAAM,QAAQ,KAAK,SAAS,KAAK;AACjC,QAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,WAAM,KAAK,eAAe,KAAK,EAAE;AAAA,EACpE;AACA,MAAI;AAAA;AAAA,8CAAuE;AAC3E,MAAI,0CAA0C;AAChD;AAEA,SAAS,aAAmB;AAC1B,MAAI,GAAG,IAAI,wBAAwB,KAAK,EAAE;AAC1C,MAAI;AAAA;AAAA,qEAAgF;AACpF,MAAI;AAAA,CAA8D;AAClE,MAAI;AAAA;AAAA,CAA2D;AAC/D,MAAI;AAAA,gEAA4E,YAAY,IAAI;AAClG;AAEA,eAAe,OAAsB;AACnC,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,QAAM,UAAU,KAAK,CAAC;AAEtB,MAAI,YAAY,YAAY,YAAY,QAAQ,CAAC,SAAS;AACxD,eAAW;AACX;AAAA,EACF;AAEA,QAAM,UAAU,eAAe;AAE/B,MAAI;AACF,QAAI,YAAY,OAAO;AACrB,YAAM,QAAQ,KAAK,MAAM,CAAC;AAC1B,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,6DAA6D;AACnE,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,cAAc,OAAO,OAAO;AAAA,IACpC,WAAW,YAAY,QAAQ;AAC7B,YAAM,eAAe;AAAA,IACvB,OAAO;AACL,YAAM,oBAAoB,OAAO,EAAE;AACnC,iBAAW;AACX,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,SAAS,KAAK;AACZ,UAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AACtD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,KAAK;","names":[]}
|