@multiplatform.one/theme 7.4.1 → 7.6.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/README.md +2 -1
- package/package.json +5 -5
- package/src/audit/index.ts +19 -0
- package/src/audit/themeMatrix.spec.ts +274 -0
- package/src/audit/themeMatrix.ts +630 -0
- package/src/figma/figmaTokens.spec.ts +25 -21
- package/src/figma/figmaTokens.ts +2 -2
- package/src/font.ts +37 -25
- package/src/index.ts +12 -0
- package/src/keyboardFocusRing.ts +12 -6
- package/src/theme/FontKnobStyles.tsx +14 -31
- package/src/theme/Tint.tsx +3 -2
- package/src/theme/animations/css.ts +14 -1
- package/src/theme/colorRules.spec.ts +306 -2
- package/src/theme/colorRules.ts +118 -0
- package/src/theme/cornerSmoothing.native.ts +39 -2
- package/src/theme/cornerSmoothing.spec.ts +270 -3
- package/src/theme/cornerSmoothing.ts +147 -10
- package/src/theme/createDefaultThemeConfig.spec.ts +107 -1
- package/src/theme/createDefaultThemeConfig.ts +27 -8
- package/src/theme/defaults/builderOptions.ts +23 -10
- package/src/theme/defaults/categoryFonts.ts +24 -0
- package/src/theme/defaults/fonts.spec.ts +163 -10
- package/src/theme/defaults/fonts.theme.spec.tsx +139 -0
- package/src/theme/defaults/fonts.ts +214 -50
- package/src/theme/defaults/index.ts +1 -0
- package/src/theme/devtools/ThemeDevtoolsPanel.tsx +0 -11
- package/src/theme/focusState.spec.ts +119 -1
- package/src/theme/focusState.ts +32 -7
- package/src/theme/fontCategoryMetrics.ts +57 -0
- package/src/theme/fontCategoryStacks.ts +37 -0
- package/src/theme/fontKnobStyles.spec.ts +15 -2
- package/src/theme/glyphPaint.spec.ts +26 -0
- package/src/theme/glyphPaint.ts +46 -0
- package/src/theme/index.ts +4 -0
- package/src/theme/knobs.ts +18 -2
- package/src/theme/layoutTokens.spec.ts +3 -1
- package/src/theme/layoutTokens.ts +47 -4
- package/src/theme/mpo13Proof.spec.ts +3 -3
- package/src/theme/mpo19Proof.spec.ts +285 -0
- package/src/theme/presets.ts +1 -1
- package/src/theme/radiusClass.spec.ts +394 -0
- package/src/theme/radiusClass.ts +203 -4
- package/src/theme/radiusClassTable.generated.ts +121 -0
- package/src/theme/recipeInputs.ts +223 -36
- package/src/theme/recipes.ts +68 -4
- package/src/theme/resolveKnobs.spec.ts +155 -13
- package/src/theme/resolveKnobs.ts +193 -27
- package/src/theme/sizeLadder.spec.ts +84 -0
- package/src/theme/sizeRecipes.spec.ts +19 -6
- package/src/theme/sizeRecipes.ts +43 -13
- package/src/theme/theme.native.tsx +2 -0
- package/src/theme/theme.provider.spec.ts +9 -0
- package/src/theme/theme.tsx +6 -3
- package/src/theme/tint.spec.tsx +36 -35
- package/src/theme/useResolvedKnobs.ts +6 -3
- package/types/audit/index.d.ts +2 -0
- package/types/audit/index.d.ts.map +1 -1
- package/types/audit/themeMatrix.d.ts +172 -0
- package/types/audit/themeMatrix.d.ts.map +1 -0
- package/types/figma/figmaTokens.d.ts +1 -1
- package/types/figma/figmaTokens.d.ts.map +1 -1
- package/types/font.d.ts.map +1 -1
- package/types/index.d.ts +2 -0
- package/types/index.d.ts.map +1 -1
- package/types/keyboardFocusRing.d.ts +11 -5
- package/types/keyboardFocusRing.d.ts.map +1 -1
- package/types/theme/FontKnobStyles.d.ts +8 -12
- package/types/theme/FontKnobStyles.d.ts.map +1 -1
- package/types/theme/Tint.d.ts +2 -1
- package/types/theme/Tint.d.ts.map +1 -1
- package/types/theme/animations/css.d.ts +15 -2
- package/types/theme/animations/css.d.ts.map +1 -1
- package/types/theme/colorRules.d.ts +59 -1
- package/types/theme/colorRules.d.ts.map +1 -1
- package/types/theme/cornerSmoothing.d.ts +42 -20
- package/types/theme/cornerSmoothing.d.ts.map +1 -1
- package/types/theme/cornerSmoothing.native.d.ts +22 -2
- package/types/theme/cornerSmoothing.native.d.ts.map +1 -1
- package/types/theme/createDefaultThemeConfig.d.ts +21 -3
- package/types/theme/createDefaultThemeConfig.d.ts.map +1 -1
- package/types/theme/defaults/builderOptions.d.ts.map +1 -1
- package/types/theme/defaults/categoryFonts.d.ts +23 -0
- package/types/theme/defaults/categoryFonts.d.ts.map +1 -0
- package/types/theme/defaults/fonts.d.ts +140 -2
- package/types/theme/defaults/fonts.d.ts.map +1 -1
- package/types/theme/defaults/index.d.ts +1 -0
- package/types/theme/defaults/index.d.ts.map +1 -1
- package/types/theme/devtools/ThemeDevtoolsPanel.d.ts.map +1 -1
- package/types/theme/focusState.d.ts +32 -6
- package/types/theme/focusState.d.ts.map +1 -1
- package/types/theme/fontCategoryMetrics.d.ts +36 -0
- package/types/theme/fontCategoryMetrics.d.ts.map +1 -0
- package/types/theme/fontCategoryStacks.d.ts +24 -0
- package/types/theme/fontCategoryStacks.d.ts.map +1 -0
- package/types/theme/glyphPaint.d.ts +16 -0
- package/types/theme/glyphPaint.d.ts.map +1 -0
- package/types/theme/index.d.ts +4 -0
- package/types/theme/index.d.ts.map +1 -1
- package/types/theme/knobs.d.ts +10 -2
- package/types/theme/knobs.d.ts.map +1 -1
- package/types/theme/layoutTokens.d.ts +46 -4
- package/types/theme/layoutTokens.d.ts.map +1 -1
- package/types/theme/radiusClass.d.ts +96 -4
- package/types/theme/radiusClass.d.ts.map +1 -1
- package/types/theme/radiusClassTable.generated.d.ts +146 -0
- package/types/theme/radiusClassTable.generated.d.ts.map +1 -0
- package/types/theme/recipeInputs.d.ts +85 -14
- package/types/theme/recipeInputs.d.ts.map +1 -1
- package/types/theme/recipes.d.ts +78 -4
- package/types/theme/recipes.d.ts.map +1 -1
- package/types/theme/resolveKnobs.d.ts +12 -1
- package/types/theme/resolveKnobs.d.ts.map +1 -1
- package/types/theme/sizeRecipes.d.ts +27 -14
- package/types/theme/sizeRecipes.d.ts.map +1 -1
- package/types/theme/theme.d.ts.map +1 -1
- package/types/theme/theme.native.d.ts.map +1 -1
- package/types/theme/useResolvedKnobs.d.ts +2 -2
- package/types/theme/useResolvedKnobs.d.ts.map +1 -1
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
SIZE_RECIPE_COMPACT_RATIOS,
|
|
8
8
|
SIZE_RECIPE_HEIGHTS,
|
|
9
9
|
SIZE_RECIPE_HEIGHTS_TOUCH,
|
|
10
|
+
SIZE_RECIPE_RADII,
|
|
10
11
|
SIZE_RECIPE_RATIOS,
|
|
11
12
|
applyTouchFloor,
|
|
12
13
|
defaultRecipeInputs,
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
sizeRecipeIconVariants,
|
|
23
24
|
sizeRecipes,
|
|
24
25
|
sizeRecipeTypeVariants,
|
|
26
|
+
textFieldInset,
|
|
25
27
|
type SizeRecipe,
|
|
26
28
|
} from "./sizeRecipes";
|
|
27
29
|
|
|
@@ -75,10 +77,9 @@ describe("size recipes", () => {
|
|
|
75
77
|
}
|
|
76
78
|
});
|
|
77
79
|
|
|
78
|
-
it("static variants match
|
|
80
|
+
it("static variants match the generated table for every token", () => {
|
|
79
81
|
for (const token of RECIPE_KEYS) {
|
|
80
|
-
const recipe =
|
|
81
|
-
expect(sizeRecipes[token]).toEqual(recipe);
|
|
82
|
+
const recipe = sizeRecipes[token];
|
|
82
83
|
expect(sizeRecipeBoxVariants[token]).toEqual({
|
|
83
84
|
height: recipe.height,
|
|
84
85
|
paddingHorizontal: recipe.paddingHorizontal,
|
|
@@ -90,6 +91,7 @@ describe("size recipes", () => {
|
|
|
90
91
|
height: recipe.iconSize,
|
|
91
92
|
});
|
|
92
93
|
}
|
|
94
|
+
expect(sizeRecipeFromHeight(44)).toEqual(sizeRecipes.$4);
|
|
93
95
|
});
|
|
94
96
|
|
|
95
97
|
it("sizeRecipeForToken falls back to $4", () => {
|
|
@@ -230,7 +232,7 @@ describe("generateSizeRecipes (LC-70)", () => {
|
|
|
230
232
|
expect(generated.families.control.recipes.$4.height).toBe(44);
|
|
231
233
|
expect(generated.families.controlCompact.recipes.$4.height).toBe(44);
|
|
232
234
|
expect(generated.families.control.recipes.$4.paddingHorizontal).toBe(18);
|
|
233
|
-
expect(generated.families.controlCompact.recipes.$4.paddingHorizontal).toBe(
|
|
235
|
+
expect(generated.families.controlCompact.recipes.$4.paddingHorizontal).toBe(16);
|
|
234
236
|
expect(generated.families.controlCompact.recipes.$4.paddingHorizontal).toBeLessThan(
|
|
235
237
|
generated.families.control.recipes.$4.paddingHorizontal,
|
|
236
238
|
);
|
|
@@ -260,12 +262,23 @@ describe("generateSizeRecipes (LC-70)", () => {
|
|
|
260
262
|
expect(sizeRecipeTypeVariants).toBe(recipeFamilies.control.typeVariants);
|
|
261
263
|
expect(sizeRecipeIconVariants).toBe(recipeFamilies.control.iconVariants);
|
|
262
264
|
expect(SIZE_RECIPE_HEIGHTS).toBe(recipeFamilies.control.heights);
|
|
265
|
+
expect(SIZE_RECIPE_RADII).toBe(recipeFamilies.control.radii);
|
|
263
266
|
});
|
|
264
267
|
|
|
265
268
|
it("sizeRecipeEscape is identity", () => {
|
|
266
269
|
expect(sizeRecipeEscape(32)).toBe(32);
|
|
267
270
|
expect(sizeRecipeEscape("keep")).toBe("keep");
|
|
268
271
|
});
|
|
272
|
+
|
|
273
|
+
it("textFieldInset is min(padX, floor((height-fontSize)/2)) — $4 → 15 (LC-84)", () => {
|
|
274
|
+
expect(textFieldInset(sizeRecipes.$4)).toBe(15);
|
|
275
|
+
expect(textFieldInset({ height: 44, paddingHorizontal: 18, fontSize: 14 })).toBe(15);
|
|
276
|
+
expect(textFieldInset({ height: 32, paddingHorizontal: 12, fontSize: 14 })).toBe(9);
|
|
277
|
+
expect(textFieldInset({ height: 48, paddingHorizontal: 8, fontSize: 14 })).toBe(8);
|
|
278
|
+
expect(textFieldInset(sizeRecipes.$4)).toBeLessThanOrEqual(
|
|
279
|
+
Math.floor((sizeRecipes.$4.height - sizeRecipes.$4.fontSize) / 2),
|
|
280
|
+
);
|
|
281
|
+
});
|
|
269
282
|
});
|
|
270
283
|
|
|
271
284
|
describe("size recipe families", () => {
|
|
@@ -291,8 +304,8 @@ describe("size recipe families", () => {
|
|
|
291
304
|
expect(compact.boxVariants.$4.paddingHorizontal).toBeLessThan(
|
|
292
305
|
control.boxVariants.$4.paddingHorizontal,
|
|
293
306
|
);
|
|
294
|
-
expect(compact.boxVariants.$4.paddingHorizontal).toBe(
|
|
295
|
-
expect(compact.boxVariants.$4.gap).toBe(
|
|
307
|
+
expect(compact.boxVariants.$4.paddingHorizontal).toBe(16);
|
|
308
|
+
expect(compact.boxVariants.$4.gap).toBe(9);
|
|
296
309
|
expect(sizeRecipeForToken("$4", { family: "controlCompact" })).toEqual(compact.recipes.$4);
|
|
297
310
|
});
|
|
298
311
|
});
|
package/src/theme/sizeRecipes.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Coordinated control-size recipes (LC-
|
|
2
|
+
* Coordinated control-size recipes (LC-75 SIZE-RECIPE, LC-80 RECIPE-INPUTS).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The default ladder is the measured Tamagui v5 table in recipeInputs
|
|
5
|
+
* (padX / font / icon / radius per size token). Gap equals radius at
|
|
6
|
+
* every size and at every borderRadius knob stop (`applyRadiusStop`).
|
|
7
|
+
* A linear ratio is only the `{ baseHeight }` fallback — not a
|
|
8
|
+
* documented divergence (MPO-46 / R6).
|
|
7
9
|
*
|
|
8
10
|
* Tables are GENERATED from `defaultRecipeInputs` at module eval (Tamagui
|
|
9
11
|
* 2.0.0-rc.41 flattens `styled(View, { variants: { size: tables } })` when
|
|
@@ -13,25 +15,30 @@
|
|
|
13
15
|
* reserve it for non-enumerable values only. Do NOT put recipe tables on a
|
|
14
16
|
* `createStyledContext` primitive (`neverFlatten`).
|
|
15
17
|
*
|
|
16
|
-
* Reference md ($4 / $true): height 44, padX 18, font 14, icon 16,
|
|
17
|
-
* (the measured tamagui.dev $4 control — MPO-13).
|
|
18
|
+
* Reference md ($4 / $true): height 44, padX 18, font 14, icon 16, radius 9,
|
|
19
|
+
* gap 9 (the measured tamagui.dev $4 control — MPO-13 / MPO-19 X1/X2).
|
|
18
20
|
* `sizeToken` remains the recipe KEY (string "$4") so styled() variants
|
|
19
21
|
* can switch; it is not a height scalar.
|
|
20
22
|
*
|
|
21
|
-
* Families: `control`
|
|
22
|
-
* `
|
|
23
|
+
* Families: `control` reads `inputs.tokenTable`. `controlCompact` reads
|
|
24
|
+
* `compactTokenTable` at the SAME heights (Input padX, tighter type).
|
|
23
25
|
*
|
|
24
|
-
* On touch (LC-
|
|
25
|
-
* lift painted height to ≥ 44
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* On touch (LC-77), `applyTouchFloor` / `sizeRecipeForToken(token, { touch: true })`
|
|
27
|
+
* lift painted height to ≥ 44. Static `sizeRecipe*Variants` stay on the
|
|
28
|
+
* desktop table — runtime fragments carry the floor; consumers spread
|
|
29
|
+
* `knobProps.control` after `size`.
|
|
28
30
|
*/
|
|
29
31
|
|
|
30
32
|
export {
|
|
31
33
|
DEFAULT_SIZE_RECIPE_INPUTS,
|
|
34
|
+
SIZE_RECIPE_RADIUS_STOPS,
|
|
32
35
|
SIZE_RECIPE_TOKENS,
|
|
33
36
|
SIZE_TOKEN_EXPONENTS,
|
|
37
|
+
TAMAGUI_COMPACT_SIZE_TABLE,
|
|
38
|
+
TAMAGUI_CONTROL_SIZE_TABLE,
|
|
39
|
+
TAMAGUI_INPUT_PADX,
|
|
34
40
|
TOUCH_HEIGHT_FLOOR,
|
|
41
|
+
applyRadiusStop,
|
|
35
42
|
cloneSizeRecipeInputs,
|
|
36
43
|
createRecipeFamilies,
|
|
37
44
|
defaultRecipeInputs,
|
|
@@ -39,6 +46,7 @@ export {
|
|
|
39
46
|
generateSizeRecipeTables,
|
|
40
47
|
generateSizeRecipes,
|
|
41
48
|
mergeRecipeInputs,
|
|
49
|
+
recipeFromTokenChannels,
|
|
42
50
|
resolveSizeRecipeInputs,
|
|
43
51
|
} from "./recipeInputs";
|
|
44
52
|
export type {
|
|
@@ -52,13 +60,17 @@ export type {
|
|
|
52
60
|
SizeRecipeFamilyName,
|
|
53
61
|
SizeRecipeIconVariant,
|
|
54
62
|
SizeRecipeInputs,
|
|
63
|
+
SizeRecipeRadiusStop,
|
|
55
64
|
SizeRecipeRatios,
|
|
56
65
|
SizeRecipeTables,
|
|
57
66
|
SizeRecipeToken,
|
|
67
|
+
SizeRecipeTokenChannels,
|
|
68
|
+
SizeRecipeTokenTable,
|
|
58
69
|
SizeRecipeTypeVariant,
|
|
59
70
|
} from "./recipeInputs";
|
|
60
71
|
|
|
61
72
|
import {
|
|
73
|
+
cloneSizeRecipeInputs,
|
|
62
74
|
defaultRecipeInputs,
|
|
63
75
|
generateSizeRecipes,
|
|
64
76
|
sizeRecipeFromHeight as recipeFromHeight,
|
|
@@ -88,6 +100,7 @@ function adoptFamily(target: SizeRecipeFamily, source: SizeRecipeFamily): void {
|
|
|
88
100
|
replaceRecord(target.typeVariants, source.typeVariants);
|
|
89
101
|
replaceRecord(target.iconVariants, source.iconVariants);
|
|
90
102
|
replaceRecord(target.heightVariants, source.heightVariants);
|
|
103
|
+
replaceRecord(target.radii, source.radii);
|
|
91
104
|
}
|
|
92
105
|
|
|
93
106
|
const initial = generateSizeRecipes(defaultRecipeInputs);
|
|
@@ -106,6 +119,7 @@ export const sizeRecipeTypeVariants = recipeFamilies.control.typeVariants;
|
|
|
106
119
|
export const sizeRecipeIconVariants = recipeFamilies.control.iconVariants;
|
|
107
120
|
export const SIZE_RECIPE_HEIGHTS = recipeFamilies.control.heights;
|
|
108
121
|
export const SIZE_RECIPE_HEIGHTS_TOUCH = recipeFamilies.control.touchHeights;
|
|
122
|
+
export const SIZE_RECIPE_RADII = recipeFamilies.control.radii;
|
|
109
123
|
export const SIZE_RECIPE_RATIOS = recipeFamilies.control.ratios;
|
|
110
124
|
export const SIZE_RECIPE_COMPACT_RATIOS = recipeFamilies.controlCompact.ratios;
|
|
111
125
|
|
|
@@ -139,6 +153,7 @@ function adoptGenerated(next: GeneratedSizeRecipes): GeneratedSizeRecipes {
|
|
|
139
153
|
boxVariants: sizeRecipeBoxVariants,
|
|
140
154
|
typeVariants: sizeRecipeTypeVariants,
|
|
141
155
|
iconVariants: sizeRecipeIconVariants,
|
|
156
|
+
radii: SIZE_RECIPE_RADII,
|
|
142
157
|
families: recipeFamilies,
|
|
143
158
|
};
|
|
144
159
|
return current;
|
|
@@ -150,7 +165,7 @@ export function setSizeRecipeInputs(partial: Partial<RecipeInputs> = {}): Genera
|
|
|
150
165
|
}
|
|
151
166
|
|
|
152
167
|
export function getSizeRecipeInputs(): RecipeInputs {
|
|
153
|
-
return
|
|
168
|
+
return cloneSizeRecipeInputs(current.inputs);
|
|
154
169
|
}
|
|
155
170
|
|
|
156
171
|
export function getGeneratedSizeRecipes(): GeneratedSizeRecipes {
|
|
@@ -210,3 +225,18 @@ export function sizeRecipeForToken(
|
|
|
210
225
|
export function sizeRecipeEscape<T>(value: T): T {
|
|
211
226
|
return value;
|
|
212
227
|
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* LC-84 TEXT-INSET — optical vertical inset of a text field, never larger
|
|
231
|
+
* than the recipe padX. Extra horizontal space is legal only when an icon
|
|
232
|
+
* well occupies that side, not as empty-field padX.
|
|
233
|
+
*
|
|
234
|
+
* min(paddingHorizontal, floor((height − fontSize) / 2))
|
|
235
|
+
*
|
|
236
|
+
* `$4` (44 / 18 / 14) → 15. Button ladders keep recipe.paddingHorizontal (18).
|
|
237
|
+
*/
|
|
238
|
+
export function textFieldInset(
|
|
239
|
+
recipe: Pick<SizeRecipe, "height" | "paddingHorizontal" | "fontSize">,
|
|
240
|
+
): number {
|
|
241
|
+
return Math.min(recipe.paddingHorizontal, Math.floor((recipe.height - recipe.fontSize) / 2));
|
|
242
|
+
}
|
|
@@ -2,6 +2,7 @@ import { ToastProvider } from "@tamagui/toast";
|
|
|
2
2
|
import { useContext, useMemo } from "react";
|
|
3
3
|
import { type CreateTamaguiProps, TamaguiProvider, type TamaguiProviderProps } from "tamagui";
|
|
4
4
|
import type { PropsWithChildren } from "react";
|
|
5
|
+
import { CornerSmoothingStyles } from "./cornerSmoothing";
|
|
5
6
|
import { FontKnobStyles } from "./FontKnobStyles";
|
|
6
7
|
import { PresetContext, type PresetContextValue } from "./PresetContext";
|
|
7
8
|
import { defaultPreset } from "./presets";
|
|
@@ -61,6 +62,7 @@ function KnobBridge({ children }: PropsWithChildren) {
|
|
|
61
62
|
const tree = (
|
|
62
63
|
<>
|
|
63
64
|
<FontKnobStyles />
|
|
65
|
+
<CornerSmoothingStyles />
|
|
64
66
|
{children}
|
|
65
67
|
</>
|
|
66
68
|
);
|
|
@@ -15,6 +15,15 @@ describe("ThemeProvider knob injectors", () => {
|
|
|
15
15
|
expect(bridge).toContain("<FontKnobStyles");
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
+
it("mounts CornerSmoothingStyles inside KnobBridge so the squircle sheet is not tree-shaken", () => {
|
|
19
|
+
const src = readFileSync(join(here, "theme.tsx"), "utf8");
|
|
20
|
+
expect(src).toMatch(/import \{ CornerSmoothingStyles \} from "\.\/cornerSmoothing"/);
|
|
21
|
+
const bridge = src.slice(src.indexOf("function KnobBridge"));
|
|
22
|
+
expect(bridge).toContain("<CornerSmoothingStyles");
|
|
23
|
+
const native = readFileSync(join(here, "theme.native.tsx"), "utf8");
|
|
24
|
+
expect(native).toContain("<CornerSmoothingStyles");
|
|
25
|
+
});
|
|
26
|
+
|
|
18
27
|
it("does not invent a second knob store — cookies still feed PresetContext", () => {
|
|
19
28
|
const src = readFileSync(join(here, "theme.tsx"), "utf8");
|
|
20
29
|
expect(src).toContain("readPresetCookie");
|
package/src/theme/theme.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import { type CreateTamaguiProps, TamaguiProvider, type TamaguiProviderProps } f
|
|
|
5
5
|
import type { PropsWithChildren } from "react";
|
|
6
6
|
import { animationDurations } from "./animations/css";
|
|
7
7
|
import { getCookieWatchList, readOverridesCookie, readPresetCookie } from "./cookies";
|
|
8
|
+
import { CornerSmoothingStyles } from "./cornerSmoothing";
|
|
8
9
|
import { FontKnobStyles } from "./FontKnobStyles";
|
|
9
10
|
import { PresetContext, type PresetContextValue } from "./PresetContext";
|
|
10
11
|
import { defaultPreset } from "./presets";
|
|
@@ -157,9 +158,10 @@ export function ThemeProvider<T extends CreateTamaguiProps>({
|
|
|
157
158
|
* If an ancestor PresetContext already exists (e.g. from a Storybook decorator),
|
|
158
159
|
* the bridge is a pass-through to avoid overriding it.
|
|
159
160
|
*
|
|
160
|
-
* FontKnobStyles
|
|
161
|
-
*
|
|
162
|
-
*
|
|
161
|
+
* FontKnobStyles and CornerSmoothingStyles mount here (not only in
|
|
162
|
+
* Storybook CreatePreview) so heading/body fonts and the corner-shape
|
|
163
|
+
* stylesheet restyle every shipped app that uses ThemeProvider. Hairline
|
|
164
|
+
* still self-mounts on module load.
|
|
163
165
|
*/
|
|
164
166
|
function KnobBridge({ children }: PropsWithChildren) {
|
|
165
167
|
const existingCtx = useContext(PresetContext);
|
|
@@ -192,6 +194,7 @@ function KnobBridge({ children }: PropsWithChildren) {
|
|
|
192
194
|
const tree = (
|
|
193
195
|
<>
|
|
194
196
|
<FontKnobStyles />
|
|
197
|
+
<CornerSmoothingStyles />
|
|
195
198
|
{children}
|
|
196
199
|
</>
|
|
197
200
|
);
|
package/src/theme/tint.spec.tsx
CHANGED
|
@@ -13,12 +13,16 @@ import type { ThemeName } from "@tamagui/web";
|
|
|
13
13
|
import { PresetContext, type PresetContextValue } from "./PresetContext";
|
|
14
14
|
import type { Preset } from "./preset.types";
|
|
15
15
|
import { defaultKnobs } from "./knobs";
|
|
16
|
+
import { defaultPreset } from "./presets";
|
|
16
17
|
import { Tint, useTintDepth } from "./Tint";
|
|
17
18
|
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
// Helpers
|
|
20
21
|
// ---------------------------------------------------------------------------
|
|
21
22
|
|
|
23
|
+
/** Decorative nest family (R12) — the same four names as `defaultPreset.tints`. */
|
|
24
|
+
const FAMILY: ThemeName[] = ["orange", "blue", "purple", "pink"];
|
|
25
|
+
|
|
22
26
|
function makePreset(tints: ThemeName[]): Preset {
|
|
23
27
|
return {
|
|
24
28
|
theme: "light" as ThemeName,
|
|
@@ -42,71 +46,70 @@ function collectThemes(html: string): string[] {
|
|
|
42
46
|
return Array.from(html.matchAll(/data-tamagui-theme="([^"]+)"/g), (m) => m[1]);
|
|
43
47
|
}
|
|
44
48
|
|
|
49
|
+
function nestTints(
|
|
50
|
+
count: number,
|
|
51
|
+
innermost: ReactNode = createElement("span", null, "inner"),
|
|
52
|
+
): ReactNode {
|
|
53
|
+
let node: ReactNode = innermost;
|
|
54
|
+
for (let i = 0; i < count; i++) {
|
|
55
|
+
node = createElement(Tint, null, node);
|
|
56
|
+
}
|
|
57
|
+
return node;
|
|
58
|
+
}
|
|
59
|
+
|
|
45
60
|
// ---------------------------------------------------------------------------
|
|
46
61
|
// Tests
|
|
47
62
|
// ---------------------------------------------------------------------------
|
|
48
63
|
|
|
49
64
|
describe("Tint", () => {
|
|
50
|
-
it("
|
|
51
|
-
|
|
65
|
+
it("defaultPreset.tints is the four-name decorative family", () => {
|
|
66
|
+
expect(defaultPreset.tints).toEqual(FAMILY);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("selects tints[0] for a single <Tint> (depth 1)", () => {
|
|
52
70
|
const tree = wrapWithPreset(
|
|
53
|
-
|
|
71
|
+
FAMILY,
|
|
54
72
|
createElement(Tint, null, createElement("span", null, "hello")),
|
|
55
73
|
);
|
|
56
74
|
const html = renderToHtml(tree);
|
|
57
75
|
const themes = collectThemes(html);
|
|
58
|
-
// depth = 0 (parent) + 1 = 1 → tints[1 %
|
|
59
|
-
expect(themes).toEqual(["
|
|
76
|
+
// depth = 0 (parent) + 1 = 1 → tints[(1 - 1) % 4] = "orange"
|
|
77
|
+
expect(themes).toEqual(["orange"]);
|
|
60
78
|
});
|
|
61
79
|
|
|
62
80
|
it("increments depth correctly with nested <Tint>", () => {
|
|
63
|
-
const tints: ThemeName[] = ["red", "green", "blue"];
|
|
64
81
|
const tree = wrapWithPreset(
|
|
65
|
-
|
|
82
|
+
FAMILY,
|
|
66
83
|
createElement(Tint, null, createElement(Tint, null, createElement("span", null, "inner"))),
|
|
67
84
|
);
|
|
68
85
|
const html = renderToHtml(tree);
|
|
69
86
|
const themes = collectThemes(html);
|
|
70
|
-
// outer: depth=1 → tints[
|
|
71
|
-
expect(themes).toEqual(["
|
|
87
|
+
// outer: depth=1 → tints[0]="orange", inner: depth=2 → tints[1]="blue"
|
|
88
|
+
expect(themes).toEqual(["orange", "blue"]);
|
|
72
89
|
});
|
|
73
90
|
|
|
74
91
|
it("wraps via modulo when depth exceeds tints.length", () => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const tree = wrapWithPreset(
|
|
78
|
-
tints,
|
|
79
|
-
createElement(
|
|
80
|
-
Tint,
|
|
81
|
-
null,
|
|
82
|
-
createElement(
|
|
83
|
-
Tint,
|
|
84
|
-
null,
|
|
85
|
-
createElement(Tint, null, createElement(Tint, null, createElement("span", null, "deep"))),
|
|
86
|
-
),
|
|
87
|
-
),
|
|
88
|
-
);
|
|
92
|
+
// 5 nested Tints: depths 1..5 → indices 0,1,2,3,0 → orange,blue,purple,pink,orange
|
|
93
|
+
const tree = wrapWithPreset(FAMILY, nestTints(5, createElement("span", null, "deep")));
|
|
89
94
|
const html = renderToHtml(tree);
|
|
90
95
|
const themes = collectThemes(html);
|
|
91
|
-
expect(themes).toEqual(["
|
|
96
|
+
expect(themes).toEqual(["orange", "blue", "purple", "pink", "orange"]);
|
|
92
97
|
});
|
|
93
98
|
|
|
94
99
|
it("applies alt prop offset", () => {
|
|
95
|
-
|
|
96
|
-
// alt=2 at top level: depth = 0 + 1 + 2 = 3 → tints[3%3] = "red"
|
|
100
|
+
// alt=2 at top level: depth = 0 + 1 + 2 = 3 → tints[(3 - 1) % 4] = "purple"
|
|
97
101
|
const tree = wrapWithPreset(
|
|
98
|
-
|
|
102
|
+
FAMILY,
|
|
99
103
|
createElement(Tint, { alt: 2 }, createElement("span", null, "alt")),
|
|
100
104
|
);
|
|
101
105
|
const html = renderToHtml(tree);
|
|
102
106
|
const themes = collectThemes(html);
|
|
103
|
-
expect(themes).toEqual(["
|
|
107
|
+
expect(themes).toEqual(["purple"]);
|
|
104
108
|
});
|
|
105
109
|
|
|
106
110
|
it("skips Theme wrapper when disable is true", () => {
|
|
107
|
-
const tints: ThemeName[] = ["red", "green", "blue"];
|
|
108
111
|
const tree = wrapWithPreset(
|
|
109
|
-
|
|
112
|
+
FAMILY,
|
|
110
113
|
createElement(Tint, { disable: true }, createElement("span", null, "no theme")),
|
|
111
114
|
);
|
|
112
115
|
const html = renderToHtml(tree);
|
|
@@ -115,10 +118,9 @@ describe("Tint", () => {
|
|
|
115
118
|
});
|
|
116
119
|
|
|
117
120
|
it("still increments depth when disabled (so children see correct depth)", () => {
|
|
118
|
-
|
|
119
|
-
// disabled outer (depth=1, no theme wrap), inner (depth=2, wraps with tints[2%3]="blue")
|
|
121
|
+
// disabled outer (depth=1, no theme wrap), inner (depth=2, wraps with tints[1]="blue")
|
|
120
122
|
const tree = wrapWithPreset(
|
|
121
|
-
|
|
123
|
+
FAMILY,
|
|
122
124
|
createElement(
|
|
123
125
|
Tint,
|
|
124
126
|
{ disable: true },
|
|
@@ -163,14 +165,13 @@ describe("useTintDepth", () => {
|
|
|
163
165
|
});
|
|
164
166
|
|
|
165
167
|
it("returns current depth inside nested <Tint> components", () => {
|
|
166
|
-
const tints: ThemeName[] = ["red", "green", "blue"];
|
|
167
168
|
let capturedDepth = -1;
|
|
168
169
|
const Probe = () => {
|
|
169
170
|
capturedDepth = useTintDepth();
|
|
170
171
|
return createElement("span", null, "probe");
|
|
171
172
|
};
|
|
172
173
|
const tree = wrapWithPreset(
|
|
173
|
-
|
|
174
|
+
FAMILY,
|
|
174
175
|
createElement(Tint, null, createElement(Tint, null, createElement(Probe))),
|
|
175
176
|
);
|
|
176
177
|
renderToHtml(tree);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, useContext, useEffect, useMemo, useState } from "react";
|
|
2
|
-
import type
|
|
2
|
+
import { type SizeTokens, useThemeName } from "tamagui";
|
|
3
3
|
import { defaultKnobs, type Knobs } from "./knobs";
|
|
4
4
|
import type { IntentOverride } from "./preset.types";
|
|
5
5
|
import type { KnobPropsOverride, ResolvedKnobs } from "./recipes";
|
|
@@ -111,12 +111,14 @@ export const solidButtonIntents = new Set(["error", "warning", "success"]);
|
|
|
111
111
|
* 6. Apply density (space only; compact option wins when provided)
|
|
112
112
|
* 7. Re-clamp to Surface ceiling (compact option cannot exceed parent)
|
|
113
113
|
* 8. OS reduced-motion forces animation="none"
|
|
114
|
-
* 9. Call resolveKnobs(mergedKnobs, override) — override merges last
|
|
114
|
+
* 9. Call resolveKnobs(mergedKnobs, override, scheme) — override merges last
|
|
115
115
|
*/
|
|
116
116
|
export function useResolvedKnobs(options?: UseResolvedKnobsOptions): ResolvedKnobs {
|
|
117
117
|
const presetCtx = usePresetContext();
|
|
118
118
|
const contextIntent = useIntentContext();
|
|
119
119
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
120
|
+
const themeName = useThemeName() as string | undefined;
|
|
121
|
+
const scheme = themeName?.startsWith("dark") ? "dark" : "light";
|
|
120
122
|
const surfaceCtx = SurfaceContext.useStyledContext();
|
|
121
123
|
const surfaceSize = surfaceCtx?.size ?? "unset";
|
|
122
124
|
const surfaceDensity = surfaceCtx?.density ?? "unset";
|
|
@@ -186,7 +188,7 @@ export function useResolvedKnobs(options?: UseResolvedKnobsOptions): ResolvedKno
|
|
|
186
188
|
merged = { ...merged, animation: "none" };
|
|
187
189
|
}
|
|
188
190
|
|
|
189
|
-
const resolved = resolveKnobs(merged, override);
|
|
191
|
+
const resolved = resolveKnobs(merged, override, scheme);
|
|
190
192
|
|
|
191
193
|
if (intent && component === "Button" && solidButtonIntents.has(intent)) {
|
|
192
194
|
const labelColor = merged.fillStyle === "filled" ? "$color" : "$color11";
|
|
@@ -210,5 +212,6 @@ export function useResolvedKnobs(options?: UseResolvedKnobsOptions): ResolvedKno
|
|
|
210
212
|
prefersReducedMotion,
|
|
211
213
|
surfaceSize,
|
|
212
214
|
surfaceDensity,
|
|
215
|
+
scheme,
|
|
213
216
|
]);
|
|
214
217
|
}
|
package/types/audit/index.d.ts
CHANGED
|
@@ -2,4 +2,6 @@ export type { AuditReport, AuditSummary, ElementAudit, PropertyAudit, TextProper
|
|
|
2
2
|
export { runConstraintAudit } from "./constraintAudit";
|
|
3
3
|
export type { AuditDiff, ElementDiff, PropertyDiff } from "./diffReport";
|
|
4
4
|
export { diffAuditReports, formatAuditReport } from "./diffReport";
|
|
5
|
+
export type { GeometryDiff, GeometryMove, MatrixElementGeometry, MatrixRect, MatrixSnapshot, MatrixTextSample, NoBreakageInput, NoBreakageResult, TextContrastResult, TextContrastViolation, } from "./themeMatrix";
|
|
6
|
+
export { auditSignatures, captureMatrixSnapshot, diffGeometry, evaluateNoBreakage, evaluateTextContrast, } from "./themeMatrix";
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACnE,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme-matrix invariance + no-breakage assertions (MPO-18).
|
|
3
|
+
*
|
|
4
|
+
* The theme matrix sweeps every story cell across the globals axes
|
|
5
|
+
* (scheme × theme colour × preset) and holds TWO separate assertions,
|
|
6
|
+
* never one:
|
|
7
|
+
*
|
|
8
|
+
* 1. GEOMETRY INVARIANCE across the THEME axis — switching the theme
|
|
9
|
+
* colour may repaint ink, never move a box. Colour is the one axis
|
|
10
|
+
* whose whole contract is "paint only" (LC-80 RECIPE-INPUTS: size
|
|
11
|
+
* recipes are generated from inputs at config time; Tamagui colour
|
|
12
|
+
* themes stay the colour path). Any geometry delta across colours
|
|
13
|
+
* means a recipe consumed a theme option.
|
|
14
|
+
*
|
|
15
|
+
* 2. NO-BREAKAGE across the PRESET axis — presets are EXPECTED to move
|
|
16
|
+
* pixels (boldPreset flips radius/border/weight/space; heroPreset
|
|
17
|
+
* moves the page title scale), so geometry equality is deliberately
|
|
18
|
+
* NOT asserted there. What must hold in every preset cell: the story
|
|
19
|
+
* renders, structural values stay on the knob scales
|
|
20
|
+
* (runConstraintAudit off-scale count vs the default cell), and text
|
|
21
|
+
* ink keeps the WCAG floor (evaluateTextContrast).
|
|
22
|
+
*
|
|
23
|
+
* MEASURING RULE: every text assertion here measures TEXT NODES — the
|
|
24
|
+
* computed style of the element that DIRECTLY contains the text, and the
|
|
25
|
+
* Range-measured rect of the text itself — never the story frame. The
|
|
26
|
+
* frame's font-family is always Inter and its colour is not the ink
|
|
27
|
+
* (that trap shipped three wrong tickets: MPO-40/44/48).
|
|
28
|
+
*
|
|
29
|
+
* `captureMatrixSnapshot` is completely self-contained (no imports, no
|
|
30
|
+
* closures) so it can be passed straight to Playwright's
|
|
31
|
+
* `page.evaluate(captureMatrixSnapshot)`, exactly like
|
|
32
|
+
* `runConstraintAudit`. The comparators are pure Node-side functions so
|
|
33
|
+
* vitest can hold them to the tripwire tests without a browser.
|
|
34
|
+
*/
|
|
35
|
+
export interface MatrixRect {
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
w: number;
|
|
39
|
+
h: number;
|
|
40
|
+
}
|
|
41
|
+
export interface MatrixElementGeometry {
|
|
42
|
+
/** Stable structural path from the story root (tag:index-among-same-tag). */
|
|
43
|
+
key: string;
|
|
44
|
+
tag: string;
|
|
45
|
+
rect: MatrixRect;
|
|
46
|
+
/**
|
|
47
|
+
* Geometry-bearing computed properties. The theme axis must never move
|
|
48
|
+
* any of these; colour properties are deliberately absent.
|
|
49
|
+
*/
|
|
50
|
+
props: Record<string, string>;
|
|
51
|
+
/** Range-measured rect of the element's DIRECT text nodes, when any. */
|
|
52
|
+
textRect?: MatrixRect;
|
|
53
|
+
}
|
|
54
|
+
export interface MatrixTextSample {
|
|
55
|
+
/** Structural key of the element that DIRECTLY contains the text node. */
|
|
56
|
+
key: string;
|
|
57
|
+
/** First characters of the text node (identification only). */
|
|
58
|
+
text: string;
|
|
59
|
+
/** Composited ink colour as #rrggbb (alpha already blended over background). */
|
|
60
|
+
color: string;
|
|
61
|
+
/** Composited effective background as #rrggbb. */
|
|
62
|
+
background: string;
|
|
63
|
+
/** False when no opaque backdrop could be resolved (gradient/image/alpha chain). */
|
|
64
|
+
backgroundResolved: boolean;
|
|
65
|
+
/** True when a background-image/gradient sits between text and backdrop. */
|
|
66
|
+
overImage: boolean;
|
|
67
|
+
fontSizePx: number;
|
|
68
|
+
fontWeightNum: number;
|
|
69
|
+
rect: MatrixRect;
|
|
70
|
+
}
|
|
71
|
+
export interface MatrixSnapshot {
|
|
72
|
+
/** False when the story root is missing or empty — always a failure. */
|
|
73
|
+
storyRendered: boolean;
|
|
74
|
+
geometry: MatrixElementGeometry[];
|
|
75
|
+
textSamples: MatrixTextSample[];
|
|
76
|
+
}
|
|
77
|
+
export interface GeometryMove {
|
|
78
|
+
key: string;
|
|
79
|
+
property: string;
|
|
80
|
+
before: string;
|
|
81
|
+
after: string;
|
|
82
|
+
}
|
|
83
|
+
export interface GeometryDiff {
|
|
84
|
+
identical: boolean;
|
|
85
|
+
/** Elements present in `before` but missing in `after`. */
|
|
86
|
+
removedKeys: string[];
|
|
87
|
+
/** Elements present in `after` but missing in `before`. */
|
|
88
|
+
addedKeys: string[];
|
|
89
|
+
moves: GeometryMove[];
|
|
90
|
+
}
|
|
91
|
+
export interface TextContrastViolation {
|
|
92
|
+
key: string;
|
|
93
|
+
text: string;
|
|
94
|
+
color: string;
|
|
95
|
+
background: string;
|
|
96
|
+
ratio: number;
|
|
97
|
+
required: number;
|
|
98
|
+
}
|
|
99
|
+
export interface TextContrastResult {
|
|
100
|
+
measured: number;
|
|
101
|
+
unmeasurable: number;
|
|
102
|
+
violations: TextContrastViolation[];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Captures the geometry + text-ink snapshot of the rendered story.
|
|
106
|
+
*
|
|
107
|
+
* Self-contained by construction — pass directly to
|
|
108
|
+
* `page.evaluate(captureMatrixSnapshot)`.
|
|
109
|
+
*/
|
|
110
|
+
export declare function captureMatrixSnapshot(): MatrixSnapshot;
|
|
111
|
+
/**
|
|
112
|
+
* Geometry invariance diff for the THEME axis: every element must keep its
|
|
113
|
+
* rect, its text rect, and every geometry-bearing computed property.
|
|
114
|
+
* `epsilonPx` absorbs sub-pixel raster jitter in rect measurements only —
|
|
115
|
+
* computed properties compare exactly.
|
|
116
|
+
*/
|
|
117
|
+
export declare function diffGeometry(before: MatrixSnapshot, after: MatrixSnapshot, options?: {
|
|
118
|
+
epsilonPx?: number;
|
|
119
|
+
}): GeometryDiff;
|
|
120
|
+
/**
|
|
121
|
+
* The contrast assertion for the matrix (and for downstream repos — call
|
|
122
|
+
* this instead of keeping a local contrast spec): WCAG AA floors from
|
|
123
|
+
* `colorRules`, large text (≥24px, or ≥18.66px at ≥700) takes the 3:1
|
|
124
|
+
* floor, everything else 4.5:1. Samples whose backdrop could not be
|
|
125
|
+
* resolved (gradient/image/never-opaque chain) are counted, never
|
|
126
|
+
* silently dropped.
|
|
127
|
+
*/
|
|
128
|
+
export declare function evaluateTextContrast(samples: MatrixTextSample[]): TextContrastResult;
|
|
129
|
+
/** One matrix cell's no-breakage inputs (preset axis). */
|
|
130
|
+
export interface NoBreakageInput {
|
|
131
|
+
storyRendered: boolean;
|
|
132
|
+
/** Off-scale violation count from `runConstraintAudit` in this cell. */
|
|
133
|
+
offScaleViolations: number;
|
|
134
|
+
/** Off-scale count in the same story+scheme at the DEFAULT preset. */
|
|
135
|
+
baselineOffScaleViolations: number;
|
|
136
|
+
/**
|
|
137
|
+
* Per-violation signatures in this cell — see {@link auditSignatures}. A
|
|
138
|
+
* gate that reports "32 violations where the default cell had 31" names
|
|
139
|
+
* nothing a person can go and fix; with these it names the elements.
|
|
140
|
+
*/
|
|
141
|
+
offScaleSignatures?: string[];
|
|
142
|
+
/** The same signatures in the DEFAULT-preset cell. */
|
|
143
|
+
baselineOffScaleSignatures?: string[];
|
|
144
|
+
/** Contrast result of this cell. */
|
|
145
|
+
contrast: TextContrastResult;
|
|
146
|
+
/** Contrast violation count in the same story+scheme at the DEFAULT preset. */
|
|
147
|
+
baselineContrastViolations: number;
|
|
148
|
+
/** The DEFAULT-preset cell's contrast result, for naming the new misses. */
|
|
149
|
+
baselineContrast?: TextContrastResult;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Flattens a `runConstraintAudit` report into one signature per violation,
|
|
153
|
+
* `"<element label> :: <violation>"`, so two cells can be compared by what
|
|
154
|
+
* broke rather than by how many things broke.
|
|
155
|
+
*/
|
|
156
|
+
export declare function auditSignatures(violations: Array<{
|
|
157
|
+
label: string;
|
|
158
|
+
violations: string[];
|
|
159
|
+
}>): string[];
|
|
160
|
+
export interface NoBreakageResult {
|
|
161
|
+
ok: boolean;
|
|
162
|
+
failures: string[];
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* NO-BREAKAGE evaluation for the preset axis. Geometry equality is
|
|
166
|
+
* deliberately NOT part of this: presets are expected to move pixels.
|
|
167
|
+
* Breakage means: the story failed to render, structural values fell off
|
|
168
|
+
* the knob scales beyond the default cell's standing debt, or text ink
|
|
169
|
+
* lost contrast the default cell still had.
|
|
170
|
+
*/
|
|
171
|
+
export declare function evaluateNoBreakage(input: NoBreakageInput): NoBreakageResult;
|
|
172
|
+
//# sourceMappingURL=themeMatrix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"themeMatrix.d.ts","sourceRoot":"","sources":["../../src/audit/themeMatrix.ts"],"names":[],"mappings":"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"}
|
|
@@ -65,7 +65,7 @@ export interface FigmaRadiusMode {
|
|
|
65
65
|
/** `Sizing` collection variable to alias (e.g. `radius-4`). */
|
|
66
66
|
figmaName: string;
|
|
67
67
|
px: number;
|
|
68
|
-
/** Outer/nested radius fragment (`knobProps.
|
|
68
|
+
/** Outer/nested radius fragment (`knobProps.borderRadiusNested`). */
|
|
69
69
|
outerToken: string;
|
|
70
70
|
outerFigmaName: string;
|
|
71
71
|
outerPx: number;
|