@theme-registry/refract 0.1.9 → 0.1.10

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/cli.js CHANGED
@@ -6110,7 +6110,7 @@ function groupLeaves(leaves) {
6110
6110
  }
6111
6111
  const SECTIONS = [
6112
6112
  { id: "palette", title: "Colour", eyebrow: "Palette",
6113
- note: "Every rung is a token you can reference. The marked rung is the family's <code>base</code>; click any identifier to copy it." },
6113
+ note: "Every rung is a token you can reference. A ladder is an absolute lightness scale and the seed is <em>not</em> snapped onto it &mdash; the marked rung is where the family's <code>base</code> lands, not a rung it equals. Click any identifier to copy it." },
6114
6114
  { id: "type", title: "Type scale", eyebrow: "Typography" },
6115
6115
  { id: "space", title: "Spacing and size", eyebrow: "Space",
6116
6116
  note: "There is no separate <code>padding</code> token — spacing <em>is</em> the padding scale, so it is shown both as a measure and as an applied inset." },
@@ -6144,6 +6144,33 @@ const rowOf = (id, specimen, value, centred = false) => `<div class="rfp-row${ce
6144
6144
  `<div class="rfp-rowval">${esc(value)}</div></div>`;
6145
6145
  /** Is this colour-family child a numeric ladder rung (`50`…`900`)? */
6146
6146
  const isRung = (name) => /^\d+$/.test(name);
6147
+ /** OKLCH lightness (0–100) of a hex colour, or `undefined` for anything else. */
6148
+ function lightnessOf(value) {
6149
+ if (!/^#[0-9a-f]{3}([0-9a-f]{3})?$/i.test(value.trim()))
6150
+ return undefined;
6151
+ try {
6152
+ return rgbToOklch(convertHexToRGB(value.trim())).L;
6153
+ }
6154
+ catch {
6155
+ return undefined;
6156
+ }
6157
+ }
6158
+ /**
6159
+ * Which rung the family's `base` LANDS on — never which rung it *is*.
6160
+ *
6161
+ * A numeric ladder is an absolute lightness scale (`L = (1000 − label) / 10`) and refract
6162
+ * deliberately **does not snap** the seed onto it: `refract create` reports where a seed falls
6163
+ * (`#4c6ef5` → L 59.1% ≈ 400) rather than moving it. So the base almost never equals a rung, and
6164
+ * testing for equality marks nothing. Report the nearest rung by lightness instead — true, and the
6165
+ * question a reader actually has.
6166
+ */
6167
+ function baseLandsOn(base, rungs) {
6168
+ const baseL = base === undefined ? undefined : lightnessOf(base);
6169
+ if (baseL === undefined || rungs.length === 0)
6170
+ return undefined;
6171
+ const nominalL = (step) => (1000 - Number(step)) / 10;
6172
+ return rungs.reduce((best, [step]) => (Math.abs(nominalL(step) - baseL) < Math.abs(nominalL(best) - baseL) ? step : best), rungs[0][0]);
6173
+ }
6147
6174
  /** Nearest px magnitude of a dimension value, for bar widths. `undefined` when it has no magnitude. */
6148
6175
  function pxOf(value) {
6149
6176
  const match = /^(-?[\d.]+)\s*(px|rem|em)?$/.exec(String(value).trim());
@@ -6176,34 +6203,45 @@ function renderPalette(leaves, tokenName) {
6176
6203
  if (rungs.length >= 3) {
6177
6204
  // A ladder: contiguous rungs read as a ramp in a way a row-per-token list never does.
6178
6205
  rungs.sort((a, b) => Number(a[0]) - Number(b[0]));
6206
+ const lands = baseLandsOn(base, rungs);
6179
6207
  const strip = rungs
6180
6208
  .map(([step, hex]) => {
6181
- const isBase = base !== undefined && hex.toLowerCase() === base.toLowerCase();
6182
- return (`<div class="rfp-rung"${isBase ? ' data-base="true"' : ""} title="colors.${esc(family)}.${esc(step)} · ${esc(hex)}">` +
6209
+ const isLanding = lands !== undefined && step === lands;
6210
+ return (`<div class="rfp-rung"${isLanding ? ' data-lands="true"' : ""}` +
6211
+ ` title="colors.${esc(family)}.${esc(step)} · ${esc(hex)}${isLanding ? " · base lands here" : ""}">` +
6183
6212
  `<div class="rfp-rung-chip" data-hex="${esc(hex)}" style="background:${cssValue(hex)}"></div>` +
6184
6213
  `<div class="rfp-rung-foot">${esc(step)}</div></div>`);
6185
6214
  })
6186
6215
  .join("");
6187
6216
  ladders.push(`<div class="rfp-ladder"><div><div class="rfp-ladder-name">${esc(family)}</div>` +
6188
- (base ? `<div class="rfp-ladder-base">base · ${esc(base)}</div>` : "") +
6217
+ (base
6218
+ ? `<div class="rfp-ladder-base">base · ${esc(base)}` +
6219
+ (lands ? `<br>lands &asymp; ${esc(lands)}` : "") +
6220
+ `</div>`
6221
+ : "") +
6189
6222
  idButton(`colors.${family}`, tokenName === null || tokenName === void 0 ? void 0 : tokenName(`colors.${family}`)) +
6190
6223
  `</div><div class="rfp-rungs">${strip}</div></div>`);
6191
6224
  continue;
6192
6225
  }
6193
- // Not a ladder — render each member as a swatch card. When the family declares a `text`
6194
- // pairing, the card renders that text ON the colour with a live contrast readout, which is the
6195
- // same pairing `refract audit` scores.
6226
+ // Not a ladder — render each member as a swatch card.
6227
+ //
6228
+ // The contrast readout goes ONLY on the member that genuinely declares the pairing: the family
6229
+ // base against its own `text`. Derived tints (`brand.dark`, `surface.lighter`, …) were never
6230
+ // meant to carry that text, so scoring them produces "fail" badges that read as a defect in the
6231
+ // user's theme when nothing is wrong. On a page whose whole job is to tell the truth about a
6232
+ // theme, inventing a pairing to score is the worst kind of noise.
6196
6233
  const text = (_c = members.find(([name]) => name === "text")) === null || _c === void 0 ? void 0 : _c[1];
6197
6234
  for (const [member, hex] of members) {
6198
6235
  if (member === "text")
6199
6236
  continue;
6200
- const path = member === "base" ? `colors.${family}` : `colors.${family}.${member}`;
6201
- pairs.push(`<div class="rfp-pair"><div class="rfp-pair-swatch" data-bg="${esc(hex)}"${text ? ` data-fg="${esc(text)}"` : ""}` +
6202
- ` style="background:${cssValue(hex)}${text ? `;color:${cssValue(text)}` : ""}">` +
6203
- `<span class="rfp-pair-sample">Aa</span>` +
6204
- (text ? `<span class="rfp-pair-ratio"></span>` : "") +
6237
+ const isBase = member === "base";
6238
+ const paired = isBase ? text : undefined;
6239
+ const path = isBase ? `colors.${family}` : `colors.${family}.${member}`;
6240
+ pairs.push(`<div class="rfp-pair"><div class="rfp-pair-swatch" data-bg="${esc(hex)}"${paired ? ` data-fg="${esc(paired)}"` : ""}` +
6241
+ ` style="background:${cssValue(hex)}${paired ? `;color:${cssValue(paired)}` : ""}">` +
6242
+ (paired ? `<span class="rfp-pair-sample">Aa</span><span class="rfp-pair-ratio"></span>` : "") +
6205
6243
  `</div><div class="rfp-pair-foot">${idButton(path, tokenName === null || tokenName === void 0 ? void 0 : tokenName(path))}` +
6206
- `<span class="rfp-hex">${esc(hex)}${text ? ` on ${esc(text)}` : ""}</span></div></div>`);
6244
+ `<span class="rfp-hex">${esc(hex)}${paired ? ` on ${esc(paired)}` : ""}</span></div></div>`);
6207
6245
  }
6208
6246
  }
6209
6247
  let html = "";
@@ -6211,7 +6249,7 @@ function renderPalette(leaves, tokenName) {
6211
6249
  html += plate("Families", `${ladders.length} · ${leaves.length} tokens`, ladders.join(""));
6212
6250
  }
6213
6251
  if (pairs.length) {
6214
- html += plate("Swatches", "contrast computed against each token's paired <code>text</code>", `<div class="rfp-pairs">${pairs.join("")}</div>`);
6252
+ html += plate("Swatches", "contrast scored only where a <code>text</code> pairing is declared — derived tints carry none", `<div class="rfp-pairs">${pairs.join("")}</div>`);
6215
6253
  }
6216
6254
  return html;
6217
6255
  }
@@ -6691,8 +6729,8 @@ const CHROME_CSS = `
6691
6729
  .rfp-rungs{display:flex;border-radius:6px;overflow:hidden;border:1px solid var(--rfp-rule)}
6692
6730
  .rfp-rung{flex:1 1 0;min-width:0}
6693
6731
  .rfp-rung-chip{height:52px}
6694
- .rfp-rung[data-base="true"] .rfp-rung-foot{color:var(--rfp-ink);font-weight:600}
6695
- .rfp-rung[data-base="true"] .rfp-rung-foot::before{content:" "}
6732
+ .rfp-rung[data-lands="true"] .rfp-rung-foot{color:var(--rfp-ink);font-weight:600}
6733
+ .rfp-rung[data-lands="true"] .rfp-rung-foot::before{content:" "}
6696
6734
  .rfp-rung-foot{padding:5px 2px 6px;text-align:center;background:var(--rfp-panel);border-top:1px solid var(--rfp-rule);
6697
6735
  font-family:var(--rfp-mono);font-size:10px;font-variant-numeric:tabular-nums;color:var(--rfp-ink-2)}
6698
6736
  .rfp-pairs{display:grid;grid-template-columns:repeat(auto-fill,minmax(184px,1fr));gap:12px}