@multiplatform.one/theme 7.34.4 → 7.36.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
|
@@ -3,20 +3,23 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Stored numbers are the source of truth. Derived projections (heights,
|
|
5
5
|
* recipes, box/type/icon variants, touch heights, radii) are never
|
|
6
|
-
* handwritten at a call site. The
|
|
7
|
-
*
|
|
8
|
-
* gap
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* handwritten at a call site. The default inputs are READ off the generated
|
|
7
|
+
* token scale (`scale/generateScale.ts`): height = `$size`, padX = `$space`,
|
|
8
|
+
* radius (and gap) = `$radius` at the same key, so a raw `$size`/`$space`
|
|
9
|
+
* prop and the recipe at that key are the same number. `{ control }` (and
|
|
10
|
+
* `{ type }`) regenerate every table from a new scale.
|
|
11
11
|
*
|
|
12
12
|
* Radius steps with the size token. The borderRadius knob overrides the
|
|
13
13
|
* painted corners while internal gap stays on the size recipe. `radiusPx`
|
|
14
|
-
* on inputs is the $4 / medium default
|
|
14
|
+
* on inputs is `$radius.true`, the $4 / medium default.
|
|
15
15
|
*
|
|
16
16
|
* Tamagui `createThemes` / theme-builder still emits COLOR palettes only.
|
|
17
17
|
* Do not stuff recipe keys into `getTheme()` / `themes`.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
+
import { scaleRadiusPx } from "./scale/activeScale";
|
|
21
|
+
import { generateScale } from "./scale/generateScale";
|
|
22
|
+
import { SIZE_RECIPE_TOKENS, type SizeRecipeToken, defaultScaleInputs } from "./scale/scaleInputs";
|
|
20
23
|
import {
|
|
21
24
|
cloneTileSizeInputs,
|
|
22
25
|
generateTileSizeLadder,
|
|
@@ -25,22 +28,10 @@ import {
|
|
|
25
28
|
type TileSizeLadder,
|
|
26
29
|
} from "./tileSizes";
|
|
27
30
|
|
|
28
|
-
export
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"$2.5",
|
|
33
|
-
"$3",
|
|
34
|
-
"$3.5",
|
|
35
|
-
"$4",
|
|
36
|
-
"$true",
|
|
37
|
-
"$5",
|
|
38
|
-
"$6",
|
|
39
|
-
] as const;
|
|
40
|
-
|
|
41
|
-
export type SizeRecipeToken = (typeof SIZE_RECIPE_TOKENS)[number];
|
|
42
|
-
|
|
43
|
-
export type SizeRecipeFamilyName = "control" | "controlCompact";
|
|
31
|
+
export { SIZE_RECIPE_TOKENS, SIZE_TOKEN_EXPONENTS } from "./scale/scaleInputs";
|
|
32
|
+
export type { SizeRecipeToken } from "./scale/scaleInputs";
|
|
33
|
+
|
|
34
|
+
export type SizeRecipeFamilyName = "control" | "chip" | "menuRow" | "tab";
|
|
44
35
|
/** @deprecated Use `SizeRecipeFamilyName`. */
|
|
45
36
|
export type RecipeFamilyName = SizeRecipeFamilyName;
|
|
46
37
|
|
|
@@ -61,49 +52,44 @@ export type SizeRecipeTokenChannels = {
|
|
|
61
52
|
|
|
62
53
|
export type SizeRecipeTokenTable = Partial<Record<SizeRecipeToken, SizeRecipeTokenChannels>>;
|
|
63
54
|
|
|
55
|
+
const defaultScale = generateScale(defaultScaleInputs);
|
|
56
|
+
|
|
64
57
|
/**
|
|
65
|
-
* borderRadius knob stops (px)
|
|
66
|
-
*
|
|
67
|
-
*
|
|
58
|
+
* borderRadius knob stops (px): the `$radius` tokens the knob resolves
|
|
59
|
+
* ($0/$2/$4/$6/$12). These shape overrides do not retarget the control's
|
|
60
|
+
* internal gap.
|
|
68
61
|
*/
|
|
69
62
|
export const SIZE_RECIPE_RADIUS_STOPS = {
|
|
70
|
-
none: 0,
|
|
71
|
-
small:
|
|
72
|
-
medium:
|
|
73
|
-
large:
|
|
74
|
-
full:
|
|
63
|
+
none: defaultScale.tokens.radius[0],
|
|
64
|
+
small: defaultScale.tokens.radius[2],
|
|
65
|
+
medium: defaultScale.tokens.radius[4],
|
|
66
|
+
large: defaultScale.tokens.radius[6],
|
|
67
|
+
full: defaultScale.tokens.radius[12],
|
|
75
68
|
} as const;
|
|
76
69
|
|
|
77
70
|
export type SizeRecipeRadiusStop = keyof typeof SIZE_RECIPE_RADIUS_STOPS;
|
|
78
71
|
|
|
79
72
|
export type SizeRecipeInputs = {
|
|
80
|
-
|
|
81
|
-
|
|
73
|
+
/** `$size.$4` px of the scale the tables were generated from (`ScaleInputs.control`). */
|
|
74
|
+
control: number;
|
|
75
|
+
/** Body `$true` px of that scale (`ScaleInputs.type`); the label/icon ladders follow it. */
|
|
76
|
+
type: number;
|
|
82
77
|
tokenSteps: Record<string, number>;
|
|
83
|
-
/**
|
|
84
|
-
tokenHeights
|
|
85
|
-
/**
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
sizeFactors?: Partial<Record<SizeRecipeToken, number>>;
|
|
90
|
-
/**
|
|
91
|
-
* Measured per-token channels (padX / font / icon / radius). When
|
|
92
|
-
* present, enumerable recipes read this table and set gap = radius.
|
|
93
|
-
* `{ baseHeight }` without an explicit tokenTable drops it so the
|
|
94
|
-
* geometric fallback can run.
|
|
95
|
-
*/
|
|
96
|
-
tokenTable?: SizeRecipeTokenTable;
|
|
97
|
-
/** Same-height tighter family (Chip / `recipeFamily="controlCompact"`). */
|
|
98
|
-
compactTokenTable?: SizeRecipeTokenTable;
|
|
78
|
+
/** Desktop px per recipe key: `$size` at the key. */
|
|
79
|
+
tokenHeights: Record<string, number>;
|
|
80
|
+
/** Per-token channels (padX / font / icon / radius); recipes set gap = radius. */
|
|
81
|
+
tokenTable: SizeRecipeTokenTable;
|
|
82
|
+
/** Same-height tighter family (Chip / `recipeFamily="chip"`). */
|
|
83
|
+
chipTokenTable: SizeRecipeTokenTable;
|
|
99
84
|
/**
|
|
100
85
|
* Input padX (one space half-step below the button at the same token).
|
|
101
|
-
* $4 =
|
|
86
|
+
* $4 = 14 vs the button's 16. Stored on inputs so the generator remains
|
|
102
87
|
* the single writer; Input consumes this, not a second handwritten map.
|
|
103
88
|
*/
|
|
104
|
-
inputPadX
|
|
89
|
+
inputPadX: Partial<Record<SizeRecipeToken, number>>;
|
|
90
|
+
/** Channel / height at $4; sizes recipes for heights off the table (touch, numeric `size`). */
|
|
105
91
|
ratios: SizeRecipeRatios;
|
|
106
|
-
|
|
92
|
+
chipRatios: SizeRecipeRatios;
|
|
107
93
|
radiusPx: number;
|
|
108
94
|
touchFloor: number;
|
|
109
95
|
/**
|
|
@@ -167,245 +153,80 @@ export type GeneratedSizeRecipes = {
|
|
|
167
153
|
tiles: TileSizeLadder;
|
|
168
154
|
};
|
|
169
155
|
|
|
170
|
-
export const
|
|
171
|
-
$1: -3,
|
|
172
|
-
"$1.5": -2.5,
|
|
173
|
-
$2: -2,
|
|
174
|
-
"$2.5": -1.5,
|
|
175
|
-
$3: -1,
|
|
176
|
-
"$3.5": -0.5,
|
|
177
|
-
$4: 0,
|
|
178
|
-
$true: 0,
|
|
179
|
-
$5: 1,
|
|
180
|
-
$6: 2,
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
// Stock Tamagui `$size` px as measured from the live tamagui.dev CSS vars
|
|
184
|
-
// (MPO-13 fidelity pass): $1:20 $1.5:24 $2:28 $2.5:32 $3:36 $3.5:40
|
|
185
|
-
// $4/$true:44 $5:52 $6:64. The recipe key "$4" and the raw Tamagui token
|
|
186
|
-
// `$size.4` resolve to the SAME height — the C1 split (recipe 32 vs token
|
|
187
|
-
// 44) is gone.
|
|
188
|
-
const DEFAULT_TOKEN_HEIGHTS: Record<string, number> = {
|
|
189
|
-
$1: 20,
|
|
190
|
-
"$1.5": 24,
|
|
191
|
-
$2: 28,
|
|
192
|
-
"$2.5": 32,
|
|
193
|
-
$3: 36,
|
|
194
|
-
"$3.5": 40,
|
|
195
|
-
$4: 44,
|
|
196
|
-
$true: 44,
|
|
197
|
-
$5: 52,
|
|
198
|
-
$6: 64,
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
/** Lossless relative table: the stock Tamagui 20/24/28/32/36/40/44/52/64 ramp at baseHeight 44. */
|
|
202
|
-
export const defaultSizeFactors: Record<SizeRecipeToken, number> = {
|
|
203
|
-
$1: 20 / 44,
|
|
204
|
-
"$1.5": 24 / 44,
|
|
205
|
-
$2: 28 / 44,
|
|
206
|
-
"$2.5": 32 / 44,
|
|
207
|
-
$3: 36 / 44,
|
|
208
|
-
"$3.5": 40 / 44,
|
|
209
|
-
$4: 1,
|
|
210
|
-
$true: 1,
|
|
211
|
-
$5: 52 / 44,
|
|
212
|
-
$6: 64 / 44,
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Measured Tamagui v5 Button ladder (rendered reference §6.1) plus the
|
|
217
|
-
* integer token-scale fills for stops the site did not photograph.
|
|
218
|
-
*
|
|
219
|
-
* padX = `$space` at the same key (2/4/7/10/13/16/18/24/32).
|
|
220
|
-
* radius = `$radius` at the same key (3/5/7/9/10/16); half-steps sit
|
|
221
|
-
* halfway on that scale (4/6/8) because v5 has no $1.5/$2.5/$3.5 radius.
|
|
222
|
-
* font = Inter body at the same key (11/12/13/14/16/18); half-steps take
|
|
223
|
-
* the next integer stop.
|
|
224
|
-
* icon steps with size and keeps the existing $4 = 16 contract.
|
|
225
|
-
* $2/$3/$4/$6 padX / font / radius are the photographed values (7/13/18/32,
|
|
226
|
-
* 12/13/14/18, 5/7/9/16).
|
|
227
|
-
*/
|
|
228
|
-
export const TAMAGUI_CONTROL_SIZE_TABLE: Record<SizeRecipeToken, SizeRecipeTokenChannels> = {
|
|
229
|
-
$1: { paddingHorizontal: 2, fontSize: 11, iconSize: 10, radius: 3 },
|
|
230
|
-
"$1.5": { paddingHorizontal: 4, fontSize: 12, iconSize: 11, radius: 4 },
|
|
231
|
-
$2: { paddingHorizontal: 7, fontSize: 12, iconSize: 12, radius: 5 },
|
|
232
|
-
"$2.5": { paddingHorizontal: 10, fontSize: 13, iconSize: 14, radius: 6 },
|
|
233
|
-
$3: { paddingHorizontal: 13, fontSize: 13, iconSize: 14, radius: 7 },
|
|
234
|
-
"$3.5": { paddingHorizontal: 16, fontSize: 14, iconSize: 15, radius: 8 },
|
|
235
|
-
$4: { paddingHorizontal: 18, fontSize: 14, iconSize: 16, radius: 9 },
|
|
236
|
-
$true: { paddingHorizontal: 18, fontSize: 14, iconSize: 16, radius: 9 },
|
|
237
|
-
$5: { paddingHorizontal: 24, fontSize: 16, iconSize: 18, radius: 10 },
|
|
238
|
-
$6: { paddingHorizontal: 32, fontSize: 18, iconSize: 20, radius: 16 },
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Input padX — `getSpace(val, { shift: -1 })` on the v5 space scale
|
|
243
|
-
* (rendered reference §6.2). $2/$3/$4 are the photographed 4/10/16;
|
|
244
|
-
* $4 is 16 against the button's 18.
|
|
245
|
-
*/
|
|
246
|
-
export const TAMAGUI_INPUT_PADX: Record<SizeRecipeToken, number> = {
|
|
247
|
-
$1: 1,
|
|
248
|
-
"$1.5": 2,
|
|
249
|
-
$2: 4,
|
|
250
|
-
"$2.5": 7,
|
|
251
|
-
$3: 10,
|
|
252
|
-
"$3.5": 13,
|
|
253
|
-
$4: 16,
|
|
254
|
-
$true: 16,
|
|
255
|
-
$5: 21,
|
|
256
|
-
$6: 24,
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* controlCompact: same height / radius (so gap == radius) as control;
|
|
261
|
-
* padX is the Input table (one space half-step tighter); font/icon sit
|
|
262
|
-
* one type step below the control table.
|
|
263
|
-
*/
|
|
264
|
-
export const TAMAGUI_COMPACT_SIZE_TABLE: Record<SizeRecipeToken, SizeRecipeTokenChannels> = {
|
|
265
|
-
$1: { paddingHorizontal: 1, fontSize: 10, iconSize: 9, radius: 3 },
|
|
266
|
-
"$1.5": { paddingHorizontal: 2, fontSize: 11, iconSize: 10, radius: 4 },
|
|
267
|
-
$2: { paddingHorizontal: 4, fontSize: 11, iconSize: 11, radius: 5 },
|
|
268
|
-
"$2.5": { paddingHorizontal: 7, fontSize: 12, iconSize: 12, radius: 6 },
|
|
269
|
-
$3: { paddingHorizontal: 10, fontSize: 12, iconSize: 13, radius: 7 },
|
|
270
|
-
"$3.5": { paddingHorizontal: 13, fontSize: 13, iconSize: 14, radius: 8 },
|
|
271
|
-
$4: { paddingHorizontal: 16, fontSize: 13, iconSize: 14, radius: 9 },
|
|
272
|
-
$true: { paddingHorizontal: 16, fontSize: 13, iconSize: 14, radius: 9 },
|
|
273
|
-
$5: { paddingHorizontal: 21, fontSize: 14, iconSize: 16, radius: 10 },
|
|
274
|
-
$6: { paddingHorizontal: 24, fontSize: 16, iconSize: 18, radius: 16 },
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
// Geometric fallback only — used when `{ baseHeight }` drops tokenTable.
|
|
278
|
-
// Anchored at the measured $4 so a doubled baseHeight still doubles $4.
|
|
279
|
-
const FALLBACK_RATIOS: SizeRecipeRatios = {
|
|
280
|
-
padX: 18 / 44,
|
|
281
|
-
font: 14 / 44,
|
|
282
|
-
icon: 16 / 44,
|
|
283
|
-
gap: 9 / 44,
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
const FALLBACK_COMPACT_RATIOS: SizeRecipeRatios = {
|
|
287
|
-
padX: 16 / 44,
|
|
288
|
-
font: 13 / 44,
|
|
289
|
-
icon: 14 / 44,
|
|
290
|
-
gap: 9 / 44,
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
export const DEFAULT_SIZE_RECIPE_INPUTS: SizeRecipeInputs = {
|
|
294
|
-
// Tamagui `$size.true` = 44 — the iOS touch minimum, measured on every
|
|
295
|
-
// tamagui.dev button and input (MPO-13 C2).
|
|
296
|
-
baseHeight: 44,
|
|
297
|
-
stepRatio: 1.25,
|
|
298
|
-
tokenSteps: { ...SIZE_TOKEN_EXPONENTS },
|
|
299
|
-
tokenHeights: { ...DEFAULT_TOKEN_HEIGHTS },
|
|
300
|
-
sizeFactors: { ...defaultSizeFactors },
|
|
301
|
-
tokenTable: { ...TAMAGUI_CONTROL_SIZE_TABLE },
|
|
302
|
-
compactTokenTable: { ...TAMAGUI_COMPACT_SIZE_TABLE },
|
|
303
|
-
inputPadX: { ...TAMAGUI_INPUT_PADX },
|
|
304
|
-
ratios: { ...FALLBACK_RATIOS },
|
|
305
|
-
compactRatios: { ...FALLBACK_COMPACT_RATIOS },
|
|
306
|
-
// Tamagui `$radius.true` = 9 — the $4 / medium default. Per-token
|
|
307
|
-
// radii live on tokenTable; this is the knob's medium stop and the
|
|
308
|
-
// $4 table row, not a flat radius for every size.
|
|
309
|
-
radiusPx: 9,
|
|
310
|
-
touchFloor: 44,
|
|
311
|
-
};
|
|
156
|
+
export const DEFAULT_SIZE_RECIPE_INPUTS: SizeRecipeInputs = defaultScale.recipeInputs;
|
|
312
157
|
|
|
313
158
|
export const defaultRecipeInputs = DEFAULT_SIZE_RECIPE_INPUTS;
|
|
314
159
|
|
|
315
160
|
export const TOUCH_HEIGHT_FLOOR = DEFAULT_SIZE_RECIPE_INPUTS.touchFloor;
|
|
316
161
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
162
|
+
/** Rows of `over` replace rows of `base`; a `$4` override without `$true` carries to `$true`. */
|
|
163
|
+
function mergeTokenTable(
|
|
164
|
+
base: SizeRecipeTokenTable,
|
|
165
|
+
over?: SizeRecipeTokenTable,
|
|
166
|
+
): SizeRecipeTokenTable {
|
|
321
167
|
const next: SizeRecipeTokenTable = {};
|
|
322
168
|
for (const token of SIZE_RECIPE_TOKENS) {
|
|
323
|
-
const row =
|
|
169
|
+
const row = over?.[token] ?? (token === "$true" ? over?.$4 : undefined) ?? base[token];
|
|
324
170
|
if (row) next[token] = { ...row };
|
|
325
171
|
}
|
|
326
172
|
return next;
|
|
327
173
|
}
|
|
328
174
|
|
|
329
|
-
function
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
175
|
+
function mergeTokenHeights(
|
|
176
|
+
base: Record<string, number>,
|
|
177
|
+
over?: Record<string, number>,
|
|
178
|
+
): Record<string, number> {
|
|
179
|
+
const next = { ...base, ...over };
|
|
180
|
+
if (over?.$4 != null && over.$true == null) next.$true = over.$4;
|
|
181
|
+
return next;
|
|
333
182
|
}
|
|
334
183
|
|
|
335
184
|
export function cloneSizeRecipeInputs(inputs: SizeRecipeInputs): SizeRecipeInputs {
|
|
336
185
|
return {
|
|
337
186
|
...inputs,
|
|
338
187
|
tokenSteps: { ...inputs.tokenSteps },
|
|
339
|
-
tokenHeights:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
inputPadX: clonePadX(inputs.inputPadX),
|
|
188
|
+
tokenHeights: { ...inputs.tokenHeights },
|
|
189
|
+
tokenTable: mergeTokenTable(inputs.tokenTable),
|
|
190
|
+
chipTokenTable: mergeTokenTable(inputs.chipTokenTable),
|
|
191
|
+
inputPadX: { ...inputs.inputPadX },
|
|
344
192
|
ratios: { ...inputs.ratios },
|
|
345
|
-
|
|
193
|
+
chipRatios: { ...inputs.chipRatios },
|
|
346
194
|
tile: inputs.tile ? cloneTileSizeInputs(inputs.tile) : undefined,
|
|
347
195
|
};
|
|
348
196
|
}
|
|
349
197
|
|
|
350
198
|
/**
|
|
351
|
-
* Fill defaults. `{
|
|
352
|
-
*
|
|
199
|
+
* Fill defaults. `{ control }` / `{ type }` regenerate every table from a
|
|
200
|
+
* new scale; explicit tables, heights and ratios then merge over it per row.
|
|
353
201
|
*/
|
|
354
202
|
export function resolveSizeRecipeInputs(partial: Partial<SizeRecipeInputs> = {}): SizeRecipeInputs {
|
|
355
|
-
const
|
|
356
|
-
partial.
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
203
|
+
const base =
|
|
204
|
+
partial.control == null && partial.type == null
|
|
205
|
+
? DEFAULT_SIZE_RECIPE_INPUTS
|
|
206
|
+
: generateScale({
|
|
207
|
+
...defaultScaleInputs,
|
|
208
|
+
control: partial.control ?? DEFAULT_SIZE_RECIPE_INPUTS.control,
|
|
209
|
+
type: partial.type ?? DEFAULT_SIZE_RECIPE_INPUTS.type,
|
|
210
|
+
}).recipeInputs;
|
|
362
211
|
|
|
363
212
|
const resolved: SizeRecipeInputs = {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
tokenSteps: { ...
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
213
|
+
control: base.control,
|
|
214
|
+
type: base.type,
|
|
215
|
+
tokenSteps: { ...base.tokenSteps, ...partial.tokenSteps },
|
|
216
|
+
tokenHeights: mergeTokenHeights(base.tokenHeights, partial.tokenHeights),
|
|
217
|
+
tokenTable: mergeTokenTable(base.tokenTable, partial.tokenTable),
|
|
218
|
+
chipTokenTable: mergeTokenTable(base.chipTokenTable, partial.chipTokenTable),
|
|
219
|
+
inputPadX: { ...base.inputPadX, ...partial.inputPadX },
|
|
220
|
+
ratios: { ...base.ratios, ...partial.ratios },
|
|
221
|
+
chipRatios: { ...base.chipRatios, ...partial.chipRatios },
|
|
222
|
+
radiusPx: partial.radiusPx ?? base.radiusPx,
|
|
223
|
+
touchFloor: partial.touchFloor ?? base.touchFloor,
|
|
371
224
|
};
|
|
372
225
|
|
|
373
226
|
if (partial.tile !== undefined) {
|
|
374
227
|
resolved.tile = partial.tile ? resolveTileSizeInputs(partial.tile) : undefined;
|
|
375
228
|
}
|
|
376
229
|
|
|
377
|
-
if (hasTokenHeights) {
|
|
378
|
-
resolved.tokenHeights = partial.tokenHeights ? { ...partial.tokenHeights } : undefined;
|
|
379
|
-
if (hasSizeFactors) {
|
|
380
|
-
resolved.sizeFactors = partial.sizeFactors ? { ...partial.sizeFactors } : undefined;
|
|
381
|
-
}
|
|
382
|
-
} else if (hasSizeFactors) {
|
|
383
|
-
resolved.sizeFactors = partial.sizeFactors ? { ...partial.sizeFactors } : undefined;
|
|
384
|
-
} else if (!scalingOverride) {
|
|
385
|
-
resolved.tokenHeights = { ...DEFAULT_SIZE_RECIPE_INPUTS.tokenHeights };
|
|
386
|
-
resolved.sizeFactors = { ...DEFAULT_SIZE_RECIPE_INPUTS.sizeFactors };
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
if (hasTokenTable) {
|
|
390
|
-
resolved.tokenTable = partial.tokenTable ? cloneTokenTable(partial.tokenTable) : undefined;
|
|
391
|
-
} else if (!scalingOverride) {
|
|
392
|
-
resolved.tokenTable = cloneTokenTable(DEFAULT_SIZE_RECIPE_INPUTS.tokenTable);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
if (hasCompactTable) {
|
|
396
|
-
resolved.compactTokenTable = partial.compactTokenTable
|
|
397
|
-
? cloneTokenTable(partial.compactTokenTable)
|
|
398
|
-
: undefined;
|
|
399
|
-
} else if (!scalingOverride) {
|
|
400
|
-
resolved.compactTokenTable = cloneTokenTable(DEFAULT_SIZE_RECIPE_INPUTS.compactTokenTable);
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
if (hasInputPadX) {
|
|
404
|
-
resolved.inputPadX = partial.inputPadX ? clonePadX(partial.inputPadX) : undefined;
|
|
405
|
-
} else if (!scalingOverride) {
|
|
406
|
-
resolved.inputPadX = clonePadX(DEFAULT_SIZE_RECIPE_INPUTS.inputPadX);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
230
|
return resolved;
|
|
410
231
|
}
|
|
411
232
|
|
|
@@ -416,12 +237,7 @@ function clampHeight(value: number): number {
|
|
|
416
237
|
}
|
|
417
238
|
|
|
418
239
|
function heightForToken(token: string, inputs: SizeRecipeInputs): number {
|
|
419
|
-
|
|
420
|
-
if (explicitPx != null) return clampHeight(explicitPx);
|
|
421
|
-
const factor = inputs.sizeFactors?.[token as SizeRecipeToken];
|
|
422
|
-
if (factor != null) return clampHeight(inputs.baseHeight * factor);
|
|
423
|
-
const step = inputs.tokenSteps[token] ?? 0;
|
|
424
|
-
return clampHeight(inputs.baseHeight * inputs.stepRatio ** step);
|
|
240
|
+
return clampHeight(inputs.tokenHeights[token] ?? inputs.control);
|
|
425
241
|
}
|
|
426
242
|
|
|
427
243
|
export function sizeRecipeFromHeight(
|
|
@@ -456,7 +272,7 @@ export function applyRadiusStop<T extends { gap: number }>(
|
|
|
456
272
|
recipe: T,
|
|
457
273
|
stop: SizeRecipeRadiusStop,
|
|
458
274
|
): T {
|
|
459
|
-
return { ...recipe, gap: SIZE_RECIPE_RADIUS_STOPS[stop] };
|
|
275
|
+
return { ...recipe, gap: scaleRadiusPx(SIZE_RECIPE_RADIUS_STOPS[stop]) };
|
|
460
276
|
}
|
|
461
277
|
|
|
462
278
|
/** Knob fragment token → stop name. Default medium is `$4`. */
|
|
@@ -482,7 +298,7 @@ export function resolveControlRadius(
|
|
|
482
298
|
if (stop === "medium") {
|
|
483
299
|
return { radius: recipe.gap, gap: recipe.gap };
|
|
484
300
|
}
|
|
485
|
-
const px = SIZE_RECIPE_RADIUS_STOPS[stop];
|
|
301
|
+
const px = scaleRadiusPx(SIZE_RECIPE_RADIUS_STOPS[stop]);
|
|
486
302
|
return { radius: px, gap: recipe.gap };
|
|
487
303
|
}
|
|
488
304
|
|
|
@@ -491,32 +307,9 @@ function generateTouchHeights(
|
|
|
491
307
|
inputs: SizeRecipeInputs,
|
|
492
308
|
tokens: readonly string[],
|
|
493
309
|
): Record<string, number> {
|
|
494
|
-
const { touchFloor, tokenSteps } = inputs;
|
|
495
|
-
const mdDesktop = heights.$4 ?? inputs.baseHeight;
|
|
496
|
-
const floored: Record<string, number> = {};
|
|
497
|
-
for (const token of tokens) {
|
|
498
|
-
floored[token] = Math.max(heights[token], touchFloor);
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
let mdTouch = Math.max(floored.$4 ?? touchFloor, MD_TOUCH_MIN);
|
|
502
|
-
const below = tokens.filter((token) => (tokenSteps[token] ?? 0) < 0);
|
|
503
|
-
const maxBelow =
|
|
504
|
-
below.length > 0 ? Math.max(...below.map((token) => floored[token])) : touchFloor;
|
|
505
|
-
if (mdTouch <= maxBelow) {
|
|
506
|
-
const nextSmaller = heights.$3 ?? mdDesktop;
|
|
507
|
-
mdTouch = maxBelow + Math.max(mdDesktop - nextSmaller, 1);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
310
|
const heightsTouch: Record<string, number> = {};
|
|
511
311
|
for (const token of tokens) {
|
|
512
|
-
|
|
513
|
-
if (step < 0) {
|
|
514
|
-
heightsTouch[token] = floored[token];
|
|
515
|
-
} else if (step === 0) {
|
|
516
|
-
heightsTouch[token] = mdTouch;
|
|
517
|
-
} else {
|
|
518
|
-
heightsTouch[token] = Math.max(floored[token], mdTouch + (heights[token] - mdDesktop));
|
|
519
|
-
}
|
|
312
|
+
heightsTouch[token] = Math.max(heights[token], inputs.touchFloor);
|
|
520
313
|
}
|
|
521
314
|
return heightsTouch;
|
|
522
315
|
}
|
|
@@ -533,13 +326,14 @@ export function generateSizeRecipeTables(
|
|
|
533
326
|
inputs: SizeRecipeInputs,
|
|
534
327
|
ratios: SizeRecipeRatios = inputs.ratios,
|
|
535
328
|
table: SizeRecipeTokenTable | undefined = inputs.tokenTable,
|
|
329
|
+
heightOf: (token: SizeRecipeToken) => number = (token) => heightForToken(token, inputs),
|
|
536
330
|
): SizeRecipeTables {
|
|
537
331
|
const tokens = SIZE_RECIPE_TOKENS;
|
|
538
332
|
const heights: Record<string, number> = {};
|
|
539
333
|
for (const token of tokens) {
|
|
540
|
-
heights[token] =
|
|
334
|
+
heights[token] = heightOf(token);
|
|
541
335
|
}
|
|
542
|
-
if (inputs.tokenHeights
|
|
336
|
+
if (inputs.tokenHeights.$true == null) {
|
|
543
337
|
heights.$true = heights.$4;
|
|
544
338
|
}
|
|
545
339
|
|
|
@@ -559,7 +353,7 @@ export function generateSizeRecipeTables(
|
|
|
559
353
|
: sizeRecipeFromHeight(heights[token], ratios);
|
|
560
354
|
const radius = channels ? channels.radius : recipe.gap;
|
|
561
355
|
recipes[token] = recipe;
|
|
562
|
-
recipesTouch[token] =
|
|
356
|
+
recipesTouch[token] = { ...recipe, height: touchHeights[token] };
|
|
563
357
|
radii[token] = radius;
|
|
564
358
|
boxVariants[token] = {
|
|
565
359
|
height: recipe.height,
|
|
@@ -586,19 +380,83 @@ export function generateSizeRecipeTables(
|
|
|
586
380
|
};
|
|
587
381
|
}
|
|
588
382
|
|
|
383
|
+
/** Recipe keys in ladder order; `$true` reads as `$4`. */
|
|
384
|
+
const RECIPE_LADDER = SIZE_RECIPE_TOKENS.filter((token) => token !== "$true");
|
|
385
|
+
|
|
386
|
+
/** The recipe key one step below `token` on the ladder ($4 / $true -> $3.5, floor $1). */
|
|
387
|
+
export function recipeKeyBelow(token: SizeRecipeToken): SizeRecipeToken {
|
|
388
|
+
const index = RECIPE_LADDER.indexOf(token === "$true" ? "$4" : token);
|
|
389
|
+
return RECIPE_LADDER[Math.max(0, index - 1)];
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/** The recipe key one step above `token` on the ladder ($4 / $true -> $5, ceiling $6). */
|
|
393
|
+
export function recipeKeyAbove(token: SizeRecipeToken): SizeRecipeToken {
|
|
394
|
+
const index = RECIPE_LADDER.indexOf(token === "$true" ? "$4" : token);
|
|
395
|
+
return RECIPE_LADDER[Math.min(RECIPE_LADDER.length - 1, index + 1)];
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function ratiosOf(table: SizeRecipeTokenTable, height: number): SizeRecipeRatios {
|
|
399
|
+
const row = table.$4;
|
|
400
|
+
if (!row) return { padX: 0, font: 0, icon: 0, gap: 0 };
|
|
401
|
+
return {
|
|
402
|
+
padX: row.paddingHorizontal / height,
|
|
403
|
+
font: row.fontSize / height,
|
|
404
|
+
icon: row.iconSize / height,
|
|
405
|
+
gap: row.radius / height,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Row families read off the control table, never a second px source:
|
|
411
|
+
* - `menuRow` (menu / listbox / command rows): height one key below the
|
|
412
|
+
* control token (36 at `$4`), padX the `$3` space, type and icon the
|
|
413
|
+
* token's own.
|
|
414
|
+
* - `tab`: height and padX one key below, type and icon the token's own.
|
|
415
|
+
* Both lift to `touchFloor` on touch like every family.
|
|
416
|
+
*/
|
|
417
|
+
function deriveRowFamilyTables(inputs: SizeRecipeInputs): {
|
|
418
|
+
menuRow: SizeRecipeTokenTable;
|
|
419
|
+
tab: SizeRecipeTokenTable;
|
|
420
|
+
} {
|
|
421
|
+
const menuRow: SizeRecipeTokenTable = {};
|
|
422
|
+
const tab: SizeRecipeTokenTable = {};
|
|
423
|
+
const rowPadX = inputs.tokenTable.$3?.paddingHorizontal;
|
|
424
|
+
for (const token of SIZE_RECIPE_TOKENS) {
|
|
425
|
+
const own = channelsForToken(token, inputs.tokenTable);
|
|
426
|
+
const below = channelsForToken(recipeKeyBelow(token), inputs.tokenTable);
|
|
427
|
+
if (!own || !below) continue;
|
|
428
|
+
menuRow[token] = { ...own, paddingHorizontal: rowPadX ?? below.paddingHorizontal };
|
|
429
|
+
tab[token] = { ...own, paddingHorizontal: below.paddingHorizontal };
|
|
430
|
+
}
|
|
431
|
+
return { menuRow, tab };
|
|
432
|
+
}
|
|
433
|
+
|
|
589
434
|
export function createRecipeFamilies(
|
|
590
435
|
inputs: SizeRecipeInputs | Partial<SizeRecipeInputs> = {},
|
|
591
436
|
): RecipeFamilies {
|
|
592
437
|
const resolved = cloneSizeRecipeInputs(resolveSizeRecipeInputs(inputs));
|
|
593
438
|
const control = generateSizeRecipeTables(resolved, resolved.ratios, resolved.tokenTable);
|
|
594
|
-
const
|
|
439
|
+
const chip = generateSizeRecipeTables(resolved, resolved.chipRatios, resolved.chipTokenTable);
|
|
440
|
+
const rows = deriveRowFamilyTables(resolved);
|
|
441
|
+
const heightBelow = (token: SizeRecipeToken) => heightForToken(recipeKeyBelow(token), resolved);
|
|
442
|
+
const rowHeight = heightBelow("$4");
|
|
443
|
+
const menuRow = generateSizeRecipeTables(
|
|
444
|
+
resolved,
|
|
445
|
+
ratiosOf(rows.menuRow, rowHeight),
|
|
446
|
+
rows.menuRow,
|
|
447
|
+
heightBelow,
|
|
448
|
+
);
|
|
449
|
+
const tab = generateSizeRecipeTables(
|
|
595
450
|
resolved,
|
|
596
|
-
|
|
597
|
-
|
|
451
|
+
ratiosOf(rows.tab, rowHeight),
|
|
452
|
+
rows.tab,
|
|
453
|
+
heightBelow,
|
|
598
454
|
);
|
|
599
455
|
return {
|
|
600
456
|
control: { ...control, name: "control" },
|
|
601
|
-
|
|
457
|
+
chip: { ...chip, name: "chip" },
|
|
458
|
+
menuRow: { ...menuRow, name: "menuRow" },
|
|
459
|
+
tab: { ...tab, name: "tab" },
|
|
602
460
|
};
|
|
603
461
|
}
|
|
604
462
|
|