@aedis/cli 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,9 +6,9 @@ before any file is written, npm dependencies are pinned to exact versions at lea
6
6
  script runs.
7
7
 
8
8
  ```bash
9
- npx @aedis/cli@0.2.2 init
10
- npx @aedis/cli@0.2.2 add button approval-card
11
- npx @aedis/cli@0.2.2 diff
9
+ npx @aedis/cli@0.4.0 init
10
+ npx @aedis/cli@0.4.0 add button approval-card
11
+ npx @aedis/cli@0.4.0 diff
12
12
  ```
13
13
 
14
14
  Always pin the version, as above. Never run `npx aedis`: the unscoped `aedis` package on npm is not this one.
package/dist/aedis.js CHANGED
@@ -307,7 +307,9 @@ const shadows = {
307
307
  };
308
308
  const fonts = {
309
309
  sans: "-apple-system, BlinkMacSystemFont, \"Segoe UI Variable Display\", \"Segoe UI\", system-ui, sans-serif",
310
- mono: "ui-monospace, \"SF Mono\", \"Cascadia Code\", Menlo, Consolas, monospace"
310
+ mono: "ui-monospace, \"SF Mono\", \"Cascadia Code\", Menlo, Consolas, monospace",
311
+ /** Headings; the sans unless a theme gives the display its own family. */
312
+ display: "var(--font-sans)"
311
313
  };
312
314
  /** Tracking tightens and leading drops as size grows. Tailwind: `text-<name>`. */
313
315
  const typeScale = {
@@ -522,8 +524,21 @@ const MIN_TEXT_PX = 12;
522
524
  const themeFonts = {
523
525
  system: fonts.sans,
524
526
  rounded: `ui-rounded, "SF Pro Rounded", ${fonts.sans}`,
525
- serif: "ui-serif, \"New York\", Georgia, \"Times New Roman\", serif"
527
+ serif: "ui-serif, \"New York\", Georgia, \"Times New Roman\", serif",
528
+ mono: fonts.mono
526
529
  };
530
+ const fontSlots = [
531
+ "sans",
532
+ "display",
533
+ "mono"
534
+ ];
535
+ /** A family name a theme may name: letters, digits, spaces and hyphens, so it can never close the quotes or the rule. */
536
+ const FAMILY = /^[A-Za-z][A-Za-z0-9 -]{0,47}$/;
537
+ /** The CSS stack for a font choice: a preset, or a self-hosted family quoted ahead of the system fallback. */
538
+ function fontStack(slot, choice) {
539
+ if (has(themeFonts, choice)) return themeFonts[choice];
540
+ return `"${choice}", ${slot === "mono" ? fonts.mono : fonts.sans}`;
541
+ }
527
542
  /** A stored or shared theme larger than this is refused before parsing. */
528
543
  const MAX_THEME_BYTES = 16384;
529
544
  const modes = ["light", "dark"];
@@ -569,6 +584,7 @@ function validateTheme(input) {
569
584
  "shadow",
570
585
  "motion",
571
586
  "font",
587
+ "fonts",
572
588
  "type"
573
589
  ], "");
574
590
  if (input.version !== 1) errors.push("version must be 1");
@@ -634,6 +650,19 @@ function validateTheme(input) {
634
650
  if (typeof input.font === "string" && has(themeFonts, input.font)) theme.font = input.font;
635
651
  else errors.push(`font must be one of ${Object.keys(themeFonts).join(", ")}`);
636
652
  }
653
+ if (input.fonts !== void 0) {
654
+ if (!isRecord(input.fonts)) errors.push("fonts must be an object with sans, display or mono");
655
+ else {
656
+ errors.push(...unknownKeys(input.fonts, fontSlots, "fonts."));
657
+ theme.fonts = {};
658
+ for (const slot of fontSlots) {
659
+ const v = input.fonts[slot];
660
+ if (v === void 0) continue;
661
+ if (typeof v === "string" && (has(themeFonts, v.trim()) || FAMILY.test(v.trim()))) theme.fonts[slot] = v.trim();
662
+ else errors.push(`fonts.${slot} must be one of ${Object.keys(themeFonts).join(", ")} or a family name of letters, digits, spaces and hyphens`);
663
+ }
664
+ }
665
+ }
637
666
  if (input.type !== void 0) {
638
667
  if (!isRecord(input.type)) errors.push("type must be an object");
639
668
  else {
@@ -697,6 +726,7 @@ function themeVariables(theme, mode) {
697
726
  for (const [k, v] of Object.entries(theme.blur ?? {})) vars[`--blur-${k}`] = `${v}px`;
698
727
  if (theme.motion !== void 0) for (const [k, v] of Object.entries(durations)) vars[`--duration-${k}`] = `${num(parseFloat(v) * theme.motion)}ms`;
699
728
  if (theme.font) vars["--font-sans"] = themeFonts[theme.font];
729
+ for (const [slot, choice] of Object.entries(theme.fonts ?? {})) vars[`--font-${slot}`] = fontStack(slot, choice);
700
730
  if (theme.type) Object.assign(vars, typeVariables(theme.type));
701
731
  return vars;
702
732
  }
@@ -1588,7 +1618,7 @@ function planFiles(items, config, root) {
1588
1618
  }
1589
1619
  //#endregion
1590
1620
  //#region src/cli.ts
1591
- const VERSION = "0.2.2";
1621
+ const VERSION = "0.4.0";
1592
1622
  /** What `aedis init` installs: config, theme tokens, cn and the security primitives. */
1593
1623
  const INIT_ITEMS = [
1594
1624
  "theme",
@@ -1752,7 +1782,7 @@ async function run(argv, io) {
1752
1782
  }
1753
1783
  if (!existsSync(path.join(root, "package.json"))) throw new Error(`${root} has no package.json; run inside your app`);
1754
1784
  if (command === "init") {
1755
- const config = readConfig(root) ?? defaultConfig(root, flags.release ?? `v0.2.2`);
1785
+ const config = readConfig(root) ?? defaultConfig(root, flags.release ?? `v0.4.0`);
1756
1786
  if (!isRelease(config.release)) throw new Error(`invalid release ${config.release}`);
1757
1787
  const decoded = flags.preset === void 0 ? null : decodePreset(flags.preset);
1758
1788
  if (decoded && !decoded.ok) throw new Error(`preset refused: ${decoded.error}`);
@@ -1788,7 +1818,7 @@ ${themeToCss(theme)}
1788
1818
  }
1789
1819
  if (command === "theme" && args[0] === "import") {
1790
1820
  if (!args[1]) throw new Error("theme import: give the theme's JSON file");
1791
- const config = readConfig(root) ?? defaultConfig(root, `v0.2.2`);
1821
+ const config = readConfig(root) ?? defaultConfig(root, `v0.4.0`);
1792
1822
  const input = insideProject(root, path.relative(root, path.resolve(io.cwd, args[1])));
1793
1823
  const result = themeImport(readFileSync(input, "utf8"), path.basename(input));
1794
1824
  if (!result.ok) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aedis/cli",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "description": "Add Aedis UI components to your app with verified provenance: signed releases, exact and aged dependencies, no install scripts.",
5
5
  "keywords": [
6
6
  "aedis",