arekui 1.0.0 → 1.0.2

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 (54) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +198 -198
  3. package/arekui.css +3279 -3279
  4. package/arekui.d.ts +328 -328
  5. package/arekui.js +450 -450
  6. package/package.json +59 -57
  7. package/scripts/build-custom.js +318 -318
  8. package/src/arekui.css +55 -55
  9. package/src/base/neo-overrides.css +317 -317
  10. package/src/base/reset.css +67 -67
  11. package/src/base/tokens.css +304 -304
  12. package/src/components/accordion.css +34 -34
  13. package/src/components/alert.css +26 -26
  14. package/src/components/badge.css +33 -33
  15. package/src/components/breadcrumb.css +33 -33
  16. package/src/components/button.css +103 -103
  17. package/src/components/card.css +24 -24
  18. package/src/components/carousel.css +14 -14
  19. package/src/components/chat.css +78 -78
  20. package/src/components/drawer.css +53 -53
  21. package/src/components/file-upload.css +51 -51
  22. package/src/components/footer.css +26 -26
  23. package/src/components/forms.css +69 -69
  24. package/src/components/hero.css +22 -22
  25. package/src/components/join.css +14 -14
  26. package/src/components/link.css +24 -24
  27. package/src/components/menu.css +56 -56
  28. package/src/components/misc.css +57 -57
  29. package/src/components/modal.css +32 -32
  30. package/src/components/navbar.css +37 -37
  31. package/src/components/pagination.css +46 -46
  32. package/src/components/popover.css +70 -70
  33. package/src/components/progress.css +19 -19
  34. package/src/components/prose.css +80 -80
  35. package/src/components/rating.css +37 -37
  36. package/src/components/scroll-top.css +36 -36
  37. package/src/components/skeleton.css +54 -54
  38. package/src/components/swap.css +45 -45
  39. package/src/components/table.css +22 -22
  40. package/src/components/tabs.css +24 -24
  41. package/src/components/tag.css +101 -101
  42. package/src/components/textured.css +34 -34
  43. package/src/components/timeline.css +34 -34
  44. package/src/components/toast.css +134 -134
  45. package/src/components/tooltip.css +24 -24
  46. package/src/utilities/borders.css +152 -152
  47. package/src/utilities/colors.css +73 -73
  48. package/src/utilities/hover.css +33 -33
  49. package/src/utilities/layout.css +100 -100
  50. package/src/utilities/neo-utilities.css +95 -95
  51. package/src/utilities/responsive.css +128 -128
  52. package/src/utilities/sizing.css +91 -91
  53. package/src/utilities/spacing.css +130 -130
  54. package/src/utilities/typography.css +94 -94
@@ -1,318 +1,318 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Arekui Build — scans your source and outputs only what you use.
5
- *
6
- * Usage:
7
- * npx arekui-build # reads arekui.config.js
8
- * npx arekui-build -i ./src -o ./assets # overrides with flags
9
- * npx arekui-build --sourcemap
10
- * npx arekui-build --full # include everything
11
- *
12
- * Config file (arekui.config.js or arekui.config.json):
13
- * module.exports = {
14
- * input: "./src", // directory to scan
15
- * output: "./assets", // output directory
16
- * name: "arekui", // output filename (without .min.css)
17
- * sourcemap: false,
18
- * full: false, // true = ignore scan, include all
19
- * };
20
- *
21
- * CLI flags override config file values.
22
- */
23
-
24
- const fs = require("fs");
25
- const path = require("path");
26
- const { bundle } = require("lightningcss");
27
-
28
- // ── Load config file ───────────────────────────────────────────────────────
29
- function loadConfig() {
30
- const candidates = ["arekui.config.js", "arekui.config.json"];
31
- for (const file of candidates) {
32
- const full = path.resolve(file);
33
- if (fs.existsSync(full)) {
34
- try {
35
- console.log(`\x1b[90m config: ${file}\x1b[0m`);
36
- return file.endsWith(".json")
37
- ? JSON.parse(fs.readFileSync(full, "utf-8"))
38
- : require(full);
39
- } catch (e) {
40
- console.error(`\x1b[31m✗\x1b[0m Failed to load ${file}: ${e.message}`);
41
- process.exit(1);
42
- }
43
- }
44
- }
45
- return {};
46
- }
47
-
48
- // ── CLI args (override config) ─────────────────────────────────────────────
49
- function getArg(flags) {
50
- const idx = process.argv.findIndex((a) => flags.includes(a));
51
- return idx === -1 ? null : process.argv[idx + 1];
52
- }
53
-
54
- const config = loadConfig();
55
-
56
- const input = getArg(["-i", "--input"]) || config.input || ".";
57
- const output = getArg(["-o", "--output"]) || config.output || "assets";
58
- const name = getArg(["-n", "--name"]) || config.name || "arekui";
59
- const sourcemap =
60
- process.argv.includes("--sourcemap") || config.sourcemap === true;
61
- const full = process.argv.includes("--full") || config.full === true;
62
-
63
- const srcDir = path.resolve(input);
64
- const outDir = path.resolve(output);
65
-
66
- // ── Component → CSS class mapping ──────────────────────────────────────────
67
- const COMPONENT_CLASSES = {
68
- accordion: ["ar-accordion", "ar-collapse"],
69
- alert: ["ar-alert"],
70
- badge: ["ar-badge"],
71
- breadcrumb: ["ar-breadcrumb"],
72
- button: ["ar-btn"],
73
- card: ["ar-card", "ar-card-body", "ar-card-title", "ar-card-figure"],
74
- carousel: ["ar-carousel", "ar-carousel-item"],
75
- chat: ["ar-chat", "ar-chat-bubble"],
76
- drawer: ["ar-drawer"],
77
- "file-upload": ["ar-file-upload"],
78
- footer: ["ar-footer"],
79
- forms: [
80
- "ar-input",
81
- "ar-textarea",
82
- "ar-select",
83
- "ar-checkbox",
84
- "ar-radio",
85
- "ar-toggle",
86
- "ar-range",
87
- "ar-label",
88
- "ar-fieldset",
89
- ],
90
- hero: ["ar-hero"],
91
- join: ["ar-join"],
92
- link: ["ar-link"],
93
- menu: ["ar-menu", "ar-dropdown"],
94
- misc: ["ar-divider", "ar-stepper", "ar-step", "ar-avatar"],
95
- modal: ["ar-modal"],
96
- navbar: ["ar-navbar"],
97
- pagination: ["ar-pagination"],
98
- popover: ["ar-popover"],
99
- progress: ["ar-progress"],
100
- prose: ["ar-prose"],
101
- rating: ["ar-rating"],
102
- "scroll-top": ["ar-scroll-top"],
103
- skeleton: ["ar-skeleton"],
104
- swap: ["ar-swap"],
105
- table: ["ar-table"],
106
- tabs: ["ar-tabs", "ar-tab"],
107
- tag: ["ar-tag"],
108
- textured: ["ar-bg-img"],
109
- timeline: ["ar-timeline"],
110
- toast: ["ar-toast"],
111
- tooltip: ["ar-tooltip"],
112
- };
113
-
114
- const UTILITY_PATTERNS = {
115
- spacing: [
116
- /^ar-p/,
117
- /^ar-px/,
118
- /^ar-py/,
119
- /^ar-m/,
120
- /^ar-mt/,
121
- /^ar-mb/,
122
- /^ar-my/,
123
- /^ar-mx/,
124
- /^ar-gap/,
125
- ],
126
- layout: [
127
- /^ar-flex/,
128
- /^ar-inline-flex/,
129
- /^ar-flex-col/,
130
- /^ar-flex-wrap/,
131
- /^ar-items-/,
132
- /^ar-justify-/,
133
- /^ar-grid/,
134
- /^ar-block/,
135
- /^ar-hidden/,
136
- ],
137
- typography: [/^ar-text-/, /^ar-font-/, /^ar-leading-/, /^ar-tracking-/],
138
- sizing: [
139
- /^ar-w-/,
140
- /^ar-h-/,
141
- /^ar-min-h-/,
142
- /^ar-max-w-/,
143
- /^ar-aspect-video/,
144
- /^ar-object-cover/,
145
- ],
146
- colors: [
147
- /^ar-bg-base/,
148
- /^ar-bg-neutral/,
149
- /^ar-bg-primary/,
150
- /^ar-bg-secondary/,
151
- /^ar-bg-accent/,
152
- /^ar-text-base/,
153
- /^ar-text-gray/,
154
- ],
155
- borders: [/^ar-border/, /^ar-rounded/, /^ar-shadow-/],
156
- hover: [/^ar-hover-/],
157
- responsive: [/^ar-md:/, /^ar-lg:/],
158
- "neo-utilities": [/^ar-neo-/],
159
- };
160
-
161
- // ── Scan source files ──────────────────────────────────────────────────────
162
- function findSourceFiles(dir) {
163
- const exts = [".html", ".jsx", ".vue", ".svelte", ".tsx", ".ts", ".js"];
164
- const files = [];
165
-
166
- function walk(d) {
167
- for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
168
- const full = path.join(d, entry.name);
169
- if (
170
- entry.isDirectory() &&
171
- !entry.name.startsWith(".") &&
172
- entry.name !== "node_modules"
173
- ) {
174
- walk(full);
175
- } else if (entry.isFile() && exts.includes(path.extname(entry.name))) {
176
- files.push(full);
177
- }
178
- }
179
- }
180
- walk(dir);
181
- return files;
182
- }
183
-
184
- function scan(dir) {
185
- const files = findSourceFiles(dir);
186
- const content = files.map((f) => fs.readFileSync(f, "utf-8")).join("\n");
187
- const tokens = new Set();
188
- let m;
189
- const re = /ar-[\w-]+/g;
190
- while ((m = re.exec(content)) !== null) tokens.add(m[0]);
191
- return tokens;
192
- }
193
-
194
- function detectComponents(classes) {
195
- const found = new Set();
196
- for (const [comp, patterns] of Object.entries(COMPONENT_CLASSES)) {
197
- for (const cls of classes) {
198
- if (patterns.some((p) => cls === p || cls.startsWith(p + "-"))) {
199
- found.add(comp);
200
- break;
201
- }
202
- }
203
- }
204
- return [...found];
205
- }
206
-
207
- function detectUtilities(classes) {
208
- const found = new Set();
209
- for (const [util, regexes] of Object.entries(UTILITY_PATTERNS)) {
210
- for (const cls of classes) {
211
- if (regexes.some((r) => r.test(cls))) {
212
- found.add(util);
213
- break;
214
- }
215
- }
216
- }
217
- return [...found];
218
- }
219
-
220
- // ── Build CSS ──────────────────────────────────────────────────────────────
221
- const COMPONENT_FILES = {
222
- accordion: "accordion",
223
- alert: "alert",
224
- badge: "badge",
225
- breadcrumb: "breadcrumb",
226
- button: "button",
227
- card: "card",
228
- carousel: "carousel",
229
- chat: "chat",
230
- drawer: "drawer",
231
- "file-upload": "file-upload",
232
- footer: "footer",
233
- forms: "forms",
234
- hero: "hero",
235
- join: "join",
236
- link: "link",
237
- menu: "menu",
238
- misc: "misc",
239
- modal: "modal",
240
- navbar: "navbar",
241
- pagination: "pagination",
242
- popover: "popover",
243
- progress: "progress",
244
- prose: "prose",
245
- rating: "rating",
246
- "scroll-top": "scroll-top",
247
- skeleton: "skeleton",
248
- swap: "swap",
249
- table: "table",
250
- tabs: "tabs",
251
- tag: "tag",
252
- textured: "textured",
253
- timeline: "timeline",
254
- toast: "toast",
255
- tooltip: "tooltip",
256
- };
257
-
258
- function buildCSS(components, utilities) {
259
- const imports = [
260
- `@import "./base/tokens.css" layer(base);`,
261
- `@import "./base/reset.css" layer(base);`,
262
- `@import "./base/neo-overrides.css" layer(base);`,
263
- ];
264
-
265
- for (const c of components) {
266
- imports.push(
267
- `@import "./components/${COMPONENT_FILES[c] || c}.css" layer(components);`,
268
- );
269
- }
270
- for (const u of utilities) {
271
- imports.push(`@import "./utilities/${u}.css" layer(utilities);`);
272
- }
273
-
274
- return `@layer base, components, utilities;\n\n${imports.join("\n")}\n`;
275
- }
276
-
277
- // ── Main ───────────────────────────────────────────────────────────────────
278
- const orchestrator = path.join(__dirname, "..", "src", "arekui.css");
279
- const tmpFile = path.join(path.dirname(orchestrator), "__build.css");
280
-
281
- try {
282
- let components, utilities;
283
-
284
- if (full) {
285
- components = Object.keys(COMPONENT_FILES);
286
- utilities = Object.keys(UTILITY_PATTERNS);
287
- console.log(`\x1b[36m📦\x1b[0m Including all components`);
288
- } else {
289
- console.log(`\x1b[36m⏳\x1b[0m Scanning ${srcDir}...`);
290
- const classes = scan(srcDir);
291
- components = detectComponents(classes);
292
- utilities = detectUtilities(classes);
293
- console.log(` Found ${classes.size} ar-* tokens`);
294
- console.log(` Components: ${components.join(", ") || "(none)"}`);
295
- console.log(` Utilities: ${utilities.join(", ") || "(none)"}`);
296
- }
297
-
298
- fs.writeFileSync(tmpFile, buildCSS(components, utilities), "utf-8");
299
- fs.mkdirSync(outDir, { recursive: true });
300
-
301
- const result = bundle({
302
- filename: tmpFile,
303
- minify: true,
304
- sourceMap: sourcemap,
305
- });
306
-
307
- const outFile = path.join(outDir, `${name}.min.css`);
308
- fs.writeFileSync(outFile, result.code);
309
- if (sourcemap && result.map) fs.writeFileSync(outFile + ".map", result.map);
310
-
311
- console.log(`\n\x1b[32m✓\x1b[0m Built → ${outFile}`);
312
- console.log(
313
- ` ${components.length} components, ${utilities.length} utilities`,
314
- );
315
- console.log(` ${(result.code.length / 1024).toFixed(1)}KB`);
316
- } finally {
317
- if (fs.existsSync(tmpFile)) fs.unlinkSync(tmpFile);
318
- }
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Arekui Build — scans your source and outputs only what you use.
5
+ *
6
+ * Usage:
7
+ * npx arekui-build # reads arekui.config.js
8
+ * npx arekui-build -i ./src -o ./assets # overrides with flags
9
+ * npx arekui-build --sourcemap
10
+ * npx arekui-build --full # include everything
11
+ *
12
+ * Config file (arekui.config.js or arekui.config.json):
13
+ * module.exports = {
14
+ * input: "./src", // directory to scan
15
+ * output: "./assets", // output directory
16
+ * name: "arekui", // output filename (without .min.css)
17
+ * sourcemap: false,
18
+ * full: false, // true = ignore scan, include all
19
+ * };
20
+ *
21
+ * CLI flags override config file values.
22
+ */
23
+
24
+ const fs = require("fs");
25
+ const path = require("path");
26
+ const { bundle } = require("lightningcss");
27
+
28
+ // ── Load config file ───────────────────────────────────────────────────────
29
+ function loadConfig() {
30
+ const candidates = ["arekui.config.js", "arekui.config.json"];
31
+ for (const file of candidates) {
32
+ const full = path.resolve(file);
33
+ if (fs.existsSync(full)) {
34
+ try {
35
+ console.log(`\x1b[90m config: ${file}\x1b[0m`);
36
+ return file.endsWith(".json")
37
+ ? JSON.parse(fs.readFileSync(full, "utf-8"))
38
+ : require(full);
39
+ } catch (e) {
40
+ console.error(`\x1b[31m✗\x1b[0m Failed to load ${file}: ${e.message}`);
41
+ process.exit(1);
42
+ }
43
+ }
44
+ }
45
+ return {};
46
+ }
47
+
48
+ // ── CLI args (override config) ─────────────────────────────────────────────
49
+ function getArg(flags) {
50
+ const idx = process.argv.findIndex((a) => flags.includes(a));
51
+ return idx === -1 ? null : process.argv[idx + 1];
52
+ }
53
+
54
+ const config = loadConfig();
55
+
56
+ const input = getArg(["-i", "--input"]) || config.input || ".";
57
+ const output = getArg(["-o", "--output"]) || config.output || "assets";
58
+ const name = getArg(["-n", "--name"]) || config.name || "arekui";
59
+ const sourcemap =
60
+ process.argv.includes("--sourcemap") || config.sourcemap === true;
61
+ const full = process.argv.includes("--full") || config.full === true;
62
+
63
+ const srcDir = path.resolve(input);
64
+ const outDir = path.resolve(output);
65
+
66
+ // ── Component → CSS class mapping ──────────────────────────────────────────
67
+ const COMPONENT_CLASSES = {
68
+ accordion: ["ar-accordion", "ar-collapse"],
69
+ alert: ["ar-alert"],
70
+ badge: ["ar-badge"],
71
+ breadcrumb: ["ar-breadcrumb"],
72
+ button: ["ar-btn"],
73
+ card: ["ar-card", "ar-card-body", "ar-card-title", "ar-card-figure"],
74
+ carousel: ["ar-carousel", "ar-carousel-item"],
75
+ chat: ["ar-chat", "ar-chat-bubble"],
76
+ drawer: ["ar-drawer"],
77
+ "file-upload": ["ar-file-upload"],
78
+ footer: ["ar-footer"],
79
+ forms: [
80
+ "ar-input",
81
+ "ar-textarea",
82
+ "ar-select",
83
+ "ar-checkbox",
84
+ "ar-radio",
85
+ "ar-toggle",
86
+ "ar-range",
87
+ "ar-label",
88
+ "ar-fieldset",
89
+ ],
90
+ hero: ["ar-hero"],
91
+ join: ["ar-join"],
92
+ link: ["ar-link"],
93
+ menu: ["ar-menu", "ar-dropdown"],
94
+ misc: ["ar-divider", "ar-stepper", "ar-step", "ar-avatar"],
95
+ modal: ["ar-modal"],
96
+ navbar: ["ar-navbar"],
97
+ pagination: ["ar-pagination"],
98
+ popover: ["ar-popover"],
99
+ progress: ["ar-progress"],
100
+ prose: ["ar-prose"],
101
+ rating: ["ar-rating"],
102
+ "scroll-top": ["ar-scroll-top"],
103
+ skeleton: ["ar-skeleton"],
104
+ swap: ["ar-swap"],
105
+ table: ["ar-table"],
106
+ tabs: ["ar-tabs", "ar-tab"],
107
+ tag: ["ar-tag"],
108
+ textured: ["ar-bg-img"],
109
+ timeline: ["ar-timeline"],
110
+ toast: ["ar-toast"],
111
+ tooltip: ["ar-tooltip"],
112
+ };
113
+
114
+ const UTILITY_PATTERNS = {
115
+ spacing: [
116
+ /^ar-p/,
117
+ /^ar-px/,
118
+ /^ar-py/,
119
+ /^ar-m/,
120
+ /^ar-mt/,
121
+ /^ar-mb/,
122
+ /^ar-my/,
123
+ /^ar-mx/,
124
+ /^ar-gap/,
125
+ ],
126
+ layout: [
127
+ /^ar-flex/,
128
+ /^ar-inline-flex/,
129
+ /^ar-flex-col/,
130
+ /^ar-flex-wrap/,
131
+ /^ar-items-/,
132
+ /^ar-justify-/,
133
+ /^ar-grid/,
134
+ /^ar-block/,
135
+ /^ar-hidden/,
136
+ ],
137
+ typography: [/^ar-text-/, /^ar-font-/, /^ar-leading-/, /^ar-tracking-/],
138
+ sizing: [
139
+ /^ar-w-/,
140
+ /^ar-h-/,
141
+ /^ar-min-h-/,
142
+ /^ar-max-w-/,
143
+ /^ar-aspect-video/,
144
+ /^ar-object-cover/,
145
+ ],
146
+ colors: [
147
+ /^ar-bg-base/,
148
+ /^ar-bg-neutral/,
149
+ /^ar-bg-primary/,
150
+ /^ar-bg-secondary/,
151
+ /^ar-bg-accent/,
152
+ /^ar-text-base/,
153
+ /^ar-text-gray/,
154
+ ],
155
+ borders: [/^ar-border/, /^ar-rounded/, /^ar-shadow-/],
156
+ hover: [/^ar-hover-/],
157
+ responsive: [/^ar-md:/, /^ar-lg:/],
158
+ "neo-utilities": [/^ar-neo-/],
159
+ };
160
+
161
+ // ── Scan source files ──────────────────────────────────────────────────────
162
+ function findSourceFiles(dir) {
163
+ const exts = [".html", ".jsx", ".vue", ".svelte", ".tsx", ".ts", ".js"];
164
+ const files = [];
165
+
166
+ function walk(d) {
167
+ for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
168
+ const full = path.join(d, entry.name);
169
+ if (
170
+ entry.isDirectory() &&
171
+ !entry.name.startsWith(".") &&
172
+ entry.name !== "node_modules"
173
+ ) {
174
+ walk(full);
175
+ } else if (entry.isFile() && exts.includes(path.extname(entry.name))) {
176
+ files.push(full);
177
+ }
178
+ }
179
+ }
180
+ walk(dir);
181
+ return files;
182
+ }
183
+
184
+ function scan(dir) {
185
+ const files = findSourceFiles(dir);
186
+ const content = files.map((f) => fs.readFileSync(f, "utf-8")).join("\n");
187
+ const tokens = new Set();
188
+ let m;
189
+ const re = /ar-[\w-]+/g;
190
+ while ((m = re.exec(content)) !== null) tokens.add(m[0]);
191
+ return tokens;
192
+ }
193
+
194
+ function detectComponents(classes) {
195
+ const found = new Set();
196
+ for (const [comp, patterns] of Object.entries(COMPONENT_CLASSES)) {
197
+ for (const cls of classes) {
198
+ if (patterns.some((p) => cls === p || cls.startsWith(p + "-"))) {
199
+ found.add(comp);
200
+ break;
201
+ }
202
+ }
203
+ }
204
+ return [...found];
205
+ }
206
+
207
+ function detectUtilities(classes) {
208
+ const found = new Set();
209
+ for (const [util, regexes] of Object.entries(UTILITY_PATTERNS)) {
210
+ for (const cls of classes) {
211
+ if (regexes.some((r) => r.test(cls))) {
212
+ found.add(util);
213
+ break;
214
+ }
215
+ }
216
+ }
217
+ return [...found];
218
+ }
219
+
220
+ // ── Build CSS ──────────────────────────────────────────────────────────────
221
+ const COMPONENT_FILES = {
222
+ accordion: "accordion",
223
+ alert: "alert",
224
+ badge: "badge",
225
+ breadcrumb: "breadcrumb",
226
+ button: "button",
227
+ card: "card",
228
+ carousel: "carousel",
229
+ chat: "chat",
230
+ drawer: "drawer",
231
+ "file-upload": "file-upload",
232
+ footer: "footer",
233
+ forms: "forms",
234
+ hero: "hero",
235
+ join: "join",
236
+ link: "link",
237
+ menu: "menu",
238
+ misc: "misc",
239
+ modal: "modal",
240
+ navbar: "navbar",
241
+ pagination: "pagination",
242
+ popover: "popover",
243
+ progress: "progress",
244
+ prose: "prose",
245
+ rating: "rating",
246
+ "scroll-top": "scroll-top",
247
+ skeleton: "skeleton",
248
+ swap: "swap",
249
+ table: "table",
250
+ tabs: "tabs",
251
+ tag: "tag",
252
+ textured: "textured",
253
+ timeline: "timeline",
254
+ toast: "toast",
255
+ tooltip: "tooltip",
256
+ };
257
+
258
+ function buildCSS(components, utilities) {
259
+ const imports = [
260
+ `@import "./base/tokens.css" layer(base);`,
261
+ `@import "./base/reset.css" layer(base);`,
262
+ `@import "./base/neo-overrides.css" layer(base);`,
263
+ ];
264
+
265
+ for (const c of components) {
266
+ imports.push(
267
+ `@import "./components/${COMPONENT_FILES[c] || c}.css" layer(components);`,
268
+ );
269
+ }
270
+ for (const u of utilities) {
271
+ imports.push(`@import "./utilities/${u}.css" layer(utilities);`);
272
+ }
273
+
274
+ return `@layer base, components, utilities;\n\n${imports.join("\n")}\n`;
275
+ }
276
+
277
+ // ── Main ───────────────────────────────────────────────────────────────────
278
+ const orchestrator = path.join(__dirname, "..", "src", "arekui.css");
279
+ const tmpFile = path.join(path.dirname(orchestrator), "__build.css");
280
+
281
+ try {
282
+ let components, utilities;
283
+
284
+ if (full) {
285
+ components = Object.keys(COMPONENT_FILES);
286
+ utilities = Object.keys(UTILITY_PATTERNS);
287
+ console.log(`\x1b[36m📦\x1b[0m Including all components`);
288
+ } else {
289
+ console.log(`\x1b[36m⏳\x1b[0m Scanning ${srcDir}...`);
290
+ const classes = scan(srcDir);
291
+ components = detectComponents(classes);
292
+ utilities = detectUtilities(classes);
293
+ console.log(` Found ${classes.size} ar-* tokens`);
294
+ console.log(` Components: ${components.join(", ") || "(none)"}`);
295
+ console.log(` Utilities: ${utilities.join(", ") || "(none)"}`);
296
+ }
297
+
298
+ fs.writeFileSync(tmpFile, buildCSS(components, utilities), "utf-8");
299
+ fs.mkdirSync(outDir, { recursive: true });
300
+
301
+ const result = bundle({
302
+ filename: tmpFile,
303
+ minify: true,
304
+ sourceMap: sourcemap,
305
+ });
306
+
307
+ const outFile = path.join(outDir, `${name}.min.css`);
308
+ fs.writeFileSync(outFile, result.code);
309
+ if (sourcemap && result.map) fs.writeFileSync(outFile + ".map", result.map);
310
+
311
+ console.log(`\n\x1b[32m✓\x1b[0m Built → ${outFile}`);
312
+ console.log(
313
+ ` ${components.length} components, ${utilities.length} utilities`,
314
+ );
315
+ console.log(` ${(result.code.length / 1024).toFixed(1)}KB`);
316
+ } finally {
317
+ if (fs.existsSync(tmpFile)) fs.unlinkSync(tmpFile);
318
+ }