@multiplatform.one/theme 8.2.2 → 8.4.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 (187) hide show
  1. package/dist/cjs/index.gnome.cjs +4 -1
  2. package/dist/cjs/index.gnome.native.js +3 -0
  3. package/dist/cjs/index.gnome.native.js.map +1 -1
  4. package/dist/cjs/menuRow.cjs +1 -1
  5. package/dist/cjs/menuRow.native.js +1 -1
  6. package/dist/cjs/theme/accentInk.cjs +6 -2
  7. package/dist/cjs/theme/accentInk.native.js +6 -2
  8. package/dist/cjs/theme/accentInk.native.js.map +1 -1
  9. package/dist/cjs/theme/chartPalette.cjs +3 -3
  10. package/dist/cjs/theme/chartPalette.native.js +5 -4
  11. package/dist/cjs/theme/chartPalette.native.js.map +1 -1
  12. package/dist/cjs/theme/colorRules.cjs +5 -0
  13. package/dist/cjs/theme/colorRules.native.js +6 -0
  14. package/dist/cjs/theme/colorRules.native.js.map +1 -1
  15. package/dist/cjs/theme/controlTiers.cjs +9 -5
  16. package/dist/cjs/theme/controlTiers.native.js +10 -5
  17. package/dist/cjs/theme/controlTiers.native.js.map +1 -1
  18. package/dist/cjs/theme/createThemes.cjs +212 -8
  19. package/dist/cjs/theme/createThemes.native.js +397 -12
  20. package/dist/cjs/theme/createThemes.native.js.map +1 -1
  21. package/dist/cjs/theme/defaults/builderOptions.cjs +9 -4
  22. package/dist/cjs/theme/defaults/builderOptions.native.js +9 -4
  23. package/dist/cjs/theme/defaults/builderOptions.native.js.map +1 -1
  24. package/dist/cjs/theme/fillContrast.cjs +4 -1
  25. package/dist/cjs/theme/fillContrast.native.js +4 -1
  26. package/dist/cjs/theme/fillContrast.native.js.map +1 -1
  27. package/dist/cjs/theme/index.cjs +1 -0
  28. package/dist/cjs/theme/index.native.js +1 -0
  29. package/dist/cjs/theme/index.native.js.map +1 -1
  30. package/dist/cjs/theme/nativeSchemePreference.cjs +2 -1
  31. package/dist/cjs/theme/nativeSchemePreference.native.js +2 -1
  32. package/dist/cjs/theme/nativeSchemePreference.native.js.map +1 -1
  33. package/dist/cjs/theme/nativeTheme.native.js.map +1 -1
  34. package/dist/cjs/theme/overlaySurfaces.cjs +2 -2
  35. package/dist/cjs/theme/overlaySurfaces.native.js +2 -2
  36. package/dist/cjs/theme/overlaySurfaces.native.js.map +1 -1
  37. package/dist/cjs/theme/readableColor.cjs +20 -9
  38. package/dist/cjs/theme/readableColor.native.js +20 -9
  39. package/dist/cjs/theme/readableColor.native.js.map +1 -1
  40. package/dist/cjs/theme/reducedMotion.cjs +49 -0
  41. package/dist/cjs/theme/reducedMotion.native.js +81 -0
  42. package/dist/cjs/theme/reducedMotion.native.js.map +1 -0
  43. package/dist/cjs/theme/resolveKnobs.cjs +4 -1
  44. package/dist/cjs/theme/resolveKnobs.native.js +4 -1
  45. package/dist/cjs/theme/resolveKnobs.native.js.map +1 -1
  46. package/dist/cjs/theme/tokenNumber.cjs +34 -0
  47. package/dist/cjs/theme/tokenNumber.native.js +39 -0
  48. package/dist/cjs/theme/tokenNumber.native.js.map +1 -0
  49. package/dist/cjs/theme/useResolvedKnobs.cjs +2 -22
  50. package/dist/cjs/theme/useResolvedKnobs.native.js +2 -30
  51. package/dist/cjs/theme/useResolvedKnobs.native.js.map +1 -1
  52. package/dist/esm/index.gnome.mjs +3 -2
  53. package/dist/esm/index.gnome.mjs.map +1 -1
  54. package/dist/esm/index.gnome.native.js +3 -2
  55. package/dist/esm/index.gnome.native.js.map +1 -1
  56. package/dist/esm/menuRow.mjs +1 -1
  57. package/dist/esm/menuRow.native.js +1 -1
  58. package/dist/esm/theme/accentInk.mjs +6 -3
  59. package/dist/esm/theme/accentInk.mjs.map +1 -1
  60. package/dist/esm/theme/accentInk.native.js +6 -3
  61. package/dist/esm/theme/accentInk.native.js.map +1 -1
  62. package/dist/esm/theme/chartPalette.mjs +3 -3
  63. package/dist/esm/theme/chartPalette.mjs.map +1 -1
  64. package/dist/esm/theme/chartPalette.native.js +5 -4
  65. package/dist/esm/theme/chartPalette.native.js.map +1 -1
  66. package/dist/esm/theme/colorRules.mjs +5 -1
  67. package/dist/esm/theme/colorRules.mjs.map +1 -1
  68. package/dist/esm/theme/colorRules.native.js +6 -1
  69. package/dist/esm/theme/colorRules.native.js.map +1 -1
  70. package/dist/esm/theme/controlTiers.mjs +9 -6
  71. package/dist/esm/theme/controlTiers.mjs.map +1 -1
  72. package/dist/esm/theme/controlTiers.native.js +10 -6
  73. package/dist/esm/theme/controlTiers.native.js.map +1 -1
  74. package/dist/esm/theme/createThemes.mjs +215 -12
  75. package/dist/esm/theme/createThemes.mjs.map +1 -1
  76. package/dist/esm/theme/createThemes.native.js +400 -16
  77. package/dist/esm/theme/createThemes.native.js.map +1 -1
  78. package/dist/esm/theme/defaults/builderOptions.mjs +10 -6
  79. package/dist/esm/theme/defaults/builderOptions.mjs.map +1 -1
  80. package/dist/esm/theme/defaults/builderOptions.native.js +10 -6
  81. package/dist/esm/theme/defaults/builderOptions.native.js.map +1 -1
  82. package/dist/esm/theme/fillContrast.mjs +5 -2
  83. package/dist/esm/theme/fillContrast.mjs.map +1 -1
  84. package/dist/esm/theme/fillContrast.native.js +5 -2
  85. package/dist/esm/theme/fillContrast.native.js.map +1 -1
  86. package/dist/esm/theme/index.mjs +1 -0
  87. package/dist/esm/theme/index.mjs.map +1 -1
  88. package/dist/esm/theme/index.native.js +1 -0
  89. package/dist/esm/theme/index.native.js.map +1 -1
  90. package/dist/esm/theme/nativeSchemePreference.mjs +2 -1
  91. package/dist/esm/theme/nativeSchemePreference.mjs.map +1 -1
  92. package/dist/esm/theme/nativeSchemePreference.native.js +2 -1
  93. package/dist/esm/theme/nativeSchemePreference.native.js.map +1 -1
  94. package/dist/esm/theme/nativeTheme.mjs.map +1 -1
  95. package/dist/esm/theme/nativeTheme.native.js.map +1 -1
  96. package/dist/esm/theme/overlaySurfaces.mjs +2 -2
  97. package/dist/esm/theme/overlaySurfaces.native.js +2 -2
  98. package/dist/esm/theme/readableColor.mjs +20 -9
  99. package/dist/esm/theme/readableColor.mjs.map +1 -1
  100. package/dist/esm/theme/readableColor.native.js +20 -9
  101. package/dist/esm/theme/readableColor.native.js.map +1 -1
  102. package/dist/esm/theme/reducedMotion.mjs +24 -0
  103. package/dist/esm/theme/reducedMotion.mjs.map +1 -0
  104. package/dist/esm/theme/reducedMotion.native.js +53 -0
  105. package/dist/esm/theme/reducedMotion.native.js.map +1 -0
  106. package/dist/esm/theme/resolveKnobs.mjs +4 -1
  107. package/dist/esm/theme/resolveKnobs.mjs.map +1 -1
  108. package/dist/esm/theme/resolveKnobs.native.js +4 -1
  109. package/dist/esm/theme/resolveKnobs.native.js.map +1 -1
  110. package/dist/esm/theme/tokenNumber.mjs +9 -0
  111. package/dist/esm/theme/tokenNumber.mjs.map +1 -0
  112. package/dist/esm/theme/tokenNumber.native.js +11 -0
  113. package/dist/esm/theme/tokenNumber.native.js.map +1 -0
  114. package/dist/esm/theme/useResolvedKnobs.mjs +2 -22
  115. package/dist/esm/theme/useResolvedKnobs.mjs.map +1 -1
  116. package/dist/esm/theme/useResolvedKnobs.native.js +2 -30
  117. package/dist/esm/theme/useResolvedKnobs.native.js.map +1 -1
  118. package/package.json +5 -5
  119. package/src/figma/figmaTokens.spec.ts +2 -1
  120. package/src/index.gnome.ts +2 -0
  121. package/src/menuRow.palette.spec.ts +20 -7
  122. package/src/menuRow.spec.ts +2 -2
  123. package/src/menuRow.ts +3 -3
  124. package/src/theme/accentInk.ts +8 -2
  125. package/src/theme/accentOnSurface.spec.tsx +6 -1
  126. package/src/theme/chartPalette.spec.ts +2 -2
  127. package/src/theme/chartPalette.ts +9 -9
  128. package/src/theme/colorRules.ts +13 -0
  129. package/src/theme/controlEdges.spec.ts +114 -0
  130. package/src/theme/controlTiers.ts +18 -9
  131. package/src/theme/createDefaultThemeConfig.spec.ts +135 -12
  132. package/src/theme/createThemes.ts +363 -24
  133. package/src/theme/defaults/builderOptions.ts +25 -8
  134. package/src/theme/defaults/secondaryInk.spec.ts +10 -5
  135. package/src/theme/fillContrast.spec.ts +8 -2
  136. package/src/theme/fillContrast.ts +10 -2
  137. package/src/theme/houseGround.spec.ts +1 -1
  138. package/src/theme/index.ts +1 -0
  139. package/src/theme/nativeSchemePreference.ts +2 -1
  140. package/src/theme/nativeTheme.tsx +1 -1
  141. package/src/theme/overlaySurfaces.tsx +2 -2
  142. package/src/theme/readableColor.ts +23 -11
  143. package/src/theme/recipes.ts +1 -0
  144. package/src/theme/reducedMotion.native.spec.ts +28 -0
  145. package/src/theme/reducedMotion.native.ts +36 -0
  146. package/src/theme/reducedMotion.ts +27 -0
  147. package/src/theme/resolveKnobs.spec.ts +4 -4
  148. package/src/theme/resolveKnobs.ts +6 -4
  149. package/src/theme/selectionFill.spec.ts +58 -0
  150. package/src/theme/sheetGrabber.spec.ts +4 -0
  151. package/src/theme/switchThumb.spec.ts +13 -1
  152. package/src/theme/themeKeyRegistry.spec.ts +26 -0
  153. package/src/theme/tokenNumber.spec.tsx +47 -0
  154. package/src/theme/tokenNumber.ts +18 -0
  155. package/src/theme/useResolvedKnobs.ts +2 -27
  156. package/types/index.gnome.d.ts +2 -1
  157. package/types/index.gnome.d.ts.map +1 -1
  158. package/types/menuRow.d.ts +5 -5
  159. package/types/theme/accentInk.d.ts +1 -0
  160. package/types/theme/accentInk.d.ts.map +1 -1
  161. package/types/theme/chartPalette.d.ts +2 -2
  162. package/types/theme/colorRules.d.ts +9 -0
  163. package/types/theme/colorRules.d.ts.map +1 -1
  164. package/types/theme/controlTiers.d.ts +11 -5
  165. package/types/theme/controlTiers.d.ts.map +1 -1
  166. package/types/theme/createThemes.d.ts +21 -12
  167. package/types/theme/createThemes.d.ts.map +1 -1
  168. package/types/theme/defaults/builderOptions.d.ts +9 -1
  169. package/types/theme/defaults/builderOptions.d.ts.map +1 -1
  170. package/types/theme/fillContrast.d.ts.map +1 -1
  171. package/types/theme/index.d.ts +1 -0
  172. package/types/theme/index.d.ts.map +1 -1
  173. package/types/theme/nativeSchemePreference.d.ts.map +1 -1
  174. package/types/theme/nativeTheme.d.ts +1 -1
  175. package/types/theme/nativeTheme.d.ts.map +1 -1
  176. package/types/theme/overlaySurfaces.d.ts +2 -2
  177. package/types/theme/readableColor.d.ts.map +1 -1
  178. package/types/theme/recipes.d.ts +3 -0
  179. package/types/theme/recipes.d.ts.map +1 -1
  180. package/types/theme/reducedMotion.d.ts +3 -0
  181. package/types/theme/reducedMotion.d.ts.map +1 -0
  182. package/types/theme/reducedMotion.native.d.ts +3 -0
  183. package/types/theme/reducedMotion.native.d.ts.map +1 -0
  184. package/types/theme/resolveKnobs.d.ts.map +1 -1
  185. package/types/theme/tokenNumber.d.ts +10 -0
  186. package/types/theme/tokenNumber.d.ts.map +1 -0
  187. package/types/theme/useResolvedKnobs.d.ts.map +1 -1
@@ -1,4 +1,4 @@
1
- import { createContext, useContext, useMemo, useSyncExternalStore } from "react";
1
+ import { createContext, useContext, useMemo } from "react";
2
2
  import { useThemeName } from "tamagui";
3
3
  import { useTouchSurface } from "./useTouchSurface.native.js";
4
4
  import { defaultKnobs } from "./knobs.native.js";
@@ -6,6 +6,7 @@ import { resolveKnobs } from "./resolveKnobs.native.js";
6
6
  import { usePresetContext } from "./PresetContext.native.js";
7
7
  import { defaultIntents } from "./intents.native.js";
8
8
  import { clampSurfaceSize, SurfaceContext } from "./Surface.native.js";
9
+ import { usePrefersReducedMotion } from "./reducedMotion.native.js";
9
10
  function _type_of(obj) {
10
11
  "@swc/helpers - typeof";
11
12
 
@@ -15,35 +16,6 @@ var IntentContext = createContext(null);
15
16
  function useIntentContext() {
16
17
  return useContext(IntentContext);
17
18
  }
18
- var reducedMotionQuery = "(prefers-reduced-motion: reduce)";
19
- var serverReducedMotion = function serverReducedMotion2() {
20
- return false;
21
- };
22
- function readReducedMotion() {
23
- var _window_matchMedia, _window;
24
- return typeof window !== "undefined" && !!((_window_matchMedia = (_window = window).matchMedia) === null || _window_matchMedia === void 0 ? void 0 : _window_matchMedia.call(_window, reducedMotionQuery).matches);
25
- }
26
- function subscribeReducedMotion(notify) {
27
- if (typeof window === "undefined" || !window.matchMedia) return function () {};
28
- var mq = window.matchMedia(reducedMotionQuery);
29
- if (typeof mq.addEventListener === "function") {
30
- mq.addEventListener("change", notify);
31
- return function () {
32
- return mq.removeEventListener("change", notify);
33
- };
34
- }
35
- if (typeof mq.addListener === "function") {
36
- mq.addListener(notify);
37
- return function () {
38
- var _mq_removeListener;
39
- return (_mq_removeListener = mq.removeListener) === null || _mq_removeListener === void 0 ? void 0 : _mq_removeListener.call(mq, notify);
40
- };
41
- }
42
- return function () {};
43
- }
44
- function usePrefersReducedMotion() {
45
- return useSyncExternalStore(subscribeReducedMotion, readReducedMotion, serverReducedMotion);
46
- }
47
19
  var solidButtonIntents = /* @__PURE__ */new Set(["error", "warning", "success"]);
48
20
  var solidPaletteThemes = /* @__PURE__ */new Set(["accent"]);
49
21
  function useResolvedKnobs(options) {
@@ -1 +1 @@
1
- {"version":3,"names":["createContext","useContext","useMemo","useSyncExternalStore","useThemeName","useTouchSurface","defaultKnobs","resolveKnobs","usePresetContext","defaultIntents","clampSurfaceSize","SurfaceContext","_type_of","obj","Symbol","constructor","IntentContext","useIntentContext","reducedMotionQuery","serverReducedMotion","serverReducedMotion2","readReducedMotion","_window_matchMedia","_window","window","matchMedia","call","matches","subscribeReducedMotion","notify","mq","addEventListener","removeEventListener","addListener","_mq_removeListener","removeListener","usePrefersReducedMotion","solidButtonIntents","Set","solidPaletteThemes","useResolvedKnobs","options","_ref","_ref1","_ref2","_ref3","_ref4","touch","presetCtx","contextIntent","prefersReducedMotion","themeName","scheme","startsWith","surfaceCtx","useStyledContext","surfaceSize","size","painted","intent","component","override","sizeOverride","baseKnobs","preset","knobs","overrides","merged","_ref5","intentOverrides","intents","knobOverrides","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","Object","entries","iterator","_step","next","done","key","value","err","return"],"sources":["../../../src/theme/useResolvedKnobs.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["createContext","useContext","useMemo","useThemeName","useTouchSurface","defaultKnobs","resolveKnobs","usePresetContext","defaultIntents","clampSurfaceSize","SurfaceContext","usePrefersReducedMotion","_type_of","obj","Symbol","constructor","IntentContext","useIntentContext","solidButtonIntents","Set","solidPaletteThemes","useResolvedKnobs","options","_ref","_ref1","_ref2","_ref3","_ref4","touch","presetCtx","contextIntent","prefersReducedMotion","themeName","scheme","startsWith","surfaceCtx","useStyledContext","surfaceSize","size","painted","intent","component","override","sizeOverride","baseKnobs","preset","knobs","overrides","merged","_ref5","intentOverrides","intents","knobOverrides","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","Object","entries","iterator","_step","next","done","key","value","err","return","componentOverride"],"sources":["../../../src/theme/useResolvedKnobs.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplatform.one/theme",
3
- "version": "8.2.2",
3
+ "version": "8.4.0",
4
4
  "description": "Tamagui theme system for multiplatform.one",
5
5
  "keywords": [
6
6
  "multiplatform",
@@ -163,8 +163,8 @@
163
163
  "access": "public"
164
164
  },
165
165
  "dependencies": {
166
- "@multiplatform.one/platform": "^8.2.2",
167
- "@multiplatform.one/store": "^8.2.2",
166
+ "@multiplatform.one/platform": "^8.4.0",
167
+ "@multiplatform.one/store": "^8.4.0",
168
168
  "@tamagui/animations-react-native": "2.7.6",
169
169
  "@tamagui/colors": "2.7.6",
170
170
  "@tamagui/config": "2.7.6",
@@ -180,8 +180,8 @@
180
180
  },
181
181
  "devDependencies": {
182
182
  "@expo/prebuild-config": "55.0.18",
183
- "@multiplatform.one/config": "8.2.2",
184
- "@multiplatform.one/test-utils": "8.2.2",
183
+ "@multiplatform.one/config": "8.4.0",
184
+ "@multiplatform.one/test-utils": "8.4.0",
185
185
  "@tamagui/animations-css": "2.7.6",
186
186
  "@tamagui/animations-reanimated": "2.7.6",
187
187
  "@tamagui/build": "2.7.6",
@@ -104,7 +104,8 @@ describe("buildFigmaTokens", () => {
104
104
  // BUILDER's derivation again rather than mpo's re-anchoring. That is
105
105
  // the correction landing, and what this pins is that it landed —
106
106
  // borderColor back off color5, the background states no longer forced.
107
- expect(result.semantic.borderColor?.alias).toBe("color4");
107
+ // FZ-9281: the dark edge is measured per scope, so no one alias either.
108
+ expect(result.semantic.borderColor?.alias).toBeNull();
108
109
  // LC-152: the secondary ink is a different ramp step per scheme, so no one alias.
109
110
  expect(result.semantic.textMuted?.alias).toBeNull();
110
111
  expect(result.semantic.placeholderColor?.alias).toBe("color9");
@@ -207,6 +207,7 @@ export {
207
207
  controlTierDisabled,
208
208
  controlTierPaint,
209
209
  controlTierWash,
210
+ controlTrackFill,
210
211
  isDarkThemeName,
211
212
  } from "./theme/controlTiers";
212
213
  export type { ControlTier, ControlTierPaint } from "./theme/controlTiers";
@@ -541,4 +542,5 @@ export type { ThemeSubset } from "./theme/subsetThemes";
541
542
  export type { SizeKey } from "./theme/scale/scaleInputs";
542
543
  export { listHeightForRows } from "./theme/listRows";
543
544
  export { useTouchSurface } from "./theme/useTouchSurface";
545
+ export { tokenNumber } from "./theme/tokenNumber";
544
546
  export type { GenericFonts, MediaQueryKey, ThemeName } from "@tamagui/web";
@@ -1,8 +1,10 @@
1
1
  /**
2
- * FZ-8557 (Round 40): a checked menu row is a selection tint on its panel in
3
- * every theme. Dark steps lighter than the `$color4` overlay, never a hole;
4
- * light stays a tint on the white panel, never a slab; the check is the
5
- * accent (ink when hue-less) and holds 3:1 on the fill.
2
+ * FZ-8557 (Round 40), FZ-8400 (Round 52): a checked menu row is a selection
3
+ * tint on its panel in every theme. Dark sits exactly one ramp step above the
4
+ * `$color5` overlay and never jumps two, lighter, never a hole; measured, that
5
+ * step stays under 1.33:1, the stock ramp's widest at `$color5` to `$color6`.
6
+ * Light stays a tint on the white panel, `$color3`, never a slab, under 1.3:1.
7
+ * The check is the accent (ink when hue-less) and holds 3:1 on the fill.
6
8
  */
7
9
  import { describe, expect, it } from "vitest";
8
10
  import { contrastRatio, normalizeToHex, relativeLuminance } from "./theme/colorRules";
@@ -35,12 +37,23 @@ describe("a checked menu row is a selection tint on its panel (FZ-8557)", () =>
35
37
  it(`${name}`, () => {
36
38
  const theme = themes[name];
37
39
  expect(theme, name).toBeTruthy();
38
- const panel = token(theme!, scheme === "dark" ? "$color4" : "$background");
39
- const fill = token(theme!, menuRowChecked(scheme).backgroundColor);
40
+ const panel = token(theme!, scheme === "dark" ? "$color5" : "$background");
41
+ const fillToken = menuRowChecked(scheme).backgroundColor;
42
+ const fill = token(theme!, fillToken);
40
43
  const ratio = contrastRatio(lum(fill), lum(panel));
41
44
  if (scheme === "dark") expect(lum(fill), `${fill} on ${panel}`).toBeGreaterThan(lum(panel));
42
45
  else expect(lum(fill), `${fill} on ${panel}`).toBeLessThan(lum(panel));
43
- expect(ratio, `${fill} on ${panel}`).toBeLessThan(1.3);
46
+ if (scheme === "dark") {
47
+ const panelStep = Array.from({ length: 12 }, (_, i) => i + 1).find(
48
+ (step) => token(theme!, `$color${step}`) === panel,
49
+ );
50
+ expect(panelStep, `${panel} is a ramp step`).toBeDefined();
51
+ expect(
52
+ Number(fillToken.replace("$color", "")) - panelStep!,
53
+ `${fillToken} on step ${panelStep}`,
54
+ ).toBe(1);
55
+ }
56
+ expect(ratio, `${fill} on ${panel}`).toBeLessThan(scheme === "dark" ? 1.33 : 1.3);
44
57
  const check = resolveMenuRowCheckInk(theme!);
45
58
  expect(contrastRatio(lum(check), lum(fill)), `${check} on ${fill}`).toBeGreaterThanOrEqual(
46
59
  3,
@@ -36,8 +36,8 @@ describe("menuRowChecked (LC-262 checked row, FZ-8355 r6, FZ-8557)", () => {
36
36
  expect(menuRowChecked("light").backgroundColor).toBe("$color3");
37
37
  });
38
38
 
39
- it("lifts dark rows to $color5, a step lighter than the $color4 dark overlay", () => {
40
- expect(menuRowChecked("dark").backgroundColor).toBe("$color5");
39
+ it("lifts dark rows to $color6, a step lighter than the $color5 dark overlay", () => {
40
+ expect(menuRowChecked("dark").backgroundColor).toBe("$color6");
41
41
  });
42
42
 
43
43
  it("keeps the fill through hover and press, and leaves focus rings to the consumer", () => {
package/src/menuRow.ts CHANGED
@@ -44,8 +44,8 @@ export const menuRowFrame = {
44
44
  * The fill is a selection tint one step off the panel toward the ink, the way
45
45
  * HIG lifts a selection off its material (FZ-8557, Round 40). Light rests on
46
46
  * `$color3` over the white `$color1` panel, a tint and not the `$color4` slab.
47
- * A dark overlay is `$color4` (`surface2`), so dark rests on `$color5`, a step
48
- * lighter: a recessed `$color2` read as a hole in the panel. In a colour theme
47
+ * A dark overlay is `$color5` (the house `surface2`, FZ-8400), so dark rests on
48
+ * `$color6`, a step lighter: a recessed `$color2` read as a hole in the panel. In a colour theme
49
49
  * both steps carry its hue. Hover and press keep the fill, so a checked row
50
50
  * never drops to the transient hover fill. Spread it last on the row so it
51
51
  * wins over the consumer's hover and keyboard-cursor fills; a consumer that
@@ -53,7 +53,7 @@ export const menuRowFrame = {
53
53
  * the consumer's.
54
54
  */
55
55
  export function menuRowChecked(scheme: ColorScheme) {
56
- const fill = scheme === "dark" ? "$color5" : "$color3";
56
+ const fill = scheme === "dark" ? "$color6" : "$color3";
57
57
  return {
58
58
  backgroundColor: fill,
59
59
  hoverStyle: { backgroundColor: fill },
@@ -109,6 +109,12 @@ export function identityKeys(themeName: string): string[] {
109
109
  : accentStepKeys;
110
110
  }
111
111
 
112
+ export function pageSurfaces(name: string, values: Record<string, string>): (string | undefined)[] {
113
+ return name.startsWith("dark")
114
+ ? [values.color1, values.color2, values.color5]
115
+ : [values.color1, values.color2];
116
+ }
117
+
112
118
  /**
113
119
  * FZ-9608. Every theme with the ink {@link useAccentOnSurface} picks inside it,
114
120
  * as `accentOnSurface`. On web the hook then hands back `$accentOnSurface`, so
@@ -125,7 +131,7 @@ export function withAccentOnSurface(
125
131
  const accentOnSurface = resolveAccentOnSurface({
126
132
  identity: identityKeys(name).map((key) => values[key]),
127
133
  accentSteps: accentStepKeys.map((key) => values[key]),
128
- surfaces: [values.color1, values.color2],
134
+ surfaces: pageSurfaces(name, values),
129
135
  ink: values.color12,
130
136
  });
131
137
  return [name, { ...theme, accentOnSurface }];
@@ -149,7 +155,7 @@ export function withIdentityInk(
149
155
  if (!values.color12) return [name, theme];
150
156
  const identityInk = resolveIdentityInk({
151
157
  candidates: identityKeys(name).map((key) => values[key]),
152
- surfaces: [values.color1, values.color2],
158
+ surfaces: pageSurfaces(name, values),
153
159
  ink: values.color12,
154
160
  });
155
161
  return [name, { ...theme, identityInk }];
@@ -63,7 +63,12 @@ function Probe({ seen }: { seen: Seen }) {
63
63
  const accent = useAccentOnSurface();
64
64
  seen.accent = accent.startsWith("$") ? (theme[accent.slice(1)]?.val ?? accent) : accent;
65
65
  seen.identity = useIdentityInkOnSurface();
66
- seen.surfaces = [theme.color1?.val ?? "", theme.color2?.val ?? ""];
66
+ // A dark overlay paints `$color5`, so dark accent ink holds AA there too (FZ-8400).
67
+ seen.surfaces = [
68
+ theme.color1?.val ?? "",
69
+ theme.color2?.val ?? "",
70
+ ...(String(seen.name).startsWith("dark") ? [theme.color5?.val ?? ""] : []),
71
+ ];
67
72
  seen.accentSteps = Array.from({ length: 12 }, (_, i) => theme[`accent${i + 1}`]?.val ?? "");
68
73
  return null;
69
74
  }
@@ -113,7 +113,7 @@ describe("resolveChartPalette", () => {
113
113
  }
114
114
  });
115
115
 
116
- it("retains the dark cycle order while deepening its failing violet slot", () => {
116
+ it("retains the dark cycle order while lightening its failing violet slot", () => {
117
117
  const palette = resolveChartPalette({ scheme: "dark", identitySolid: "#aaaaaa" });
118
118
  expect(palette.categorical).toEqual([
119
119
  Colors.blueDark.blue9,
@@ -122,7 +122,7 @@ describe("resolveChartPalette", () => {
122
122
  Colors.amberDark.amber9,
123
123
  Colors.pinkDark.pink9,
124
124
  Colors.tealDark.teal9,
125
- Colors.violetDark.violet10,
125
+ Colors.violetDark.violet11,
126
126
  Colors.redDark.red9,
127
127
  ]);
128
128
  });
@@ -48,8 +48,8 @@ export interface ResolveChartPaletteInput {
48
48
  /** Ordered alternatives when the identity cannot meet the mark contrast floor. */
49
49
  identityCandidates?: readonly (string | undefined)[];
50
50
  /**
51
- * The active colour theme's page and Card fills (`$color2` and `$color3`
52
- * under v5's templates, the same in every sub-theme of that colour). A
51
+ * The active colour theme's page and Card fills (`$background` and the
52
+ * LC-151 card step, the same in every sub-theme of that colour). A
53
53
  * tint's surfaces are deeper than the reference whites, so the identity
54
54
  * must clear them too, and one palette serves a chart on the page or in a
55
55
  * Card.
@@ -67,8 +67,8 @@ export interface ResolveChartPaletteInput {
67
67
  * Fixed categorical hue cycle: Radix solids ordered so neighbouring
68
68
  * entries sit far apart on the hue wheel (min adjacent distance ~78°).
69
69
  * Light blue, orange, green, amber and teal deepen within their hue to clear
70
- * 3:1 on every built page and Card surface. Dark violet deepens for tinted
71
- * card backgrounds.
70
+ * 3:1 on every built page and Card surface. Dark violet lightens to step 11
71
+ * to clear the tinted `$color4` cards (FZ-8400).
72
72
  */
73
73
  const categoricalHueCycle = [
74
74
  { family: "blue", light: Colors.blue.blue10, dark: Colors.blueDark.blue9 },
@@ -77,7 +77,7 @@ const categoricalHueCycle = [
77
77
  { family: "amber", light: Colors.amber.amber11, dark: Colors.amberDark.amber9 },
78
78
  { family: "pink", light: Colors.pink.pink9, dark: Colors.pinkDark.pink9 },
79
79
  { family: "teal", light: Colors.teal.teal11, dark: Colors.tealDark.teal9 },
80
- { family: "violet", light: Colors.violet.violet9, dark: Colors.violetDark.violet10 },
80
+ { family: "violet", light: Colors.violet.violet9, dark: Colors.violetDark.violet11 },
81
81
  { family: "red", light: Colors.red.red9, dark: Colors.redDark.red9 },
82
82
  ] as const;
83
83
 
@@ -298,10 +298,10 @@ export function useChartPalette(): ChartPalette {
298
298
  const isTint = nameParts.length > 1 && tintHueNames.has(nameParts[1]);
299
299
  const color9 = theme.color9?.val;
300
300
  const accent = theme.accentBackground?.val;
301
- const page = theme.color2?.val;
302
- // The Card fill on the LC-151 ladder: the grouped white step in light, one
303
- // step above the page in dark.
304
- const card = (scheme === "light" ? theme.color1 : theme.color3)?.val;
301
+ const page = (theme.background ?? theme.color2)?.val;
302
+ // The Card fill on the LC-151 ladder: the grouped white step in light,
303
+ // `$color4` in dark (FZ-8400).
304
+ const card = (scheme === "light" ? theme.color1 : theme.color4)?.val;
305
305
  const identitySolid = isTint ? (color9 ?? accent) : (accent ?? color9);
306
306
  const color10 = theme.color10?.val;
307
307
  const color11 = theme.color11?.val;
@@ -116,6 +116,19 @@ export function isLightGround(ground: string): boolean {
116
116
  return hex !== null && relativeLuminance(hex) > 0.5;
117
117
  }
118
118
 
119
+ /**
120
+ * The ground an off Switch track is measured over (LC-172): the page in light,
121
+ * the `$color4` card or field in dark, where grouped layouts put a switch and
122
+ * where UISwitch composites its system fill over the cell (FZ-8400).
123
+ */
124
+ export function switchOffGround(scope: {
125
+ background?: string;
126
+ color4?: string;
127
+ }): string | undefined {
128
+ if (!scope.background) return undefined;
129
+ return isLightGround(scope.background) ? scope.background : (scope.color4 ?? scope.background);
130
+ }
131
+
119
132
  /** HIG's system fill at `alpha` composited over `ground`, as an opaque hex colour. */
120
133
  export function systemFillHex(ground: string, alpha: number): string | null {
121
134
  const hex = normalizeToHex(ground);
@@ -0,0 +1,114 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { contrastRatio, minContrastRatio, normalizeToHex, relativeLuminance } from "./colorRules";
3
+ import { createThemesBuilder } from "./createThemes";
4
+ import { resolveThemeThroughParents } from "./dedupeInherited";
5
+ import { defaultAccentTheme } from "./defaults/accent";
6
+ import { defaultBaseTheme } from "./defaults/base";
7
+ import { defaultBuilderOptions } from "./defaults/builderOptions";
8
+
9
+ const themes = createThemesBuilder(
10
+ defaultBaseTheme,
11
+ defaultAccentTheme,
12
+ defaultBuilderOptions,
13
+ ).themes() as Record<string, Record<string, string>>;
14
+
15
+ const intents = new Set(["error", "warning", "success"]);
16
+
17
+ function ratio(a: string | undefined, b: string | undefined) {
18
+ const aHex = normalizeToHex(a ?? "");
19
+ const bHex = normalizeToHex(b ?? "");
20
+ if (!aHex || !bHex) throw new Error(`Expected opaque colours: ${a}, ${b}`);
21
+ return contrastRatio(relativeLuminance(aHex), relativeLuminance(bHex));
22
+ }
23
+
24
+ const resolve = (name: string) =>
25
+ resolveThemeThroughParents(themes, name) as unknown as Record<string, string>;
26
+
27
+ const scopes = Object.keys(themes).filter(
28
+ (name) => /^(light|dark)(_[a-z]+)?$/.test(name) && !/_(accent|active)$/.test(name),
29
+ );
30
+ const hueScopes = scopes.filter((name) => !intents.has(name.split("_")[1] ?? ""));
31
+ const intentScopes = scopes.filter((name) => intents.has(name.split("_")[1] ?? ""));
32
+
33
+ describe("LC-299 CONTROL-EDGE: control edges clear WCAG 1.4.11's 3:1", () => {
34
+ it("covers both schemes and every preset hue", () => {
35
+ for (const hue of ["blue", "purple", "green", "orange", "pink"]) {
36
+ expect(hueScopes).toContain(`light_${hue}`);
37
+ expect(hueScopes).toContain(`dark_${hue}`);
38
+ }
39
+ });
40
+
41
+ for (const scope of hueScopes) {
42
+ it(`${scope}: field edges hold 3:1 on the page and on their own fill`, () => {
43
+ const page = resolve(scope);
44
+ for (const control of ["Input", "TextArea", "SelectTrigger", "InputContainerFrame"]) {
45
+ const field = resolve(`${scope}_${control}`);
46
+ for (const key of ["borderColorField", "borderColorFieldHover"]) {
47
+ expect(
48
+ ratio(field[key], page.background),
49
+ `${control} ${key} on page`,
50
+ ).toBeGreaterThanOrEqual(minContrastRatio);
51
+ expect(
52
+ ratio(field[key], field.background),
53
+ `${control} ${key} on its fill`,
54
+ ).toBeGreaterThanOrEqual(minContrastRatio);
55
+ }
56
+ }
57
+ });
58
+
59
+ it(`${scope}: the segmented frame edge holds 3:1 on the page`, () => {
60
+ const page = resolve(scope);
61
+ expect(ratio(page.borderColorControl, page.background)).toBeGreaterThanOrEqual(
62
+ minContrastRatio,
63
+ );
64
+ });
65
+
66
+ it(`${scope}: the off Switch track edge`, () => {
67
+ const page = resolve(scope);
68
+ const track = resolve(`${scope}_Switch`);
69
+ if (scope.startsWith("light")) {
70
+ expect(ratio(track.switchTrackOffBorder, page.background)).toBeGreaterThanOrEqual(
71
+ minContrastRatio,
72
+ );
73
+ } else {
74
+ expect(track.switchTrackOffBorder).toBe(track.switchTrackOff);
75
+ }
76
+ });
77
+ }
78
+
79
+ for (const scope of intentScopes) {
80
+ it(`${scope}: an intent field edge comes from its own ramp and holds 3:1`, () => {
81
+ const scheme = scope.split("_")[0]!;
82
+ const own = Array.from({ length: 12 }, (_, index) => themes[scope]![`color${index + 1}`]);
83
+ const pages = hueScopes.filter((name) => name.startsWith(`${scheme}_`)).concat(scheme);
84
+ for (const control of ["Input", "TextArea", "SelectTrigger", "InputContainerFrame"]) {
85
+ const field = resolve(`${scope}_${control}`);
86
+ for (const key of ["borderColorField", "borderColorFieldHover"]) {
87
+ expect(own, `${control} ${key}`).toContain(field[key]);
88
+ for (const page of pages)
89
+ expect(
90
+ ratio(field[key], resolve(page).background),
91
+ `${control} ${key} on ${page}`,
92
+ ).toBeGreaterThanOrEqual(minContrastRatio);
93
+ expect(
94
+ ratio(field[key], field.background),
95
+ `${control} ${key} on its fill`,
96
+ ).toBeGreaterThanOrEqual(minContrastRatio);
97
+ }
98
+ }
99
+ });
100
+ }
101
+
102
+ it("picks a neutral edge, not a tint that reads as the accent", () => {
103
+ for (const scope of hueScopes) {
104
+ const scheme = scope.split("_")[0]!;
105
+ const neutral = Array.from(
106
+ { length: 12 },
107
+ (_, index) => themes[scheme]![`color${index + 1}`],
108
+ );
109
+ const page = resolve(scope);
110
+ expect(neutral, `${scope} field`).toContain(page.borderColorField);
111
+ expect(neutral, `${scope} control`).toContain(page.borderColorControl);
112
+ }
113
+ });
114
+ });
@@ -4,11 +4,11 @@
4
4
  *
5
5
  * - `tinted`, in content: a filled wash with no edge, the preset's radius and
6
6
  * the size token's height. Light washes at `$color3` (#ededed on the stock
7
- * ramp), dark one step further up at `$color4`, because dark `$color3` sits
8
- * a single lightness point off the page and the button would vanish. On an
9
- * elevated ground (`useElevatedSurface()`: an overlay frame or an unnested
10
- * Panel) dark climbs one more step to `$color5`, because the dark elevated
11
- * tint is `$color4` itself (HIG: a control's fill sits above the elevated
7
+ * ramp), dark at `$color5`, one step above the `$color4` card and field it
8
+ * usually sits in (LC-151, FZ-8400). On an elevated ground
9
+ * (`useElevatedSurface()`: an overlay frame or an unnested Panel) dark
10
+ * climbs one more step to `$color6`, because the dark elevated tint is
11
+ * `$color5` itself (HIG: a control's fill sits above the elevated
12
12
  * background it is on). Light's elevated ground is the page step, so its
13
13
  * wash stays put.
14
14
  * - `plain`, inside a bar (`useBarSurface()`): ink only at rest, the tinted
@@ -30,11 +30,11 @@ export interface ControlTierPaint {
30
30
  }
31
31
 
32
32
  const lightWash: ControlTierPaint = { rest: "$color3", hover: "$color4", press: "$color5" };
33
- const darkWash: ControlTierPaint = { rest: "$color4", hover: "$color5", press: "$color6" };
33
+ const darkWash: ControlTierPaint = { rest: "$color5", hover: "$color6", press: "$color7" };
34
34
  const darkElevatedWash: ControlTierPaint = {
35
- rest: "$color5",
36
- hover: "$color6",
37
- press: "$color7",
35
+ rest: "$color6",
36
+ hover: "$color7",
37
+ press: "$color8",
38
38
  };
39
39
 
40
40
  /** The tinted wash for a scheme and ground: rest, hover and press fills. */
@@ -43,6 +43,15 @@ export function controlTierWash(dark: boolean, elevated = false): ControlTierPai
43
43
  return elevated ? darkElevatedWash : darkWash;
44
44
  }
45
45
 
46
+ /**
47
+ * A Slider or Progress track: `$color5`, a step above a dark `$color4` card;
48
+ * on a dark elevated ground `$color6`, a step above the `$color5` overlay
49
+ * (FZ-7944, FZ-8400). Light keeps `$color5`.
50
+ */
51
+ export function controlTrackFill(dark: boolean, elevated = false): string {
52
+ return dark && elevated ? "$color6" : "$color5";
53
+ }
54
+
46
55
  /** Rest, hover and press fills for a tier in a scheme, on the page or an elevated ground. */
47
56
  export function controlTierPaint(
48
57
  tier: ControlTier,