@wix/himalaya-cli 0.1051.0 → 0.1052.0

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.
Files changed (2) hide show
  1. package/dist/cli.mjs +238 -181
  2. package/package.json +2 -2
package/dist/cli.mjs CHANGED
@@ -5603,7 +5603,6 @@ function walk(node, registry, path2, out) {
5603
5603
  var SYSTEM_FONT_FAMILY, TONAL_ELEVATION_ALPHA;
5604
5604
  var init_tokens = __esm({
5605
5605
  "../../core/ts/src/tokens.ts"() {
5606
- "use strict";
5607
5606
  SYSTEM_FONT_FAMILY = "$system";
5608
5607
  TONAL_ELEVATION_ALPHA = [0, 0.05, 0.08, 0.11, 0.12, 0.14];
5609
5608
  }
@@ -5630,7 +5629,6 @@ function resolveTranslation(value, catalog, sourceCatalog) {
5630
5629
  var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
5631
5630
  var init_bindings = __esm({
5632
5631
  "../../core/ts/src/bindings.ts"() {
5633
- "use strict";
5634
5632
  BINDING_SIGILS = ["service", "flag", "item", "t"];
5635
5633
  BINDING_SIGIL_RE = new RegExp(
5636
5634
  `^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
@@ -11371,6 +11369,177 @@ var init_idiom = __esm({
11371
11369
  }
11372
11370
  });
11373
11371
 
11372
+ // ../../core/ts/src/brand-color-math.ts
11373
+ function channel2(hex2, offset) {
11374
+ return Number.parseInt(hex2.slice(offset, offset + 2), 16);
11375
+ }
11376
+ function toHex(r, g, b) {
11377
+ return `#${[r, g, b].map((value) => Math.round(value).toString(16).padStart(2, "0")).join("")}`.toUpperCase();
11378
+ }
11379
+ function mix(color, background, colorWeight) {
11380
+ const values = [1, 3, 5].map((offset) => channel2(color, offset) * colorWeight + channel2(background, offset) * (1 - colorWeight));
11381
+ return toHex(values[0], values[1], values[2]);
11382
+ }
11383
+ function relativeLuminance2(color) {
11384
+ const linear = [1, 3, 5].map((offset) => {
11385
+ const value = channel2(color, offset) / 255;
11386
+ return value <= 0.03928 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
11387
+ });
11388
+ return 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2];
11389
+ }
11390
+ function contrastRatio2(a, b) {
11391
+ const la = relativeLuminance2(a);
11392
+ const lb = relativeLuminance2(b);
11393
+ return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
11394
+ }
11395
+ function lstar(color) {
11396
+ const y = relativeLuminance2(color);
11397
+ return y <= 8856e-6 ? y * 903.3 : 116 * Math.cbrt(y) - 16;
11398
+ }
11399
+ function deriveAccentSurface(accent, surface, weight) {
11400
+ const tint = mix(accent, surface, weight);
11401
+ if (contrastRatio2(tint, surface) >= ACCENT_SURFACE_MIN_DELTA) return tint;
11402
+ const away = relativeLuminance2(surface) < 0.5 ? "#FFFFFF" : "#000000";
11403
+ for (let w = 0.02; w <= 0.5; w += 0.02) {
11404
+ const candidate = mix(away, surface, w);
11405
+ if (contrastRatio2(candidate, surface) >= ACCENT_SURFACE_MIN_DELTA) return candidate;
11406
+ }
11407
+ return tint;
11408
+ }
11409
+ function deriveSecondaryAccent(primary) {
11410
+ const shade2 = mix(primary, "#000000", SECONDARY_SHADE_WEIGHT);
11411
+ if (lstar(shade2) >= SECONDARY_MIN_LSTAR) return shade2;
11412
+ return mix(primary, "#FFFFFF", SECONDARY_SHADE_WEIGHT);
11413
+ }
11414
+ function textOn(color) {
11415
+ const luminance2 = relativeLuminance2(color);
11416
+ const whiteContrast = 1.05 / (luminance2 + 0.05);
11417
+ const blackContrast = (luminance2 + 0.05) / 0.05;
11418
+ return whiteContrast >= blackContrast ? "#FFFFFF" : "#000000";
11419
+ }
11420
+ function tuneDarkAccent(brand, darkSurface, lightSurface) {
11421
+ const kitInherentlyDark = lstar(lightSurface) < 50;
11422
+ if (kitInherentlyDark && contrastRatio2(brand, darkSurface) >= DARK_ARM_TARGET_CONTRAST && lstar(brand) <= DARK_ARM_LSTAR_CAP) {
11423
+ return brand;
11424
+ }
11425
+ let lift = DARK_ARM_MIN_LIFT;
11426
+ let candidate = mix(brand, "#FFFFFF", 1 - lift);
11427
+ while (contrastRatio2(candidate, darkSurface) < DARK_ARM_TARGET_CONTRAST && lift < 0.6) {
11428
+ lift += 0.04;
11429
+ candidate = mix(brand, "#FFFFFF", 1 - lift);
11430
+ }
11431
+ while (lstar(candidate) > DARK_ARM_LSTAR_CAP) {
11432
+ const darker = mix(candidate, "#000000", 0.94);
11433
+ if (contrastRatio2(darker, darkSurface) < DARK_ARM_FLOOR_CONTRAST) break;
11434
+ candidate = darker;
11435
+ }
11436
+ return candidate;
11437
+ }
11438
+ function textOnArm(accent) {
11439
+ return contrastRatio2("#FFFFFF", accent) >= 4.5 ? "#FFFFFF" : textOn(accent);
11440
+ }
11441
+ function tuneHighContrastAccent(brand, surface) {
11442
+ const towards = relativeLuminance2(surface) < 0.5 ? "#FFFFFF" : "#000000";
11443
+ let candidate = brand;
11444
+ for (let lift = 0; lift <= 0.9 && contrastRatio2(candidate, surface) < HIGH_CONTRAST_TARGET; lift += 0.04) {
11445
+ candidate = mix(brand, towards, 1 - lift);
11446
+ }
11447
+ return candidate;
11448
+ }
11449
+ function deriveAccentText(accent, surfaces) {
11450
+ const all = (typeof surfaces === "string" ? [surfaces] : [...surfaces]).map((s) => s.slice(0, 7));
11451
+ const page = all[0];
11452
+ const worst = (color) => Math.min(...all.map((s) => contrastRatio2(color, s)));
11453
+ const opaque = accent.length === 9 ? mix(accent.slice(0, 7), page, channel2(accent, 7) / 255) : accent;
11454
+ if (worst(opaque) >= ACCENT_TEXT_MIN_CONTRAST) return opaque;
11455
+ const pole = worst("#FFFFFF") >= worst("#000000") ? "#FFFFFF" : "#000000";
11456
+ for (let step = 1; step <= 100; step++) {
11457
+ const candidate = mix(pole, opaque, step / 100);
11458
+ if (worst(candidate) >= ACCENT_TEXT_MIN_CONTRAST) return candidate;
11459
+ }
11460
+ if (all.length > 1) {
11461
+ const side2 = (hex2) => relativeLuminance2(hex2) > MID_GREY_LUMINANCE;
11462
+ const sameSide = all.filter((s) => side2(s) === side2(page));
11463
+ return deriveAccentText(accent, sameSide.length < all.length ? sameSide : [page]);
11464
+ }
11465
+ return pole;
11466
+ }
11467
+ function textSurfacesOf(colors) {
11468
+ const out = { light: [], dark: [], highContrast: [] };
11469
+ for (const name of TEXT_BACKDROP_TOKENS) {
11470
+ const value = colors[name];
11471
+ for (const arm of ["light", "dark", "highContrast"]) {
11472
+ const hex2 = typeof value === "string" ? value : value && typeof value === "object" && !Array.isArray(value) ? value[arm] ?? value.light : void 0;
11473
+ if (typeof hex2 === "string" && hex2.startsWith("#") && hex2.length >= 7) out[arm].push(hex2);
11474
+ }
11475
+ }
11476
+ return out;
11477
+ }
11478
+ function stripBrandFromIdiom(tokens) {
11479
+ const idiom = tokens.idiom;
11480
+ if (!idiom || typeof idiom !== "object" || Array.isArray(idiom)) return;
11481
+ for (const overlay of Object.values(idiom)) {
11482
+ if (!overlay || typeof overlay !== "object" || Array.isArray(overlay)) continue;
11483
+ const o = overlay;
11484
+ const colors = o.colors;
11485
+ if (colors && typeof colors === "object" && !Array.isArray(colors)) {
11486
+ for (const key2 of BRAND_COLOR_TOKENS) delete colors[key2];
11487
+ if (Object.keys(colors).length === 0) delete o.colors;
11488
+ }
11489
+ const shadows = o.shadows;
11490
+ const glow = shadows && typeof shadows === "object" && !Array.isArray(shadows) ? shadows[BRAND_GLOW_SHADOW] : void 0;
11491
+ if (glow && typeof glow === "object" && !Array.isArray(glow) && "color" in glow) {
11492
+ delete glow.color;
11493
+ if (Object.keys(glow).length === 0) delete shadows[BRAND_GLOW_SHADOW];
11494
+ if (Object.keys(shadows).length === 0) delete o.shadows;
11495
+ }
11496
+ }
11497
+ }
11498
+ function deriveAccentFamily(primary, secondary, surfaces, textSurfaces = {}) {
11499
+ const primaryDark = tuneDarkAccent(primary, surfaces.dark, surfaces.light);
11500
+ const secondaryDark = tuneDarkAccent(secondary, surfaces.dark, surfaces.light);
11501
+ const primaryHigh = tuneHighContrastAccent(primary, surfaces.highContrast);
11502
+ const secondaryHigh = tuneHighContrastAccent(secondary, surfaces.highContrast);
11503
+ return {
11504
+ accentPrimary: { light: primary, dark: primaryDark, highContrast: primaryHigh },
11505
+ accentSecondary: { light: secondary, dark: secondaryDark, highContrast: secondaryHigh },
11506
+ accentSurface: {
11507
+ light: deriveAccentSurface(primary, surfaces.light, ACCENT_SURFACE_LIGHT_WEIGHT),
11508
+ dark: deriveAccentSurface(primaryDark, surfaces.dark, 0.24),
11509
+ highContrast: deriveAccentSurface(primaryHigh, surfaces.highContrast, 0.24)
11510
+ },
11511
+ textOnAccent: {
11512
+ light: textOnArm(primary),
11513
+ dark: textOnArm(primaryDark),
11514
+ highContrast: textOn(primaryHigh)
11515
+ },
11516
+ accentText: {
11517
+ light: deriveAccentText(primary, [surfaces.light, ...textSurfaces.light ?? []]),
11518
+ dark: deriveAccentText(primaryDark, [surfaces.dark, ...textSurfaces.dark ?? []]),
11519
+ highContrast: deriveAccentText(primaryHigh, [surfaces.highContrast, ...textSurfaces.highContrast ?? []])
11520
+ }
11521
+ };
11522
+ }
11523
+ var ACCENT_SURFACE_MIN_DELTA, ACCENT_SURFACE_LIGHT_WEIGHT, SECONDARY_SHADE_WEIGHT, SECONDARY_MIN_LSTAR, DARK_ARM_MIN_LIFT, DARK_ARM_TARGET_CONTRAST, DARK_ARM_FLOOR_CONTRAST, DARK_ARM_LSTAR_CAP, HIGH_CONTRAST_TARGET, ACCENT_TEXT_MIN_CONTRAST, MID_GREY_LUMINANCE, TEXT_BACKDROP_TOKENS, BRAND_COLOR_TOKENS, BRAND_GLOW_SHADOW;
11524
+ var init_brand_color_math = __esm({
11525
+ "../../core/ts/src/brand-color-math.ts"() {
11526
+ ACCENT_SURFACE_MIN_DELTA = 1.08;
11527
+ ACCENT_SURFACE_LIGHT_WEIGHT = 0.12;
11528
+ SECONDARY_SHADE_WEIGHT = 0.72;
11529
+ SECONDARY_MIN_LSTAR = 22;
11530
+ DARK_ARM_MIN_LIFT = 0.08;
11531
+ DARK_ARM_TARGET_CONTRAST = 3.4;
11532
+ DARK_ARM_FLOOR_CONTRAST = 3;
11533
+ DARK_ARM_LSTAR_CAP = 80;
11534
+ HIGH_CONTRAST_TARGET = 8.5;
11535
+ ACCENT_TEXT_MIN_CONTRAST = 4.5;
11536
+ MID_GREY_LUMINANCE = 0.179;
11537
+ TEXT_BACKDROP_TOKENS = ["surfaceSecondary", "surfaceElevated", "surfaceSubtle", "surfaceTertiary"];
11538
+ BRAND_COLOR_TOKENS = ["accentPrimary", "accentSecondary", "accentSurface", "textOnAccent", "accentText"];
11539
+ BRAND_GLOW_SHADOW = "glow";
11540
+ }
11541
+ });
11542
+
11374
11543
  // src/token-lint.ts
11375
11544
  import { existsSync as existsSync13, readFileSync as readFileSync14 } from "node:fs";
11376
11545
  import { join as join16 } from "node:path";
@@ -11537,13 +11706,71 @@ function contrastFindings(colors) {
11537
11706
  });
11538
11707
  }
11539
11708
  }
11709
+ accentOnSurfaces(colors, declared, findings);
11540
11710
  return [...findings.values()];
11541
11711
  }
11542
- var AA_TEXT, CONTRAST_PAIRS, SCHEMES, channels, toHex, mixHex;
11712
+ function sameHueClearingAll(fg, bgs, target = AA_TEXT) {
11713
+ const base = fg.slice(0, 7);
11714
+ const poles = onLightSide(bgs[0]) ? ["#000000", "#FFFFFF"] : ["#FFFFFF", "#000000"];
11715
+ for (let step = 0; step <= 100; step++) {
11716
+ for (const pole of poles) {
11717
+ const candidate = mixHex(base, pole, 1 - step / 100);
11718
+ if (bgs.every((bg) => contrastRatio(candidate, bg) >= target)) return candidate;
11719
+ }
11720
+ }
11721
+ return void 0;
11722
+ }
11723
+ function accentOnSurfaces(colors, declared, findings) {
11724
+ const hasAccentText = colors.accentText !== void 0;
11725
+ for (const fgName of hasAccentText ? ["accentText", "accentPrimary"] : ["accentPrimary"]) {
11726
+ if (colors[fgName] === void 0) continue;
11727
+ const role = fgName === "accentText" ? "the colour of accent text" : hasAccentText ? "still the colour of some accent text (the selected Tabs label on web, rich-text links on Android)" : "the colour of accent text (no accentText is declared, so accent text is painted with accentPrimary)";
11728
+ accentOnSurfacesFor(fgName, role, colors, declared, findings);
11729
+ }
11730
+ }
11731
+ function accentOnSurfacesFor(fgName, role, colors, declared, findings) {
11732
+ for (const surface of TEXT_BACKDROP_TOKENS) {
11733
+ if (colors[surface] === void 0) continue;
11734
+ for (const scheme of SCHEMES) {
11735
+ if (!declared.has(scheme)) continue;
11736
+ const fg = schemeValue(colors[fgName], scheme);
11737
+ const bg = schemeValue(colors[surface], scheme);
11738
+ if (!fg || !bg) continue;
11739
+ const painted = paintedOver(fg, bg);
11740
+ if (!painted) continue;
11741
+ const pageRaw = schemeValue(colors.surfacePrimary, scheme);
11742
+ const page = pageRaw && paintedOver(fg, pageRaw) ? pageRaw.slice(0, 7) : void 0;
11743
+ const opaqueBg = bg.slice(0, 7);
11744
+ if (page === opaqueBg) continue;
11745
+ if (page && contrastRatio(paintedOver(fg, pageRaw), page) < AA_TEXT) continue;
11746
+ const ratio = contrastRatio(painted, opaqueBg);
11747
+ if (ratio >= AA_TEXT) continue;
11748
+ const key2 = `${fgName}|${surface}|${fg}|${bg}|${page ?? ""}`;
11749
+ const same2 = findings.get(key2);
11750
+ if (same2) {
11751
+ same2.schemes.push(scheme);
11752
+ continue;
11753
+ }
11754
+ const opposite = page !== void 0 && onLightSide(page) !== onLightSide(opaqueBg);
11755
+ const noSingle = page !== void 0 && opposite && contrastRatio(page, opaqueBg) < AA_TEXT * AA_TEXT;
11756
+ const suggestion = noSingle ? void 0 : sameHueClearingAll(painted, page ? [page, opaqueBg] : [opaqueBg]);
11757
+ const measured = (c) => page ? `${contrastRatio(c, opaqueBg).toFixed(2)}:1 on ${surface}, ${contrastRatio(c, page).toFixed(2)}:1 on surfacePrimary` : `${contrastRatio(c, opaqueBg).toFixed(2)}:1`;
11758
+ const restructure = ` Move ${surface} to the page's side of mid-grey (a ${page && onLightSide(page) ? "light" : "dark"} ${surface} on this page), or scope an explicit accent for that section with \`modifiers.theme\` (e.g. { "colors": { "accentText": "#RRGGBB" } } on the card).`;
11759
+ const fix = noSingle ? ` surfacePrimary (${page}) and ${surface} (${opaqueBg}) sit on opposite sides of mid-grey, so no single accent text colour can clear ${AA_TEXT}:1 on both.${restructure}` : suggestion ? ` A same-hue ${fgName} that clears it${page ? " and the page" : ""} is ${suggestion} (${measured(suggestion)}).` + (opposite ? ` The page and ${surface} sit on opposite sides of mid-grey, so only a narrow mid-tone clears both.${restructure}` : "") : ` No ${fgName} of this hue clears ${AA_TEXT}:1 on ${surface}${page ? " and the page" : ""}.` + (opposite ? restructure : "");
11760
+ findings.set(key2, {
11761
+ key: key2,
11762
+ schemes: [scheme],
11763
+ render: (schemes) => `colors.${fgName} (${fg}) on colors.${surface} (${bg}) is ${ratio.toFixed(2)}:1 in ${schemes.join(" / ")} \u2014 below the WCAG AA ${AA_TEXT}:1 for text. ${fgName} is ${role}, and a transparent label \u2014 a plain or link button, an inline action \u2014 has no background of its own, so inside a card or sheet it is read against ${surface}, not the page.${fix}`
11764
+ });
11765
+ }
11766
+ }
11767
+ }
11768
+ var AA_TEXT, CONTRAST_PAIRS, SCHEMES, channels, toHex2, mixHex, onLightSide;
11543
11769
  var init_token_lint = __esm({
11544
11770
  "src/token-lint.ts"() {
11545
11771
  init_token_colors();
11546
11772
  init_idiom();
11773
+ init_brand_color_math();
11547
11774
  AA_TEXT = 4.5;
11548
11775
  CONTRAST_PAIRS = [
11549
11776
  {
@@ -11559,11 +11786,12 @@ var init_token_lint = __esm({
11559
11786
  ];
11560
11787
  SCHEMES = ["light", "dark", "highContrast"];
11561
11788
  channels = (hex2) => [1, 3, 5].map((i) => parseInt(hex2.slice(i, i + 2), 16));
11562
- toHex = (rgb) => `#${rgb.map((c) => Math.round(Math.min(255, Math.max(0, c))).toString(16).padStart(2, "0")).join("")}`.toUpperCase();
11789
+ toHex2 = (rgb) => `#${rgb.map((c) => Math.round(Math.min(255, Math.max(0, c))).toString(16).padStart(2, "0")).join("")}`.toUpperCase();
11563
11790
  mixHex = (a, b, w) => {
11564
11791
  const [ca, cb] = [channels(a), channels(b)];
11565
- return toHex(ca.map((c, i) => c * w + cb[i] * (1 - w)));
11792
+ return toHex2(ca.map((c, i) => c * w + cb[i] * (1 - w)));
11566
11793
  };
11794
+ onLightSide = (hex2) => contrastRatio("#000000", hex2) >= contrastRatio("#FFFFFF", hex2);
11567
11795
  }
11568
11796
  });
11569
11797
 
@@ -12332,7 +12560,7 @@ function luminance([r, g, b]) {
12332
12560
  });
12333
12561
  return 0.2126 * lin[0] + 0.7152 * lin[1] + 0.0722 * lin[2];
12334
12562
  }
12335
- function contrastRatio2(a, b) {
12563
+ function contrastRatio3(a, b) {
12336
12564
  const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
12337
12565
  return (hi + 0.05) / (lo + 0.05);
12338
12566
  }
@@ -12341,11 +12569,11 @@ async function contrastingBackdrop(mark, requested) {
12341
12569
  const { dominant } = await sharp(mark).stats();
12342
12570
  const ink = [dominant.r, dominant.g, dominant.b];
12343
12571
  const want = hexToRgb(requested);
12344
- if (!want || contrastRatio2(ink, want) >= MIN_BACKDROP_CONTRAST) return requested;
12572
+ if (!want || contrastRatio3(ink, want) >= MIN_BACKDROP_CONTRAST) return requested;
12345
12573
  const towardsWhite = luminance(ink) < 0.5;
12346
12574
  for (const amount of [0.35, 0.55, 0.75, 0.9]) {
12347
- const candidate = mix(want, towardsWhite ? [255, 255, 255] : [0, 0, 0], amount);
12348
- if (contrastRatio2(ink, candidate) >= MIN_BACKDROP_CONTRAST) return rgbToHex(candidate);
12575
+ const candidate = mix2(want, towardsWhite ? [255, 255, 255] : [0, 0, 0], amount);
12576
+ if (contrastRatio3(ink, candidate) >= MIN_BACKDROP_CONTRAST) return rgbToHex(candidate);
12349
12577
  }
12350
12578
  return towardsWhite ? "#FFFFFF" : "#000000";
12351
12579
  }
@@ -12355,7 +12583,7 @@ function hexToRgb(hex2) {
12355
12583
  const n = parseInt(m[1], 16);
12356
12584
  return [n >> 16 & 255, n >> 8 & 255, n & 255];
12357
12585
  }
12358
- function mix(a, b, t) {
12586
+ function mix2(a, b, t) {
12359
12587
  return [0, 1, 2].map((i) => Math.round(a[i] + (b[i] - a[i]) * t));
12360
12588
  }
12361
12589
  function rgbToHex([r, g, b]) {
@@ -54671,177 +54899,6 @@ var init_tokens3 = __esm({
54671
54899
  }
54672
54900
  });
54673
54901
 
54674
- // ../../core/ts/src/brand-color-math.ts
54675
- function channel2(hex2, offset) {
54676
- return Number.parseInt(hex2.slice(offset, offset + 2), 16);
54677
- }
54678
- function toHex2(r, g, b) {
54679
- return `#${[r, g, b].map((value) => Math.round(value).toString(16).padStart(2, "0")).join("")}`.toUpperCase();
54680
- }
54681
- function mix2(color, background, colorWeight) {
54682
- const values = [1, 3, 5].map((offset) => channel2(color, offset) * colorWeight + channel2(background, offset) * (1 - colorWeight));
54683
- return toHex2(values[0], values[1], values[2]);
54684
- }
54685
- function relativeLuminance2(color) {
54686
- const linear = [1, 3, 5].map((offset) => {
54687
- const value = channel2(color, offset) / 255;
54688
- return value <= 0.03928 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
54689
- });
54690
- return 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2];
54691
- }
54692
- function contrastRatio3(a, b) {
54693
- const la = relativeLuminance2(a);
54694
- const lb = relativeLuminance2(b);
54695
- return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
54696
- }
54697
- function lstar(color) {
54698
- const y = relativeLuminance2(color);
54699
- return y <= 8856e-6 ? y * 903.3 : 116 * Math.cbrt(y) - 16;
54700
- }
54701
- function deriveAccentSurface(accent, surface, weight) {
54702
- const tint = mix2(accent, surface, weight);
54703
- if (contrastRatio3(tint, surface) >= ACCENT_SURFACE_MIN_DELTA) return tint;
54704
- const away = relativeLuminance2(surface) < 0.5 ? "#FFFFFF" : "#000000";
54705
- for (let w = 0.02; w <= 0.5; w += 0.02) {
54706
- const candidate = mix2(away, surface, w);
54707
- if (contrastRatio3(candidate, surface) >= ACCENT_SURFACE_MIN_DELTA) return candidate;
54708
- }
54709
- return tint;
54710
- }
54711
- function deriveSecondaryAccent(primary) {
54712
- const shade2 = mix2(primary, "#000000", SECONDARY_SHADE_WEIGHT);
54713
- if (lstar(shade2) >= SECONDARY_MIN_LSTAR) return shade2;
54714
- return mix2(primary, "#FFFFFF", SECONDARY_SHADE_WEIGHT);
54715
- }
54716
- function textOn(color) {
54717
- const luminance2 = relativeLuminance2(color);
54718
- const whiteContrast = 1.05 / (luminance2 + 0.05);
54719
- const blackContrast = (luminance2 + 0.05) / 0.05;
54720
- return whiteContrast >= blackContrast ? "#FFFFFF" : "#000000";
54721
- }
54722
- function tuneDarkAccent(brand, darkSurface, lightSurface) {
54723
- const kitInherentlyDark = lstar(lightSurface) < 50;
54724
- if (kitInherentlyDark && contrastRatio3(brand, darkSurface) >= DARK_ARM_TARGET_CONTRAST && lstar(brand) <= DARK_ARM_LSTAR_CAP) {
54725
- return brand;
54726
- }
54727
- let lift = DARK_ARM_MIN_LIFT;
54728
- let candidate = mix2(brand, "#FFFFFF", 1 - lift);
54729
- while (contrastRatio3(candidate, darkSurface) < DARK_ARM_TARGET_CONTRAST && lift < 0.6) {
54730
- lift += 0.04;
54731
- candidate = mix2(brand, "#FFFFFF", 1 - lift);
54732
- }
54733
- while (lstar(candidate) > DARK_ARM_LSTAR_CAP) {
54734
- const darker = mix2(candidate, "#000000", 0.94);
54735
- if (contrastRatio3(darker, darkSurface) < DARK_ARM_FLOOR_CONTRAST) break;
54736
- candidate = darker;
54737
- }
54738
- return candidate;
54739
- }
54740
- function textOnArm(accent) {
54741
- return contrastRatio3("#FFFFFF", accent) >= 4.5 ? "#FFFFFF" : textOn(accent);
54742
- }
54743
- function tuneHighContrastAccent(brand, surface) {
54744
- const towards = relativeLuminance2(surface) < 0.5 ? "#FFFFFF" : "#000000";
54745
- let candidate = brand;
54746
- for (let lift = 0; lift <= 0.9 && contrastRatio3(candidate, surface) < HIGH_CONTRAST_TARGET; lift += 0.04) {
54747
- candidate = mix2(brand, towards, 1 - lift);
54748
- }
54749
- return candidate;
54750
- }
54751
- function deriveAccentText(accent, surfaces) {
54752
- const all = (typeof surfaces === "string" ? [surfaces] : [...surfaces]).map((s) => s.slice(0, 7));
54753
- const page = all[0];
54754
- const worst = (color) => Math.min(...all.map((s) => contrastRatio3(color, s)));
54755
- const opaque = accent.length === 9 ? mix2(accent.slice(0, 7), page, channel2(accent, 7) / 255) : accent;
54756
- if (worst(opaque) >= ACCENT_TEXT_MIN_CONTRAST) return opaque;
54757
- const pole = worst("#FFFFFF") >= worst("#000000") ? "#FFFFFF" : "#000000";
54758
- for (let step = 1; step <= 100; step++) {
54759
- const candidate = mix2(pole, opaque, step / 100);
54760
- if (worst(candidate) >= ACCENT_TEXT_MIN_CONTRAST) return candidate;
54761
- }
54762
- if (all.length > 1) {
54763
- const side2 = (hex2) => relativeLuminance2(hex2) > MID_GREY_LUMINANCE;
54764
- const sameSide = all.filter((s) => side2(s) === side2(page));
54765
- return deriveAccentText(accent, sameSide.length < all.length ? sameSide : [page]);
54766
- }
54767
- return pole;
54768
- }
54769
- function textSurfacesOf(colors) {
54770
- const out = { light: [], dark: [], highContrast: [] };
54771
- for (const name of TEXT_BACKDROP_TOKENS) {
54772
- const value = colors[name];
54773
- for (const arm of ["light", "dark", "highContrast"]) {
54774
- const hex2 = typeof value === "string" ? value : value && typeof value === "object" && !Array.isArray(value) ? value[arm] ?? value.light : void 0;
54775
- if (typeof hex2 === "string" && hex2.startsWith("#") && hex2.length >= 7) out[arm].push(hex2);
54776
- }
54777
- }
54778
- return out;
54779
- }
54780
- function stripBrandFromIdiom(tokens) {
54781
- const idiom = tokens.idiom;
54782
- if (!idiom || typeof idiom !== "object" || Array.isArray(idiom)) return;
54783
- for (const overlay of Object.values(idiom)) {
54784
- if (!overlay || typeof overlay !== "object" || Array.isArray(overlay)) continue;
54785
- const o = overlay;
54786
- const colors = o.colors;
54787
- if (colors && typeof colors === "object" && !Array.isArray(colors)) {
54788
- for (const key2 of BRAND_COLOR_TOKENS) delete colors[key2];
54789
- if (Object.keys(colors).length === 0) delete o.colors;
54790
- }
54791
- const shadows = o.shadows;
54792
- const glow = shadows && typeof shadows === "object" && !Array.isArray(shadows) ? shadows[BRAND_GLOW_SHADOW] : void 0;
54793
- if (glow && typeof glow === "object" && !Array.isArray(glow) && "color" in glow) {
54794
- delete glow.color;
54795
- if (Object.keys(glow).length === 0) delete shadows[BRAND_GLOW_SHADOW];
54796
- if (Object.keys(shadows).length === 0) delete o.shadows;
54797
- }
54798
- }
54799
- }
54800
- function deriveAccentFamily(primary, secondary, surfaces, textSurfaces = {}) {
54801
- const primaryDark = tuneDarkAccent(primary, surfaces.dark, surfaces.light);
54802
- const secondaryDark = tuneDarkAccent(secondary, surfaces.dark, surfaces.light);
54803
- const primaryHigh = tuneHighContrastAccent(primary, surfaces.highContrast);
54804
- const secondaryHigh = tuneHighContrastAccent(secondary, surfaces.highContrast);
54805
- return {
54806
- accentPrimary: { light: primary, dark: primaryDark, highContrast: primaryHigh },
54807
- accentSecondary: { light: secondary, dark: secondaryDark, highContrast: secondaryHigh },
54808
- accentSurface: {
54809
- light: deriveAccentSurface(primary, surfaces.light, ACCENT_SURFACE_LIGHT_WEIGHT),
54810
- dark: deriveAccentSurface(primaryDark, surfaces.dark, 0.24),
54811
- highContrast: deriveAccentSurface(primaryHigh, surfaces.highContrast, 0.24)
54812
- },
54813
- textOnAccent: {
54814
- light: textOnArm(primary),
54815
- dark: textOnArm(primaryDark),
54816
- highContrast: textOn(primaryHigh)
54817
- },
54818
- accentText: {
54819
- light: deriveAccentText(primary, [surfaces.light, ...textSurfaces.light ?? []]),
54820
- dark: deriveAccentText(primaryDark, [surfaces.dark, ...textSurfaces.dark ?? []]),
54821
- highContrast: deriveAccentText(primaryHigh, [surfaces.highContrast, ...textSurfaces.highContrast ?? []])
54822
- }
54823
- };
54824
- }
54825
- var ACCENT_SURFACE_MIN_DELTA, ACCENT_SURFACE_LIGHT_WEIGHT, SECONDARY_SHADE_WEIGHT, SECONDARY_MIN_LSTAR, DARK_ARM_MIN_LIFT, DARK_ARM_TARGET_CONTRAST, DARK_ARM_FLOOR_CONTRAST, DARK_ARM_LSTAR_CAP, HIGH_CONTRAST_TARGET, ACCENT_TEXT_MIN_CONTRAST, MID_GREY_LUMINANCE, TEXT_BACKDROP_TOKENS, BRAND_COLOR_TOKENS, BRAND_GLOW_SHADOW;
54826
- var init_brand_color_math = __esm({
54827
- "../../core/ts/src/brand-color-math.ts"() {
54828
- ACCENT_SURFACE_MIN_DELTA = 1.08;
54829
- ACCENT_SURFACE_LIGHT_WEIGHT = 0.12;
54830
- SECONDARY_SHADE_WEIGHT = 0.72;
54831
- SECONDARY_MIN_LSTAR = 22;
54832
- DARK_ARM_MIN_LIFT = 0.08;
54833
- DARK_ARM_TARGET_CONTRAST = 3.4;
54834
- DARK_ARM_FLOOR_CONTRAST = 3;
54835
- DARK_ARM_LSTAR_CAP = 80;
54836
- HIGH_CONTRAST_TARGET = 8.5;
54837
- ACCENT_TEXT_MIN_CONTRAST = 4.5;
54838
- MID_GREY_LUMINANCE = 0.179;
54839
- TEXT_BACKDROP_TOKENS = ["surfaceSecondary", "surfaceElevated", "surfaceSubtle", "surfaceTertiary"];
54840
- BRAND_COLOR_TOKENS = ["accentPrimary", "accentSecondary", "accentSurface", "textOnAccent", "accentText"];
54841
- BRAND_GLOW_SHADOW = "glow";
54842
- }
54843
- });
54844
-
54845
54902
  // src/site-analyze/branding-derive.ts
54846
54903
  function secondBrandColour(wst) {
54847
54904
  for (const name of ["--wst-color-fill-accent-2", "--wst-color-fill-accent-3"]) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1051.0",
3
+ "version": "0.1052.0",
4
4
  "type": "module",
5
5
  "description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
6
6
  "keywords": [
@@ -65,5 +65,5 @@
65
65
  "artifactId": "himalaya-cli"
66
66
  }
67
67
  },
68
- "falconPackageHash": "58b06c2960e8754fcd0e94b0f25c485969f0365bf0292b70f6d85a19"
68
+ "falconPackageHash": "418916efab2e1d4bc74db7d4eeb30ad2b9c0d20534c7d5757fcec730"
69
69
  }