@siyahi/tools 0.1.9-next.28 → 0.1.9-next.29

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/contrast.mjs CHANGED
@@ -23,13 +23,14 @@ import { readTheme } from "./theme.mjs";
23
23
  * What a component paints, written as Tailwind writes it:
24
24
  * `muted` is the token, `muted/50` the token at 50% over what lies under it,
25
25
  * and `positive@60` is `color-mix(in oklab, var(--positive) 60%, var(--card))`,
26
- * a treemap tile; `positive@heat-5` takes the share from the theme's --heat-5.
26
+ * a treemap tile; `positive@heat-5` and `negative/wash` take the share from the
27
+ * theme's --heat-5 or --wash.
27
28
  * @typedef {string} Paint
28
29
  */
29
30
  /**
30
31
  * `surface` limits a pair to the canvas or the card, for a paint only one of them ever holds, such as a chart card's
31
- * hover band.
32
- * @typedef {{ fg: Paint, bg: Paint, min: number, scheme?: Scheme, surface?: "background" | "card" }} Pair
32
+ * hover band. A list of paints for `bg` lays each over the one before, such as a footer band over an exception's wash.
33
+ * @typedef {{ fg: Paint, bg: Paint | Paint[], min: number, scheme?: Scheme, surface?: "background" | "card" }} Pair
33
34
  */
34
35
 
35
36
  const TEXT = 4.5;
@@ -103,6 +104,29 @@ const PAIRS = [
103
104
  // A StatusHeatmap's degraded and critical days against a healthy one, its
104
105
  // default 30% grey, so a bad day stands out of a run of good ones.
105
106
  ...["warning", "destructive"].map((fg) => ({ fg, bg: "muted-foreground/30", min: MARK })),
107
+ // An exception the page marks, washed in its tone at the theme's --wash. A
108
+ // stat tile mixes the tone into the card, opaque (`@wash`); a table row lays
109
+ // it over what is under it (`/wash`). On either: text, muted lines, a Delta
110
+ // icon and --chart-1 (a tile's Sparkline, a row's DataBar; a run of gains or
111
+ // losses takes --positive or --negative, as the SectionCards rule says). A
112
+ // tile's footer band sits over its wash, and a StatusBadge's dot on its own
113
+ // wash over a row's.
114
+ ...["negative@wash", "negative/wash", "warning@wash", "warning/wash"].flatMap((wash) => [
115
+ { fg: "foreground", bg: wash, min: TEXT },
116
+ { fg: "muted-foreground", bg: wash, min: TEXT },
117
+ { fg: "positive", bg: wash, min: MARK },
118
+ { fg: "negative", bg: wash, min: MARK },
119
+ { fg: "chart-1", bg: wash, min: MARK },
120
+ ]),
121
+ ...["negative", "warning"].map((tone) => ({
122
+ fg: "muted-foreground",
123
+ bg: [`${tone}@wash`, "muted/50"],
124
+ min: TEXT,
125
+ })),
126
+ ...[
127
+ ["negative", ["negative/wash", "negative/8"]],
128
+ ["warning", ["warning/wash", "warning/10"]],
129
+ ].map(([fg, bg]) => ({ fg: String(fg), bg: /** @type {Paint[]} */ (bg), min: MARK })),
106
130
  // The selected tab's fill against its list.
107
131
  { fg: "foreground", bg: "muted", min: MARK },
108
132
  // Chart marks on the canvas and the card. A dimmed bar keeps its full colour
@@ -151,13 +175,13 @@ export function checkContrast(theme) {
151
175
  const paintOver = (paint, under) => {
152
176
  const [, name = "", sep, amount = ""] = /^([\w-]+)(?:([/@])([\w.-]+))?$/.exec(paint) ?? [];
153
177
  const base = token(name);
178
+ // A share is a number, or the name of a theme token holding a percentage, such as heat-5.
179
+ const share = /^[\d.]+$/.test(amount) ? Number(amount) : sep ? percentage(amount) : 100;
154
180
  if (sep === "@") {
155
- // A share is a number, or the name of a theme token holding a percentage, such as heat-5.
156
- const share = /^[\d.]+$/.test(amount) ? Number(amount) : percentage(amount);
157
181
  const rgb = oklchToSrgb(mixOklab(base, token("card"), share / 100));
158
182
  return { rgb, name: `--${name} ${share}% in --card` };
159
183
  }
160
- const alpha = base.alpha * (sep === "/" ? Number(amount) / 100 : 1);
184
+ const alpha = (base.alpha * share) / 100;
161
185
  if (alpha === 1) return { rgb: oklchToSrgb(base), name: `--${paint}` };
162
186
  return { rgb: over({ ...base, alpha }, under.rgb), name: `--${paint} over ${under.name}` };
163
187
  };
@@ -166,7 +190,7 @@ export function checkContrast(theme) {
166
190
  for (const surface of SURFACES) {
167
191
  if (pair.surface && pair.surface !== surface) continue;
168
192
  const page = { rgb: oklchToSrgb(token(surface)), name: `--${surface}` };
169
- const bg = pair.bg ? paintOver(pair.bg, page) : page;
193
+ const bg = [pair.bg].flat().reduce((under, paint) => (paint ? paintOver(paint, under) : under), page);
170
194
  const fg = paintOver(pair.fg, bg);
171
195
  const [fgHex, bgHex] = [srgbHex(fg.rgb), srgbHex(bg.rgb)];
172
196
  const ratio = contrastSrgb(fg.rgb, bg.rgb);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siyahi/tools",
3
- "version": "0.1.9-next.28",
3
+ "version": "0.1.9-next.29",
4
4
  "description": "Checks and build helpers for Siyahi pages: a lint plugin, a font preload plugin, a theme contrast check, and screenshot and layout shift scripts.",
5
5
  "homepage": "https://siyahi.jatinbansal.com",
6
6
  "license": "MIT",
@@ -14,7 +14,7 @@ export type Check = {
14
14
  export type Paint = string;
15
15
  export type Pair = {
16
16
  fg: Paint;
17
- bg: Paint;
17
+ bg: Paint | Paint[];
18
18
  min: number;
19
19
  scheme?: Scheme;
20
20
  surface?: "background" | "card";