@multiplatform.one/theme 7.34.3 → 7.35.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/package.json +20 -5
- package/src/audit/constraintAudit.spec.ts +274 -87
- package/src/audit/constraintAudit.ts +135 -120
- package/src/audit/constraintScope.spec.ts +1 -1
- package/src/audit/designTokens.ts +42 -0
- package/src/audit/themeMatrix.spec.ts +83 -2
- package/src/audit/themeMatrix.ts +33 -1
- package/src/figma/figmaTokens.spec.ts +26 -34
- package/src/figma/figmaTokens.ts +26 -50
- package/src/fonts/createFontLoader.ts +4 -1
- package/src/menuRow.ts +4 -1
- package/src/theme/FontKnobStyles.tsx +2 -1
- package/src/theme/Preset.stories.tsx +0 -1
- package/src/theme/Preset.tsx +6 -1
- package/src/theme/PresetContext.ts +4 -0
- package/src/theme/Surface.spec.tsx +114 -67
- package/src/theme/Surface.stories.tsx +8 -25
- package/src/theme/Surface.tsx +87 -43
- package/src/theme/accentFloor.spec.ts +37 -11
- package/src/theme/activateThemeConfig.ts +22 -6
- package/src/theme/animations/animations.spec.ts +62 -0
- package/src/theme/animations/css.ts +9 -35
- package/src/theme/animations/reactNative.ts +98 -25
- package/src/theme/boundaryFloor.spec.ts +57 -0
- package/src/theme/chartPalette.spec.ts +56 -27
- package/src/theme/chartPalette.ts +33 -28
- package/src/theme/colorRules.spec.ts +32 -72
- package/src/theme/cookies.spec.ts +49 -18
- package/src/theme/cookies.ts +36 -7
- package/src/theme/cookiesPersistence.spec.ts +5 -5
- package/src/theme/createDefaultThemeConfig.spec.ts +182 -20
- package/src/theme/createDefaultThemeConfig.ts +34 -28
- package/src/theme/createThemes.ts +169 -218
- package/src/theme/defaults/accent.ts +3 -35
- package/src/theme/defaults/base.ts +14 -53
- package/src/theme/defaults/builderOptions.ts +68 -85
- package/src/theme/defaults/categoryFonts.ts +10 -0
- package/src/theme/defaults/fonts.spec.ts +84 -4
- package/src/theme/defaults/fonts.ts +166 -124
- package/src/theme/defaults/house.ts +48 -0
- package/src/theme/defaults/index.ts +1 -0
- package/src/theme/defaults/neutralRamp.spec.ts +52 -47
- package/src/theme/devtools/ColorLineVisualizer.tsx +6 -6
- package/src/theme/devtools/ThemeDevtoolsPanel.setMarkers.spec.tsx +13 -6
- package/src/theme/devtools/ThemeDevtoolsPanel.tsx +14 -77
- package/src/theme/devtools/animationOptions.spec.ts +23 -37
- package/src/theme/devtools/animationOptions.ts +4 -6
- package/src/theme/devtools/buildSnapshot.ts +0 -3
- package/src/theme/devtools/knobIcons.tsx +4 -24
- package/src/theme/focusState.spec.ts +9 -30
- package/src/theme/index.ts +17 -0
- package/src/theme/intentFill.spec.ts +42 -0
- package/src/theme/knobs.ts +14 -42
- package/src/theme/layoutTokens.ts +15 -1
- package/src/theme/layoutTokensHooks.spec.tsx +8 -4
- package/src/theme/mergedTokens.ts +20 -0
- package/src/theme/motion.spec.ts +84 -0
- package/src/theme/motion.ts +53 -0
- package/src/theme/motionStops.ts +17 -0
- package/src/theme/motionTiming.ts +59 -0
- package/src/theme/mpo13Proof.spec.ts +43 -46
- package/src/theme/mpo19Proof.spec.ts +13 -14
- package/src/theme/namedInkFloor.spec.ts +60 -0
- package/src/theme/overlaySurfaces.tsx +330 -0
- package/src/theme/preset.types.ts +16 -0
- package/src/theme/presetPreview.ts +32 -0
- package/src/theme/presetRoot.spec.tsx +89 -0
- package/src/theme/presetStore.persistence.spec.ts +141 -0
- package/src/theme/presetStore.spec.ts +205 -0
- package/src/theme/presetStore.ts +286 -0
- package/src/theme/presetUserSync.spec.tsx +168 -0
- package/src/theme/presetUserSync.ts +47 -0
- package/src/theme/presets.spec.ts +22 -15
- package/src/theme/presets.ts +22 -10
- package/src/theme/radiusClass.spec.ts +60 -41
- package/src/theme/radiusClass.ts +17 -4
- package/src/theme/radiusClassTable.generated.ts +3 -3
- package/src/theme/readableColor.spec.ts +59 -152
- package/src/theme/readableColor.ts +34 -174
- package/src/theme/recipeInputs.ts +153 -295
- package/src/theme/recipes.ts +58 -18
- package/src/theme/resolveKnobs.spec.ts +528 -588
- package/src/theme/resolveKnobs.ts +250 -325
- package/src/theme/scale/ScaleStyles.native.tsx +19 -0
- package/src/theme/scale/ScaleStyles.tsx +48 -0
- package/src/theme/scale/activeScale.ts +30 -0
- package/src/theme/scale/deriveRecipeInputs.ts +110 -0
- package/src/theme/scale/generateScale.spec.ts +260 -0
- package/src/theme/scale/generateScale.ts +147 -0
- package/src/theme/scale/index.ts +54 -0
- package/src/theme/scale/installScaleConfig.native.spec.ts +77 -0
- package/src/theme/scale/installScaleConfig.native.ts +57 -0
- package/src/theme/scale/installScaleConfig.ts +7 -0
- package/src/theme/scale/scaleAttribute.ts +21 -0
- package/src/theme/scale/scaleCss.probe.spec.tsx +64 -0
- package/src/theme/scale/scaleCss.spec.ts +132 -0
- package/src/theme/scale/scaleCss.ts +95 -0
- package/src/theme/scale/scaleFonts.ts +106 -0
- package/src/theme/scale/scaleInputs.ts +322 -0
- package/src/theme/scale/themeScales.ts +181 -0
- package/src/theme/scale/useActiveScale.spec.tsx +129 -0
- package/src/theme/scale/useActiveScale.ts +95 -0
- package/src/theme/schemeStore.spec.ts +81 -0
- package/src/theme/schemeStore.ts +67 -0
- package/src/theme/shared.spec.ts +7 -6
- package/src/theme/shared.tsx +37 -3
- package/src/theme/sizeLadder.spec.ts +37 -36
- package/src/theme/sizeRecipes.spec.ts +179 -85
- package/src/theme/sizeRecipes.ts +48 -25
- package/src/theme/subsetThemes.spec.ts +9 -3
- package/src/theme/switchThumb.spec.ts +69 -0
- package/src/theme/syntaxFloor.spec.ts +11 -8
- package/src/theme/theme.hydration.native.spec.tsx +51 -0
- package/src/theme/theme.native.tsx +59 -21
- package/src/theme/theme.palette.spec.tsx +76 -0
- package/src/theme/theme.preset.native.spec.tsx +73 -0
- package/src/theme/theme.provider.spec.ts +143 -1
- package/src/theme/theme.tsx +61 -25
- package/src/theme/tileSizes.ts +6 -7
- package/src/theme/transitionProps.native.ts +25 -2
- package/src/theme/transitionProps.spec.ts +34 -0
- package/src/theme/transitionProps.ts +26 -2
- package/src/theme/usePresetSwitch.native.spec.tsx +68 -0
- package/src/theme/usePresetSwitch.native.ts +32 -0
- package/src/theme/usePresetSwitch.spec.tsx +103 -0
- package/src/theme/usePresetSwitch.ts +54 -0
- package/src/theme/useResolvedKnobs.hydration.spec.tsx +2 -2
- package/src/theme/useResolvedKnobs.ts +23 -90
- package/src/theme/useResolvedKnobsBehavior.spec.tsx +25 -30
- package/src/theme/useSchemePreference.native.ts +33 -0
- package/src/theme/useSchemePreference.spec.tsx +51 -0
- package/src/theme/useSchemePreference.ts +32 -0
- package/src/theme/useSchemePreference.web.spec.tsx +32 -0
- package/src/theme/useTheme.native.spec.tsx +68 -0
- package/src/theme/useTheme.native.ts +49 -24
- package/src/theme/useTheme.ts +7 -4
- package/types/audit/constraintAudit.d.ts +6 -5
- package/types/audit/constraintAudit.d.ts.map +1 -1
- package/types/audit/designTokens.d.ts +13 -0
- package/types/audit/designTokens.d.ts.map +1 -0
- package/types/audit/themeMatrix.d.ts +10 -0
- package/types/audit/themeMatrix.d.ts.map +1 -1
- package/types/figma/figmaTokens.d.ts +11 -28
- package/types/figma/figmaTokens.d.ts.map +1 -1
- package/types/fonts/createFontLoader.d.ts.map +1 -1
- package/types/menuRow.d.ts +4 -1
- package/types/menuRow.d.ts.map +1 -1
- package/types/theme/FontKnobStyles.d.ts.map +1 -1
- package/types/theme/Preset.d.ts.map +1 -1
- package/types/theme/PresetContext.d.ts +4 -0
- package/types/theme/PresetContext.d.ts.map +1 -1
- package/types/theme/Surface.d.ts +57 -26
- package/types/theme/Surface.d.ts.map +1 -1
- package/types/theme/activateThemeConfig.d.ts +5 -3
- package/types/theme/activateThemeConfig.d.ts.map +1 -1
- package/types/theme/animations/css.d.ts +27 -34
- package/types/theme/animations/css.d.ts.map +1 -1
- package/types/theme/animations/reactNative.d.ts +196 -45
- package/types/theme/animations/reactNative.d.ts.map +1 -1
- package/types/theme/chartPalette.d.ts +11 -3
- package/types/theme/chartPalette.d.ts.map +1 -1
- package/types/theme/colorRules.d.ts +1 -1
- package/types/theme/cookies.d.ts +12 -1
- package/types/theme/cookies.d.ts.map +1 -1
- package/types/theme/createDefaultThemeConfig.d.ts +13 -13
- package/types/theme/createDefaultThemeConfig.d.ts.map +1 -1
- package/types/theme/createThemes.d.ts +58 -2
- package/types/theme/createThemes.d.ts.map +1 -1
- package/types/theme/defaults/accent.d.ts.map +1 -1
- package/types/theme/defaults/base.d.ts.map +1 -1
- package/types/theme/defaults/builderOptions.d.ts.map +1 -1
- package/types/theme/defaults/categoryFonts.d.ts +10 -0
- package/types/theme/defaults/categoryFonts.d.ts.map +1 -1
- package/types/theme/defaults/fonts.d.ts +330 -30
- package/types/theme/defaults/fonts.d.ts.map +1 -1
- package/types/theme/defaults/house.d.ts +8 -0
- package/types/theme/defaults/house.d.ts.map +1 -0
- 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 +3 -3
- package/types/theme/devtools/ThemeDevtoolsPanel.d.ts.map +1 -1
- package/types/theme/devtools/animationOptions.d.ts.map +1 -1
- package/types/theme/devtools/buildSnapshot.d.ts.map +1 -1
- package/types/theme/devtools/knobIcons.d.ts +0 -3
- package/types/theme/devtools/knobIcons.d.ts.map +1 -1
- package/types/theme/index.d.ts +11 -0
- package/types/theme/index.d.ts.map +1 -1
- package/types/theme/knobs.d.ts +8 -36
- package/types/theme/knobs.d.ts.map +1 -1
- package/types/theme/layoutTokens.d.ts +13 -1
- package/types/theme/layoutTokens.d.ts.map +1 -1
- package/types/theme/mergedTokens.d.ts +11 -0
- package/types/theme/mergedTokens.d.ts.map +1 -0
- package/types/theme/motion.d.ts +17 -0
- package/types/theme/motion.d.ts.map +1 -0
- package/types/theme/motionStops.d.ts +3 -0
- package/types/theme/motionStops.d.ts.map +1 -0
- package/types/theme/motionTiming.d.ts +36 -0
- package/types/theme/motionTiming.d.ts.map +1 -0
- package/types/theme/overlaySurfaces.d.ts +70 -0
- package/types/theme/overlaySurfaces.d.ts.map +1 -0
- package/types/theme/preset.types.d.ts +16 -0
- package/types/theme/preset.types.d.ts.map +1 -1
- package/types/theme/presetPreview.d.ts +14 -0
- package/types/theme/presetPreview.d.ts.map +1 -0
- package/types/theme/presetStore.d.ts +40 -0
- package/types/theme/presetStore.d.ts.map +1 -0
- package/types/theme/presetUserSync.d.ts +7 -0
- package/types/theme/presetUserSync.d.ts.map +1 -0
- package/types/theme/presets.d.ts +12 -4
- package/types/theme/presets.d.ts.map +1 -1
- package/types/theme/radiusClass.d.ts +5 -2
- package/types/theme/radiusClass.d.ts.map +1 -1
- package/types/theme/radiusClassTable.generated.d.ts +3 -3
- package/types/theme/readableColor.d.ts +11 -49
- package/types/theme/readableColor.d.ts.map +1 -1
- package/types/theme/recipeInputs.d.ts +39 -70
- package/types/theme/recipeInputs.d.ts.map +1 -1
- package/types/theme/recipes.d.ts +79 -18
- package/types/theme/recipes.d.ts.map +1 -1
- package/types/theme/resolveKnobs.d.ts +64 -32
- package/types/theme/resolveKnobs.d.ts.map +1 -1
- package/types/theme/scale/ScaleStyles.d.ts +18 -0
- package/types/theme/scale/ScaleStyles.d.ts.map +1 -0
- package/types/theme/scale/ScaleStyles.native.d.ts +10 -0
- package/types/theme/scale/ScaleStyles.native.d.ts.map +1 -0
- package/types/theme/scale/activeScale.d.ts +13 -0
- package/types/theme/scale/activeScale.d.ts.map +1 -0
- package/types/theme/scale/deriveRecipeInputs.d.ts +10 -0
- package/types/theme/scale/deriveRecipeInputs.d.ts.map +1 -0
- package/types/theme/scale/generateScale.d.ts +38 -0
- package/types/theme/scale/generateScale.d.ts.map +1 -0
- package/types/theme/scale/index.d.ts +17 -0
- package/types/theme/scale/index.d.ts.map +1 -0
- package/types/theme/scale/installScaleConfig.d.ts +4 -0
- package/types/theme/scale/installScaleConfig.d.ts.map +1 -0
- package/types/theme/scale/installScaleConfig.native.d.ts +13 -0
- package/types/theme/scale/installScaleConfig.native.d.ts.map +1 -0
- package/types/theme/scale/scaleAttribute.d.ts +14 -0
- package/types/theme/scale/scaleAttribute.d.ts.map +1 -0
- package/types/theme/scale/scaleCss.d.ts +25 -0
- package/types/theme/scale/scaleCss.d.ts.map +1 -0
- package/types/theme/scale/scaleFonts.d.ts +16 -0
- package/types/theme/scale/scaleFonts.d.ts.map +1 -0
- package/types/theme/scale/scaleInputs.d.ts +66 -0
- package/types/theme/scale/scaleInputs.d.ts.map +1 -0
- package/types/theme/scale/themeScales.d.ts +52 -0
- package/types/theme/scale/themeScales.d.ts.map +1 -0
- package/types/theme/scale/useActiveScale.d.ts +31 -0
- package/types/theme/scale/useActiveScale.d.ts.map +1 -0
- package/types/theme/schemeStore.d.ts +6 -0
- package/types/theme/schemeStore.d.ts.map +1 -0
- package/types/theme/shared.d.ts +18 -0
- package/types/theme/shared.d.ts.map +1 -1
- package/types/theme/sizeRecipes.d.ts +20 -15
- package/types/theme/sizeRecipes.d.ts.map +1 -1
- package/types/theme/theme.d.ts +2 -1
- package/types/theme/theme.d.ts.map +1 -1
- package/types/theme/theme.native.d.ts +10 -1
- package/types/theme/theme.native.d.ts.map +1 -1
- package/types/theme/tileSizes.d.ts +6 -7
- package/types/theme/tileSizes.d.ts.map +1 -1
- package/types/theme/transitionProps.d.ts +3 -1
- package/types/theme/transitionProps.d.ts.map +1 -1
- package/types/theme/transitionProps.native.d.ts +3 -1
- package/types/theme/transitionProps.native.d.ts.map +1 -1
- package/types/theme/usePresetSwitch.d.ts +10 -0
- package/types/theme/usePresetSwitch.d.ts.map +1 -0
- package/types/theme/usePresetSwitch.native.d.ts +10 -0
- package/types/theme/usePresetSwitch.native.d.ts.map +1 -0
- package/types/theme/useResolvedKnobs.d.ts +13 -13
- package/types/theme/useResolvedKnobs.d.ts.map +1 -1
- package/types/theme/useSchemePreference.d.ts +8 -0
- package/types/theme/useSchemePreference.d.ts.map +1 -0
- package/types/theme/useSchemePreference.native.d.ts +8 -0
- package/types/theme/useSchemePreference.native.d.ts.map +1 -0
- package/types/theme/useTheme.d.ts +4 -2
- package/types/theme/useTheme.d.ts.map +1 -1
- package/types/theme/useTheme.native.d.ts +10 -1
- package/types/theme/useTheme.native.d.ts.map +1 -1
|
@@ -57,16 +57,16 @@ describe("persistPresetOverrides / loadPresetOverrides", () => {
|
|
|
57
57
|
|
|
58
58
|
it("chunks oversized overrides across multiple cookies and reassembles them", () => {
|
|
59
59
|
const bigValue = "x".repeat(8000);
|
|
60
|
-
persistPresetOverrides({
|
|
60
|
+
persistPresetOverrides({ headingFont: bigValue } as unknown as Partial<Knobs>);
|
|
61
61
|
// The serialized JSON exceeds the 3.5 KB split threshold → several chunks.
|
|
62
62
|
expect(document.cookie).toContain(`${cookieOverridesPrefix}.0=`);
|
|
63
63
|
expect(document.cookie).toContain(`${cookieOverridesPrefix}.1=`);
|
|
64
|
-
expect(loadPresetOverrides()).toEqual({
|
|
64
|
+
expect(loadPresetOverrides()).toEqual({ headingFont: bigValue });
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
it("cleans up stale chunk cookies when the payload shrinks", () => {
|
|
68
68
|
const bigValue = "y".repeat(8000);
|
|
69
|
-
persistPresetOverrides({
|
|
69
|
+
persistPresetOverrides({ headingFont: bigValue } as unknown as Partial<Knobs>);
|
|
70
70
|
persistPresetOverrides({ borderRadius: "small" } as Partial<Knobs>);
|
|
71
71
|
expect(loadPresetOverrides()).toEqual({ borderRadius: "small" });
|
|
72
72
|
expect(document.cookie).not.toContain(`${cookieOverridesPrefix}.1=`);
|
|
@@ -74,9 +74,9 @@ describe("persistPresetOverrides / loadPresetOverrides", () => {
|
|
|
74
74
|
|
|
75
75
|
it("reads from a raw cookie map (SSR) without touching the document", () => {
|
|
76
76
|
const raw = {
|
|
77
|
-
[`${cookieOverridesPrefix}.0`]: JSON.stringify({
|
|
77
|
+
[`${cookieOverridesPrefix}.0`]: JSON.stringify({ elevation: "large" }),
|
|
78
78
|
};
|
|
79
|
-
expect(loadPresetOverrides(raw)).toEqual({
|
|
79
|
+
expect(loadPresetOverrides(raw)).toEqual({ elevation: "large" });
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
it("treats corrupted cookie JSON as no overrides", () => {
|
|
@@ -26,10 +26,16 @@ import {
|
|
|
26
26
|
defaultConfig as v5DefaultConfig,
|
|
27
27
|
mediaQueryDefaultActive as v5MediaQueryDefaultActive,
|
|
28
28
|
} from "@tamagui/config/v5";
|
|
29
|
-
import { tokens as v5Tokens } from "@tamagui/themes/v5";
|
|
29
|
+
import { tokens as v5Tokens, themes as stockThemes } from "@tamagui/themes/v5";
|
|
30
30
|
import { contrastRatio, minContrastRatio, normalizeToHex, relativeLuminance } from "./colorRules";
|
|
31
31
|
import { TAMAGUI_ERA, createDefaultThemeConfig } from "./createDefaultThemeConfig";
|
|
32
|
-
import
|
|
32
|
+
import { generateScale } from "./scale/generateScale";
|
|
33
|
+
import { defaultScaleInputs, v5ScaleInputs } from "./scale/scaleInputs";
|
|
34
|
+
import { DEFAULT_SCALE_ID } from "./scale/themeScales";
|
|
35
|
+
import { createTamagui } from "tamagui";
|
|
36
|
+
import { boldPreset, densePreset, heroPreset, roomyPreset } from "./presets";
|
|
37
|
+
import { createThemesBuilder, type GetThemeProps } from "./createThemes";
|
|
38
|
+
import { defaultBaseTheme, defaultAccentTheme } from "./defaults";
|
|
33
39
|
import { setSizeRecipeInputs } from "./sizeRecipes";
|
|
34
40
|
|
|
35
41
|
// Mirrors the shc app theme config: a consumer getTheme written against the
|
|
@@ -122,25 +128,25 @@ describe("createDefaultThemeConfig — builderOptions.getTheme composition (DF-0
|
|
|
122
128
|
}
|
|
123
129
|
});
|
|
124
130
|
|
|
125
|
-
it("recipeInputs: {
|
|
131
|
+
it("recipeInputs: { control: 40 } regenerates the control family on ThemeConfig, not color themes", () => {
|
|
126
132
|
const config = createDefaultThemeConfig({
|
|
127
|
-
recipeInputs: {
|
|
133
|
+
recipeInputs: { control: 40 },
|
|
128
134
|
});
|
|
129
135
|
expect(config.recipeFamilies?.control.boxVariants.$4.height).toBe(40);
|
|
130
136
|
expect(config.recipeFamilies?.control.recipes.$4).toEqual({
|
|
131
137
|
height: 40,
|
|
132
|
-
paddingHorizontal:
|
|
133
|
-
fontSize:
|
|
134
|
-
iconSize:
|
|
135
|
-
gap:
|
|
138
|
+
paddingHorizontal: 16,
|
|
139
|
+
fontSize: 15,
|
|
140
|
+
iconSize: 16,
|
|
141
|
+
gap: 8,
|
|
136
142
|
});
|
|
137
|
-
expect(config.recipeInputs?.
|
|
143
|
+
expect(config.recipeInputs?.control).toBe(40);
|
|
138
144
|
const themes = (config.tamagui as unknown as { themes: RawThemes }).themes;
|
|
139
145
|
for (const [name, theme] of Object.entries(themes)) {
|
|
140
|
-
expect(theme, name).not.toHaveProperty("
|
|
146
|
+
expect(theme, name).not.toHaveProperty("control");
|
|
141
147
|
expect(theme, name).not.toHaveProperty("radiusPx");
|
|
142
148
|
expect(theme, name).not.toHaveProperty("paddingHorizontal");
|
|
143
|
-
expect(theme, name).not.toHaveProperty("
|
|
149
|
+
expect(theme, name).not.toHaveProperty("tokenHeights");
|
|
144
150
|
}
|
|
145
151
|
});
|
|
146
152
|
|
|
@@ -152,7 +158,7 @@ describe("createDefaultThemeConfig — builderOptions.getTheme composition (DF-0
|
|
|
152
158
|
expect(normalizeToHex(theme.outlineColor)).toBeTruthy();
|
|
153
159
|
expect(theme.textMuted).toBe(theme.color11);
|
|
154
160
|
}
|
|
155
|
-
expect(config.recipeFamilies?.control.boxVariants.$4.height).toBe(
|
|
161
|
+
expect(config.recipeFamilies?.control.boxVariants.$4.height).toBe(40);
|
|
156
162
|
});
|
|
157
163
|
|
|
158
164
|
it("registers serif so headingFont can resolve a family without a per-app font map", () => {
|
|
@@ -234,25 +240,181 @@ describe("createDefaultThemeConfig — Tamagui era pin (MPO-19 X13 / W0-era-pin)
|
|
|
234
240
|
expect(config.tamagui.settings.mediaQueryDefaultActive).toEqual(v5MediaQueryDefaultActive);
|
|
235
241
|
});
|
|
236
242
|
|
|
237
|
-
it("
|
|
243
|
+
it("the generator reproduces v5 token values exactly for every non-color group", () => {
|
|
238
244
|
const groups = ["size", "space", "radius", "zIndex"] as const;
|
|
239
245
|
for (const group of groups) {
|
|
240
|
-
const resolved = tokenGroupValues(
|
|
246
|
+
const resolved = tokenGroupValues(generateScale(v5ScaleInputs).tokens, group);
|
|
241
247
|
const v5 = tokenGroupValues(v5Tokens as unknown as RawTokens, group);
|
|
242
248
|
expect(Object.keys(v5).length, `${group} group present in v5`).toBeGreaterThan(0);
|
|
243
249
|
expect(resolved, `tokens.${group}`).toEqual(v5);
|
|
244
250
|
}
|
|
245
251
|
});
|
|
246
252
|
|
|
247
|
-
it("
|
|
253
|
+
it("installs the house default scale tokens", () => {
|
|
254
|
+
expect(config.tamagui.tokens).toEqual(generateScale(defaultScaleInputs).tokens);
|
|
255
|
+
expect(tokenGroupValues(config.tamagui.tokens, "space").true).toBe(16);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("anchors radius.true at 8, the house base radius", () => {
|
|
248
259
|
const radius = tokenGroupValues(config.tamagui.tokens, "radius");
|
|
249
|
-
expect(radius.true).toBe(
|
|
250
|
-
expect(radius["4"]).toBe(
|
|
260
|
+
expect(radius.true).toBe(8);
|
|
261
|
+
expect(radius["4"]).toBe(8);
|
|
251
262
|
});
|
|
252
263
|
|
|
253
|
-
it("anchors size.true at
|
|
264
|
+
it("anchors size.true at 40, the house base control height", () => {
|
|
254
265
|
const size = tokenGroupValues(config.tamagui.tokens, "size");
|
|
255
|
-
expect(size.true).toBe(
|
|
256
|
-
expect(size["4"]).toBe(
|
|
266
|
+
expect(size.true).toBe(40);
|
|
267
|
+
expect(size["4"]).toBe(40);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
describe("createDefaultThemeConfig — preset scales (FZ-7158 WP-a2)", () => {
|
|
272
|
+
const presets = { hero: heroPreset, bold: boldPreset, dense: densePreset, roomy: roomyPreset };
|
|
273
|
+
|
|
274
|
+
it("keys one scale per preset name and shares entries across equal inputs", () => {
|
|
275
|
+
const config = createDefaultThemeConfig({ presets });
|
|
276
|
+
const scales = config.scales ?? {};
|
|
277
|
+
expect(Object.keys(scales).sort()).toEqual([
|
|
278
|
+
"bold",
|
|
279
|
+
DEFAULT_SCALE_ID,
|
|
280
|
+
"dense",
|
|
281
|
+
"hero",
|
|
282
|
+
"roomy",
|
|
283
|
+
]);
|
|
284
|
+
expect(scales.hero).toBe(scales[DEFAULT_SCALE_ID]);
|
|
285
|
+
expect(scales.bold).toBe(scales[DEFAULT_SCALE_ID]);
|
|
286
|
+
expect(scales.dense?.id).toBe("dense");
|
|
287
|
+
expect(scales.roomy?.id).toBe("roomy");
|
|
288
|
+
expect(scales[DEFAULT_SCALE_ID]?.presets).toEqual([DEFAULT_SCALE_ID, "hero", "bold"]);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("reuses the base config for the default scale and builds the others only when asked", () => {
|
|
292
|
+
const build = vi.mocked(createTamagui);
|
|
293
|
+
build.mockClear();
|
|
294
|
+
const config = createDefaultThemeConfig({ presets });
|
|
295
|
+
expect(build).toHaveBeenCalledTimes(1);
|
|
296
|
+
expect(config.scales?.[DEFAULT_SCALE_ID]?.tamagui()).toBe(config.tamagui);
|
|
297
|
+
expect(build).toHaveBeenCalledTimes(1);
|
|
298
|
+
|
|
299
|
+
const dense = config.scales?.dense?.tamagui();
|
|
300
|
+
expect(build).toHaveBeenCalledTimes(2);
|
|
301
|
+
expect(config.scales?.dense?.tamagui()).toBe(dense);
|
|
302
|
+
expect(build).toHaveBeenCalledTimes(2);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("builds a scale config from the same props with only its tokens and fonts swapped", () => {
|
|
306
|
+
const config = createDefaultThemeConfig({ presets });
|
|
307
|
+
const base = config.tamagui as unknown as Record<string, unknown>;
|
|
308
|
+
const dense = config.scales?.dense?.tamagui() as unknown as Record<string, unknown>;
|
|
309
|
+
expect(dense.themes).toBe(base.themes);
|
|
310
|
+
expect(dense.settings).toBe(base.settings);
|
|
311
|
+
expect(dense.media).toBe(base.media);
|
|
312
|
+
expect(dense.tokens).toEqual(generateScale({ control: 36, type: 14 }).tokens);
|
|
313
|
+
const fonts = dense.fonts as Record<string, { size: Record<string, number> }>;
|
|
314
|
+
expect(fonts.body.size.true).toBe(14);
|
|
315
|
+
expect(fonts.heading.size["4"]).toBe(
|
|
316
|
+
generateScale({ control: 36, type: 14 }).fonts.headingSizes[4],
|
|
317
|
+
);
|
|
318
|
+
expect(Object.keys(fonts).sort()).toEqual(Object.keys(base.fonts as object).sort());
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("derives each scale's recipe inputs from its own tokens", () => {
|
|
322
|
+
const config = createDefaultThemeConfig({ presets });
|
|
323
|
+
expect(config.scales?.dense?.recipeInputs.tokenHeights.$4).toBe(36);
|
|
324
|
+
expect(config.scales?.roomy?.recipeInputs.tokenHeights.$4).toBe(48);
|
|
325
|
+
expect(config.scales?.[DEFAULT_SCALE_ID]?.recipeInputs).toEqual(config.recipeInputs);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
describe("the v5 theme matrix", () => {
|
|
330
|
+
const config = createDefaultThemeConfig();
|
|
331
|
+
const themes = config.tamagui.themes as unknown as RawThemes;
|
|
332
|
+
|
|
333
|
+
it("binds the v5 shadow3 alpha in both schemes", () => {
|
|
334
|
+
for (const [scheme, alphas] of [
|
|
335
|
+
["light", [0.04, 0.08, 0.12, 0.22, 0.33, 0.44]],
|
|
336
|
+
["dark", [0.15, 0.23, 0.33, 0.45, 0.65, 0.8]],
|
|
337
|
+
] as const) {
|
|
338
|
+
alphas.forEach((alpha, index) => {
|
|
339
|
+
expect(themes[scheme][`shadow${index + 1}`]).toBe(`rgba(0,0,0,${alpha})`);
|
|
340
|
+
});
|
|
341
|
+
expect(themes[scheme].shadowColor).toBe(`rgba(0,0,0,${alphas[2]})`);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("uses v5 surface templates for pages and components", () => {
|
|
346
|
+
for (const scheme of ["light", "dark"] as const) {
|
|
347
|
+
expect(themes[scheme].background).toBe(themes[scheme].color2);
|
|
348
|
+
expect(themes[`${scheme}_Card`].background).toBe(themes[scheme].color3);
|
|
349
|
+
}
|
|
350
|
+
const button = themes.light_Button;
|
|
351
|
+
expect(relativeLuminance(normalizeToHex(button.backgroundHover)!)).toBeGreaterThan(
|
|
352
|
+
relativeLuminance(normalizeToHex(button.background)!),
|
|
353
|
+
);
|
|
354
|
+
for (const component of [
|
|
355
|
+
"SwitchThumb",
|
|
356
|
+
"SliderTrack",
|
|
357
|
+
"Tooltip",
|
|
358
|
+
"Checkbox",
|
|
359
|
+
"RadioGroupItem",
|
|
360
|
+
]) {
|
|
361
|
+
expect(themes).not.toHaveProperty(`light_${component}`);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it("builds gray children from their own opaque palette", () => {
|
|
366
|
+
for (const scheme of ["light", "dark"] as const) {
|
|
367
|
+
expect(themes[`${scheme}_gray`].color3).toBe(stockThemes[`${scheme}_gray`].color3);
|
|
368
|
+
for (const suffix of ["active", "alt1", "alt2"]) {
|
|
369
|
+
const child = themes[`${scheme}_gray_${suffix}`];
|
|
370
|
+
expect(child).toBeDefined();
|
|
371
|
+
for (const key of ["color", "background", "borderColor"]) {
|
|
372
|
+
expect(child[key]).toMatch(/, 1\)$/);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("uses v5 templates for additional themes and honors component overrides", () => {
|
|
379
|
+
const custom = createDefaultThemeConfig({
|
|
380
|
+
additionalThemes: { brand: defaultAccentTheme },
|
|
381
|
+
builderOptions: { componentThemes: { Custom: { template: "surface1" } } },
|
|
382
|
+
}).tamagui.themes as unknown as RawThemes;
|
|
383
|
+
for (const scheme of ["light", "dark"] as const) {
|
|
384
|
+
expect(custom[`${scheme}_brand`].background).toBe(custom[`${scheme}_brand`].color2);
|
|
385
|
+
expect(custom[`${scheme}_Custom`].background).toBe(custom[scheme].color3);
|
|
386
|
+
expect(custom).not.toHaveProperty(`${scheme}_Button`);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("honors an explicit grandchildren map in both builder paths", () => {
|
|
391
|
+
const seen: string[] = [];
|
|
392
|
+
const builder = createThemesBuilder(defaultBaseTheme, defaultAccentTheme, {
|
|
393
|
+
grandChildrenThemes: { raised: { template: "surface1" } },
|
|
394
|
+
getTheme: ({ name }) => {
|
|
395
|
+
seen.push(name);
|
|
396
|
+
return {};
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
expect(builder.themes()).toHaveProperty("light_blue_raised");
|
|
400
|
+
expect(builder.themes()).not.toHaveProperty("light_blue_alt1");
|
|
401
|
+
seen.length = 0;
|
|
402
|
+
builder.addTheme("brand", defaultAccentTheme);
|
|
403
|
+
expect(seen).toContain("light_blue_raised");
|
|
404
|
+
expect(seen).not.toContain("light_blue_alt1");
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it("allows callers to disable component themes", () => {
|
|
408
|
+
const custom = createThemesBuilder(defaultBaseTheme, defaultAccentTheme, {
|
|
409
|
+
componentThemes: false,
|
|
410
|
+
}).themes();
|
|
411
|
+
expect(Object.keys(custom).some((name) => /_[A-Z]/.test(name))).toBe(false);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it("ships 462 themes and the heading-scope category fonts in under 260 KB of CSS (the v4 matrix and stock spread shipped 913 KB)", async () => {
|
|
415
|
+
const { createTamagui: build } = await vi.importActual<typeof import("tamagui")>("tamagui");
|
|
416
|
+
const css = build(config.tamagui).getCSS();
|
|
417
|
+
expect(Object.keys(themes)).toHaveLength(462);
|
|
418
|
+
expect(Buffer.byteLength(css, "utf8")).toBeLessThan(260_000);
|
|
257
419
|
});
|
|
258
420
|
});
|
|
@@ -13,8 +13,11 @@ import { defaultAccentTheme } from "./defaults/accent";
|
|
|
13
13
|
import { defaultBaseTheme } from "./defaults/base";
|
|
14
14
|
import { defaultBuilderOptions } from "./defaults/builderOptions";
|
|
15
15
|
import { defaultFonts } from "./defaults/fonts";
|
|
16
|
+
import { scaleFontSet } from "./scale/scaleFonts";
|
|
16
17
|
import type { Preset } from "./preset.types";
|
|
17
18
|
import { type SizeRecipeInputs } from "./recipeInputs";
|
|
19
|
+
import { generateScale } from "./scale/generateScale";
|
|
20
|
+
import { defaultScaleInputs } from "./scale/scaleInputs";
|
|
18
21
|
import { type ThemeConfig, createThemeConfig } from "./shared";
|
|
19
22
|
import { assertResolvableThemeValues } from "./themeValue";
|
|
20
23
|
import { getGeneratedSizeRecipes, getSizeRecipeInputs, setSizeRecipeInputs } from "./sizeRecipes";
|
|
@@ -30,9 +33,10 @@ import { type ThemeSubset, subsetThemes } from "./subsetThemes";
|
|
|
30
33
|
* against v5, never against v4 or the legacy root exports. Asserted by the
|
|
31
34
|
* era block in `createDefaultThemeConfig.spec.ts`.
|
|
32
35
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
+
* The non-color tokens and the body/heading type tables come from one
|
|
37
|
+
* generator (`scale/generateScale.ts`), spec-pinned to the v5 values at the
|
|
38
|
+
* default inputs, so `$size`/`$space` props and the size recipes read the
|
|
39
|
+
* same numbers.
|
|
36
40
|
*/
|
|
37
41
|
export const TAMAGUI_ERA = "v5" as const;
|
|
38
42
|
/** MPO-19 proof alias — same pin as `TAMAGUI_ERA`. */
|
|
@@ -49,7 +53,7 @@ export interface CreateDefaultThemeConfigOptions {
|
|
|
49
53
|
fonts?: Record<string, GenericFont>;
|
|
50
54
|
/** Animation config (defaults to framework reanimated animations) */
|
|
51
55
|
animations?: CreateTamaguiProps["animations"];
|
|
52
|
-
/** Options for the theme builder (grandChildrenThemes, getTheme) */
|
|
56
|
+
/** Options for the theme builder (componentThemes, grandChildrenThemes, getTheme) */
|
|
53
57
|
builderOptions?: CreateThemesBuilderOptions;
|
|
54
58
|
/** Override tamagui settings */
|
|
55
59
|
settings?: Partial<NonNullable<CreateTamaguiProps["settings"]>>;
|
|
@@ -60,10 +64,11 @@ export interface CreateDefaultThemeConfigOptions {
|
|
|
60
64
|
/** Default preset name to use when no `mp.preset` cookie is set */
|
|
61
65
|
defaultPreset?: string;
|
|
62
66
|
/**
|
|
63
|
-
* Size-recipe inputs (LC-70). Merged over
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
+
* Size-recipe inputs (LC-70). Merged over the inputs derived from the
|
|
68
|
+
* default scale (`defaultRecipeInputs`); tables are generated, written into
|
|
69
|
+
* the live aliases Button/Input already import, and attached on
|
|
70
|
+
* ThemeConfig as `recipeInputs` / `recipeFamilies`. Not written into
|
|
71
|
+
* Tamagui `themes` (those stay color palettes from createThemes /
|
|
67
72
|
* theme-builder).
|
|
68
73
|
*/
|
|
69
74
|
recipeInputs?: Partial<SizeRecipeInputs>;
|
|
@@ -76,15 +81,14 @@ export interface CreateDefaultThemeConfigOptions {
|
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
/**
|
|
79
|
-
* Compose a consumer `getTheme` WITH the framework default instead of
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* component sub-theme border/outline anchors — then the consumer's result is
|
|
84
|
+
* Compose a consumer `getTheme` WITH the framework default instead of replacing
|
|
85
|
+
* it. The default always runs first — it derives the solid ≥3:1 `$outlineColor`
|
|
86
|
+
* focus ring (DG-A11Y-01) and semantic aliases — then the consumer's result is
|
|
83
87
|
* merged over it per key, so a partial override keeps every derivation it
|
|
84
88
|
* doesn't explicitly change. Consumer entries that resolve to nullish are
|
|
85
|
-
* dropped: a getTheme written against the full base ramp (`theme.color5`
|
|
86
|
-
*
|
|
87
|
-
*
|
|
89
|
+
* dropped: a getTheme written against the full base ramp (`theme.color5` etc.)
|
|
90
|
+
* also runs inside narrow component sub-themes where those steps don't exist,
|
|
91
|
+
* and its undefineds must not erase the defaults (DF-03).
|
|
88
92
|
*/
|
|
89
93
|
function composeGetTheme(
|
|
90
94
|
custom: CreateThemesBuilderOptions["getTheme"],
|
|
@@ -108,11 +112,9 @@ function composeGetTheme(
|
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
/**
|
|
111
|
-
* Builds
|
|
112
|
-
* with
|
|
113
|
-
*
|
|
114
|
-
* heading/body fonts, the category fonts the bodyFont knob resolves, and the
|
|
115
|
-
* interaction-ramp `getTheme` theme builder.
|
|
115
|
+
* Builds Tamagui's v5 grey ramp, inverted-base accent and colour themes,
|
|
116
|
+
* with the house accessibility floors. Fonts include Inter heading/body
|
|
117
|
+
* and the category faces selected by the bodyFont knob.
|
|
116
118
|
* Every option overrides its piece independently: `base` and `accent` each
|
|
117
119
|
* replace their default, `fonts` are spread OVER the defaults so a partial
|
|
118
120
|
* font map keeps the default heading/body and category faces, and `builderOptions.getTheme`
|
|
@@ -123,6 +125,7 @@ export function createDefaultThemeConfig(
|
|
|
123
125
|
options: CreateDefaultThemeConfigOptions = {},
|
|
124
126
|
): ThemeConfig {
|
|
125
127
|
setSizeRecipeInputs(options.recipeInputs ?? {});
|
|
128
|
+
const scale = generateScale(defaultScaleInputs);
|
|
126
129
|
const base = options.base ?? defaultBaseTheme;
|
|
127
130
|
const accent = options.accent ?? defaultAccentTheme;
|
|
128
131
|
const themesBuilder = createThemesBuilder(base, accent, {
|
|
@@ -144,24 +147,23 @@ export function createDefaultThemeConfig(
|
|
|
144
147
|
// pipeline (e.g. the Frappe SPA) where runtime JS themes are required.
|
|
145
148
|
// Always keep themes to ensure TamaguiProvider has valid theme data.
|
|
146
149
|
const themes = options.subset ? subsetThemes(builtThemes, options.subset) : builtThemes;
|
|
150
|
+
const fonts = {
|
|
151
|
+
...defaultConfig.fonts,
|
|
152
|
+
...defaultFonts,
|
|
153
|
+
...options.fonts,
|
|
154
|
+
} as Record<string, GenericFont>;
|
|
147
155
|
return createThemeConfig(
|
|
148
156
|
{
|
|
149
157
|
...defaultConfig,
|
|
158
|
+
tokens: scale.tokens,
|
|
150
159
|
animations: options.animations ?? animations,
|
|
151
160
|
disableSSR: false,
|
|
152
|
-
fonts
|
|
153
|
-
...defaultConfig.fonts,
|
|
154
|
-
...defaultFonts,
|
|
155
|
-
...options.fonts,
|
|
156
|
-
},
|
|
161
|
+
fonts,
|
|
157
162
|
shorthands,
|
|
158
163
|
shouldAddPrefersColorThemes: true,
|
|
159
164
|
themeClassNameOnRoot: true,
|
|
160
165
|
themes,
|
|
161
166
|
allowedStyleValues: undefined,
|
|
162
|
-
// Tokens come from `defaultConfig` above, and from nothing else — see
|
|
163
|
-
// the `tamaguiEra` note. There is no second token source to disagree
|
|
164
|
-
// with the era pin.
|
|
165
167
|
settings: {
|
|
166
168
|
...defaultConfig.settings,
|
|
167
169
|
allowedStyleValues: "somewhat-strict-web",
|
|
@@ -181,6 +183,10 @@ export function createDefaultThemeConfig(
|
|
|
181
183
|
defaultPreset: options.defaultPreset,
|
|
182
184
|
recipeInputs: getSizeRecipeInputs(),
|
|
183
185
|
recipeFamilies: getGeneratedSizeRecipes().families,
|
|
186
|
+
scale: {
|
|
187
|
+
fonts: (tables) => scaleFontSet(fonts, scale.fonts, tables),
|
|
188
|
+
recipeOverrides: options.recipeInputs,
|
|
189
|
+
},
|
|
184
190
|
},
|
|
185
191
|
);
|
|
186
192
|
}
|