aplance-ui 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/dist/api.d.ts +175 -0
  4. package/dist/api.js +1954 -0
  5. package/dist/api.js.map +1 -0
  6. package/dist/frameworks/astro/astro.config.snippet.md +23 -0
  7. package/dist/frameworks/astro/postcss.config.mjs.template +20 -0
  8. package/dist/frameworks/astro/vite-inline.snippet.md +22 -0
  9. package/dist/frameworks/electron-vite/vite.config.snippet.md +44 -0
  10. package/dist/frameworks/next/layout-import.snippet.md +19 -0
  11. package/dist/frameworks/next/next.config.snippet.md +15 -0
  12. package/dist/frameworks/next/postcss.config.js.template +16 -0
  13. package/dist/frameworks/tanstack-start/postcss.config.ts.template +17 -0
  14. package/dist/frameworks/tanstack-start/vite-inline.snippet.md +22 -0
  15. package/dist/frameworks/vite-react/postcss.config.ts.template +16 -0
  16. package/dist/frameworks/vite-react/vite-inline.snippet.md +20 -0
  17. package/dist/frameworks/vite-react/vite.config.ts.template +48 -0
  18. package/dist/index.js +2047 -0
  19. package/dist/index.js.map +1 -0
  20. package/package.json +63 -0
  21. package/registry/components/primitives/icon/icon.module.css +63 -0
  22. package/registry/components/primitives/icon/icon.tsx +53 -0
  23. package/registry/components/primitives/modal/modal-context.ts +19 -0
  24. package/registry/components/primitives/modal/modal.module.css +415 -0
  25. package/registry/components/primitives/modal/modal.tsx +550 -0
  26. package/registry/components/primitives/popover/popover-context.ts +28 -0
  27. package/registry/components/primitives/popover/popover.module.css +28 -0
  28. package/registry/components/primitives/popover/popover.tsx +465 -0
  29. package/registry/components/ui/accordion/accordion.module.css +208 -0
  30. package/registry/components/ui/accordion/accordion.tsx +327 -0
  31. package/registry/components/ui/avatar/avatar.module.css +32 -0
  32. package/registry/components/ui/avatar/avatar.tsx +37 -0
  33. package/registry/components/ui/badge/badge.module.css +103 -0
  34. package/registry/components/ui/badge/badge.tsx +29 -0
  35. package/registry/components/ui/button/button.module.css +216 -0
  36. package/registry/components/ui/button/button.tsx +133 -0
  37. package/registry/components/ui/chart/chart.module.css +168 -0
  38. package/registry/components/ui/chart/chart.tsx +1293 -0
  39. package/registry/components/ui/chart/types.ts +210 -0
  40. package/registry/components/ui/chart/utils.ts +59 -0
  41. package/registry/components/ui/copy-button/copy-button.module.css +21 -0
  42. package/registry/components/ui/copy-button/copy-button.tsx +123 -0
  43. package/registry/components/ui/countdown/countdown.module.css +5 -0
  44. package/registry/components/ui/countdown/countdown.tsx +152 -0
  45. package/registry/components/ui/data-table/checkbox-column.tsx +59 -0
  46. package/registry/components/ui/data-table/data-table.module.css +594 -0
  47. package/registry/components/ui/data-table/data-table.tsx +1109 -0
  48. package/registry/components/ui/data-table/filter-bar.tsx +33 -0
  49. package/registry/components/ui/data-table/pagination-bar.tsx +125 -0
  50. package/registry/components/ui/data-table/types.ts +594 -0
  51. package/registry/components/ui/data-table/useDataTable.tsx +573 -0
  52. package/registry/components/ui/data-table/utils.ts +445 -0
  53. package/registry/components/ui/empty-state/empty-state.module.css +26 -0
  54. package/registry/components/ui/empty-state/empty-state.tsx +32 -0
  55. package/registry/components/ui/input-fields/color-picker/color-palette.module.css +102 -0
  56. package/registry/components/ui/input-fields/color-picker/color-palette.tsx +92 -0
  57. package/registry/components/ui/input-fields/color-picker/color-picker.module.css +29 -0
  58. package/registry/components/ui/input-fields/color-picker/color-picker.tsx +168 -0
  59. package/registry/components/ui/input-fields/common/field-message/field-message.module.css +28 -0
  60. package/registry/components/ui/input-fields/common/field-message/field-message.tsx +39 -0
  61. package/registry/components/ui/input-fields/common/input-field-common.module.css +318 -0
  62. package/registry/components/ui/input-fields/common/input-field-native.module.css +267 -0
  63. package/registry/components/ui/input-fields/common/picker-popover-common.module.css +40 -0
  64. package/registry/components/ui/input-fields/common/select-button/select-button.module.css +9 -0
  65. package/registry/components/ui/input-fields/common/select-button/select-button.tsx +171 -0
  66. package/registry/components/ui/input-fields/common/types.ts +38 -0
  67. package/registry/components/ui/input-fields/custom-select/custom-select.module.css +56 -0
  68. package/registry/components/ui/input-fields/custom-select/custom-select.tsx +403 -0
  69. package/registry/components/ui/input-fields/date-picker/calendar.module.css +311 -0
  70. package/registry/components/ui/input-fields/date-picker/calendar.tsx +186 -0
  71. package/registry/components/ui/input-fields/date-picker/date-picker.module.css +57 -0
  72. package/registry/components/ui/input-fields/date-picker/date-picker.tsx +945 -0
  73. package/registry/components/ui/input-fields/date-picker/types.ts +102 -0
  74. package/registry/components/ui/input-fields/date-picker/utils.ts +236 -0
  75. package/registry/components/ui/input-fields/emoji-picker/emoji-palette.module.css +90 -0
  76. package/registry/components/ui/input-fields/emoji-picker/emoji-palette.tsx +168 -0
  77. package/registry/components/ui/input-fields/emoji-picker/emoji-picker.module.css +8 -0
  78. package/registry/components/ui/input-fields/emoji-picker/emoji-picker.tsx +102 -0
  79. package/registry/components/ui/input-fields/emoji-picker/utils.ts +505 -0
  80. package/registry/components/ui/input-fields/field-group/field-group.module.css +86 -0
  81. package/registry/components/ui/input-fields/field-group/field-group.tsx +86 -0
  82. package/registry/components/ui/input-fields/input/input.tsx +319 -0
  83. package/registry/components/ui/input-fields/media-input/kind-icons.tsx +62 -0
  84. package/registry/components/ui/input-fields/media-input/media-input.module.css +294 -0
  85. package/registry/components/ui/input-fields/media-input/media-input.tsx +327 -0
  86. package/registry/components/ui/input-fields/media-input/media-preview.tsx +101 -0
  87. package/registry/components/ui/input-fields/media-input/types.ts +129 -0
  88. package/registry/components/ui/input-fields/media-input/useMediaUpload.tsx +302 -0
  89. package/registry/components/ui/input-fields/media-input/utils.ts +325 -0
  90. package/registry/components/ui/input-fields/otp-input/otp-input.module.css +24 -0
  91. package/registry/components/ui/input-fields/otp-input/otp-input.tsx +291 -0
  92. package/registry/components/ui/input-fields/select/select.tsx +118 -0
  93. package/registry/components/ui/input-fields/switch/switch.module.css +70 -0
  94. package/registry/components/ui/input-fields/switch/switch.tsx +59 -0
  95. package/registry/components/ui/input-fields/textarea/textarea.tsx +133 -0
  96. package/registry/components/ui/input-fields/time-picker/time-picker.module.css +57 -0
  97. package/registry/components/ui/input-fields/time-picker/time-picker.tsx +437 -0
  98. package/registry/components/ui/loader/loader.module.css +156 -0
  99. package/registry/components/ui/loader/loader.tsx +102 -0
  100. package/registry/components/ui/stepper/stepper.module.css +294 -0
  101. package/registry/components/ui/stepper/stepper.tsx +197 -0
  102. package/registry/components/ui/tabs/tabs.module.css +150 -0
  103. package/registry/components/ui/tabs/tabs.tsx +134 -0
  104. package/registry/components/ui/toast/toast.module.css +159 -0
  105. package/registry/components/ui/toast/toast.tsx +104 -0
  106. package/registry/components/ui/tooltip/tooltip.module.css +82 -0
  107. package/registry/components/ui/tooltip/tooltip.tsx +72 -0
  108. package/registry/global.d.ts +4 -0
  109. package/registry/hooks/useFocusOutside.tsx +33 -0
  110. package/registry/hooks/useResizeObserver.tsx +32 -0
  111. package/registry/lib/dom.ts +25 -0
  112. package/registry/lib/string.ts +23 -0
  113. package/registry/registry.json +719 -0
  114. package/registry/styles/app.css +240 -0
  115. package/registry/styles/components.css +78 -0
  116. package/registry/styles/fonts/geist-regular.woff2 +0 -0
  117. package/registry/styles/globals.css +7 -0
  118. package/registry/styles/media.css +25 -0
  119. package/registry/styles/utilities.css +90 -0
  120. package/registry/themes/colors/blue.css +37 -0
  121. package/registry/themes/colors/green.css +37 -0
  122. package/registry/themes/colors/rose.css +37 -0
  123. package/registry/themes/colors/slate.css +37 -0
  124. package/registry/themes/colors/stone.css +37 -0
  125. package/registry/themes/colors/violet.css +37 -0
  126. package/registry/themes/colors/zinc.css +37 -0
  127. package/registry/themes/radius/pill.css +8 -0
  128. package/registry/themes/radius/rounded.css +8 -0
  129. package/registry/themes/radius/sharp.css +8 -0
  130. package/registry/themes/spacing/compact.css +17 -0
  131. package/registry/themes/spacing/spacious.css +17 -0
  132. package/registry/tsconfig.json +25 -0
package/dist/api.js ADDED
@@ -0,0 +1,1954 @@
1
+ // src/commands/init.ts
2
+ import { join as join9, relative as relative4 } from "path";
3
+ import pc4 from "picocolors";
4
+
5
+ // src/lib/fs-ops.ts
6
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
7
+ import { dirname, relative } from "path";
8
+ import pc3 from "picocolors";
9
+ import * as p2 from "@clack/prompts";
10
+
11
+ // src/lib/errors.ts
12
+ var CliError = class extends Error {
13
+ code;
14
+ hint;
15
+ constructor(code, message, hint) {
16
+ super(message);
17
+ this.name = "CliError";
18
+ this.code = code;
19
+ this.hint = hint;
20
+ }
21
+ };
22
+ var ConfigError = class extends CliError {
23
+ constructor(code, message, hint) {
24
+ super(code, message, hint);
25
+ this.name = "ConfigError";
26
+ }
27
+ };
28
+ var TemplateError = class extends CliError {
29
+ constructor(code, message, hint) {
30
+ super(code, message, hint);
31
+ this.name = "TemplateError";
32
+ }
33
+ };
34
+ var RegistryError = class extends CliError {
35
+ constructor(code, message, hint) {
36
+ super(code, message, hint);
37
+ this.name = "RegistryError";
38
+ }
39
+ };
40
+ var AbortError = class extends CliError {
41
+ constructor(message = "Aborted by user.") {
42
+ super("E_ABORTED", message);
43
+ this.name = "AbortError";
44
+ }
45
+ };
46
+
47
+ // src/lib/logger.ts
48
+ import pc from "picocolors";
49
+ var indent = (s, level) => s.split("\n").map((line) => " ".repeat(level) + line).join("\n");
50
+ var logger = {
51
+ ok: (msg, level = 0) => console.log(indent(`${pc.green("\u2713")} ${msg}`, level)),
52
+ info: (msg, level = 0) => console.log(indent(`${pc.cyan("\u25C6")} ${msg}`, level)),
53
+ action: (msg, level = 0) => console.log(indent(`${pc.gray("\u2192")} ${msg}`, level)),
54
+ warn: (msg, level = 0) => console.log(indent(`${pc.yellow("\u25B2")} ${msg}`, level)),
55
+ error: (msg, level = 0) => console.error(indent(`${pc.red("\u2717")} ${msg}`, level)),
56
+ dim: (msg) => pc.dim(msg)
57
+ };
58
+
59
+ // src/lib/ui.ts
60
+ import * as p from "@clack/prompts";
61
+ import pc2 from "picocolors";
62
+ var unwrap = (value) => {
63
+ if (p.isCancel(value)) throw new AbortError();
64
+ return value;
65
+ };
66
+ var brand = () => {
67
+ const colours = [pc2.magenta, pc2.cyan, pc2.blue];
68
+ const gradient = "aplance-ui".split("").map((ch, i) => colours[i % colours.length](ch)).join("");
69
+ return `${gradient} ${pc2.dim("\xB7")} ${pc2.dim("design system scaffolder")}`;
70
+ };
71
+ var headline = (subtitle) => {
72
+ p.intro(brand());
73
+ if (subtitle) p.log.message(pc2.dim(subtitle));
74
+ };
75
+ var goodbye = (message) => p.outro(pc2.green(message));
76
+ var select2 = async (opts) => unwrap(await p.select(opts));
77
+ var multiselect2 = async (opts) => unwrap(await p.multiselect(opts));
78
+ var confirm2 = async (opts) => unwrap(await p.confirm(opts));
79
+ var note2 = (body, title) => p.note(body, title);
80
+ var step = (message) => p.log.step(message);
81
+ var info = (message) => p.log.info(message);
82
+ var warn = (message) => p.log.warn(message);
83
+
84
+ // src/lib/fs-ops.ts
85
+ var ensureDir = (filePath) => {
86
+ const dir = dirname(filePath);
87
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
88
+ };
89
+ var sameContent = (target, content) => {
90
+ if (!existsSync(target)) return false;
91
+ try {
92
+ if (Buffer.isBuffer(content)) {
93
+ return readFileSync(target).equals(content);
94
+ }
95
+ return readFileSync(target, "utf8") === content;
96
+ } catch {
97
+ return false;
98
+ }
99
+ };
100
+ var planActions = async (ops, opts) => {
101
+ const plan = [];
102
+ let bulk = null;
103
+ for (const op of ops) {
104
+ if (sameContent(op.target, op.content)) {
105
+ plan.push({ op, action: "unchanged" });
106
+ continue;
107
+ }
108
+ if (!existsSync(op.target)) {
109
+ plan.push({ op, action: "write" });
110
+ continue;
111
+ }
112
+ if (opts.mode === "force") {
113
+ plan.push({ op, action: "write" });
114
+ continue;
115
+ }
116
+ if (opts.mode === "skip") {
117
+ plan.push({ op, action: "skip" });
118
+ continue;
119
+ }
120
+ if (opts.mode === "dry-run") {
121
+ plan.push({ op, action: "write" });
122
+ continue;
123
+ }
124
+ if (bulk === "all") {
125
+ plan.push({ op, action: "write" });
126
+ continue;
127
+ }
128
+ if (bulk === "skip-all") {
129
+ plan.push({ op, action: "skip" });
130
+ continue;
131
+ }
132
+ const choice = unwrap(
133
+ await p2.select({
134
+ message: `${pc3.yellow("exists")} ${op.label}`,
135
+ options: [
136
+ { value: "overwrite", label: "Overwrite" },
137
+ { value: "skip", label: "Skip" },
138
+ { value: "all", label: "Overwrite all remaining" },
139
+ { value: "skip-all", label: "Skip all remaining" },
140
+ { value: "abort", label: "Abort" }
141
+ ],
142
+ initialValue: "skip"
143
+ })
144
+ );
145
+ if (choice === "abort") throw new AbortError();
146
+ if (choice === "all") {
147
+ bulk = "all";
148
+ plan.push({ op, action: "write" });
149
+ } else if (choice === "skip-all") {
150
+ bulk = "skip-all";
151
+ plan.push({ op, action: "skip" });
152
+ } else {
153
+ plan.push({ op, action: choice === "overwrite" ? "write" : "skip" });
154
+ }
155
+ }
156
+ return plan;
157
+ };
158
+ var applyFileOps = async (ops, opts) => {
159
+ const plan = await planActions(ops, opts);
160
+ if (opts.mode === "dry-run") {
161
+ for (const { op, action } of plan) {
162
+ const rel = relative(opts.cwd, op.target);
163
+ if (action === "write") logger.action(`would write ${rel}`);
164
+ else if (action === "skip") logger.action(`would skip ${rel}`);
165
+ else logger.action(`unchanged ${logger.dim(rel)}`);
166
+ }
167
+ return {
168
+ written: plan.filter((x) => x.action === "write").length,
169
+ skipped: plan.filter((x) => x.action === "skip").length,
170
+ unchanged: plan.filter((x) => x.action === "unchanged").length
171
+ };
172
+ }
173
+ let written = 0;
174
+ let skipped = 0;
175
+ let unchanged = 0;
176
+ for (const { op, action } of plan) {
177
+ const rel = relative(opts.cwd, op.target);
178
+ if (action === "write") {
179
+ try {
180
+ ensureDir(op.target);
181
+ writeFileSync(op.target, op.content);
182
+ } catch (err) {
183
+ const cause = err instanceof Error ? err.message : String(err);
184
+ throw new Error(
185
+ `Failed to write ${rel}: ${cause}
186
+ ${written} file(s) were already written before this failure. Fix the underlying issue (permissions? disk space?) and re-run - identical files will be detected as unchanged and skipped.`
187
+ );
188
+ }
189
+ logger.ok(`wrote ${rel}`);
190
+ written++;
191
+ } else if (action === "skip") {
192
+ logger.action(`skip ${logger.dim(rel)}`);
193
+ skipped++;
194
+ } else {
195
+ unchanged++;
196
+ }
197
+ }
198
+ return { written, skipped, unchanged };
199
+ };
200
+
201
+ // src/lib/styles.ts
202
+ import { readdirSync, readFileSync as readFileSync3, statSync, existsSync as existsSync3 } from "fs";
203
+ import { join as join2, relative as relative2, sep, posix } from "path";
204
+
205
+ // src/lib/registry.ts
206
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
207
+ import { dirname as dirname2, join } from "path";
208
+ import { fileURLToPath } from "url";
209
+ var resolveRegistryRoot = () => {
210
+ const here = dirname2(fileURLToPath(import.meta.url));
211
+ for (const depth of [1, 2, 3, 4]) {
212
+ const candidate = join(here, ...Array(depth).fill(".."), "registry");
213
+ if (existsSync2(join(candidate, "registry.json"))) return candidate;
214
+ }
215
+ throw new RegistryError(
216
+ "E_REGISTRY_MISSING",
217
+ `Bundled registry not found next to the CLI binary.`,
218
+ `This indicates a packaging problem - reinstall the aplance-ui CLI.`
219
+ );
220
+ };
221
+ var EXPECTED_VERSION = 3;
222
+ var EMPTY_INSTALL_META = {
223
+ baseDependencies: {},
224
+ baseDevDependencies: {},
225
+ utilitiesDevDependencies: {},
226
+ packageVersions: {}
227
+ };
228
+ var loadRegistry = () => {
229
+ const root = resolveRegistryRoot();
230
+ const manifestPath = join(root, "registry.json");
231
+ const raw = readFileSync2(manifestPath, "utf8");
232
+ const parsed = JSON.parse(raw);
233
+ if (parsed.version !== EXPECTED_VERSION) {
234
+ throw new RegistryError(
235
+ "E_REGISTRY_MISSING",
236
+ `Unsupported registry version ${parsed.version}. This CLI expects version ${EXPECTED_VERSION}.`
237
+ );
238
+ }
239
+ return {
240
+ ...parsed,
241
+ themes: parsed.themes ?? { colors: [], radii: [], spacing: [] },
242
+ installMeta: parsed.installMeta ?? EMPTY_INSTALL_META,
243
+ root
244
+ };
245
+ };
246
+ var resolveUnits = (registry, names) => {
247
+ const byName = new Map(registry.units.map((u) => [u.name, u]));
248
+ for (const name of names) {
249
+ if (!byName.has(name)) {
250
+ throw new RegistryError(
251
+ "E_UNKNOWN_UNIT",
252
+ `Unknown unit "${name}".`,
253
+ `Run \`aplance-ui list\` to see every available unit.`
254
+ );
255
+ }
256
+ }
257
+ const visited = /* @__PURE__ */ new Set();
258
+ const result = [];
259
+ const visit = (name) => {
260
+ if (visited.has(name)) return;
261
+ visited.add(name);
262
+ const unit = byName.get(name);
263
+ if (!unit) return;
264
+ for (const dep of unit.deps) visit(dep);
265
+ result.push(unit);
266
+ };
267
+ for (const name of names) visit(name);
268
+ return result;
269
+ };
270
+ var allUnitsInOrder = (registry) => resolveUnits(registry, registry.units.map((u) => u.name));
271
+ var pickVariant = (list, id, dimensionLabel) => {
272
+ const match = list.find((t) => t.id === id);
273
+ if (!match) {
274
+ const available = list.map((t) => t.id).join(", ");
275
+ throw new RegistryError(
276
+ "E_UNKNOWN_THEME",
277
+ `Unknown ${dimensionLabel} "${id}". Available: ${available}.`
278
+ );
279
+ }
280
+ return match;
281
+ };
282
+ var findColor = (registry, id) => pickVariant(registry.themes.colors, id, "color");
283
+ var findRadius = (registry, id) => pickVariant(registry.themes.radii, id, "radius");
284
+ var findSpacing = (registry, id) => pickVariant(registry.themes.spacing, id, "spacing");
285
+
286
+ // src/lib/styles.ts
287
+ var planUtilitiesGitignoreOp = (opts) => ({
288
+ target: join2(opts.targetStylesDir, ".gitignore"),
289
+ content: GITIGNORE_BODY,
290
+ label: "styles/.gitignore"
291
+ });
292
+ var GITIGNORE_BODY = "# Generated by postcss-token-utilities on every build - do not commit.\nutilities.gen.css\n";
293
+ var EXCLUDE_PATTERNS = [/\.gen\.css$/];
294
+ var BINARY_EXTENSIONS = /\.(woff2?|ttf|otf|eot|png|jpe?g|gif|webp|avif|ico)$/i;
295
+ var toPosix = (p3) => p3.split(sep).join(posix.sep);
296
+ var walkStyles = (dir, base) => {
297
+ const out = [];
298
+ for (const entry of readdirSync(dir)) {
299
+ const full = join2(dir, entry);
300
+ if (statSync(full).isDirectory()) {
301
+ out.push(...walkStyles(full, base));
302
+ } else {
303
+ const rel = toPosix(relative2(base, full));
304
+ if (EXCLUDE_PATTERNS.some((re) => re.test(rel))) continue;
305
+ out.push(rel);
306
+ }
307
+ }
308
+ return out;
309
+ };
310
+ var readOverride = (registry, theme, kind) => {
311
+ if (!theme.file) return null;
312
+ const abs = join2(registry.root, theme.file);
313
+ if (!existsSync3(abs)) return null;
314
+ return { id: theme.id, kind, css: readFileSync3(abs, "utf8") };
315
+ };
316
+ var planStylesOps = (opts) => {
317
+ const sourceStylesDir = join2(opts.registry.root, "styles");
318
+ const relFiles = walkStyles(sourceStylesDir, sourceStylesDir);
319
+ const overrides = [];
320
+ const colorOverride = readOverride(
321
+ opts.registry,
322
+ findColor(opts.registry, opts.color),
323
+ "color"
324
+ );
325
+ if (colorOverride) overrides.push(colorOverride);
326
+ const radiusOverride = readOverride(
327
+ opts.registry,
328
+ findRadius(opts.registry, opts.radius),
329
+ "radius"
330
+ );
331
+ if (radiusOverride) overrides.push(radiusOverride);
332
+ const spacingOverride = readOverride(
333
+ opts.registry,
334
+ findSpacing(opts.registry, opts.spacing),
335
+ "spacing"
336
+ );
337
+ if (spacingOverride) overrides.push(spacingOverride);
338
+ return relFiles.map((relPath) => {
339
+ const sourceAbs = join2(sourceStylesDir, relPath);
340
+ const targetAbs = join2(opts.targetStylesDir, relPath);
341
+ const isApp = relPath === "app.css";
342
+ const content = BINARY_EXTENSIONS.test(sourceAbs) ? readFileSync3(sourceAbs) : isApp && overrides.length > 0 ? mergeOverrides(readFileSync3(sourceAbs, "utf8"), overrides) : readFileSync3(sourceAbs, "utf8");
343
+ return {
344
+ target: targetAbs,
345
+ content,
346
+ label: `styles/${relPath}`
347
+ };
348
+ });
349
+ };
350
+ var escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
351
+ var parseOverrideBlocks = (css) => {
352
+ const stripped = css.replace(/\/\*[\s\S]*?\*\//g, "");
353
+ const blocks = [];
354
+ const blockRe = /([^{}]+?)\{([^{}]*)\}/g;
355
+ let m;
356
+ while ((m = blockRe.exec(stripped)) !== null) {
357
+ const selector = m[1].trim();
358
+ if (!selector) continue;
359
+ const vars = [];
360
+ const varRe = /(--[a-zA-Z0-9_-]+)\s*:\s*([^;]+);/g;
361
+ let vm;
362
+ while ((vm = varRe.exec(m[2])) !== null) {
363
+ vars.push([vm[1], vm[2].trim()]);
364
+ }
365
+ if (vars.length > 0) blocks.push({ selector, vars });
366
+ }
367
+ return blocks;
368
+ };
369
+ var findTopLevelBlock = (css, selector) => {
370
+ const re = new RegExp(`(^|\\n)${escapeRegex(selector)}\\s*\\{`, "g");
371
+ const m = re.exec(css);
372
+ if (!m) return null;
373
+ const bodyStart = css.indexOf("{", m.index + m[1].length) + 1;
374
+ let depth = 0;
375
+ for (let i = bodyStart; i < css.length; i++) {
376
+ const c = css[i];
377
+ if (c === "{") depth++;
378
+ else if (c === "}") {
379
+ if (depth === 0) {
380
+ const sample = css.slice(bodyStart, i).match(/\n([ \t]+)\S/);
381
+ return { bodyStart, bodyEnd: i, indent: sample ? sample[1] : " " };
382
+ }
383
+ depth--;
384
+ }
385
+ }
386
+ return null;
387
+ };
388
+ var mergeOverrides = (base, overrides) => {
389
+ let out = base;
390
+ for (const o of overrides) {
391
+ for (const block of parseOverrideBlocks(o.css)) {
392
+ out = mergeBlock(out, block);
393
+ }
394
+ }
395
+ return out;
396
+ };
397
+ var mergeBlock = (base, block) => {
398
+ const loc = findTopLevelBlock(base, block.selector);
399
+ if (!loc) {
400
+ const lines = [
401
+ `${block.selector} {`,
402
+ ...block.vars.map(([n, v]) => ` ${n}: ${v};`),
403
+ `}`
404
+ ];
405
+ return `${base.replace(/\s*$/, "")}
406
+
407
+ ${lines.join("\n")}
408
+ `;
409
+ }
410
+ let body = base.slice(loc.bodyStart, loc.bodyEnd);
411
+ for (const [name, value] of block.vars) {
412
+ const varRe = new RegExp(`(${escapeRegex(name)}\\s*:\\s*)[^;]+;`);
413
+ if (varRe.test(body)) {
414
+ body = body.replace(varRe, `$1${value};`);
415
+ } else {
416
+ body = body.replace(/([ \t]*)$/, `${loc.indent}${name}: ${value};
417
+ $1`);
418
+ }
419
+ }
420
+ return base.slice(0, loc.bodyStart) + body + base.slice(loc.bodyEnd);
421
+ };
422
+
423
+ // src/lib/components.ts
424
+ import { readFileSync as readFileSync4 } from "fs";
425
+ import { join as join3 } from "path";
426
+ var DEFAULT_SEGMENTS = ["components", "hooks", "lib"];
427
+ var remap = (relFile, paths) => {
428
+ const idx = relFile.indexOf("/");
429
+ if (idx === -1) return relFile;
430
+ const head = relFile.slice(0, idx);
431
+ const tail = relFile.slice(idx + 1);
432
+ if (DEFAULT_SEGMENTS.includes(head)) {
433
+ const override = paths[head];
434
+ return `${override}/${tail}`;
435
+ }
436
+ return relFile;
437
+ };
438
+ var planComponentOps = (opts) => {
439
+ const ops = [];
440
+ for (const unit of opts.units) {
441
+ for (const relFile of unit.files) {
442
+ const sourceAbs = join3(opts.registry.root, relFile);
443
+ const mapped = remap(relFile, opts.paths);
444
+ const targetAbs = join3(opts.targetSrcDir, mapped);
445
+ ops.push({
446
+ target: targetAbs,
447
+ content: readFileSync4(sourceAbs, "utf8"),
448
+ label: mapped
449
+ });
450
+ }
451
+ }
452
+ return ops;
453
+ };
454
+
455
+ // src/lib/css-orchestrate.ts
456
+ import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
457
+ import { join as join5, relative as relative3 } from "path";
458
+
459
+ // src/lib/templates.ts
460
+ import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
461
+ import { dirname as dirname3, join as join4 } from "path";
462
+ import { fileURLToPath as fileURLToPath2 } from "url";
463
+ var HERE = dirname3(fileURLToPath2(import.meta.url));
464
+ var TEMPLATES_DIR = (() => {
465
+ for (const depth of [0, 1, 2, 3]) {
466
+ const candidate = join4(HERE, ...Array(depth).fill(".."), "frameworks");
467
+ if (existsSync4(candidate)) return candidate;
468
+ }
469
+ return join4(HERE, "..", "frameworks");
470
+ })();
471
+ var truthy = (v) => Boolean(v);
472
+ var resolveTemplatePath = (name) => {
473
+ const p3 = join4(TEMPLATES_DIR, name);
474
+ if (!existsSync4(p3)) {
475
+ throw new TemplateError(
476
+ "E_TEMPLATE_MISSING",
477
+ `Template not found: ${name} (looked in ${TEMPLATES_DIR}).`,
478
+ `This is a CLI packaging bug - please file an issue.`
479
+ );
480
+ }
481
+ return p3;
482
+ };
483
+ var loadTemplate = (name) => readFileSync5(resolveTemplatePath(name), "utf8");
484
+ var renderTemplate = (name, vars) => {
485
+ let src = loadTemplate(name);
486
+ src = src.replace(
487
+ /\{\{#(if|unless)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}([\s\S]*?)\{\{\/\1\}\}\n?/g,
488
+ (_full, kind, key, body) => {
489
+ const keep = kind === "if" ? truthy(vars[key]) : !truthy(vars[key]);
490
+ return keep ? body : "";
491
+ }
492
+ );
493
+ src = src.replace(
494
+ /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g,
495
+ (_full, key) => {
496
+ if (!(key in vars)) {
497
+ throw new TemplateError(
498
+ "E_TEMPLATE_RENDER",
499
+ `Template ${name} references unknown variable {{${key}}}.`,
500
+ `This is a CLI bug - please file an issue.`
501
+ );
502
+ }
503
+ const v = vars[key];
504
+ return v === void 0 || v === false ? "" : String(v);
505
+ }
506
+ );
507
+ return src;
508
+ };
509
+
510
+ // src/frameworks/shared.ts
511
+ import { posix as posix2, sep as sep2 } from "path";
512
+
513
+ // src/lib/postcss-plugins.ts
514
+ var renderPluginChain = (opts) => {
515
+ const normalizeRel = (value) => value.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "").replace(/\/+$/, "");
516
+ const rel = (...parts) => `./${parts.map(normalizeRel).filter(Boolean).join("/").replace(/\/+/g, "/")}`;
517
+ const srcDir = normalizeRel(opts.srcDir);
518
+ const stylesRel = normalizeRel(opts.stylesRel);
519
+ const stylesDir = rel(srcDir, stylesRel);
520
+ const mediaSource = `${stylesDir}/media.css`;
521
+ const tokenSource = `${stylesDir}/app.css`;
522
+ const generatedPath = `${stylesDir}/utilities.gen.css`;
523
+ const extensions = opts.contentExtensions && opts.contentExtensions.length > 0 ? opts.contentExtensions : ["tsx", "ts", "jsx", "js"];
524
+ const contentGlob = rel(srcDir, "**", `*.{${extensions.join(",")}}`);
525
+ const imports = [
526
+ `import postcssPresetEnv from "postcss-preset-env";`,
527
+ `import postcssGlobalData from "@csstools/postcss-global-data";`,
528
+ `import autoprefixer from "autoprefixer";`
529
+ ];
530
+ if (opts.withTokenUtilities) {
531
+ imports.push(`import tokenUtilities from "postcss-token-utilities";`);
532
+ }
533
+ const invocations = [];
534
+ invocations.push(
535
+ `postcssGlobalData({
536
+ files: ["${mediaSource}"],
537
+ }),`
538
+ );
539
+ if (opts.withTokenUtilities) {
540
+ invocations.push(
541
+ `tokenUtilities({
542
+ designTokenSource: "${tokenSource}",
543
+ customMediaSource: "${mediaSource}",
544
+ content: ["${contentGlob}"],
545
+ classMatcher: ["optionClassName"],
546
+ generated: {
547
+ path: "${generatedPath}",
548
+ },
549
+ }),`
550
+ );
551
+ }
552
+ invocations.push(
553
+ `postcssPresetEnv({
554
+ stage: 2,
555
+ preserve: true,
556
+ features: {
557
+ "nesting-rules": true,
558
+ "custom-media-queries": true,
559
+ "color-mix": true,
560
+ },
561
+ }),`
562
+ );
563
+ invocations.push(`autoprefixer(),`);
564
+ return { imports, invocations };
565
+ };
566
+ var indent2 = (src, level = 1) => {
567
+ const pad = " ".repeat(level);
568
+ return src.split("\n").map((line) => line.length ? pad + line : line).join("\n");
569
+ };
570
+
571
+ // src/frameworks/shared.ts
572
+ var toPosix2 = (p3) => p3.split(sep2).join(posix2.sep);
573
+ var renderPluginStrings = (opts, context, indentInvocations) => {
574
+ const chain = renderPluginChain({
575
+ withTokenUtilities: opts.withTokenUtilities,
576
+ srcDir: context.srcDir,
577
+ stylesRel: context.stylesRel,
578
+ contentExtensions: context.contentExtensions
579
+ });
580
+ const imports = chain.imports.join("\n");
581
+ const invocations = chain.invocations.map((inv) => indent2(inv, indentInvocations)).join("\n");
582
+ return { imports, invocations };
583
+ };
584
+ var toCommonJsImports = (imports) => imports.split("\n").map((line) => {
585
+ const trimmed = line.trim();
586
+ const m = trimmed.match(/^import\s+([A-Za-z_$][\w$]*)\s+from\s+"([^"]+)";?$/);
587
+ if (!m) return line;
588
+ return `const ${m[1]} = require("${m[2]}");`;
589
+ }).join("\n");
590
+ var renderInlinePlan = (args) => {
591
+ const chain = renderPluginChain({
592
+ withTokenUtilities: args.options.withTokenUtilities,
593
+ srcDir: args.context.srcDir,
594
+ stylesRel: args.context.stylesRel,
595
+ contentExtensions: args.context.contentExtensions
596
+ });
597
+ const snippetInvocations = chain.invocations.map((inv) => indent2(inv, args.snippetInvocationIndent)).join("\n");
598
+ return {
599
+ target: args.target,
600
+ imports: chain.imports,
601
+ invocations: chain.invocations,
602
+ manualSnippet: {
603
+ title: args.title,
604
+ content: renderTemplate(args.templatePath, {
605
+ imports: chain.imports.join("\n"),
606
+ invocations: snippetInvocations,
607
+ ...args.extraTemplateVars ?? {}
608
+ })
609
+ }
610
+ };
611
+ };
612
+
613
+ // src/frameworks/vite-react/index.ts
614
+ var renderViteReactCssConfig = (input, context) => {
615
+ const files = [];
616
+ const snippets = [];
617
+ if (input.placement === "inline") {
618
+ return {
619
+ files,
620
+ snippets,
621
+ inline: renderInlinePlan({
622
+ target: "vite",
623
+ title: "Merge this into your existing vite.config.ts",
624
+ templatePath: "vite-react/vite-inline.snippet.md",
625
+ context: context.pluginCtx,
626
+ options: input.options,
627
+ snippetInvocationIndent: 2,
628
+ extraTemplateVars: { pretty: input.options.prettyCssModuleNames }
629
+ })
630
+ };
631
+ }
632
+ if (input.viteConfigExists) {
633
+ const inline = renderInlinePlan({
634
+ target: "vite",
635
+ title: "Optional: move the PostCSS chain into vite.config.ts",
636
+ templatePath: "vite-react/vite-inline.snippet.md",
637
+ context: context.pluginCtx,
638
+ options: input.options,
639
+ snippetInvocationIndent: 2,
640
+ extraTemplateVars: { pretty: input.options.prettyCssModuleNames }
641
+ });
642
+ snippets.push(inline.manualSnippet);
643
+ const pc7 = renderPluginStrings(input.options, context.pluginCtx, 2);
644
+ files.push({
645
+ filename: "postcss.config.ts",
646
+ content: renderTemplate("vite-react/postcss.config.ts.template", {
647
+ imports: pc7.imports,
648
+ invocations: pc7.invocations
649
+ }),
650
+ label: "postcss.config.ts"
651
+ });
652
+ return { files, snippets };
653
+ }
654
+ const { imports, invocations } = renderPluginStrings(
655
+ input.options,
656
+ context.pluginCtx,
657
+ 4
658
+ );
659
+ files.push({
660
+ filename: "vite.config.ts",
661
+ content: renderTemplate("vite-react/vite.config.ts.template", {
662
+ imports,
663
+ invocations,
664
+ alias: input.alias,
665
+ srcDir: context.posixSrc,
666
+ pretty: input.options.prettyCssModuleNames
667
+ }),
668
+ label: "vite.config.ts"
669
+ });
670
+ return { files, snippets };
671
+ };
672
+
673
+ // src/frameworks/next/index.ts
674
+ var renderNextCssConfig = (input, context) => {
675
+ const files = [];
676
+ const snippets = [];
677
+ const { imports: esmImports, invocations } = renderPluginStrings(
678
+ input.options,
679
+ context.pluginCtx,
680
+ 2
681
+ );
682
+ const imports = toCommonJsImports(esmImports);
683
+ files.push({
684
+ filename: "postcss.config.js",
685
+ content: renderTemplate("next/postcss.config.js.template", {
686
+ imports,
687
+ invocations
688
+ }),
689
+ label: "postcss.config.js"
690
+ });
691
+ snippets.push({
692
+ title: "Wire globals.css into app/layout.tsx",
693
+ content: renderTemplate("next/layout-import.snippet.md", {
694
+ srcDir: context.posixSrc,
695
+ stylesRel: context.posixStyles,
696
+ utilities: input.options.withTokenUtilities
697
+ })
698
+ });
699
+ snippets.push({
700
+ title: "Ensure next.config.* transpiles @aplance-ui/core",
701
+ content: renderTemplate("next/next.config.snippet.md", {})
702
+ });
703
+ return { files, snippets };
704
+ };
705
+
706
+ // src/frameworks/tanstack-start/index.ts
707
+ var renderTanstackStartCssConfig = (input, context) => {
708
+ const files = [];
709
+ const snippets = [];
710
+ if (input.placement === "inline") {
711
+ return {
712
+ files,
713
+ snippets,
714
+ inline: renderInlinePlan({
715
+ target: "tanstack-start",
716
+ title: "Merge this into app.config.ts (vite block)",
717
+ templatePath: "tanstack-start/vite-inline.snippet.md",
718
+ context: context.pluginCtx,
719
+ options: input.options,
720
+ snippetInvocationIndent: 4
721
+ })
722
+ };
723
+ }
724
+ const { imports, invocations } = renderPluginStrings(
725
+ input.options,
726
+ context.pluginCtx,
727
+ 2
728
+ );
729
+ files.push({
730
+ filename: "postcss.config.ts",
731
+ content: renderTemplate("tanstack-start/postcss.config.ts.template", {
732
+ imports,
733
+ invocations
734
+ }),
735
+ label: "postcss.config.ts"
736
+ });
737
+ const inline = renderInlinePlan({
738
+ target: "tanstack-start",
739
+ title: "Optional: move the PostCSS chain into app.config.ts",
740
+ templatePath: "tanstack-start/vite-inline.snippet.md",
741
+ context: context.pluginCtx,
742
+ options: input.options,
743
+ snippetInvocationIndent: 4
744
+ });
745
+ snippets.push(inline.manualSnippet);
746
+ return { files, snippets };
747
+ };
748
+
749
+ // src/frameworks/astro/index.ts
750
+ var ASTRO_PLUGIN_CONTEXT = {
751
+ contentExtensions: ["tsx", "ts", "jsx", "js", "astro"]
752
+ };
753
+ var renderAstroCssConfig = (input, context) => {
754
+ const files = [];
755
+ const snippets = [];
756
+ snippets.push({
757
+ title: "Wire the React integration + global styles",
758
+ content: renderTemplate("astro/astro.config.snippet.md", {
759
+ stylesRel: context.posixStyles,
760
+ utilities: input.options.withTokenUtilities
761
+ })
762
+ });
763
+ if (input.placement === "inline") {
764
+ return {
765
+ files,
766
+ snippets,
767
+ inline: renderInlinePlan({
768
+ target: "astro",
769
+ title: "Merge this into astro.config.* (vite block)",
770
+ templatePath: "astro/vite-inline.snippet.md",
771
+ context: {
772
+ ...context.pluginCtx,
773
+ ...ASTRO_PLUGIN_CONTEXT
774
+ },
775
+ options: input.options,
776
+ snippetInvocationIndent: 6
777
+ })
778
+ };
779
+ }
780
+ const { imports, invocations } = renderPluginStrings(
781
+ input.options,
782
+ {
783
+ ...context.pluginCtx,
784
+ ...ASTRO_PLUGIN_CONTEXT
785
+ },
786
+ 2
787
+ );
788
+ files.push({
789
+ filename: "postcss.config.mjs",
790
+ content: renderTemplate("astro/postcss.config.mjs.template", {
791
+ imports,
792
+ invocations
793
+ }),
794
+ label: "postcss.config.mjs"
795
+ });
796
+ return { files, snippets };
797
+ };
798
+
799
+ // src/frameworks/electron-vite/index.ts
800
+ var renderElectronViteCssConfig = (input, context) => {
801
+ const files = [];
802
+ const snippets = [];
803
+ if (input.placement === "inline") {
804
+ return {
805
+ files,
806
+ snippets,
807
+ inline: renderInlinePlan({
808
+ target: "electron-vite",
809
+ title: "Merge this into electron.vite.config.ts (renderer block)",
810
+ templatePath: "electron-vite/vite.config.snippet.md",
811
+ context: context.pluginCtx,
812
+ options: input.options,
813
+ snippetInvocationIndent: 5,
814
+ extraTemplateVars: {
815
+ alias: input.alias,
816
+ srcDir: context.posixSrc,
817
+ stylesRel: context.posixStyles,
818
+ utilities: input.options.withTokenUtilities
819
+ }
820
+ })
821
+ };
822
+ }
823
+ const { imports, invocations } = renderPluginStrings(
824
+ input.options,
825
+ context.pluginCtx,
826
+ 2
827
+ );
828
+ files.push({
829
+ filename: "postcss.config.ts",
830
+ content: renderTemplate("vite-react/postcss.config.ts.template", {
831
+ imports,
832
+ invocations
833
+ }),
834
+ label: "postcss.config.ts"
835
+ });
836
+ return { files, snippets };
837
+ };
838
+
839
+ // src/frameworks/renderers.ts
840
+ var FRAMEWORK_CSS_RENDERERS = {
841
+ "vite-react": renderViteReactCssConfig,
842
+ next: renderNextCssConfig,
843
+ "tanstack-start": renderTanstackStartCssConfig,
844
+ astro: renderAstroCssConfig,
845
+ "electron-vite": renderElectronViteCssConfig
846
+ };
847
+
848
+ // src/lib/css-config.ts
849
+ var renderCssConfig = (input) => {
850
+ const posixSrc = toPosix2(input.srcDir);
851
+ const posixStyles = toPosix2(input.stylesRel);
852
+ const context = {
853
+ posixSrc,
854
+ posixStyles,
855
+ pluginCtx: {
856
+ srcDir: posixSrc,
857
+ stylesRel: posixStyles
858
+ }
859
+ };
860
+ const renderer = FRAMEWORK_CSS_RENDERERS[input.template];
861
+ if (!renderer) {
862
+ const exhaustive = input.template;
863
+ throw new TemplateError(
864
+ "E_UNKNOWN_TEMPLATE",
865
+ `Unknown framework template: ${String(exhaustive)}.`
866
+ );
867
+ }
868
+ return renderer(input, context);
869
+ };
870
+
871
+ // src/lib/css-inline.ts
872
+ var TOP_LEVEL_OBJECT_PATTERNS = [
873
+ /^[ \t]*export\s+default\s+defineConfig\s*\(\s*\{/m,
874
+ /^[ \t]*defineConfig\s*\(\s*\{/m,
875
+ /^[ \t]*export\s+default\s*\{/m
876
+ ];
877
+ var extractModuleSpecifier = (line) => {
878
+ const fromMatch = line.match(/from\s+"([^"]+)"/) ?? line.match(/from\s+'([^']+)'/);
879
+ if (fromMatch?.[1]) return fromMatch[1];
880
+ const requireMatch = line.match(/require\(\s*"([^"]+)"\s*\)/) ?? line.match(/require\(\s*'([^']+)'\s*\)/);
881
+ return requireMatch?.[1] ?? null;
882
+ };
883
+ var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
884
+ var ensureImports = (source, imports) => {
885
+ const missing = imports.filter((line) => {
886
+ const moduleName = extractModuleSpecifier(line);
887
+ if (moduleName) {
888
+ const modulePattern = new RegExp(
889
+ `from\\s+["']${escapeRegExp(moduleName)}["']|require\\(\\s*["']${escapeRegExp(moduleName)}["']\\s*\\)`
890
+ );
891
+ return !modulePattern.test(source);
892
+ }
893
+ return !source.includes(line.trim());
894
+ });
895
+ if (missing.length === 0) return source;
896
+ const importMatches = Array.from(source.matchAll(/^import[^\n]*$/gm));
897
+ if (importMatches.length === 0) {
898
+ return `${missing.join("\n")}
899
+
900
+ ${source}`;
901
+ }
902
+ const lastImport = importMatches[importMatches.length - 1];
903
+ const insertAt = lastImport.index + lastImport[0].length;
904
+ return `${source.slice(0, insertAt)}
905
+ ${missing.join("\n")}${source.slice(insertAt)}`;
906
+ };
907
+ var renderIndentedBlock = (source, indent3) => source.split("\n").map((line) => line.length > 0 ? `${indent3}${line}` : line).join("\n");
908
+ var buildCssPostcssBlock = (invocations, cssIndent) => {
909
+ const postcssIndent = `${cssIndent} `;
910
+ const pluginsIndent = `${postcssIndent} `;
911
+ const itemIndent = `${pluginsIndent} `;
912
+ const plugins = invocations.map((invocation) => renderIndentedBlock(invocation, itemIndent)).join("\n");
913
+ return [
914
+ `${cssIndent}css: {`,
915
+ `${postcssIndent}postcss: {`,
916
+ `${pluginsIndent}plugins: [`,
917
+ plugins,
918
+ `${pluginsIndent}],`,
919
+ `${postcssIndent}},`,
920
+ `${cssIndent}},`
921
+ ].join("\n");
922
+ };
923
+ var buildViteBlock = (invocations, viteIndent) => [
924
+ `${viteIndent}vite: {`,
925
+ buildCssPostcssBlock(invocations, `${viteIndent} `),
926
+ `${viteIndent}},`
927
+ ].join("\n");
928
+ var insertIntoTopLevelObject = (source, blockFactory) => {
929
+ for (const pattern of TOP_LEVEL_OBJECT_PATTERNS) {
930
+ const match = pattern.exec(source);
931
+ if (!match) continue;
932
+ const lineIndent = (match[0].match(/^[ \t]*/) ?? [""])[0];
933
+ const insertAt = match.index + match[0].length;
934
+ const block = blockFactory(`${lineIndent} `);
935
+ return `${source.slice(0, insertAt)}
936
+ ${block}${source.slice(insertAt)}`;
937
+ }
938
+ return null;
939
+ };
940
+ var findNamedObjectProperty = (source, propertyName) => {
941
+ const pattern = new RegExp(`(^[ \\t]*)${escapeRegExp(propertyName)}\\s*:\\s*\\{`, "m");
942
+ const match = pattern.exec(source);
943
+ if (!match) return null;
944
+ return {
945
+ insertAt: match.index + match[0].length,
946
+ childIndent: `${match[1] ?? ""} `
947
+ };
948
+ };
949
+ var insertIntoNamedObjectProperty = (source, propertyName, blockFactory) => {
950
+ const found = findNamedObjectProperty(source, propertyName);
951
+ if (!found) return null;
952
+ const block = blockFactory(found.childIndent);
953
+ return `${source.slice(0, found.insertAt)}
954
+ ${block}${source.slice(found.insertAt)}`;
955
+ };
956
+ var hasPostcssConfig = (source) => /\bpostcss\s*:/.test(source);
957
+ var applyViteInline = (source, invocations) => insertIntoTopLevelObject(
958
+ source,
959
+ (childIndent) => buildCssPostcssBlock(invocations, childIndent)
960
+ );
961
+ var applyVitePropertyInline = (source, invocations) => {
962
+ const inVite = insertIntoNamedObjectProperty(
963
+ source,
964
+ "vite",
965
+ (childIndent) => buildCssPostcssBlock(invocations, childIndent)
966
+ );
967
+ if (inVite) return inVite;
968
+ return insertIntoTopLevelObject(
969
+ source,
970
+ (childIndent) => buildViteBlock(invocations, childIndent)
971
+ );
972
+ };
973
+ var applyElectronRendererInline = (source, invocations) => insertIntoNamedObjectProperty(
974
+ source,
975
+ "renderer",
976
+ (childIndent) => buildCssPostcssBlock(invocations, childIndent)
977
+ );
978
+ var applyInlineCssConfig = (input) => {
979
+ if (hasPostcssConfig(input.source)) {
980
+ return {
981
+ ok: false,
982
+ reason: "Config already contains a postcss block."
983
+ };
984
+ }
985
+ const withImports = ensureImports(input.source, input.plan.imports);
986
+ const patched = (() => {
987
+ switch (input.plan.target) {
988
+ case "vite":
989
+ return applyViteInline(withImports, input.plan.invocations);
990
+ case "astro":
991
+ case "tanstack-start":
992
+ return applyVitePropertyInline(withImports, input.plan.invocations);
993
+ case "electron-vite":
994
+ return applyElectronRendererInline(withImports, input.plan.invocations);
995
+ default:
996
+ return null;
997
+ }
998
+ })();
999
+ if (!patched) {
1000
+ return {
1001
+ ok: false,
1002
+ reason: `Could not locate a writable ${input.plan.target} config object.`
1003
+ };
1004
+ }
1005
+ return { ok: true, content: patched };
1006
+ };
1007
+
1008
+ // src/lib/css-orchestrate.ts
1009
+ var planCssConfigOps = (input) => {
1010
+ const { cwd, cfg, placement, project } = input;
1011
+ const ops = [];
1012
+ const snippets = [];
1013
+ const warnings = [];
1014
+ const render = (p3) => renderCssConfig({
1015
+ template: cfg.template,
1016
+ srcDir: cfg.srcDir,
1017
+ alias: cfg.alias,
1018
+ stylesRel: cfg.paths.styles,
1019
+ options: {
1020
+ withTokenUtilities: cfg.utilities.enabled,
1021
+ prettyCssModuleNames: cfg.cssModules.pretty
1022
+ },
1023
+ placement: p3,
1024
+ viteConfigExists: Boolean(project.viteConfigPath)
1025
+ });
1026
+ let result = render(placement.effective);
1027
+ if (placement.effective === "inline" && result.inline) {
1028
+ const hostPath = placement.hostPath;
1029
+ if (!hostPath || !existsSync5(hostPath)) {
1030
+ warnings.push("Inline host config not found at apply-time. Falling back to standalone PostCSS config.");
1031
+ result = render("file");
1032
+ } else {
1033
+ const inline = applyInlineCssConfig({
1034
+ source: readFileSync6(hostPath, "utf8"),
1035
+ plan: result.inline
1036
+ });
1037
+ if (inline.ok && inline.content) {
1038
+ ops.push({
1039
+ target: hostPath,
1040
+ content: inline.content,
1041
+ label: relative3(cwd, hostPath) || hostPath
1042
+ });
1043
+ snippets.push(...result.snippets);
1044
+ result = { files: [], snippets: [] };
1045
+ } else {
1046
+ warnings.push(`Could not inline CSS plugins (${inline.reason ?? "unknown reason"}). Falling back to standalone PostCSS config.`);
1047
+ snippets.push(result.inline.manualSnippet);
1048
+ const fallback = render("file");
1049
+ result = {
1050
+ files: fallback.files,
1051
+ snippets: [...result.snippets, ...fallback.snippets]
1052
+ };
1053
+ }
1054
+ }
1055
+ }
1056
+ for (const file of result.files) {
1057
+ ops.push({
1058
+ target: join5(cwd, file.filename),
1059
+ content: file.content,
1060
+ label: file.label
1061
+ });
1062
+ }
1063
+ snippets.push(...result.snippets);
1064
+ return { ops, snippets, warnings };
1065
+ };
1066
+
1067
+ // src/lib/detect.ts
1068
+ import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
1069
+ import { join as join6 } from "path";
1070
+ var VITE_CONFIG_NAMES = [
1071
+ "vite.config.ts",
1072
+ "vite.config.mts",
1073
+ "vite.config.js",
1074
+ "vite.config.mjs"
1075
+ ];
1076
+ var NEXT_CONFIG_NAMES = [
1077
+ "next.config.ts",
1078
+ "next.config.js",
1079
+ "next.config.mjs"
1080
+ ];
1081
+ var ASTRO_CONFIG_NAMES = [
1082
+ "astro.config.ts",
1083
+ "astro.config.js",
1084
+ "astro.config.mjs"
1085
+ ];
1086
+ var ELECTRON_VITE_CONFIG_NAMES = [
1087
+ "electron.vite.config.ts",
1088
+ "electron.vite.config.js",
1089
+ "electron.vite.config.mjs"
1090
+ ];
1091
+ var TANSTACK_APP_CONFIG_NAMES = [
1092
+ "app.config.ts",
1093
+ "app.config.mts",
1094
+ "app.config.js",
1095
+ "app.config.mjs"
1096
+ ];
1097
+ var firstExisting = (cwd, names) => {
1098
+ for (const name of names) {
1099
+ const p3 = join6(cwd, name);
1100
+ if (existsSync6(p3)) return p3;
1101
+ }
1102
+ return null;
1103
+ };
1104
+ var readDeclaredDeps = (packageJsonPath) => {
1105
+ try {
1106
+ const pkg = JSON.parse(readFileSync7(packageJsonPath, "utf8"));
1107
+ return /* @__PURE__ */ new Set([
1108
+ ...Object.keys(pkg.dependencies ?? {}),
1109
+ ...Object.keys(pkg.devDependencies ?? {}),
1110
+ ...Object.keys(pkg.peerDependencies ?? {})
1111
+ ]);
1112
+ } catch {
1113
+ return /* @__PURE__ */ new Set();
1114
+ }
1115
+ };
1116
+ var detectProject = (cwd) => {
1117
+ const packageJsonPath = existsSync6(join6(cwd, "package.json")) ? join6(cwd, "package.json") : null;
1118
+ const declaredDeps = packageJsonPath ? readDeclaredDeps(packageJsonPath) : /* @__PURE__ */ new Set();
1119
+ const viteConfigPath = firstExisting(cwd, VITE_CONFIG_NAMES);
1120
+ const nextConfigPath = firstExisting(cwd, NEXT_CONFIG_NAMES);
1121
+ const astroConfigPath = firstExisting(cwd, ASTRO_CONFIG_NAMES);
1122
+ const electronViteConfigPath = firstExisting(cwd, ELECTRON_VITE_CONFIG_NAMES);
1123
+ const tanstackConfigPath = firstExisting(cwd, TANSTACK_APP_CONFIG_NAMES);
1124
+ return {
1125
+ isVite: Boolean(viteConfigPath) || declaredDeps.has("vite"),
1126
+ viteConfigPath,
1127
+ isNext: Boolean(nextConfigPath) || declaredDeps.has("next"),
1128
+ nextConfigPath,
1129
+ isAstro: Boolean(astroConfigPath) || declaredDeps.has("astro"),
1130
+ astroConfigPath,
1131
+ isTanstackStart: Boolean(tanstackConfigPath) || declaredDeps.has("@tanstack/start") || declaredDeps.has("@tanstack/react-start"),
1132
+ tanstackConfigPath,
1133
+ isElectronVite: Boolean(electronViteConfigPath) || declaredDeps.has("electron-vite"),
1134
+ electronViteConfigPath,
1135
+ packageJsonPath,
1136
+ declaredDeps
1137
+ };
1138
+ };
1139
+ var suggestTemplate = (p3) => {
1140
+ if (p3.isElectronVite) return "electron-vite";
1141
+ if (p3.isNext) return "next";
1142
+ if (p3.isAstro) return "astro";
1143
+ if (p3.isTanstackStart) return "tanstack-start";
1144
+ if (p3.isVite) return "vite-react";
1145
+ return null;
1146
+ };
1147
+ var describeProject = (p3) => {
1148
+ const parts = [];
1149
+ if (p3.isElectronVite) parts.push("electron-vite");
1150
+ else if (p3.isNext) parts.push("Next.js");
1151
+ else if (p3.isAstro) parts.push("Astro");
1152
+ else if (p3.isTanstackStart) parts.push("TanStack Start");
1153
+ else if (p3.isVite) parts.push("Vite");
1154
+ return parts.length ? parts.join(", ") : "unknown framework";
1155
+ };
1156
+
1157
+ // src/frameworks/meta.ts
1158
+ var FRAMEWORK_META = {
1159
+ "vite-react": {
1160
+ label: "Vite + React",
1161
+ supportsPrettyCssModuleNames: true,
1162
+ resolveInlineHostPath: (project) => project.viteConfigPath
1163
+ },
1164
+ next: {
1165
+ label: "Next.js (App Router)",
1166
+ supportsPrettyCssModuleNames: false,
1167
+ resolveInlineHostPath: () => null
1168
+ },
1169
+ "tanstack-start": {
1170
+ label: "TanStack Start",
1171
+ supportsPrettyCssModuleNames: true,
1172
+ resolveInlineHostPath: (project) => project.tanstackConfigPath
1173
+ },
1174
+ astro: {
1175
+ label: "Astro",
1176
+ supportsPrettyCssModuleNames: false,
1177
+ resolveInlineHostPath: (project) => project.astroConfigPath
1178
+ },
1179
+ "electron-vite": {
1180
+ label: "Electron + Vite",
1181
+ supportsPrettyCssModuleNames: true,
1182
+ resolveInlineHostPath: (project) => project.electronViteConfigPath
1183
+ }
1184
+ };
1185
+ var getFrameworkLabel = (template) => FRAMEWORK_META[template].label;
1186
+ var supportsPrettyCssModules = (template) => FRAMEWORK_META[template].supportsPrettyCssModuleNames;
1187
+ var getInlineHostPath = (template, project) => FRAMEWORK_META[template].resolveInlineHostPath(project);
1188
+
1189
+ // src/lib/config.ts
1190
+ import { existsSync as existsSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync2 } from "fs";
1191
+ import { join as join7 } from "path";
1192
+ var CONFIG_FILE_NAME = "components.json";
1193
+ var CONFIG_SCHEMA_URL = "https://aplance-ui.dev/schema.json";
1194
+ var SUPPORTED_TEMPLATES = [
1195
+ "vite-react",
1196
+ "next",
1197
+ "tanstack-start",
1198
+ "astro",
1199
+ "electron-vite"
1200
+ ];
1201
+ var CSS_CONFIG_PLACEMENTS = ["auto", "inline", "file"];
1202
+ var DEFAULT_PATHS = {
1203
+ styles: "styles",
1204
+ components: "components",
1205
+ hooks: "hooks",
1206
+ lib: "lib"
1207
+ };
1208
+ var TEMPLATE_DEFAULT_SRCDIR = {
1209
+ "vite-react": "src",
1210
+ next: "src",
1211
+ "tanstack-start": "src",
1212
+ astro: "src",
1213
+ "electron-vite": "src/renderer/src"
1214
+ };
1215
+ var makeDefaultConfig = (opts) => ({
1216
+ $schema: CONFIG_SCHEMA_URL,
1217
+ template: opts.template,
1218
+ srcDir: opts.srcDir ?? TEMPLATE_DEFAULT_SRCDIR[opts.template],
1219
+ alias: opts.alias ?? "@",
1220
+ theme: {
1221
+ color: opts.color ?? "default",
1222
+ radius: opts.radius ?? "default",
1223
+ spacing: opts.spacing ?? "default"
1224
+ },
1225
+ paths: { ...DEFAULT_PATHS },
1226
+ cssModules: { pretty: opts.pretty ?? false },
1227
+ utilities: { enabled: opts.utilities ?? false },
1228
+ cssConfig: { placement: opts.cssConfigPlacement ?? "auto" }
1229
+ });
1230
+ var configPath = (cwd) => join7(cwd, CONFIG_FILE_NAME);
1231
+ var configExists = (cwd) => existsSync7(configPath(cwd));
1232
+ var loadConfig = (cwd) => {
1233
+ const p3 = configPath(cwd);
1234
+ if (!existsSync7(p3)) {
1235
+ throw new ConfigError(
1236
+ "E_CONFIG_MISSING",
1237
+ `No ${CONFIG_FILE_NAME} found at ${p3}.`,
1238
+ `Run \`aplance-ui init\` once to create it.`
1239
+ );
1240
+ }
1241
+ let parsed;
1242
+ try {
1243
+ parsed = JSON.parse(readFileSync8(p3, "utf8"));
1244
+ } catch (err) {
1245
+ throw new ConfigError(
1246
+ "E_CONFIG_INVALID",
1247
+ `Failed to parse ${p3}: ${err.message}`,
1248
+ `Delete ${CONFIG_FILE_NAME} and re-run \`aplance-ui init\` to recreate it.`
1249
+ );
1250
+ }
1251
+ return validateConfig(parsed, p3);
1252
+ };
1253
+ var resolvePaths = (cwd, cfg) => {
1254
+ const srcDir = join7(cwd, cfg.srcDir);
1255
+ return {
1256
+ srcDir,
1257
+ stylesDir: join7(srcDir, cfg.paths.styles),
1258
+ componentsDir: join7(srcDir, cfg.paths.components),
1259
+ hooksDir: join7(srcDir, cfg.paths.hooks),
1260
+ libDir: join7(srcDir, cfg.paths.lib)
1261
+ };
1262
+ };
1263
+ var normalizeTheme = (raw) => {
1264
+ if (typeof raw === "string") {
1265
+ return { color: raw, radius: "default", spacing: "default" };
1266
+ }
1267
+ if (raw && typeof raw === "object") {
1268
+ const t = raw;
1269
+ return {
1270
+ color: typeof t.color === "string" ? t.color : "default",
1271
+ radius: typeof t.radius === "string" ? t.radius : "default",
1272
+ spacing: typeof t.spacing === "string" ? t.spacing : "default"
1273
+ };
1274
+ }
1275
+ return { color: "default", radius: "default", spacing: "default" };
1276
+ };
1277
+ var validateConfig = (raw, file) => {
1278
+ if (!raw || typeof raw !== "object") {
1279
+ throw new ConfigError(
1280
+ "E_CONFIG_INVALID",
1281
+ `${file} is not a JSON object.`
1282
+ );
1283
+ }
1284
+ const c = raw;
1285
+ const must = (cond, msg) => {
1286
+ if (!cond) throw new ConfigError("E_CONFIG_INVALID", `${file}: ${msg}`);
1287
+ };
1288
+ must(typeof c.template === "string", `"template" must be a string.`);
1289
+ must(
1290
+ SUPPORTED_TEMPLATES.includes(c.template),
1291
+ `"template" must be one of: ${SUPPORTED_TEMPLATES.join(", ")} (got "${c.template}").`
1292
+ );
1293
+ must(typeof c.srcDir === "string" && c.srcDir.length > 0, `"srcDir" must be a non-empty string.`);
1294
+ must(typeof c.alias === "string" && c.alias.length > 0, `"alias" must be a non-empty string.`);
1295
+ must(c.paths && typeof c.paths === "object", `"paths" must be an object.`);
1296
+ const ps = c.paths;
1297
+ for (const k of ["styles", "components", "hooks", "lib"]) {
1298
+ must(typeof ps[k] === "string" && ps[k].length > 0, `"paths.${k}" must be a non-empty string.`);
1299
+ }
1300
+ must(c.cssModules && typeof c.cssModules === "object", `"cssModules" must be an object.`);
1301
+ must(typeof c.cssModules.pretty === "boolean", `"cssModules.pretty" must be a boolean.`);
1302
+ must(c.utilities && typeof c.utilities === "object", `"utilities" must be an object.`);
1303
+ must(typeof c.utilities.enabled === "boolean", `"utilities.enabled" must be a boolean.`);
1304
+ if (c.cssConfig !== void 0) {
1305
+ must(c.cssConfig && typeof c.cssConfig === "object", `"cssConfig" must be an object.`);
1306
+ must(
1307
+ CSS_CONFIG_PLACEMENTS.includes(c.cssConfig.placement),
1308
+ `"cssConfig.placement" must be one of: ${CSS_CONFIG_PLACEMENTS.join(", ")} (got "${String(c.cssConfig.placement)}").`
1309
+ );
1310
+ }
1311
+ return {
1312
+ $schema: c.$schema ?? CONFIG_SCHEMA_URL,
1313
+ template: c.template,
1314
+ srcDir: c.srcDir,
1315
+ alias: c.alias,
1316
+ theme: normalizeTheme(c.theme),
1317
+ paths: ps,
1318
+ cssModules: { pretty: c.cssModules.pretty },
1319
+ utilities: { enabled: c.utilities.enabled },
1320
+ cssConfig: {
1321
+ placement: c.cssConfig?.placement ?? "auto"
1322
+ }
1323
+ };
1324
+ };
1325
+
1326
+ // src/lib/units.ts
1327
+ var BUCKETS = [
1328
+ { label: "ui", predicate: (u) => u.kind === "component" && u.group === "ui" },
1329
+ { label: "primitive", predicate: (u) => u.kind === "component" && u.group === "primitives" },
1330
+ { label: "hook", predicate: (u) => u.kind === "hook" },
1331
+ { label: "lib", predicate: (u) => u.kind === "lib" }
1332
+ ];
1333
+ var groupedUnitOptions = (units) => BUCKETS.flatMap(
1334
+ ({ label, predicate }) => units.filter(predicate).map((u) => ({
1335
+ value: u.name,
1336
+ label: u.name,
1337
+ hint: `${label}${u.deps.length ? ` \xB7 deps: ${u.deps.join(", ")}` : ""}`
1338
+ }))
1339
+ );
1340
+
1341
+ // src/lib/installer.ts
1342
+ import { spawn } from "child_process";
1343
+ import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
1344
+ import { join as join8 } from "path";
1345
+ var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
1346
+ var detectPackageManager = (cwd) => {
1347
+ const pkgJsonPath = join8(cwd, "package.json");
1348
+ if (existsSync8(pkgJsonPath)) {
1349
+ try {
1350
+ const pkg = JSON.parse(readFileSync9(pkgJsonPath, "utf8"));
1351
+ if (typeof pkg.packageManager === "string") {
1352
+ const name = pkg.packageManager.split("@")[0].trim();
1353
+ if (PACKAGE_MANAGERS.includes(name)) {
1354
+ return name;
1355
+ }
1356
+ }
1357
+ } catch {
1358
+ }
1359
+ }
1360
+ if (existsSync8(join8(cwd, "pnpm-lock.yaml"))) return "pnpm";
1361
+ if (existsSync8(join8(cwd, "yarn.lock"))) return "yarn";
1362
+ if (existsSync8(join8(cwd, "bun.lockb"))) return "bun";
1363
+ if (existsSync8(join8(cwd, "bun.lock"))) return "bun";
1364
+ if (existsSync8(join8(cwd, "package-lock.json"))) return "npm";
1365
+ return "npm";
1366
+ };
1367
+ var computeDependencyPlan = (input) => {
1368
+ const { registry, units, cfg, project } = input;
1369
+ const meta = registry.installMeta;
1370
+ const dependencies = { ...meta.baseDependencies };
1371
+ const devDependencies = { ...meta.baseDevDependencies };
1372
+ if (cfg.utilities.enabled) {
1373
+ Object.assign(devDependencies, meta.utilitiesDevDependencies);
1374
+ }
1375
+ for (const unit of units) {
1376
+ for (const pkg of unit.externalDeps) {
1377
+ if (pkg in dependencies) continue;
1378
+ const version = meta.packageVersions[pkg];
1379
+ if (!version) continue;
1380
+ dependencies[pkg] = version;
1381
+ }
1382
+ }
1383
+ const skipped = [];
1384
+ const filter = (bag) => {
1385
+ for (const name of Object.keys(bag)) {
1386
+ if (project.declaredDeps.has(name)) {
1387
+ skipped.push({ name, reason: "already-declared" });
1388
+ delete bag[name];
1389
+ }
1390
+ }
1391
+ };
1392
+ filter(dependencies);
1393
+ filter(devDependencies);
1394
+ return { dependencies, devDependencies, skipped };
1395
+ };
1396
+ var buildInstallCommands = (pm, plan) => {
1397
+ const commands = [];
1398
+ const runtimeSpecs = Object.entries(plan.dependencies).map(
1399
+ ([name, v]) => `${name}@${v}`
1400
+ );
1401
+ const devSpecs = Object.entries(plan.devDependencies).map(
1402
+ ([name, v]) => `${name}@${v}`
1403
+ );
1404
+ const runtimeArgs = installArgs(pm, runtimeSpecs, false);
1405
+ const devArgs = installArgs(pm, devSpecs, true);
1406
+ if (runtimeSpecs.length > 0) {
1407
+ commands.push({
1408
+ bin: pm,
1409
+ args: runtimeArgs,
1410
+ label: `${pm} ${runtimeArgs.join(" ")}`
1411
+ });
1412
+ }
1413
+ if (devSpecs.length > 0) {
1414
+ commands.push({
1415
+ bin: pm,
1416
+ args: devArgs,
1417
+ label: `${pm} ${devArgs.join(" ")}`
1418
+ });
1419
+ }
1420
+ return commands;
1421
+ };
1422
+ var installArgs = (pm, specs, dev) => {
1423
+ switch (pm) {
1424
+ case "npm":
1425
+ return [
1426
+ "install",
1427
+ dev ? "--save-dev" : "--save",
1428
+ "--no-fund",
1429
+ "--no-audit",
1430
+ ...specs
1431
+ ];
1432
+ case "pnpm":
1433
+ return ["add", dev ? "--save-dev" : "", ...specs].filter(Boolean);
1434
+ case "yarn":
1435
+ return ["add", dev ? "--dev" : "", ...specs].filter(Boolean);
1436
+ case "bun":
1437
+ return ["add", dev ? "--dev" : "", ...specs].filter(Boolean);
1438
+ }
1439
+ };
1440
+ var runInstall = async (commands, opts) => {
1441
+ for (const cmd of commands) {
1442
+ opts.onCommand?.(cmd);
1443
+ await new Promise((resolve, reject) => {
1444
+ const child = spawn(cmd.bin, cmd.args, {
1445
+ cwd: opts.cwd,
1446
+ stdio: "inherit",
1447
+ env: { ...process.env, ...opts.env },
1448
+ shell: process.platform === "win32"
1449
+ });
1450
+ child.on("error", reject);
1451
+ child.on("close", (code) => {
1452
+ if (code === 0) resolve();
1453
+ else
1454
+ reject(
1455
+ new Error(
1456
+ `${cmd.label} exited with code ${code ?? "null"}. Aborting install.`
1457
+ )
1458
+ );
1459
+ });
1460
+ });
1461
+ }
1462
+ };
1463
+ var describePlan = (plan) => {
1464
+ const lines = [];
1465
+ const rows = (bag) => Object.entries(bag).sort(([a], [b]) => a.localeCompare(b)).map(([name, v]) => ` ${name} ${v}`);
1466
+ if (Object.keys(plan.dependencies).length) {
1467
+ lines.push("dependencies:");
1468
+ lines.push(...rows(plan.dependencies));
1469
+ }
1470
+ if (Object.keys(plan.devDependencies).length) {
1471
+ if (lines.length) lines.push("");
1472
+ lines.push("devDependencies:");
1473
+ lines.push(...rows(plan.devDependencies));
1474
+ }
1475
+ if (plan.skipped.length) {
1476
+ if (lines.length) lines.push("");
1477
+ lines.push("already declared (kept as-is):");
1478
+ lines.push(...plan.skipped.map((s) => ` ${s.name}`));
1479
+ }
1480
+ if (!lines.length) lines.push("nothing to install - all deps already declared.");
1481
+ return lines.join("\n");
1482
+ };
1483
+
1484
+ // src/commands/init.ts
1485
+ var resolveConflictMode = (opts) => {
1486
+ if (opts.dryRun) return "dry-run";
1487
+ if (opts.force) return "force";
1488
+ return "prompt";
1489
+ };
1490
+ var resolveEffectivePlacement = (template, preference, project) => {
1491
+ const hostPath = getInlineHostPath(template, project);
1492
+ if (template === "next") {
1493
+ return {
1494
+ preference,
1495
+ effective: "file",
1496
+ hostPath: null,
1497
+ fallbackReason: preference === "file" ? void 0 : "Next.js uses a standalone postcss.config.js in this CLI."
1498
+ };
1499
+ }
1500
+ if (preference === "auto") {
1501
+ return { preference, effective: "file", hostPath };
1502
+ }
1503
+ if (preference === "inline" && !hostPath) {
1504
+ return {
1505
+ preference,
1506
+ effective: "file",
1507
+ hostPath,
1508
+ fallbackReason: "No inline config host was detected for this template; using standalone PostCSS config."
1509
+ };
1510
+ }
1511
+ return { preference, effective: preference, hostPath };
1512
+ };
1513
+ var promptForConfig = async (opts, project, registry) => {
1514
+ const suggestedTemplate = suggestTemplate(project);
1515
+ const template = opts.template ? opts.template : opts.yes ? suggestedTemplate ?? "vite-react" : await select2({
1516
+ message: "Which framework are you scaffolding for?",
1517
+ options: SUPPORTED_TEMPLATES.map((t) => ({
1518
+ value: t,
1519
+ label: getFrameworkLabel(t) + (t === suggestedTemplate ? pc4.dim(" (detected)") : "")
1520
+ })),
1521
+ initialValue: suggestedTemplate ?? "vite-react"
1522
+ });
1523
+ const colorOptions = registry.themes.colors.map((t) => ({
1524
+ value: t.id,
1525
+ label: t.label,
1526
+ hint: t.description
1527
+ }));
1528
+ const color = opts.color ? opts.color : opts.yes ? "default" : await select2({
1529
+ message: "Pick a color palette",
1530
+ options: colorOptions,
1531
+ initialValue: "default"
1532
+ });
1533
+ const radiusOptions = registry.themes.radii.map((t) => ({
1534
+ value: t.id,
1535
+ label: t.label,
1536
+ hint: t.description
1537
+ }));
1538
+ const radius = opts.radius ? opts.radius : opts.yes ? "default" : await select2({
1539
+ message: "Pick a radius scale",
1540
+ options: radiusOptions,
1541
+ initialValue: "default"
1542
+ });
1543
+ const spacingOptions = registry.themes.spacing.map((t) => ({
1544
+ value: t.id,
1545
+ label: t.label,
1546
+ hint: t.description
1547
+ }));
1548
+ const spacing = opts.spacing ? opts.spacing : opts.yes ? "default" : await select2({
1549
+ message: "Pick a spacing scale",
1550
+ options: spacingOptions,
1551
+ initialValue: "default"
1552
+ });
1553
+ let pretty = opts.prettyCssModules ?? false;
1554
+ if (!opts.yes && supportsPrettyCssModules(template) && opts.prettyCssModules === void 0) {
1555
+ pretty = await confirm2({
1556
+ message: "Use human-readable CSS Modules class names? (great in devtools)",
1557
+ initialValue: true
1558
+ });
1559
+ }
1560
+ let utilities = opts.withUtilities ?? false;
1561
+ if (!opts.yes && opts.withUtilities === void 0) {
1562
+ utilities = await confirm2({
1563
+ message: "Include postcss-token-utilities? (adds token-driven utility classes like p-4, bg-primary)",
1564
+ initialValue: false
1565
+ });
1566
+ }
1567
+ let placement = opts.cssConfigPlacement ?? "auto";
1568
+ if (!opts.yes && opts.cssConfigPlacement === void 0 && template !== "next") {
1569
+ const hostPath = getInlineHostPath(template, project);
1570
+ const hostLabel = hostPath ? relative4(opts.cwd, hostPath) || hostPath : "none detected";
1571
+ placement = await select2({
1572
+ message: "How should CSS plugins be wired?",
1573
+ options: CSS_CONFIG_PLACEMENTS.map((p3) => ({
1574
+ value: p3,
1575
+ label: p3,
1576
+ hint: p3 === "auto" ? "recommended: standalone postcss.config.*" : p3 === "inline" ? `inject into ${hostLabel}` : "write a standalone postcss.config.*"
1577
+ })),
1578
+ initialValue: "auto"
1579
+ });
1580
+ }
1581
+ return makeDefaultConfig({
1582
+ template,
1583
+ srcDir: opts.srcDir,
1584
+ alias: opts.alias,
1585
+ color,
1586
+ radius,
1587
+ spacing,
1588
+ pretty,
1589
+ utilities,
1590
+ cssConfigPlacement: placement
1591
+ });
1592
+ };
1593
+ var resolveConfig = async (opts, project, registry) => {
1594
+ if (configExists(opts.cwd) && !opts.overwriteConfig) {
1595
+ const cfg2 = loadConfig(opts.cwd);
1596
+ if (opts.srcDir) cfg2.srcDir = opts.srcDir;
1597
+ if (opts.alias) cfg2.alias = opts.alias;
1598
+ if (opts.color) cfg2.theme.color = opts.color;
1599
+ if (opts.radius) cfg2.theme.radius = opts.radius;
1600
+ if (opts.spacing) cfg2.theme.spacing = opts.spacing;
1601
+ if (opts.prettyCssModules !== void 0) cfg2.cssModules.pretty = opts.prettyCssModules;
1602
+ if (opts.withUtilities !== void 0) cfg2.utilities.enabled = opts.withUtilities;
1603
+ if (opts.cssConfigPlacement !== void 0) cfg2.cssConfig.placement = opts.cssConfigPlacement;
1604
+ return { cfg: cfg2, existed: true };
1605
+ }
1606
+ const cfg = await promptForConfig(opts, project, registry);
1607
+ return { cfg, existed: false };
1608
+ };
1609
+ var pickInitialComponents = async (opts, registry) => {
1610
+ if (opts.all) return registry.units.map((u) => u.name);
1611
+ if (opts.components && opts.components.length > 0) return opts.components;
1612
+ if (opts.yes) return [];
1613
+ const addNow = await confirm2({
1614
+ message: "Copy components/hooks into your project now?",
1615
+ initialValue: false
1616
+ });
1617
+ if (!addNow) return [];
1618
+ return multiselect2({
1619
+ message: `Select units to copy ${pc4.dim("(space to toggle, enter to confirm - leave empty to skip)")}`,
1620
+ options: groupedUnitOptions(registry.units),
1621
+ initialValues: [],
1622
+ required: false
1623
+ });
1624
+ };
1625
+ var runInit = async (opts) => {
1626
+ headline("Scaffold tokens, theme, PostCSS, and optionally copy components.");
1627
+ const registry = loadRegistry();
1628
+ const project = detectProject(opts.cwd);
1629
+ const { cfg, existed } = await resolveConfig(opts, project, registry);
1630
+ const placement = resolveEffectivePlacement(
1631
+ cfg.template,
1632
+ cfg.cssConfig.placement,
1633
+ project
1634
+ );
1635
+ const paths = resolvePaths(opts.cwd, cfg);
1636
+ const detected = project.isVite || project.isNext || project.isAstro || project.isTanstackStart || project.isElectronVite;
1637
+ const summary = [
1638
+ `${pc4.bold("framework")} ${cfg.template}`,
1639
+ `${pc4.bold("color")} ${cfg.theme.color}`,
1640
+ `${pc4.bold("radius")} ${cfg.theme.radius}`,
1641
+ `${pc4.bold("spacing")} ${cfg.theme.spacing}`,
1642
+ `${pc4.bold("srcDir")} ${cfg.srcDir}`,
1643
+ `${pc4.bold("alias")} ${cfg.alias}`,
1644
+ `${pc4.bold("css")} ${placement.preference} \u2192 ${placement.effective}`,
1645
+ detected ? `${pc4.bold("detected")} ${describeProject(project)}` : ""
1646
+ ].filter(Boolean).join("\n");
1647
+ note2(summary, "configuration");
1648
+ if (placement.fallbackReason) warn(placement.fallbackReason);
1649
+ const componentNames = await pickInitialComponents(opts, registry);
1650
+ const units = componentNames.length ? resolveUnits(registry, componentNames) : [];
1651
+ const ops = [];
1652
+ const snippetsToPrint = [];
1653
+ if (!existed || opts.overwriteConfig) {
1654
+ ops.push({
1655
+ target: join9(opts.cwd, "components.json"),
1656
+ content: JSON.stringify(cfg, null, 2) + "\n",
1657
+ label: "components.json"
1658
+ });
1659
+ }
1660
+ if (!opts.skipStyles) {
1661
+ ops.push(
1662
+ ...planStylesOps({
1663
+ registry,
1664
+ targetStylesDir: paths.stylesDir,
1665
+ color: cfg.theme.color,
1666
+ radius: cfg.theme.radius,
1667
+ spacing: cfg.theme.spacing
1668
+ })
1669
+ );
1670
+ }
1671
+ if (cfg.utilities.enabled) {
1672
+ ops.push(planUtilitiesGitignoreOp({ targetStylesDir: paths.stylesDir }));
1673
+ }
1674
+ if (!opts.skipCssConfig) {
1675
+ const css = planCssConfigOps({ cwd: opts.cwd, cfg, placement, project });
1676
+ ops.push(...css.ops);
1677
+ snippetsToPrint.push(...css.snippets);
1678
+ for (const w of css.warnings) warn(w);
1679
+ }
1680
+ if (units.length > 0) {
1681
+ ops.push(
1682
+ ...planComponentOps({
1683
+ registry,
1684
+ targetSrcDir: paths.srcDir,
1685
+ units,
1686
+ paths: cfg.paths
1687
+ })
1688
+ );
1689
+ info(`planned ${units.length} unit${units.length === 1 ? "" : "s"} to copy`);
1690
+ }
1691
+ step("Writing files\u2026");
1692
+ const result = await applyFileOps(ops, {
1693
+ cwd: opts.cwd,
1694
+ mode: resolveConflictMode(opts)
1695
+ });
1696
+ const summaryLine = `${result.written} written \xB7 ${result.skipped} skipped \xB7 ${result.unchanged} unchanged`;
1697
+ const plan = computeDependencyPlan({ registry, units, cfg, project });
1698
+ const pm = opts.packageManager ?? detectPackageManager(opts.cwd);
1699
+ const installCommands = buildInstallCommands(pm, plan);
1700
+ const hasWork = installCommands.length > 0;
1701
+ if (opts.dryRun) {
1702
+ note2(summaryLine, "dry run");
1703
+ if (hasWork) {
1704
+ note2(
1705
+ [
1706
+ describePlan(plan),
1707
+ "",
1708
+ `would run with ${pm}:`,
1709
+ ...installCommands.map((c) => ` ${c.label}`)
1710
+ ].join("\n"),
1711
+ "dry run \xB7 install"
1712
+ );
1713
+ }
1714
+ goodbye("Preview only - no files were touched.");
1715
+ return;
1716
+ }
1717
+ let willInstall;
1718
+ if (!hasWork) {
1719
+ willInstall = false;
1720
+ } else if (opts.install === false) {
1721
+ willInstall = false;
1722
+ } else if (opts.install === true || opts.yes) {
1723
+ willInstall = true;
1724
+ } else {
1725
+ note2(describePlan(plan), `install with ${pm}`);
1726
+ willInstall = await confirm2({
1727
+ message: `Run ${pm} now to install the dependencies above?`,
1728
+ initialValue: true
1729
+ });
1730
+ }
1731
+ if (willInstall) {
1732
+ step(`Installing dependencies with ${pm}\u2026`);
1733
+ await runInstall(installCommands, {
1734
+ cwd: opts.cwd,
1735
+ onCommand: (cmd) => logger.action(`$ ${cmd.label}`)
1736
+ });
1737
+ logger.ok(
1738
+ `installed ${Object.keys(plan.dependencies).length} runtime + ${Object.keys(plan.devDependencies).length} dev dependenc${Object.keys(plan.dependencies).length + Object.keys(plan.devDependencies).length === 1 ? "y" : "ies"}`
1739
+ );
1740
+ } else if (hasWork) {
1741
+ note2(
1742
+ [
1743
+ describePlan(plan),
1744
+ "",
1745
+ "run:",
1746
+ ...installCommands.map((c) => ` ${c.label}`)
1747
+ ].join("\n"),
1748
+ `manual install (skipped)`
1749
+ );
1750
+ }
1751
+ const steps = [
1752
+ `${pc4.cyan("1")} ${pc4.bold("Import styles once at your app entry")}
1753
+ import "./${cfg.paths.styles}/globals.css";`
1754
+ ];
1755
+ let stepIdx = 2;
1756
+ for (const snippet of snippetsToPrint) {
1757
+ steps.push(`${pc4.cyan(String(stepIdx++))} ${pc4.bold(snippet.title)}
1758
+ ${snippet.content.split("\n").map((l) => " " + l).join("\n")}`);
1759
+ }
1760
+ steps.push(
1761
+ `${pc4.cyan(String(stepIdx++))} ${pc4.bold("Add more components anytime")}
1762
+ npx aplance-ui add <name> ${pc4.dim("# e.g. button modal tooltip")}
1763
+ npx aplance-ui add ${pc4.dim("# interactive multi-select")}
1764
+ npx aplance-ui list ${pc4.dim("# see everything available")}`
1765
+ );
1766
+ note2(steps.join("\n\n"), "next steps");
1767
+ logger.info(summaryLine);
1768
+ goodbye("All set.");
1769
+ };
1770
+
1771
+ // src/commands/add.ts
1772
+ import pc5 from "picocolors";
1773
+ var resolveConflictMode2 = (opts) => {
1774
+ if (opts.dryRun) return "dry-run";
1775
+ if (opts.force) return "force";
1776
+ return "prompt";
1777
+ };
1778
+ var runAdd = async (opts) => {
1779
+ headline("Add components/hooks/utilities from the registry.");
1780
+ const cfg = loadConfig(opts.cwd);
1781
+ const paths = resolvePaths(opts.cwd, cfg);
1782
+ const registry = loadRegistry();
1783
+ let names = opts.names;
1784
+ if (opts.all) names = registry.units.map((u) => u.name);
1785
+ if (names.length === 0) {
1786
+ if (opts.yes) {
1787
+ goodbye("Nothing to add. Pass unit names, --all, or run without --yes for interactive mode.");
1788
+ return;
1789
+ }
1790
+ names = await pickUnits(registry.units);
1791
+ if (names.length === 0) {
1792
+ goodbye("Nothing selected.");
1793
+ return;
1794
+ }
1795
+ }
1796
+ const units = resolveUnits(registry, names);
1797
+ const depsAdded = units.filter((u) => !names.includes(u.name));
1798
+ if (depsAdded.length > 0) {
1799
+ note2(
1800
+ depsAdded.map((u) => `${pc5.dim("+")} ${u.name} ${pc5.dim("(dep)")}`).join("\n"),
1801
+ `transitive dependencies (${depsAdded.length})`
1802
+ );
1803
+ }
1804
+ const ops = planComponentOps({
1805
+ registry,
1806
+ targetSrcDir: paths.srcDir,
1807
+ units,
1808
+ paths: cfg.paths
1809
+ });
1810
+ if (cfg.utilities.enabled) {
1811
+ ops.push(planUtilitiesGitignoreOp({ targetStylesDir: paths.stylesDir }));
1812
+ }
1813
+ step(`Writing ${units.length} unit${units.length === 1 ? "" : "s"} (${ops.length} file${ops.length === 1 ? "" : "s"})\u2026`);
1814
+ const result = await applyFileOps(ops, {
1815
+ cwd: opts.cwd,
1816
+ mode: resolveConflictMode2(opts)
1817
+ });
1818
+ const summary = `${result.written} written \xB7 ${result.skipped} skipped \xB7 ${result.unchanged} unchanged`;
1819
+ const project = detectProject(opts.cwd);
1820
+ const plan = computeRuntimePlan(registry, units, project);
1821
+ const pm = opts.packageManager ?? detectPackageManager(opts.cwd);
1822
+ const installCommands = buildInstallCommands(pm, plan);
1823
+ const hasWork = installCommands.length > 0;
1824
+ if (opts.dryRun) {
1825
+ note2(summary, "dry run");
1826
+ if (hasWork) {
1827
+ note2(
1828
+ [
1829
+ describePlan(plan),
1830
+ "",
1831
+ `would run with ${pm}:`,
1832
+ ...installCommands.map((c) => ` ${c.label}`)
1833
+ ].join("\n"),
1834
+ "dry run \xB7 install"
1835
+ );
1836
+ }
1837
+ goodbye("Preview only - no files were touched.");
1838
+ return;
1839
+ }
1840
+ let willInstall;
1841
+ if (!hasWork) {
1842
+ willInstall = false;
1843
+ } else if (opts.install === false) {
1844
+ willInstall = false;
1845
+ } else if (opts.install === true || opts.yes) {
1846
+ willInstall = true;
1847
+ } else {
1848
+ note2(describePlan(plan), `install with ${pm}`);
1849
+ willInstall = await confirm2({
1850
+ message: `Run ${pm} now to install the dependencies above?`,
1851
+ initialValue: true
1852
+ });
1853
+ }
1854
+ if (willInstall) {
1855
+ step(`Installing dependencies with ${pm}\u2026`);
1856
+ await runInstall(installCommands, {
1857
+ cwd: opts.cwd,
1858
+ onCommand: (cmd) => logger.action(`$ ${cmd.label}`)
1859
+ });
1860
+ } else if (hasWork) {
1861
+ note2(
1862
+ [
1863
+ describePlan(plan),
1864
+ "",
1865
+ "run:",
1866
+ ...installCommands.map((c) => ` ${c.label}`)
1867
+ ].join("\n"),
1868
+ "manual install (skipped)"
1869
+ );
1870
+ }
1871
+ logger.info(summary);
1872
+ goodbye(`Added ${units.length} unit${units.length === 1 ? "" : "s"}.`);
1873
+ };
1874
+ var computeRuntimePlan = (registry, units, project) => {
1875
+ const dependencies = {};
1876
+ const meta = registry.installMeta;
1877
+ for (const unit of units) {
1878
+ for (const pkg of unit.externalDeps) {
1879
+ const version = meta.packageVersions[pkg];
1880
+ if (!version) continue;
1881
+ if (project.declaredDeps.has(pkg)) continue;
1882
+ dependencies[pkg] = version;
1883
+ }
1884
+ }
1885
+ return { dependencies, devDependencies: {}, skipped: [] };
1886
+ };
1887
+ var pickUnits = async (all) => multiselect2({
1888
+ message: `Select units to add ${pc5.dim("(space to toggle, enter to confirm)")}`,
1889
+ options: groupedUnitOptions(all),
1890
+ required: false
1891
+ });
1892
+
1893
+ // src/commands/list.ts
1894
+ import pc6 from "picocolors";
1895
+ var runList = (opts) => {
1896
+ const registry = loadRegistry();
1897
+ if (opts.json) {
1898
+ process.stdout.write(JSON.stringify(registry, null, 2) + "\n");
1899
+ return;
1900
+ }
1901
+ const colorCount = registry.themes.colors.length;
1902
+ const radiusCount = registry.themes.radii.length;
1903
+ const spacingCount = registry.themes.spacing.length;
1904
+ headline(
1905
+ `${registry.units.length} units \xB7 ${colorCount} colors \xB7 ${radiusCount} radii \xB7 ${spacingCount} spacing`
1906
+ );
1907
+ const ui = registry.units.filter((u) => u.kind === "component" && u.group === "ui");
1908
+ const primitives = registry.units.filter((u) => u.kind === "component" && u.group === "primitives");
1909
+ const hooks = registry.units.filter((u) => u.kind === "hook");
1910
+ const libs = registry.units.filter((u) => u.kind === "lib");
1911
+ const renderBucket = (title, units) => {
1912
+ if (units.length === 0) return null;
1913
+ const body = units.map((u) => {
1914
+ const deps = u.deps.length ? pc6.dim(` deps: ${u.deps.join(", ")}`) : "";
1915
+ return ` ${pc6.cyan(u.name.padEnd(22))}${deps}`;
1916
+ }).join("\n");
1917
+ return `${pc6.bold(title)} ${pc6.dim(`(${units.length})`)}
1918
+ ${body}`;
1919
+ };
1920
+ const blocks = [
1921
+ renderBucket("UI components", ui),
1922
+ renderBucket("Primitives", primitives),
1923
+ renderBucket("Hooks", hooks),
1924
+ renderBucket("Utilities", libs)
1925
+ ].filter(Boolean);
1926
+ note2(blocks.join("\n\n"), "registry");
1927
+ const renderVariants = (title, variants) => {
1928
+ if (variants.length === 0) return;
1929
+ const body = variants.map((t) => ` ${pc6.cyan(t.id.padEnd(12))}${pc6.dim(t.description)}`).join("\n");
1930
+ note2(body, title);
1931
+ };
1932
+ renderVariants("colors", registry.themes.colors);
1933
+ renderVariants("radii", registry.themes.radii);
1934
+ renderVariants("spacing", registry.themes.spacing);
1935
+ goodbye(`Use ${pc6.cyan("aplance-ui add <name>")} to install anything above.`);
1936
+ };
1937
+ export {
1938
+ CSS_CONFIG_PLACEMENTS,
1939
+ SUPPORTED_TEMPLATES,
1940
+ allUnitsInOrder,
1941
+ configExists,
1942
+ findColor,
1943
+ findRadius,
1944
+ findSpacing,
1945
+ loadConfig,
1946
+ loadRegistry,
1947
+ makeDefaultConfig,
1948
+ resolvePaths,
1949
+ resolveUnits,
1950
+ runAdd,
1951
+ runInit,
1952
+ runList
1953
+ };
1954
+ //# sourceMappingURL=api.js.map