atlasui-lib 0.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/CHANGELOG.md +157 -0
- package/LICENSE +21 -0
- package/README.md +253 -0
- package/dist/cli/index.js +364 -0
- package/dist/index.d.mts +1027 -0
- package/dist/index.d.ts +1027 -0
- package/dist/index.js +3954 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3733 -0
- package/dist/index.mjs.map +1 -0
- package/dist/provider.d.mts +15 -0
- package/dist/provider.d.ts +15 -0
- package/dist/provider.js +816 -0
- package/dist/provider.js.map +1 -0
- package/dist/provider.mjs +780 -0
- package/dist/provider.mjs.map +1 -0
- package/dist/tailwind.d.ts +25 -0
- package/dist/tailwind.js +129 -0
- package/package.json +138 -0
- package/src/cli/index.ts +301 -0
- package/src/cli/registry.ts +139 -0
- package/src/components/advanced-forms/index.tsx +567 -0
- package/src/components/basic/Button.tsx +135 -0
- package/src/components/basic/IconButton.tsx +69 -0
- package/src/components/basic/index.tsx +446 -0
- package/src/components/data-display/index.tsx +608 -0
- package/src/components/feedback/index.tsx +554 -0
- package/src/components/forms/index.tsx +476 -0
- package/src/components/layout/index.tsx +296 -0
- package/src/components/media/index.tsx +437 -0
- package/src/components/navigation/index.tsx +484 -0
- package/src/components/overlay/index.tsx +473 -0
- package/src/components/utility/index.tsx +411 -0
- package/src/hooks/index.ts +271 -0
- package/src/hooks/use-toast.tsx +74 -0
- package/src/index.ts +353 -0
- package/src/provider.tsx +54 -0
- package/src/styles/atlas.css +252 -0
- package/src/tailwind.ts +124 -0
- package/src/types/index.ts +95 -0
- package/src/utils/cn.ts +66 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
#!/usr/bin/env node
|
|
3
|
+
"use strict";
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// src/cli/index.ts
|
|
28
|
+
var import_path = __toESM(require("path"));
|
|
29
|
+
var import_commander = require("commander");
|
|
30
|
+
var import_chalk = __toESM(require("chalk"));
|
|
31
|
+
var import_ora = __toESM(require("ora"));
|
|
32
|
+
var import_prompts = __toESM(require("prompts"));
|
|
33
|
+
var import_fs_extra = __toESM(require("fs-extra"));
|
|
34
|
+
var import_execa = require("execa");
|
|
35
|
+
|
|
36
|
+
// src/cli/registry.ts
|
|
37
|
+
var REGISTRY = [
|
|
38
|
+
// Basic
|
|
39
|
+
{ name: "button", category: "basic", description: "Solid, outline, ghost, soft, link, danger variants. Loading state, icon slots.", deps: ["@radix-ui/react-slot", "class-variance-authority", "clsx", "tailwind-merge"] },
|
|
40
|
+
{ name: "icon-button", category: "basic", description: "Square or circular icon-only button.", deps: ["@radix-ui/react-slot", "class-variance-authority", "clsx", "tailwind-merge"] },
|
|
41
|
+
{ name: "link", category: "basic", description: "Anchor with external link indicator and underline control.", deps: ["@radix-ui/react-slot"] },
|
|
42
|
+
{ name: "badge", category: "basic", description: "Compact label \u2014 5 color variants, optional dot.", deps: ["class-variance-authority", "clsx", "tailwind-merge"] },
|
|
43
|
+
{ name: "avatar", category: "basic", description: "Image with fallback initials, status ring, 6 sizes.", deps: ["@radix-ui/react-avatar"] },
|
|
44
|
+
{ name: "avatar-group", category: "basic", description: "Stacked avatars with overflow count.", deps: ["@radix-ui/react-avatar"], registryDeps: ["avatar"] },
|
|
45
|
+
{ name: "divider", category: "basic", description: "Horizontal/vertical separator with optional center label.", deps: ["@radix-ui/react-separator"] },
|
|
46
|
+
{ name: "tag", category: "basic", description: "Closable colored tag with icon slot.", deps: [] },
|
|
47
|
+
{ name: "chip", category: "basic", description: "Toggleable chip with avatar/icon and remove button.", deps: [] },
|
|
48
|
+
{ name: "tooltip", category: "basic", description: "Radix tooltip, all four sides, configurable delay.", deps: ["@radix-ui/react-tooltip"] },
|
|
49
|
+
// Layout
|
|
50
|
+
{ name: "container", category: "layout", description: "Responsive max-width wrapper with padding control.", deps: [] },
|
|
51
|
+
{ name: "stack", category: "layout", description: "Flex column/row with gap, align, justify, divider.", deps: [] },
|
|
52
|
+
{ name: "grid", category: "layout", description: "CSS Grid with column/row/gap config.", deps: [] },
|
|
53
|
+
{ name: "flex", category: "layout", description: "Flex with full directional control.", deps: [] },
|
|
54
|
+
{ name: "section", category: "layout", description: "Semantic section with vertical padding presets.", deps: [] },
|
|
55
|
+
{ name: "spacer", category: "layout", description: "Invisible spacing element.", deps: [] },
|
|
56
|
+
{ name: "aspect-ratio", category: "layout", description: "Radix aspect-ratio container.", deps: ["@radix-ui/react-aspect-ratio"] },
|
|
57
|
+
{ name: "center", category: "layout", description: "Flex centering helper.", deps: [] },
|
|
58
|
+
{ name: "scroll-area", category: "layout", description: "Custom scrollbar via Radix ScrollArea.", deps: ["@radix-ui/react-scroll-area"] },
|
|
59
|
+
{ name: "masonry", category: "layout", description: "CSS multi-column masonry grid.", deps: [] },
|
|
60
|
+
// Navigation
|
|
61
|
+
{ name: "navbar", category: "navigation", description: "Sticky, glass-blur top bar.", deps: [] },
|
|
62
|
+
{ name: "sidebar", category: "navigation", description: "Collapsible side nav with width transition.", deps: [] },
|
|
63
|
+
{ name: "menu", category: "navigation", description: "Vertical nav menu with active/disabled states.", deps: [] },
|
|
64
|
+
{ name: "dropdown-menu", category: "navigation", description: "Full Radix Dropdown with all sub-primitives.", deps: ["@radix-ui/react-dropdown-menu"] },
|
|
65
|
+
{ name: "breadcrumb", category: "navigation", description: "Accessible trail with custom separator.", deps: [] },
|
|
66
|
+
{ name: "pagination", category: "navigation", description: "Page numbers with ellipsis and prev/next.", deps: [] },
|
|
67
|
+
{ name: "tabs", category: "navigation", description: "Line, pills, enclosed variants. Radix powered.", deps: ["@radix-ui/react-tabs"] },
|
|
68
|
+
{ name: "command-palette", category: "navigation", description: "\u2318K command palette.", deps: ["cmdk", "@radix-ui/react-dialog"], registryDeps: ["command-dialog"] },
|
|
69
|
+
{ name: "navigation-menu", category: "navigation", description: "Radix Navigation Menu for complex navbars.", deps: ["@radix-ui/react-navigation-menu"] },
|
|
70
|
+
{ name: "stepper", category: "navigation", description: "Horizontal/vertical multi-step indicator.", deps: [] },
|
|
71
|
+
// Forms
|
|
72
|
+
{ name: "input", category: "forms", description: "Left/right icon slots, sizes, error state.", deps: ["class-variance-authority"] },
|
|
73
|
+
{ name: "textarea", category: "forms", description: "Multi-line input with resize control.", deps: [] },
|
|
74
|
+
{ name: "select", category: "forms", description: "Full Radix Select with all sub-primitives.", deps: ["@radix-ui/react-select"] },
|
|
75
|
+
{ name: "checkbox", category: "forms", description: "With label, description, error state.", deps: ["@radix-ui/react-checkbox"] },
|
|
76
|
+
{ name: "radio-group", category: "forms", description: "Per-option labels and descriptions.", deps: ["@radix-ui/react-radio-group"] },
|
|
77
|
+
{ name: "switch", category: "forms", description: "Three sizes, label, description.", deps: ["@radix-ui/react-switch"] },
|
|
78
|
+
{ name: "slider", category: "forms", description: "Single-thumb range slider.", deps: ["@radix-ui/react-slider"] },
|
|
79
|
+
{ name: "range-slider", category: "forms", description: "Dual-thumb slider.", deps: ["@radix-ui/react-slider"], registryDeps: ["slider"] },
|
|
80
|
+
{ name: "date-picker", category: "forms", description: "Native date input wrapper.", deps: [] },
|
|
81
|
+
{ name: "time-picker", category: "forms", description: "Native time input wrapper.", deps: [] },
|
|
82
|
+
// Advanced Forms
|
|
83
|
+
{ name: "file-upload", category: "advanced-forms", description: "Drag-and-drop zone with click-to-upload fallback.", deps: [] },
|
|
84
|
+
{ name: "otp-input", category: "advanced-forms", description: "PIN/OTP with auto-advance and paste support.", deps: [] },
|
|
85
|
+
{ name: "color-picker", category: "advanced-forms", description: "Swatches + hex input.", deps: [] },
|
|
86
|
+
{ name: "search-input", category: "advanced-forms", description: "Search with loading state and clear button.", deps: [] },
|
|
87
|
+
{ name: "password-input", category: "advanced-forms", description: "Password with show/hide toggle.", deps: [] },
|
|
88
|
+
{ name: "combobox", category: "advanced-forms", description: "Searchable single-value select.", deps: [] },
|
|
89
|
+
{ name: "multi-select", category: "advanced-forms", description: "Multi-value select with chips.", deps: [] },
|
|
90
|
+
{ name: "form-field", category: "advanced-forms", description: "Form field wrapper with spacing.", deps: [] },
|
|
91
|
+
{ name: "form-label", category: "advanced-forms", description: "Label with required/optional indicators.", deps: [] },
|
|
92
|
+
{ name: "form-error", category: "advanced-forms", description: "Accessible error message.", deps: [] },
|
|
93
|
+
// Data Display
|
|
94
|
+
{ name: "card", category: "data-display", description: "Surface with header/content/footer slots. 5 variants.", deps: [] },
|
|
95
|
+
{ name: "table", category: "data-display", description: "Full HTML table system.", deps: [] },
|
|
96
|
+
{ name: "data-table", category: "data-display", description: "Sortable data table with loading and empty states.", deps: [] },
|
|
97
|
+
{ name: "list", category: "data-display", description: "Simple, bordered, and divided lists.", deps: [] },
|
|
98
|
+
{ name: "list-item", category: "data-display", description: "List item with icon and extra slot.", deps: [] },
|
|
99
|
+
{ name: "statistic", category: "data-display", description: "Key metric with trend indicator.", deps: [] },
|
|
100
|
+
{ name: "timeline", category: "data-display", description: "Vertical events with color-coded icons.", deps: [] },
|
|
101
|
+
{ name: "calendar", category: "data-display", description: "Month picker with highlighted dates.", deps: [] },
|
|
102
|
+
{ name: "chart", category: "data-display", description: "Chart wrapper \u2014 bring your own chart library.", deps: [] },
|
|
103
|
+
{ name: "code-block", category: "data-display", description: "Code display with copy button and line numbers.", deps: [] },
|
|
104
|
+
// Feedback
|
|
105
|
+
{ name: "alert", category: "feedback", description: "Info/success/warning/danger with optional dismiss.", deps: ["class-variance-authority"] },
|
|
106
|
+
{ name: "toast", category: "feedback", description: "Radix Toast with all sub-primitives.", deps: ["@radix-ui/react-toast"] },
|
|
107
|
+
{ name: "snackbar", category: "feedback", description: "Positioned message with action.", deps: [] },
|
|
108
|
+
{ name: "progress", category: "feedback", description: "Linear bar with color variants.", deps: ["@radix-ui/react-progress"] },
|
|
109
|
+
{ name: "circular-progress", category: "feedback", description: "SVG ring with indeterminate mode.", deps: [] },
|
|
110
|
+
{ name: "skeleton", category: "feedback", description: "Pulse placeholder for text, rect, circle.", deps: [] },
|
|
111
|
+
{ name: "loading-spinner", category: "feedback", description: "Accessible SVG spinner.", deps: [] },
|
|
112
|
+
{ name: "empty-state", category: "feedback", description: "Icon + title + description + action.", deps: [] },
|
|
113
|
+
{ name: "status-indicator", category: "feedback", description: "Online/offline/busy/away dot with pulse.", deps: [] },
|
|
114
|
+
{ name: "notification", category: "feedback", description: "Notification item with avatar, timestamp, unread dot.", deps: [] },
|
|
115
|
+
// Overlay
|
|
116
|
+
{ name: "modal", category: "overlay", description: "Preset dialog \u2014 sm to full size variants.", deps: ["@radix-ui/react-dialog"] },
|
|
117
|
+
{ name: "dialog", category: "overlay", description: "Full Radix Dialog primitive suite.", deps: ["@radix-ui/react-dialog"] },
|
|
118
|
+
{ name: "drawer", category: "overlay", description: "Slides in from any edge.", deps: ["@radix-ui/react-dialog"] },
|
|
119
|
+
{ name: "popover", category: "overlay", description: "Floating panel.", deps: ["@radix-ui/react-popover"] },
|
|
120
|
+
{ name: "hover-card", category: "overlay", description: "Rich hover preview.", deps: ["@radix-ui/react-hover-card"] },
|
|
121
|
+
{ name: "context-menu", category: "overlay", description: "Right-click menu.", deps: ["@radix-ui/react-context-menu"] },
|
|
122
|
+
{ name: "command-dialog", category: "overlay", description: "\u2318K palette.", deps: ["cmdk", "@radix-ui/react-dialog"] },
|
|
123
|
+
{ name: "sheet", category: "overlay", description: "Drawer alias.", deps: ["@radix-ui/react-dialog"], registryDeps: ["drawer"] },
|
|
124
|
+
{ name: "lightbox", category: "overlay", description: "Full-screen image overlay.", deps: ["@radix-ui/react-dialog"] },
|
|
125
|
+
{ name: "image-viewer", category: "overlay", description: "Lightbox alias.", deps: ["@radix-ui/react-dialog"], registryDeps: ["lightbox"] },
|
|
126
|
+
// Media
|
|
127
|
+
{ name: "image", category: "media", description: "Image with fallback, aspect ratio, fit, caption.", deps: [] },
|
|
128
|
+
{ name: "video-player", category: "media", description: "HTML5 video with captions/subtitles support.", deps: [] },
|
|
129
|
+
{ name: "audio-player", category: "media", description: "Custom audio UI with seek bar, cover art.", deps: [] },
|
|
130
|
+
{ name: "carousel", category: "media", description: "Autoplay, dots, arrows, loop, slidesPerView.", deps: [] },
|
|
131
|
+
{ name: "gallery", category: "media", description: "Responsive image grid with click handler.", deps: [] },
|
|
132
|
+
// Utility
|
|
133
|
+
{ name: "theme-switcher", category: "utility", description: "Icon / toggle / select variants.", deps: [] },
|
|
134
|
+
{ name: "copy-button", category: "utility", description: "Icon or labelled copy button with success feedback.", deps: [] },
|
|
135
|
+
{ name: "keyboard-shortcut", category: "utility", description: "Styled <kbd> shortcut display.", deps: [] },
|
|
136
|
+
{ name: "resizable-panel", category: "utility", description: "Drag-to-resize panel with min/max constraints.", deps: [] },
|
|
137
|
+
{ name: "drag-drop-area", category: "utility", description: "Accessible file drop zone.", deps: [] }
|
|
138
|
+
];
|
|
139
|
+
var COMPONENTS_BY_NAME = new Map(REGISTRY.map((c) => [c.name, c]));
|
|
140
|
+
var CATEGORIES = [
|
|
141
|
+
"basic",
|
|
142
|
+
"layout",
|
|
143
|
+
"navigation",
|
|
144
|
+
"forms",
|
|
145
|
+
"advanced-forms",
|
|
146
|
+
"data-display",
|
|
147
|
+
"feedback",
|
|
148
|
+
"overlay",
|
|
149
|
+
"media",
|
|
150
|
+
"utility"
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
// src/cli/index.ts
|
|
154
|
+
var banner = `
|
|
155
|
+
${import_chalk.default.bold.blue(" \u2554\u2550\u2557\u2554\u2566\u2557\u2566 \u2554\u2550\u2557\u2554\u2550\u2557\u2566 \u2566\u2566")}
|
|
156
|
+
${import_chalk.default.bold.blue(" \u2560\u2550\u2563 \u2551 \u2551 \u2560\u2550\u2563\u255A\u2550\u2557\u2551 \u2551\u2551")}
|
|
157
|
+
${import_chalk.default.bold.blue(" \u2569 \u2569 \u2569 \u2569\u2550\u255D\u2569 \u2569\u255A\u2550\u255D\u255A\u2550\u255D\u2569")}
|
|
158
|
+
${import_chalk.default.dim("Build anything. Ship faster.")}
|
|
159
|
+
${import_chalk.default.dim("by JohnDev19 \xB7 https://github.com/JohnDev19/AtlasUI")}
|
|
160
|
+
`;
|
|
161
|
+
var program = new import_commander.Command();
|
|
162
|
+
program.name("atlasui-lib").description("atlasui-lib CLI \u2014 copy components into your project").version("0.1.0", "-v, --version").addHelpText("before", banner);
|
|
163
|
+
program.command("init").description("Set up atlasui-lib in your project").option("--typescript", "Use TypeScript", true).option("--tailwind", "Configure Tailwind", true).option("--no-install", "Skip dependency install").option("-y, --yes", "Skip all prompts, use defaults").action(async (opts) => {
|
|
164
|
+
console.log(import_chalk.default.bold.blue("\n AtlasUI Init\n") + import_chalk.default.dim(" Let's get you set up\u2026\n"));
|
|
165
|
+
const cwd = process.cwd();
|
|
166
|
+
const pkgPath = import_path.default.join(cwd, "package.json");
|
|
167
|
+
if (!import_fs_extra.default.existsSync(pkgPath)) {
|
|
168
|
+
console.error(import_chalk.default.red("\n No package.json found. Run from your project root.\n"));
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
const pkg = import_fs_extra.default.readJsonSync(pkgPath);
|
|
172
|
+
const isNext = !!(pkg.dependencies?.next || pkg.devDependencies?.next);
|
|
173
|
+
const answers = opts.yes ? { componentsDir: "components/ui", cssPath: isNext ? "app/globals.css" : "src/index.css", pm: detectPM(cwd) } : await (0, import_prompts.default)([
|
|
174
|
+
{ type: "text", name: "componentsDir", message: "Where should components go?", initial: "components/ui" },
|
|
175
|
+
{ type: "text", name: "cssPath", message: "Path to your global CSS file?", initial: isNext ? "app/globals.css" : "src/index.css" },
|
|
176
|
+
{
|
|
177
|
+
type: "select",
|
|
178
|
+
name: "pm",
|
|
179
|
+
message: "Package manager?",
|
|
180
|
+
choices: [
|
|
181
|
+
{ title: "npm", value: "npm" },
|
|
182
|
+
{ title: "pnpm", value: "pnpm" },
|
|
183
|
+
{ title: "yarn", value: "yarn" },
|
|
184
|
+
{ title: "bun", value: "bun" }
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
]);
|
|
188
|
+
if (!answers.componentsDir) return;
|
|
189
|
+
import_fs_extra.default.writeJsonSync(import_path.default.join(cwd, "atlas.config.json"), {
|
|
190
|
+
$schema: "https://atlasui.vercel.app/schema.json",
|
|
191
|
+
style: "default",
|
|
192
|
+
typescript: opts.typescript ?? true,
|
|
193
|
+
tailwind: { config: "tailwind.config.ts", css: answers.cssPath, baseColor: "slate", cssVariables: true },
|
|
194
|
+
aliases: { components: `@/${answers.componentsDir}`, utils: "@/lib/utils" }
|
|
195
|
+
}, { spaces: 2 });
|
|
196
|
+
console.log(import_chalk.default.green(" \u2713 Created atlas.config.json"));
|
|
197
|
+
const utilsPath = import_path.default.join(cwd, "lib", "utils.ts");
|
|
198
|
+
if (!import_fs_extra.default.existsSync(utilsPath)) {
|
|
199
|
+
await import_fs_extra.default.ensureDir(import_path.default.dirname(utilsPath));
|
|
200
|
+
await import_fs_extra.default.writeFile(
|
|
201
|
+
utilsPath,
|
|
202
|
+
`import { type ClassValue, clsx } from "clsx";
|
|
203
|
+
import { twMerge } from "tailwind-merge";
|
|
204
|
+
|
|
205
|
+
export function cn(...inputs: ClassValue[]) {
|
|
206
|
+
return twMerge(clsx(inputs));
|
|
207
|
+
}
|
|
208
|
+
`
|
|
209
|
+
);
|
|
210
|
+
console.log(import_chalk.default.green(" \u2713 Created lib/utils.ts"));
|
|
211
|
+
}
|
|
212
|
+
if (opts.install !== false) {
|
|
213
|
+
const pm = answers.pm;
|
|
214
|
+
const spinner = (0, import_ora.default)(`Installing core deps with ${pm}\u2026`).start();
|
|
215
|
+
try {
|
|
216
|
+
const deps = ["clsx", "tailwind-merge", "class-variance-authority", "@radix-ui/react-slot"];
|
|
217
|
+
const cmd = pm === "pnpm" ? ["pnpm", "add", ...deps] : pm === "bun" ? ["bun", "add", ...deps] : pm === "yarn" ? ["yarn", "add", ...deps] : ["npm", "install", ...deps];
|
|
218
|
+
await (0, import_execa.execa)(cmd[0], cmd.slice(1), { cwd });
|
|
219
|
+
spinner.succeed(import_chalk.default.green("Core deps installed"));
|
|
220
|
+
} catch {
|
|
221
|
+
spinner.warn(import_chalk.default.yellow("Auto-install failed \u2014 run manually:"));
|
|
222
|
+
console.log(import_chalk.default.dim(" npm install clsx tailwind-merge class-variance-authority @radix-ui/react-slot\n"));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
console.log(`
|
|
226
|
+
${import_chalk.default.bold.green(" AtlasUI is ready!")}
|
|
227
|
+
|
|
228
|
+
${import_chalk.default.dim("Next steps:")}
|
|
229
|
+
${import_chalk.default.cyan("1.")} Add components: ${import_chalk.default.bold("npx atlasui-lib add button card modal")}
|
|
230
|
+
${import_chalk.default.cyan("2.")} Browse all: ${import_chalk.default.bold("npx atlasui-lib list")}
|
|
231
|
+
${import_chalk.default.cyan("3.")} Docs: ${import_chalk.default.bold("https://atlasui.vercel.app/")}
|
|
232
|
+
${import_chalk.default.cyan("4.")} Issues: ${import_chalk.default.bold("https://github.com/JohnDev19/AtlasUI/issues")}
|
|
233
|
+
`);
|
|
234
|
+
});
|
|
235
|
+
program.command("add [components...]").alias("a").description("Copy one or more components into your project").option("-d, --dir <path>", "Output directory", "components/ui").option("--overwrite", "Replace existing files").option("--no-install", "Skip npm dep install").action(async (components, opts) => {
|
|
236
|
+
const cwd = process.cwd();
|
|
237
|
+
if (!components?.length) {
|
|
238
|
+
console.log(import_chalk.default.red("\n Specify at least one component.\n"));
|
|
239
|
+
console.log(` ${import_chalk.default.dim("Example:")} ${import_chalk.default.cyan("npx atlasui-lib add button card modal\n")}`);
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
const toAdd = /* @__PURE__ */ new Set();
|
|
243
|
+
function resolve(name) {
|
|
244
|
+
const key = name.toLowerCase().replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
245
|
+
const meta = COMPONENTS_BY_NAME.get(key) || COMPONENTS_BY_NAME.get(name);
|
|
246
|
+
if (!meta) {
|
|
247
|
+
console.error(import_chalk.default.red(`
|
|
248
|
+
"${name}" not found in the registry.
|
|
249
|
+
`));
|
|
250
|
+
console.log(` Run ${import_chalk.default.cyan("npx atlasui-lib list")} to see what's available.
|
|
251
|
+
`);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
toAdd.add(meta.name);
|
|
255
|
+
meta.registryDeps?.forEach(resolve);
|
|
256
|
+
}
|
|
257
|
+
components.forEach(resolve);
|
|
258
|
+
if (!toAdd.size) return;
|
|
259
|
+
const configPath = import_path.default.join(cwd, "atlas.config.json");
|
|
260
|
+
const config = import_fs_extra.default.existsSync(configPath) ? import_fs_extra.default.readJsonSync(configPath) : null;
|
|
261
|
+
const aliasDir = config?.aliases?.components?.replace(/^@\//, "");
|
|
262
|
+
const targetDir = import_path.default.join(cwd, opts.dir ?? aliasDir ?? "components/ui");
|
|
263
|
+
console.log(import_chalk.default.bold.blue("\n AtlasUI Add\n") + import_chalk.default.dim(` Adding: ${[...toAdd].join(", ")}
|
|
264
|
+
`));
|
|
265
|
+
const allDeps = /* @__PURE__ */ new Set();
|
|
266
|
+
for (const name of toAdd) COMPONENTS_BY_NAME.get(name).deps.forEach((d) => allDeps.add(d));
|
|
267
|
+
for (const name of toAdd) {
|
|
268
|
+
const spinner = (0, import_ora.default)(`Adding ${import_chalk.default.bold(name)}`).start();
|
|
269
|
+
const pascal = name.split("-").map((p) => p[0].toUpperCase() + p.slice(1)).join("");
|
|
270
|
+
const dir = import_path.default.join(targetDir, name);
|
|
271
|
+
await import_fs_extra.default.ensureDir(dir);
|
|
272
|
+
const file = import_path.default.join(dir, "index.tsx");
|
|
273
|
+
if (import_fs_extra.default.existsSync(file) && !opts.overwrite) {
|
|
274
|
+
spinner.warn(import_chalk.default.yellow(`${name} already exists (--overwrite to replace)`));
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
await import_fs_extra.default.writeFile(
|
|
278
|
+
file,
|
|
279
|
+
`/**
|
|
280
|
+
* AtlasUI \u2014 ${pascal}
|
|
281
|
+
*
|
|
282
|
+
* Added by the atlasui-lib CLI. This file is yours \u2014 edit it however you want.
|
|
283
|
+
* Re-export from atlasui-lib to stay in sync, or paste the full source here
|
|
284
|
+
* to customise the internals.
|
|
285
|
+
*
|
|
286
|
+
* Docs: https://atlasui.vercel.app/components/${name}
|
|
287
|
+
* Source: https://github.com/JohnDev19/AtlasUI
|
|
288
|
+
*/
|
|
289
|
+
|
|
290
|
+
export { ${pascal} } from "atlasui-lib";
|
|
291
|
+
export type { ${pascal}Props } from "atlasui-lib";
|
|
292
|
+
`
|
|
293
|
+
);
|
|
294
|
+
spinner.succeed(import_chalk.default.green(`${name} \u2192 ${import_path.default.relative(cwd, file)}`));
|
|
295
|
+
}
|
|
296
|
+
if (opts.install !== false && allDeps.size > 0) {
|
|
297
|
+
const pm = detectPM(cwd);
|
|
298
|
+
const spinner = (0, import_ora.default)(`Installing ${allDeps.size} package(s)\u2026`).start();
|
|
299
|
+
try {
|
|
300
|
+
const deps = [...allDeps];
|
|
301
|
+
const cmd = pm === "pnpm" ? ["pnpm", "add", ...deps] : pm === "bun" ? ["bun", "add", ...deps] : pm === "yarn" ? ["yarn", "add", ...deps] : ["npm", "install", ...deps];
|
|
302
|
+
await (0, import_execa.execa)(cmd[0], cmd.slice(1), { cwd });
|
|
303
|
+
spinner.succeed(import_chalk.default.green(`Installed: ${deps.join(", ")}`));
|
|
304
|
+
} catch {
|
|
305
|
+
spinner.warn(import_chalk.default.yellow("Auto-install failed \u2014 run manually:"));
|
|
306
|
+
console.log(import_chalk.default.dim(` npm install ${[...allDeps].join(" ")}
|
|
307
|
+
`));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const exNames = [...toAdd].map((n) => n.split("-").map((p) => p[0].toUpperCase() + p.slice(1)).join("")).join(", ");
|
|
311
|
+
console.log(`
|
|
312
|
+
${import_chalk.default.bold.green(" Done!")} ${import_path.default.relative(cwd, targetDir)}
|
|
313
|
+
|
|
314
|
+
${import_chalk.default.cyan(`import { ${exNames} } from "@/components/ui/${[...toAdd][0]}"`)}
|
|
315
|
+
`);
|
|
316
|
+
});
|
|
317
|
+
program.command("list").alias("ls").description("List all available components").option("-c, --category <category>", "Filter by category").action((opts) => {
|
|
318
|
+
const filterCat = opts.category?.toLowerCase();
|
|
319
|
+
console.log(import_chalk.default.bold.blue("\n atlasui-lib Components\n"));
|
|
320
|
+
const cats = filterCat ? [filterCat] : CATEGORIES;
|
|
321
|
+
for (const cat of cats) {
|
|
322
|
+
const items = REGISTRY.filter((c) => c.category === cat);
|
|
323
|
+
if (!items.length) continue;
|
|
324
|
+
const label = cat.replace("-", " ").replace(/^\w/, (c) => c.toUpperCase());
|
|
325
|
+
console.log(import_chalk.default.bold(` ${label} (${items.length})`));
|
|
326
|
+
for (const c of items) {
|
|
327
|
+
console.log(` ${import_chalk.default.cyan(c.name.padEnd(22))} ${import_chalk.default.dim(c.description)}`);
|
|
328
|
+
}
|
|
329
|
+
console.log();
|
|
330
|
+
}
|
|
331
|
+
console.log(import_chalk.default.dim(` ${REGISTRY.length} components total
|
|
332
|
+
`) + import_chalk.default.dim(" Add one: ") + import_chalk.default.cyan("npx atlasui-lib add <name>\n"));
|
|
333
|
+
});
|
|
334
|
+
program.command("diff [component]").description("Compare your local copy to the latest version").action((component) => {
|
|
335
|
+
if (!component) {
|
|
336
|
+
console.log(import_chalk.default.dim("\n Usage: npx atlasui-lib diff <component>\n"));
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
console.log(import_chalk.default.bold.blue(`
|
|
340
|
+
diff: ${component}
|
|
341
|
+
`) + import_chalk.default.dim(" Comparing local copy to latest in the atlasui-lib registry\u2026\n"));
|
|
342
|
+
console.log(import_chalk.default.yellow(" \u26A0 Registry diff isn't wired up yet."));
|
|
343
|
+
console.log(import_chalk.default.dim(` Check the latest source at:
|
|
344
|
+
`) + import_chalk.default.cyan(` https://github.com/JohnDev19/AtlasUI/tree/main/src/components
|
|
345
|
+
`));
|
|
346
|
+
});
|
|
347
|
+
program.on("command:*", (operands) => {
|
|
348
|
+
console.error(import_chalk.default.red(`
|
|
349
|
+
Unknown command: "${operands[0]}"
|
|
350
|
+
`));
|
|
351
|
+
program.help();
|
|
352
|
+
process.exit(1);
|
|
353
|
+
});
|
|
354
|
+
program.parse(process.argv);
|
|
355
|
+
if (!process.argv.slice(2).length) {
|
|
356
|
+
console.log(banner);
|
|
357
|
+
program.help();
|
|
358
|
+
}
|
|
359
|
+
function detectPM(cwd) {
|
|
360
|
+
if (import_fs_extra.default.existsSync(import_path.default.join(cwd, "bun.lockb"))) return "bun";
|
|
361
|
+
if (import_fs_extra.default.existsSync(import_path.default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
362
|
+
if (import_fs_extra.default.existsSync(import_path.default.join(cwd, "yarn.lock"))) return "yarn";
|
|
363
|
+
return "npm";
|
|
364
|
+
}
|