arekui 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +16 -188
  3. package/arekui.css +3018 -367
  4. package/arekui.d.ts +47 -47
  5. package/arekui.js +402 -35
  6. package/assets/img/grunge-wall-texture-freepick-kues1.webp +0 -0
  7. package/assets/img/logo.png +0 -0
  8. package/dist/css/arekui.base.min.css +1 -0
  9. package/dist/css/arekui.broadsheet.min.css +1 -0
  10. package/dist/css/arekui.brutalist.min.css +1 -0
  11. package/dist/css/arekui.default.min.css +1 -0
  12. package/dist/css/arekui.full.min.css +1 -0
  13. package/dist/css/arekui.min.css +1 -0
  14. package/dist/css/arekui.neo.min.css +1 -0
  15. package/dist/css/arekui.pixel.min.css +1 -0
  16. package/dist/js/arekui.min.js +2 -0
  17. package/package.json +14 -9
  18. package/scripts/build-css.js +95 -0
  19. package/scripts/build-custom.js +65 -96
  20. package/scripts/build-js.js +68 -0
  21. package/scripts/clean.js +13 -0
  22. package/scripts/dev.js +97 -0
  23. package/scripts/imports.js +18 -0
  24. package/scripts/split.js +256 -0
  25. package/src/arekui.base.css +63 -0
  26. package/src/arekui.broadsheet.css +6 -0
  27. package/src/arekui.brutalist.css +8 -0
  28. package/src/arekui.core.css +64 -0
  29. package/src/arekui.css +73 -56
  30. package/src/arekui.default.css +6 -0
  31. package/src/arekui.neo.css +8 -0
  32. package/src/arekui.pixel.css +8 -0
  33. package/src/base/brutalist-overrides.css +254 -0
  34. package/src/base/neo-overrides.css +46 -31
  35. package/src/base/pixel-overrides.css +336 -0
  36. package/src/base/reset.css +118 -4
  37. package/src/base/theme-brutalist.css +111 -0
  38. package/src/base/theme-default.css +184 -0
  39. package/src/base/theme-neo.css +108 -0
  40. package/src/base/theme-pixel.css +111 -0
  41. package/src/base/tokens.css +10 -253
  42. package/src/components/accordion.css +1 -2
  43. package/src/components/alert.css +1 -2
  44. package/src/components/badge.css +1 -2
  45. package/src/components/breadcrumb.css +2 -3
  46. package/src/components/broadsheet.css +264 -0
  47. package/src/components/button.css +3 -2
  48. package/src/components/card.css +1 -2
  49. package/src/components/carousel.css +37 -1
  50. package/src/components/chat.css +5 -4
  51. package/src/components/description-list.css +34 -0
  52. package/src/components/docs.css +252 -0
  53. package/src/components/empty.css +36 -0
  54. package/src/components/file-upload.css +2 -3
  55. package/src/components/footer.css +16 -1
  56. package/src/components/forms.css +1 -2
  57. package/src/components/heading.css +27 -0
  58. package/src/components/hero.css +1 -2
  59. package/src/components/join.css +1 -2
  60. package/src/components/kbd.css +15 -0
  61. package/src/components/link.css +2 -3
  62. package/src/components/loading.css +109 -0
  63. package/src/components/menu.css +51 -1
  64. package/src/components/misc.css +40 -1
  65. package/src/components/modal.css +1 -2
  66. package/src/components/navbar.css +131 -1
  67. package/src/components/pagination.css +7 -2
  68. package/src/components/popover.css +5 -6
  69. package/src/components/progress.css +1 -2
  70. package/src/components/prose.css +2 -2
  71. package/src/components/rating.css +1 -2
  72. package/src/components/scroll-top.css +2 -2
  73. package/src/components/segmented.css +44 -0
  74. package/src/components/sidebar.css +377 -0
  75. package/src/components/skeleton.css +2 -2
  76. package/src/components/spinner.css +36 -0
  77. package/src/components/swap.css +2 -2
  78. package/src/components/table.css +1 -2
  79. package/src/components/tabs.css +2 -3
  80. package/src/components/tag.css +10 -10
  81. package/src/components/textured.css +22 -2
  82. package/src/components/timeline.css +1 -2
  83. package/src/components/toast.css +2 -2
  84. package/src/components/tooltip.css +1 -2
  85. package/src/utilities/borders.css +2 -2
  86. package/src/utilities/brutalist-utilities.css +49 -0
  87. package/src/utilities/colors.css +11 -3
  88. package/src/utilities/hover.css +2 -2
  89. package/src/utilities/layout.css +2 -2
  90. package/src/utilities/neo-utilities.css +2 -9
  91. package/src/utilities/pixel-utilities.css +88 -0
  92. package/src/utilities/responsive.css +7 -2
  93. package/src/utilities/sizing.css +16 -7
  94. package/src/utilities/spacing.css +5 -2
  95. package/src/utilities/typography.css +5 -2
  96. package/dist/arekui.min.css +0 -1
  97. package/dist/arekui.min.js +0 -2
  98. package/src/components/drawer.css +0 -53
@@ -1,31 +1,10 @@
1
1
  #!/usr/bin/env node
2
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
3
  const fs = require("fs");
25
4
  const path = require("path");
26
5
  const { bundle } = require("lightningcss");
6
+ const { BASE_IMPORTS } = require("./imports");
27
7
 
28
- // ── Load config file ───────────────────────────────────────────────────────
29
8
  function loadConfig() {
30
9
  const candidates = ["arekui.config.js", "arekui.config.json"];
31
10
  for (const file of candidates) {
@@ -45,7 +24,6 @@ function loadConfig() {
45
24
  return {};
46
25
  }
47
26
 
48
- // ── CLI args (override config) ─────────────────────────────────────────────
49
27
  function getArg(flags) {
50
28
  const idx = process.argv.findIndex((a) => flags.includes(a));
51
29
  return idx === -1 ? null : process.argv[idx + 1];
@@ -63,17 +41,18 @@ const full = process.argv.includes("--full") || config.full === true;
63
41
  const srcDir = path.resolve(input);
64
42
  const outDir = path.resolve(output);
65
43
 
66
- // ── Component → CSS class mapping ──────────────────────────────────────────
67
44
  const COMPONENT_CLASSES = {
68
45
  accordion: ["ar-accordion", "ar-collapse"],
69
46
  alert: ["ar-alert"],
70
47
  badge: ["ar-badge"],
71
48
  breadcrumb: ["ar-breadcrumb"],
49
+ broadsheet: ["ar-rule-double", "ar-masthead", "ar-folio", "ar-nameplate", "ar-banner", "ar-sheet-cols", "ar-sheet-col", "ar-plate"],
72
50
  button: ["ar-btn"],
73
51
  card: ["ar-card", "ar-card-body", "ar-card-title", "ar-card-figure"],
74
- carousel: ["ar-carousel", "ar-carousel-item"],
52
+ carousel: ["ar-carousel", "ar-carousel-item", "ar-carousel-frame", "ar-carousel-btn", "ar-carousel-btn-prev", "ar-carousel-btn-next"],
75
53
  chat: ["ar-chat", "ar-chat-bubble"],
76
- drawer: ["ar-drawer"],
54
+ "description-list": ["ar-dl", "ar-dt", "ar-dd"],
55
+ sidebar: ["ar-sidebar"],
77
56
  "file-upload": ["ar-file-upload"],
78
57
  footer: ["ar-footer"],
79
58
  forms: [
@@ -87,20 +66,33 @@ const COMPONENT_CLASSES = {
87
66
  "ar-label",
88
67
  "ar-fieldset",
89
68
  ],
69
+ heading: [
70
+ "ar-heading",
71
+ "ar-heading-eyebrow",
72
+ "ar-heading-title",
73
+ "ar-heading-desc",
74
+ "ar-heading-center",
75
+ ],
90
76
  hero: ["ar-hero"],
91
77
  join: ["ar-join"],
78
+ docs: ["ar-docs"],
79
+ empty: ["ar-empty", "ar-empty-icon", "ar-empty-title", "ar-empty-desc", "ar-empty-action"],
80
+ kbd: ["ar-kbd"],
92
81
  link: ["ar-link"],
93
- menu: ["ar-menu", "ar-dropdown"],
94
- misc: ["ar-divider", "ar-stepper", "ar-step", "ar-avatar"],
82
+ loading: ["ar-loading"],
83
+ menu: ["ar-menu", "ar-dropdown", "ar-theme-menu"],
84
+ misc: ["ar-divider", "ar-stepper", "ar-step", "ar-avatar", "ar-avatar-group", "ar-avatar-more"],
95
85
  modal: ["ar-modal"],
96
- navbar: ["ar-navbar"],
86
+ navbar: ["ar-navbar", "ar-search"],
97
87
  pagination: ["ar-pagination"],
98
88
  popover: ["ar-popover"],
99
89
  progress: ["ar-progress"],
100
90
  prose: ["ar-prose"],
101
91
  rating: ["ar-rating"],
102
92
  "scroll-top": ["ar-scroll-top"],
93
+ segmented: ["ar-segmented", "ar-segmented-input", "ar-segmented-item"],
103
94
  skeleton: ["ar-skeleton"],
95
+ spinner: ["ar-spinner"],
104
96
  swap: ["ar-swap"],
105
97
  table: ["ar-table"],
106
98
  tabs: ["ar-tabs", "ar-tab"],
@@ -154,13 +146,34 @@ const UTILITY_PATTERNS = {
154
146
  ],
155
147
  borders: [/^ar-border/, /^ar-rounded/, /^ar-shadow-/],
156
148
  hover: [/^ar-hover-/],
157
- responsive: [/^ar-md:/, /^ar-lg:/],
149
+ responsive: [/^ar-md:/, /^ar-lg:/, /^ar-hide/],
158
150
  "neo-utilities": [/^ar-neo-/],
151
+ "pixel-utilities": [/^ar-pixel-/],
152
+ "brutalist-utilities": [/^ar-brutalist-/],
159
153
  };
160
154
 
161
- // ── Scan source files ──────────────────────────────────────────────────────
162
155
  function findSourceFiles(dir) {
163
156
  const exts = [".html", ".jsx", ".vue", ".svelte", ".tsx", ".ts", ".js"];
157
+
158
+ // A consumer may point -i at a single file rather than a directory.
159
+ let stat;
160
+ try {
161
+ stat = fs.statSync(dir);
162
+ } catch {
163
+ console.error(`\x1b[31m✗\x1b[0m scan input not found: ${dir}`);
164
+ process.exit(1);
165
+ }
166
+ if (stat.isFile()) {
167
+ const ext = path.extname(dir).toLowerCase();
168
+ if (!exts.includes(ext)) {
169
+ console.error(
170
+ `\x1b[31m✗\x1b[0m ${dir} is not a scannable source - expected one of (${exts.join(" ")}) or a directory`,
171
+ );
172
+ process.exit(1);
173
+ }
174
+ return [dir];
175
+ }
176
+
164
177
  const files = [];
165
178
 
166
179
  function walk(d) {
@@ -191,90 +204,46 @@ function scan(dir) {
191
204
  return tokens;
192
205
  }
193
206
 
194
- function detectComponents(classes) {
195
- const found = new Set();
196
- for (const [comp, patterns] of Object.entries(COMPONENT_CLASSES)) {
207
+ // Both detectors answer the same question — which named groups have at least
208
+ // one matcher satisfied by a scanned token — so the double loop lives once.
209
+ function detect(groups, classes, isMatch) {
210
+ const found = [];
211
+ for (const [name, matchers] of Object.entries(groups)) {
197
212
  for (const cls of classes) {
198
- if (patterns.some((p) => cls === p || cls.startsWith(p + "-"))) {
199
- found.add(comp);
213
+ if (matchers.some((m) => isMatch(m, cls))) {
214
+ found.push(name);
200
215
  break;
201
216
  }
202
217
  }
203
218
  }
204
- return [...found];
219
+ return found;
205
220
  }
206
221
 
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];
222
+ function detectComponents(classes) {
223
+ return detect(
224
+ COMPONENT_CLASSES,
225
+ classes,
226
+ (pattern, cls) => cls === pattern || cls.startsWith(pattern + "-"),
227
+ );
218
228
  }
219
229
 
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
- };
230
+ function detectUtilities(classes) {
231
+ return detect(UTILITY_PATTERNS, classes, (pattern, cls) => pattern.test(cls));
232
+ }
257
233
 
258
234
  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
- ];
235
+ const imports = [...BASE_IMPORTS];
264
236
 
265
237
  for (const c of components) {
266
- imports.push(
267
- `@import "./components/${COMPONENT_FILES[c] || c}.css" layer(components);`,
268
- );
238
+ imports.push(`@import "./components/${c}.css" layer(components);`);
269
239
  }
270
240
  for (const u of utilities) {
271
241
  imports.push(`@import "./utilities/${u}.css" layer(utilities);`);
272
242
  }
273
243
 
274
- return `@layer base, components, utilities;\n\n${imports.join("\n")}\n`;
244
+ return `@layer base, components, themes, utilities;\n\n${imports.join("\n")}\n`;
275
245
  }
276
246
 
277
- // ── Main ───────────────────────────────────────────────────────────────────
278
247
  const orchestrator = path.join(__dirname, "..", "src", "arekui.css");
279
248
  const tmpFile = path.join(path.dirname(orchestrator), "__build.css");
280
249
 
@@ -282,7 +251,7 @@ try {
282
251
  let components, utilities;
283
252
 
284
253
  if (full) {
285
- components = Object.keys(COMPONENT_FILES);
254
+ components = Object.keys(COMPONENT_CLASSES);
286
255
  utilities = Object.keys(UTILITY_PATTERNS);
287
256
  console.log(`\x1b[36m📦\x1b[0m Including all components`);
288
257
  } else {
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const esbuild = require("esbuild");
6
+
7
+ const SRC = path.join(__dirname, "..", "arekui.js");
8
+ const DIST = path.join(__dirname, "..", "dist");
9
+ const OUT_MIN = path.join(DIST, "js", "arekui.min.js");
10
+ const OUT_MAP = path.join(DIST, "js", "arekui.min.js.map");
11
+
12
+ const args = process.argv.slice(2);
13
+ const watch = args.includes("--watch");
14
+ const sourcemap = args.includes("--sourcemap");
15
+
16
+ async function build() {
17
+ const startTime = Date.now();
18
+
19
+ fs.mkdirSync(path.dirname(OUT_MIN), { recursive: true });
20
+
21
+ try {
22
+ const result = await esbuild.build({
23
+ entryPoints: [SRC],
24
+ bundle: false,
25
+ minify: true,
26
+ sourcemap: sourcemap,
27
+ outfile: OUT_MIN,
28
+ target: ["es2018"],
29
+ format: "iife",
30
+ legalComments: "none",
31
+ banner: {
32
+ js: "/*! ArekUI v2.0.0 | MIT License */",
33
+ },
34
+ write: false,
35
+ });
36
+
37
+ for (const file of result.outputFiles) {
38
+ fs.writeFileSync(file.path, file.contents);
39
+ }
40
+
41
+ const originalSize = fs.statSync(SRC).size;
42
+ const minifiedSize = fs.statSync(OUT_MIN).size;
43
+ const reduction = ((1 - minifiedSize / originalSize) * 100).toFixed(1);
44
+ const elapsed = Date.now() - startTime;
45
+
46
+ console.log(`✓ JS built in ${elapsed}ms`);
47
+ console.log(
48
+ ` ${originalSize} → ${minifiedSize} bytes (${reduction}% reduction)`,
49
+ );
50
+ console.log(` Output: ${OUT_MIN}`);
51
+ if (sourcemap) {
52
+ console.log(` Sourcemap: ${OUT_MAP}`);
53
+ }
54
+ } catch (err) {
55
+ console.error("✗ JS build failed:", err.message);
56
+ process.exit(1);
57
+ }
58
+ }
59
+
60
+ if (watch) {
61
+ console.log(`Watching ${SRC} for changes...`);
62
+ fs.watchFile(SRC, { interval: 100 }, () => {
63
+ console.log("\nChange detected, rebuilding JS...");
64
+ build();
65
+ });
66
+ }
67
+
68
+ build();
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+
6
+ const DIST = path.join(__dirname, "..", "dist");
7
+
8
+ if (fs.existsSync(DIST)) {
9
+ fs.rmSync(DIST, { recursive: true, force: true });
10
+ console.log(`✓ Removed ${DIST}`);
11
+ } else {
12
+ console.log("ℹ Nothing to clean (dist/ doesn't exist)");
13
+ }
package/scripts/dev.js ADDED
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn, spawnSync } = require("child_process");
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+
7
+ const ROOT = path.join(__dirname, "..");
8
+ const SCRIPTS = __dirname;
9
+ const children = [];
10
+ let shuttingDown = false;
11
+
12
+ // Runs a script to completion before continuing. With { fatal: true } a
13
+ // failed run tears the dev process down instead of building on top of a
14
+ // stale bundle.
15
+ function run(script, { fatal = false } = {}) {
16
+ const result = spawnSync(process.execPath, [path.join(SCRIPTS, script)], {
17
+ cwd: ROOT,
18
+ stdio: "inherit",
19
+ });
20
+ if (result.status !== 0) {
21
+ console.error(`✗ ${script} failed`);
22
+ if (fatal) process.exit(result.status || 1);
23
+ }
24
+ }
25
+
26
+ function watchScript(script, label) {
27
+ const child = spawn(process.execPath, [path.join(SCRIPTS, script), "--watch"], {
28
+ cwd: ROOT,
29
+ stdio: ["ignore", "pipe", "pipe"],
30
+ });
31
+ const prefix = `\x1b[90m[${label}]\x1b[0m `;
32
+ const pipe = (stream, out) => {
33
+ let buffer = "";
34
+ stream.on("data", (chunk) => {
35
+ buffer += chunk.toString();
36
+ const lines = buffer.split("\n");
37
+ buffer = lines.pop();
38
+ for (const line of lines) out.write(prefix + line + "\n");
39
+ });
40
+ };
41
+ pipe(child.stdout, process.stdout);
42
+ pipe(child.stderr, process.stderr);
43
+ child.on("exit", (code, signal) => {
44
+ if (shuttingDown) return;
45
+ console.error(`${prefix}exited unexpectedly (${signal || code})`);
46
+ shutdown(1);
47
+ });
48
+ children.push(child);
49
+ }
50
+
51
+ function shutdown(code) {
52
+ if (shuttingDown) return;
53
+ shuttingDown = true;
54
+ for (const child of children) {
55
+ if (child.exitCode === null && child.signalCode === null) {
56
+ try {
57
+ child.kill();
58
+ } catch (e) {}
59
+ }
60
+ }
61
+ process.exit(code);
62
+ }
63
+
64
+ process.on("SIGINT", () => shutdown(0));
65
+ process.on("SIGTERM", () => shutdown(0));
66
+
67
+ const timers = new Map();
68
+ function debounce(key, label, fn) {
69
+ const existing = timers.get(key);
70
+ if (existing) clearTimeout(existing);
71
+ timers.set(
72
+ key,
73
+ setTimeout(() => {
74
+ timers.delete(key);
75
+ process.stdout.write(`\x1b[90m[${label}]\x1b[0m ${key} changed\n`);
76
+ fn();
77
+ }, 100),
78
+ );
79
+ }
80
+
81
+ console.log("ArekUI dev\n");
82
+
83
+ run("split.js", { fatal: true });
84
+ run("build-css.js", { fatal: true });
85
+ run("build-js.js", { fatal: true });
86
+
87
+ watchScript("build-css.js", "css");
88
+ watchScript("build-js.js", "js");
89
+
90
+ const rootCss = path.join(ROOT, "arekui.css");
91
+ if (fs.existsSync(rootCss)) {
92
+ fs.watchFile(rootCss, { interval: 200 }, () => {
93
+ debounce("arekui.css", "split", () => run("split.js"));
94
+ });
95
+ }
96
+
97
+ console.log("Watching arekui.css (Ctrl+C to stop)\n");
@@ -0,0 +1,18 @@
1
+ // The nine base-layer imports every ArekUI entry point starts with. Both
2
+ // consumers must emit them identically, so they live here once instead of
3
+ // being kept in sync by hand: split.js (the src/ orchestrators) and
4
+ // build-custom.js (the arekui-build consumer bundle).
5
+
6
+ const BASE_IMPORTS = [
7
+ '@import "./base/tokens.css" layer(base);',
8
+ '@import "./base/theme-default.css" layer(base);',
9
+ '@import "./base/theme-neo.css" layer(base);',
10
+ '@import "./base/theme-pixel.css" layer(base);',
11
+ '@import "./base/theme-brutalist.css" layer(base);',
12
+ '@import "./base/reset.css" layer(base);',
13
+ '@import "./base/neo-overrides.css" layer(themes);',
14
+ '@import "./base/pixel-overrides.css" layer(themes);',
15
+ '@import "./base/brutalist-overrides.css" layer(themes);',
16
+ ];
17
+
18
+ module.exports = { BASE_IMPORTS };