@tenphi/glaze 0.16.2 → 0.18.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.
package/dist/index.cjs CHANGED
@@ -1087,6 +1087,15 @@ const APCA_PRESETS = {
1087
1087
  min: 15
1088
1088
  };
1089
1089
  /**
1090
+ * APCA-W3 "Enhanced Level" delta added to a bare APCA target in high-contrast
1091
+ * mode when no explicit HC value is provided (analogous to WCAG AAA over AA).
1092
+ * Only applied when neither the outer `contrast` pair nor the inner `apca`
1093
+ * pair carries an explicit HC entry.
1094
+ */
1095
+ const APCA_HC_ENHANCEMENT = 15;
1096
+ /** Upper bound for an APCA Lc target after HC enhancement. */
1097
+ const APCA_MAX_LC = 106;
1098
+ /**
1090
1099
  * Resolve an APCA target — a raw Lc number (kept as-is) or an `ApcaPreset`
1091
1100
  * keyword mapped to its Lc value. The magnitude is forced non-negative.
1092
1101
  */
@@ -1100,10 +1109,35 @@ const CONTRAST_PRESETS = {
1100
1109
  "AA-large": 3,
1101
1110
  "AAA-large": 4.5
1102
1111
  };
1112
+ /**
1113
+ * WCAG high-contrast auto-promotion (analog of APCA's Enhanced Level). A bare
1114
+ * AA / AA-large preset is promoted to its spec-defined "Enhanced" successor
1115
+ * (SC 1.4.3 → SC 1.4.6) in high-contrast mode. AAA / AAA-large are already
1116
+ * the top WCAG tier and are left unchanged. Bare numeric targets have no
1117
+ * defined successor tier and are also left unchanged. An explicit HC value
1118
+ * (outer or inner pair) always overrides.
1119
+ */
1120
+ const WCAG_HC_PROMOTION = {
1121
+ AA: "AAA",
1122
+ "AA-large": "AAA-large"
1123
+ };
1103
1124
  function resolveMinContrast(value) {
1104
1125
  if (typeof value === "number") return Math.max(1, value);
1105
1126
  return CONTRAST_PRESETS[value];
1106
1127
  }
1128
+ /**
1129
+ * Resolve a WCAG target (number or preset) for a mode, applying the
1130
+ * high-contrast auto-promotion when `explicitHC` is false and the value is an
1131
+ * AA-family preset. Bare numbers and AAA-family presets pass through.
1132
+ */
1133
+ function resolveWcagTarget(value, isHighContrast, explicitHC) {
1134
+ if (typeof value === "number") return resolveMinContrast(value);
1135
+ if (isHighContrast && !explicitHC) {
1136
+ const promoted = WCAG_HC_PROMOTION[value];
1137
+ if (promoted !== void 0) return resolveMinContrast(promoted);
1138
+ }
1139
+ return resolveMinContrast(value);
1140
+ }
1107
1141
  function pickPair(p, isHighContrast) {
1108
1142
  return Array.isArray(p) ? isHighContrast ? p[1] : p[0] : p;
1109
1143
  }
@@ -1112,20 +1146,35 @@ function pickPair(p, isHighContrast) {
1112
1146
  * given mode into `{ metric, target }`. Handles the inner metric HC pair and
1113
1147
  * preset resolution. `polarity` is passed through to the result for the APCA
1114
1148
  * branch (it controls argument order in the solver); WCAG ignores it.
1115
- */
1116
- function resolveContrastForMode(spec, isHighContrast, polarity) {
1149
+ *
1150
+ * `outerExplicitHC` indicates whether the caller selected this `spec` from an
1151
+ * explicit high-contrast entry of the outer `contrast` pair. Together with the
1152
+ * inner metric pair, it decides whether the HC auto-enhancement fires:
1153
+ * - APCA: +15 Lc "Enhanced Level" boost when neither level is explicit.
1154
+ * - WCAG: AA → AAA / AA-large → AAA-large promotion (SC 1.4.3 → 1.4.6) when
1155
+ * neither level is explicit. AAA-family presets and bare numbers are left
1156
+ * unchanged (AAA is the top WCAG tier).
1157
+ * Defaults to `false` (correct for direct callers, which pass a single
1158
+ * selected spec rather than an outer pair).
1159
+ */
1160
+ function resolveContrastForMode(spec, isHighContrast, polarity, outerExplicitHC) {
1117
1161
  if (typeof spec === "number" || typeof spec === "string") return {
1118
1162
  metric: "wcag",
1119
- target: resolveMinContrast(spec)
1120
- };
1121
- if ("apca" in spec) return {
1122
- metric: "apca",
1123
- target: resolveApcaTarget(pickPair(spec.apca, isHighContrast)),
1124
- polarity: polarity ?? "fg"
1163
+ target: resolveWcagTarget(spec, isHighContrast, !!outerExplicitHC)
1125
1164
  };
1165
+ if ("apca" in spec) {
1166
+ const baseTarget = resolveApcaTarget(pickPair(spec.apca, isHighContrast));
1167
+ const innerExplicitHC = Array.isArray(spec.apca);
1168
+ return {
1169
+ metric: "apca",
1170
+ target: isHighContrast && !outerExplicitHC && !innerExplicitHC ? Math.min(baseTarget + APCA_HC_ENHANCEMENT, APCA_MAX_LC) : baseTarget,
1171
+ polarity: polarity ?? "fg"
1172
+ };
1173
+ }
1174
+ const innerExplicitHC = Array.isArray(spec.wcag);
1126
1175
  return {
1127
1176
  metric: "wcag",
1128
- target: resolveMinContrast(pickPair(spec.wcag, isHighContrast))
1177
+ target: resolveWcagTarget(pickPair(spec.wcag, isHighContrast), isHighContrast, !!outerExplicitHC || innerExplicitHC)
1129
1178
  };
1130
1179
  }
1131
1180
  const APCA_EXPONENTS = {
@@ -1827,7 +1876,8 @@ function resolveRole(name, def, ctx) {
1827
1876
  return resolveRoleInMap(name, def, ctx.defs, ctx.config.inferRole, ctx.roles);
1828
1877
  }
1829
1878
  function resolveContrastSpec(spec, isHighContrast, polarity) {
1830
- return resolveContrastForMode(isHighContrast ? pairHC(spec) : pairNormal(spec), isHighContrast, polarity);
1879
+ const outerExplicitHC = Array.isArray(spec);
1880
+ return resolveContrastForMode(isHighContrast ? pairHC(spec) : pairNormal(spec), isHighContrast, polarity, outerExplicitHC);
1831
1881
  }
1832
1882
  /**
1833
1883
  * Apply the relative-tone delta against a base, honoring `flip`.
@@ -1855,7 +1905,7 @@ function resolveDependentColor(name, def, ctx, isHighContrast, isDark, effective
1855
1905
  if (!baseResolved) throw new Error(`glaze: base "${baseName}" not yet resolved for "${name}".`);
1856
1906
  const mode = def.mode ?? "auto";
1857
1907
  const satFactor = clamp(def.saturation ?? 1, 0, 1);
1858
- const flip = def.flip ?? ctx.config.autoFlip;
1908
+ const flip = def.autoFlip ?? ctx.config.autoFlip;
1859
1909
  const pastel = effectivePastel;
1860
1910
  const baseVariant = getSchemeVariant(baseResolved, isDark, isHighContrast);
1861
1911
  const baseTone = baseVariant.t * 100;
@@ -2932,7 +2982,7 @@ function buildStandaloneValueDefs(main, options) {
2932
2982
  tone: toneOption ?? seedTone,
2933
2983
  contrast: options?.contrast,
2934
2984
  mode: options?.mode ?? "auto",
2935
- flip: options?.flip,
2985
+ autoFlip: options?.autoFlip,
2936
2986
  opacity: options?.opacity,
2937
2987
  pastel: options?.pastel,
2938
2988
  role: options?.role,
@@ -3074,7 +3124,7 @@ function createColorToken(input, configOverride) {
3074
3124
  tone: input.tone,
3075
3125
  saturation: input.saturationFactor,
3076
3126
  mode: input.mode ?? "auto",
3077
- flip: input.flip,
3127
+ autoFlip: input.autoFlip,
3078
3128
  contrast: input.contrast,
3079
3129
  opacity: input.opacity,
3080
3130
  pastel: input.pastel,
@@ -3124,7 +3174,7 @@ function buildOverridesExport(options) {
3124
3174
  if (options.tone !== void 0) out.tone = options.tone;
3125
3175
  if (options.saturationFactor !== void 0) out.saturationFactor = options.saturationFactor;
3126
3176
  if (options.mode !== void 0) out.mode = options.mode;
3127
- if (options.flip !== void 0) out.flip = options.flip;
3177
+ if (options.autoFlip !== void 0) out.autoFlip = options.autoFlip;
3128
3178
  if (options.contrast !== void 0) out.contrast = options.contrast;
3129
3179
  if (options.opacity !== void 0) out.opacity = options.opacity;
3130
3180
  if (options.name !== void 0) out.name = options.name;
@@ -3141,7 +3191,7 @@ function buildStructuredInputExport(input) {
3141
3191
  };
3142
3192
  if (input.saturationFactor !== void 0) out.saturationFactor = input.saturationFactor;
3143
3193
  if (input.mode !== void 0) out.mode = input.mode;
3144
- if (input.flip !== void 0) out.flip = input.flip;
3194
+ if (input.autoFlip !== void 0) out.autoFlip = input.autoFlip;
3145
3195
  if (input.opacity !== void 0) out.opacity = input.opacity;
3146
3196
  if (input.contrast !== void 0) out.contrast = input.contrast;
3147
3197
  if (input.name !== void 0) out.name = input.name;
@@ -3163,7 +3213,7 @@ function rehydrateOverrides(data) {
3163
3213
  if (data.tone !== void 0) out.tone = data.tone;
3164
3214
  if (data.saturationFactor !== void 0) out.saturationFactor = data.saturationFactor;
3165
3215
  if (data.mode !== void 0) out.mode = data.mode;
3166
- if (data.flip !== void 0) out.flip = data.flip;
3216
+ if (data.autoFlip !== void 0) out.autoFlip = data.autoFlip;
3167
3217
  if (data.contrast !== void 0) out.contrast = data.contrast;
3168
3218
  if (data.opacity !== void 0) out.opacity = data.opacity;
3169
3219
  if (data.name !== void 0) out.name = data.name;
@@ -3180,7 +3230,7 @@ function rehydrateStructuredInput(data) {
3180
3230
  };
3181
3231
  if (data.saturationFactor !== void 0) out.saturationFactor = data.saturationFactor;
3182
3232
  if (data.mode !== void 0) out.mode = data.mode;
3183
- if (data.flip !== void 0) out.flip = data.flip;
3233
+ if (data.autoFlip !== void 0) out.autoFlip = data.autoFlip;
3184
3234
  if (data.opacity !== void 0) out.opacity = data.opacity;
3185
3235
  if (data.contrast !== void 0) out.contrast = data.contrast;
3186
3236
  if (data.name !== void 0) out.name = data.name;
@@ -3719,6 +3769,9 @@ glaze.resetConfig = function resetConfig$1() {
3719
3769
  };
3720
3770
 
3721
3771
  //#endregion
3772
+ exports.APCA_HC_ENHANCEMENT = APCA_HC_ENHANCEMENT;
3773
+ exports.APCA_MAX_LC = APCA_MAX_LC;
3774
+ exports.APCA_PRESETS = APCA_PRESETS;
3722
3775
  exports.REF_EPS = REF_EPS;
3723
3776
  exports.apcaContrast = apcaContrast;
3724
3777
  exports.assertAllPastel = assertAllPastel;