@stigmer/theme 3.1.8 → 3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stigmer/theme",
3
- "version": "3.1.8",
3
+ "version": "3.1.10",
4
4
  "description": "Design tokens, CSS custom properties, and utility functions for Stigmer UI components",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -77,7 +77,10 @@
77
77
  --stgm-accent: oklch(0.25 0 0);
78
78
  --stgm-accent-foreground: oklch(0.96 0 0);
79
79
  --stgm-border: oklch(0.27 0 0);
80
- --stgm-input: oklch(0.27 0 0);
80
+ /* Sits above border: --stgm-input also fills the Switch off-track, which
81
+ must clear the surface-separation floor against popover (0.24) — see the
82
+ contract surface pair in contract/pairs.ts. */
83
+ --stgm-input: oklch(0.32 0 0);
81
84
  --stgm-input-bg: oklch(0.21 0 0);
82
85
  --stgm-ring: oklch(0.96 0 0);
83
86
  --stgm-chart-1: oklch(0.85 0 0);
@@ -48,6 +48,19 @@ describe("lightnessDelta", () => {
48
48
  expect(lightnessDelta("oklch(0.21 0 0)", "oklch(0.145 0 0)")).toBeCloseTo(0.065, 3);
49
49
  expect(lightnessDelta("white", "white")).toBeCloseTo(0, 5);
50
50
  });
51
+
52
+ it("composites a translucent fill over the surface first", () => {
53
+ // The default dark --stgm-input (20% white) over the popover surface:
54
+ // raw white would report a delta near 0.73; the painted fill is far
55
+ // dimmer but still clearly separated.
56
+ const delta = lightnessDelta("oklch(1 0 0 / 20%)", "oklch(0.269 0 0)");
57
+ expect(delta).toBeGreaterThan(0.045);
58
+ expect(delta).toBeLessThan(0.5);
59
+ });
60
+
61
+ it("rejects a translucent surface (nothing to composite onto)", () => {
62
+ expect(() => lightnessDelta("white", "oklch(1 0 0 / 14%)")).toThrow(/opaque surface/);
63
+ });
51
64
  });
52
65
 
53
66
  describe("isColorValue", () => {
@@ -70,10 +70,24 @@ export function contrastRatio(
70
70
  }
71
71
 
72
72
  /**
73
- * Perceptual lightness difference (OKLCH L, 0..1) between two opaque token
74
- * values. Used for surface-separation checks where WCAG has no defined
75
- * threshold.
73
+ * Perceptual lightness difference (OKLCH L, 0..1) between a fill and the
74
+ * surface it renders over. Used for surface-separation checks where WCAG
75
+ * has no defined threshold.
76
+ *
77
+ * A translucent fill (e.g. the default dark `--stgm-input: oklch(1 0 0 / 20%)`)
78
+ * is composited over the surface first, so the delta measures what the user
79
+ * actually sees — a raw translucent white would otherwise report L=1. The
80
+ * surface must be opaque; a translucent surface would itself need a backdrop
81
+ * to resolve, and no declared surface pair renders on one (caller error,
82
+ * matching {@link contrastRatio}'s posture).
76
83
  */
77
- export function lightnessDelta(valueA: string, valueB: string): number {
78
- return Math.abs(toOklch(parseColor(valueA)).l - toOklch(parseColor(valueB)).l);
84
+ export function lightnessDelta(fillValue: string, surfaceValue: string): number {
85
+ const surface = parseColor(surfaceValue);
86
+ if ((surface.alpha ?? 1) < 1) {
87
+ throw new Error(
88
+ `Surface "${surfaceValue}" is translucent — surface pairs must render on an opaque surface`,
89
+ );
90
+ }
91
+ const fill = compositeOver(parseColor(fillValue), surface);
92
+ return Math.abs(toOklch(fill).l - toOklch(surface).l);
79
93
  }
@@ -167,4 +167,6 @@ export const CONTRAST_PAIRS: readonly ContrastPair[] = [
167
167
  export const SURFACE_PAIRS: readonly ContrastPair[] = [
168
168
  pair("--stgm-muted-subtle", "--stgm-background", "surface", "user message bubble on thread background (borderless)", ["dark"]),
169
169
  pair("--stgm-muted", "--stgm-background", "surface", "code blocks, muted panels on the page (borderless)", ["dark"]),
170
+ pair("--stgm-input", "--stgm-popover", "surface", "Switch off-state track on dialog surface (ShareAgentDialog)", ["dark"]),
171
+ pair("--stgm-primary", "--stgm-popover", "surface", "Switch on-state track on dialog surface (ShareAgentDialog)", ["dark"]),
170
172
  ];
@@ -77,7 +77,10 @@
77
77
  --stgm-accent: oklch(0.25 0 0);
78
78
  --stgm-accent-foreground: oklch(0.96 0 0);
79
79
  --stgm-border: oklch(0.27 0 0);
80
- --stgm-input: oklch(0.27 0 0);
80
+ /* Sits above border: --stgm-input also fills the Switch off-track, which
81
+ must clear the surface-separation floor against popover (0.24) — see the
82
+ contract surface pair in contract/pairs.ts. */
83
+ --stgm-input: oklch(0.32 0 0);
81
84
  --stgm-input-bg: oklch(0.21 0 0);
82
85
  --stgm-ring: oklch(0.96 0 0);
83
86
  --stgm-chart-1: oklch(0.85 0 0);