@weasel-js/theme 1.5.1 → 1.5.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.
package/dist/engine.js CHANGED
@@ -1,23 +1,13 @@
1
1
  import { ALPHA_EXT } from './chunk-PJMTWM34.js';
2
2
  import { mergeAxes, fullSelection, pick, enumerateSelections, resolveTokens, pickAll, themeAxes, isByAxis, selectionKey } from './chunk-LL2ERJPZ.js';
3
- import { srgbU8ToOklab, oklabToOklch, oklchToOklab, oklabToSrgbU8 } from '@weasel-js/paint';
3
+ import { hexToOklchDeg, oklchDegToHex, srgbU8ToOklab } from '@weasel-js/paint';
4
4
 
5
- var clamp255 = (v) => Math.max(0, Math.min(255, Math.round(v)));
6
5
  function hexToRgb(hex) {
7
6
  const n = Number.parseInt(hex.slice(1), 16);
8
7
  return [n >> 16 & 255, n >> 8 & 255, n & 255];
9
8
  }
10
- function toHex(L, C, H) {
11
- const [l, a, b] = oklchToOklab(L, C, H * Math.PI / 180);
12
- const [r, g, bl] = oklabToSrgbU8(l, a, b);
13
- return `#${[r, g, bl].map((v) => clamp255(v).toString(16).padStart(2, "0")).join("")}`;
14
- }
15
- function toLch(hex) {
16
- const [r, g, b] = hexToRgb(hex);
17
- const [L, A, B] = srgbU8ToOklab(r, g, b);
18
- const [l, c, h] = oklabToOklch(L, A, B);
19
- return { L: l, C: c, H: (h * 180 / Math.PI % 360 + 360) % 360 };
20
- }
9
+ var toHex = oklchDegToHex;
10
+ var toLch = hexToOklchDeg;
21
11
  function chromaCap(L, H) {
22
12
  return toLch(toHex(L, 0.5, H)).C;
23
13
  }
@@ -638,12 +628,19 @@ function categoricalRamp(steps, gates, anchors) {
638
628
 
639
629
  // src/engine/scales.ts
640
630
  function scale(steps, p) {
641
- if (p.step === void 0 === (p.ratio === void 0)) {
642
- throw new Error("A scale takes exactly one of `step` and `ratio`");
631
+ const rules = [p.step, p.ratio, p.factors].filter((r) => r !== void 0);
632
+ if (rules.length !== 1) {
633
+ throw new Error("A scale takes exactly one of `step`, `ratio` and `factors`");
634
+ }
635
+ if (p.factors && p.factors.length !== steps.length) {
636
+ throw new Error(`A scale needs one factor per step; got ${p.factors.length} for ${steps.length} steps`);
643
637
  }
644
638
  const out = {};
645
639
  steps.forEach((name, i) => {
646
- const v = p.step !== void 0 ? p.base + p.step * i : p.base * p.ratio ** i;
640
+ let v;
641
+ if (p.factors !== void 0) v = p.base * p.factors[i];
642
+ else if (p.step !== void 0) v = p.base + p.step * i;
643
+ else v = p.base * p.ratio ** i;
647
644
  out[name] = `${Math.round(v)}px`;
648
645
  });
649
646
  return out;
@@ -865,7 +862,7 @@ var SEED_REF2 = /^\{seeds\.([\w-]+)\}$/;
865
862
  var REF = /^\{([^}]+)\}$/;
866
863
  var HEX2 = /^#[0-9a-f]{6}$/i;
867
864
  var UNTYPED = "unknown";
868
- var PARAMS = ["kind", "steps", "lightness", "curve", "hue", "chroma", "anchor", "gates", "anchors", "base", "step", "ratio"];
865
+ var PARAMS = ["kind", "steps", "lightness", "curve", "hue", "chroma", "anchor", "gates", "anchors", "base", "step", "ratio", "factors"];
869
866
  var has = (o, key) => Object.hasOwn(o, key);
870
867
  function refName(value) {
871
868
  return typeof value === "string" ? REF.exec(value.trim())?.[1] : void 0;
@@ -925,6 +922,14 @@ var Reader = class {
925
922
  optNum(x, path, fallback) {
926
923
  return x === void 0 ? fallback : this.num(x, path);
927
924
  }
925
+ optNums(x, path) {
926
+ if (x === void 0) return void 0;
927
+ if (!Array.isArray(x)) {
928
+ this.fail(path, "expected an array of numbers");
929
+ return void 0;
930
+ }
931
+ return x.map((v, i) => this.num(v, `${path}.${i}`));
932
+ }
928
933
  record(x, path) {
929
934
  if (x === void 0) return {};
930
935
  if (typeof x === "object" && x !== null && !Array.isArray(x)) return x;
@@ -1003,9 +1008,11 @@ function scaleValues(name, s, steps, issues) {
1003
1008
  const base = read.num(s.base, `${path}.base`);
1004
1009
  const step = read.optNum(s.step, `${path}.step`);
1005
1010
  const ratio = read.optNum(s.ratio, `${path}.ratio`);
1011
+ const factors = read.optNums(s.factors, `${path}.factors`);
1006
1012
  if (!read.ok) return void 0;
1007
1013
  try {
1008
- return { values: scale(steps, { base, step, ratio }), rule: step !== void 0 ? "linear" : "geometric" };
1014
+ const rule = factors !== void 0 ? "factors" : step !== void 0 ? "linear" : "geometric";
1015
+ return { values: scale(steps, { base, step, ratio, factors }), rule };
1009
1016
  } catch (e) {
1010
1017
  issues.push({ kind: "invalid", path, message: e.message });
1011
1018
  return void 0;
@@ -1511,7 +1518,6 @@ function emitCss(themes) {
1511
1518
 
1512
1519
  // src/engine/emit/dtcg.ts
1513
1520
  var REF3 = /^\{([^}.]+)\}$/;
1514
- var modeOnly = (theme, what) => new Error(`DTCG export supports a mode axis only; ${theme} ${what}`);
1515
1521
  function toDTCG(theme) {
1516
1522
  const axes = themeAxes(theme);
1517
1523
  const typeOf = (name) => {
@@ -1536,21 +1542,33 @@ function toDTCG(theme) {
1536
1542
  ...t.alpha !== void 0 ? { $extensions: { [ALPHA_EXT]: t.alpha } } : {}
1537
1543
  };
1538
1544
  };
1539
- const branches = (name, v) => {
1545
+ const flatten = (v) => {
1546
+ if (!isByAxis(v)) return v;
1547
+ if (v.by === "mode") {
1548
+ const out = { by: "mode" };
1549
+ for (const [mode, x] of Object.entries(v)) {
1550
+ if (mode === "by") continue;
1551
+ const inner = flatten(x);
1552
+ if (inner !== void 0) out[mode] = inner;
1553
+ }
1554
+ return out;
1555
+ }
1556
+ const fallback = axes[v.by]?.default;
1557
+ const chosen = fallback !== void 0 ? v[fallback] : void 0;
1558
+ return chosen === void 0 ? void 0 : flatten(chosen);
1559
+ };
1560
+ const branches = (v) => {
1540
1561
  if (!isByAxis(v)) return [];
1541
- if (v.by !== "mode") throw modeOnly(`"${name}"`, `varies by ${v.by}`);
1542
- return Object.entries(v).flatMap(([mode, x]) => {
1543
- if (mode === "by") return [];
1544
- if (isByAxis(x)) throw modeOnly(`"${name}"`, `varies by ${x.by} inside mode`);
1545
- return [[mode, x]];
1546
- });
1562
+ return Object.entries(v).flatMap(([mode, x]) => mode === "by" ? [] : [[mode, x]]);
1547
1563
  };
1548
1564
  const modes = {};
1549
1565
  for (const mode of Object.keys(axes.mode?.values ?? {})) modes[mode] = {};
1550
1566
  const primitives = {};
1551
- for (const [name, v] of Object.entries(theme.tokens)) {
1567
+ for (const [name, raw] of Object.entries(theme.tokens)) {
1568
+ const v = flatten(raw);
1569
+ if (v === void 0) continue;
1552
1570
  if (!isByAxis(v)) put(primitives, name, v);
1553
- else for (const [mode, t] of branches(name, v)) put(modes[mode] ??= {}, name, t);
1571
+ else for (const [mode, t] of branches(v)) put(modes[mode] ??= {}, name, t);
1554
1572
  }
1555
1573
  return { name: theme.name, ...axes.mode ? { defaultMode: axes.mode.default } : {}, primitives, modes };
1556
1574
  }
@@ -1587,6 +1605,12 @@ var TOKEN_HOOKS = [
1587
1605
  value: "9ch",
1588
1606
  description: "Width of a numeric field in the Properties panel."
1589
1607
  },
1608
+ {
1609
+ name: "prop-row-h",
1610
+ type: "dimension",
1611
+ value: "20px",
1612
+ description: "Floor under every Properties row, whatever control it holds. Unset, it is the panel\u2019s own field height, so it follows density \u2014 20px at the default one."
1613
+ },
1590
1614
  {
1591
1615
  name: "prop-text-width",
1592
1616
  type: "dimension",
@@ -1620,7 +1644,11 @@ var TOKEN_HOOKS = [
1620
1644
  ];
1621
1645
 
1622
1646
  // src/engine/emit/manifest.ts
1623
- var groupOf = (name) => name.includes("-") ? name.slice(0, name.indexOf("-")) : name;
1647
+ var MERGED_GROUPS = { danger: "status", warning: "status", success: "status" };
1648
+ var groupOf = (name) => {
1649
+ const prefix = name.includes("-") ? name.slice(0, name.indexOf("-")) : name;
1650
+ return MERGED_GROUPS[prefix] ?? prefix;
1651
+ };
1624
1652
  var row = (name, type, value, description, hook) => ` { name: '--wzl-${name}', type: ${JSON.stringify(type)}, group: ${JSON.stringify(groupOf(name))}, defaultValue: ${JSON.stringify(value)}, description: ${JSON.stringify(description)}, hook: ${hook} },`;
1625
1653
  function emitManifest({ baked }) {
1626
1654
  const all = pickAll(baked.tokens, fullSelection(baked.axes, {}));