@7365admin1/layer-common 3.2.2-staging.182 → 3.2.2-staging.188

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.
@@ -1,4 +1,5 @@
1
1
  import assert from "node:assert/strict";
2
+ import { readFileSync } from "node:fs";
2
3
  import { test } from "node:test";
3
4
 
4
5
  import { DARK_THEME, LIGHT_THEME, PALETTE, type TPalette } from "./theme.ts";
@@ -505,9 +506,8 @@ test("the light palette is the handoff's, value for value", () => {
505
506
  */
506
507
  test("the light theme's sub-AA pairs measure exactly what the ledger says", () => {
507
508
  const EXPECTED: Record<string, number> = {
508
- "muted on a card (table header text, sub-lines)": 3.24,
509
+ "muted on a card (KPI sub-lines, field labels)": 3.24,
509
510
  "muted on the page background": 2.99,
510
- "muted on a table header band": 3.1,
511
511
  "muted on the sidebar": 3.13,
512
512
  "muted on a disabled control's hover fill": 2.71,
513
513
  "ok label on its own chip": 4.57,
@@ -548,8 +548,8 @@ test("the light theme's sub-AA pairs measure exactly what the ledger says", () =
548
548
  const failing = measured.filter((r) => !r.passes).length;
549
549
  assert.equal(
550
550
  failing,
551
- 8,
552
- `${failing} light pairs are below AA; the recorded, accepted count is 8. ` +
551
+ 7,
552
+ `${failing} light pairs are below AA; the recorded, accepted count is 7. ` +
553
553
  "If this moved, the owner's design-fidelity decision needs re-stating."
554
554
  );
555
555
  });
@@ -560,6 +560,90 @@ test("the dark theme has no sub-AA pairs at all", () => {
560
560
  assert.deepEqual(bad, [], "dark mode was exact AND compliant - keep it that way");
561
561
  });
562
562
 
563
+ /* ------------------------------------------------------------------ */
564
+ /* The two contrast fixes QA drove, asserted at the token level AND at */
565
+ /* the stylesheet that wires them. */
566
+ /* ------------------------------------------------------------------ */
567
+
568
+ /**
569
+ * A native `<select>`'s option list is painted by the browser. With no
570
+ * background of its own the option keeps the theme's ink over whatever the
571
+ * browser paints - white on Windows/Chrome - which is 1.14:1 in dark mode.
572
+ * The rule gives it `--card`/`--text`, the same pair the themed popover uses.
573
+ */
574
+ test("a native option's own fill carries the theme ink in both themes", () => {
575
+ for (const [name, p] of [["light", PALETTE.light], ["dark", PALETTE.dark]] as const) {
576
+ assert.ok(
577
+ contrast(p.text, p.card) >= 4.5,
578
+ `${name}: option ink on the card fill is ${contrast(p.text, p.card).toFixed(2)}:1`
579
+ );
580
+ }
581
+
582
+ // What the defect measured, so the number stays on the record.
583
+ assert.equal(Number(contrast(PALETTE.dark.text, "#ffffff").toFixed(2)), 1.14);
584
+ });
585
+
586
+ /**
587
+ * The table header. `--muted` measured 3.10:1 on the header band in light -
588
+ * below AA and reported by two apps' QA. `--text2` clears AA in both themes
589
+ * while staying clearly below the primary ink the data rows use, so the
590
+ * header still reads as secondary to the data.
591
+ */
592
+ test("the table header clears AA and still reads below the data", () => {
593
+ for (const [name, p, wash] of [
594
+ ["light", PALETTE.light, "#14161a"],
595
+ ["dark", PALETTE.dark, "#ffffff"],
596
+ ] as const) {
597
+ const band = over(wash, p.card, 0.02);
598
+ const header = contrast(p.text2, band);
599
+ const data = contrast(p.text, band);
600
+
601
+ assert.ok(header >= 4.5, `${name}: header is ${header.toFixed(2)}:1, below AA`);
602
+ assert.ok(
603
+ header < data,
604
+ `${name}: the header (${header.toFixed(2)}:1) must stay below the data ` +
605
+ `(${data.toFixed(2)}:1) or it stops reading as secondary`
606
+ );
607
+ assert.ok(
608
+ contrast(p.muted, band) < header,
609
+ `${name}: --text2 must be an improvement on the --muted it replaced`
610
+ );
611
+ }
612
+ });
613
+
614
+ /**
615
+ * The ratios above are the tokens'. They say nothing about whether the CSS
616
+ * still ASKS for them - a deleted rule would leave every number here passing.
617
+ * These two assertions are the wiring. Neither can measure a real computed
618
+ * style: that needs a browser, and the measured evidence for it is in the PR.
619
+ */
620
+ test("the stylesheets still ask for the tokens the two fixes chose", () => {
621
+ const css = (f: string) =>
622
+ readFileSync(new URL(`../assets/css/${f}`, import.meta.url), "utf8")
623
+ .replace(/\/\*[\s\S]*?\*\//g, "");
624
+
625
+ const primitives = css("primitives.css");
626
+ const optionRule = primitives.slice(primitives.indexOf("select option {"));
627
+ assert.ok(
628
+ primitives.includes("select option {"),
629
+ "the native <option> fill rule is gone - dark mode goes back to 1.14:1"
630
+ );
631
+ const optionBody = optionRule.slice(0, optionRule.indexOf("}"));
632
+ assert.ok(
633
+ optionBody.includes("background-color: var(--card)"),
634
+ "the option lost its own fill, which is the whole defect"
635
+ );
636
+ assert.ok(optionBody.includes("color: var(--text)"), "the option lost its ink");
637
+
638
+ const screens = css("screens.css");
639
+ const header = screens.slice(screens.indexOf(".table-card thead th {"));
640
+ const headerBody = header.slice(0, header.indexOf("}"));
641
+ assert.ok(
642
+ headerBody.includes("color: var(--text2) !important"),
643
+ "the table header is back on a token that does not clear AA in light"
644
+ );
645
+ });
646
+
563
647
  /**
564
648
  * THE BRIDGE. Every design token in `assets/css/tokens.css` is an alias onto a
565
649
  * `--v-theme-*`, so a token whose Vuetify colour does not exist resolves to