@multiplatform.one/theme 6.1.0 → 6.3.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 +73 -0
- package/package.json +22 -9
- package/src/dates.spec.ts +75 -0
- package/src/dates.ts +130 -0
- package/src/devWarn.spec.ts +144 -0
- package/src/devWarn.ts +235 -0
- package/src/figma/figmaTokens.spec.ts +244 -0
- package/src/figma/figmaTokens.ts +503 -0
- package/src/font.ts +6 -8
- package/src/fonts/createFontLoader.web.ts +15 -4
- package/src/index.ts +7 -0
- package/src/keyboardFocusRing.ts +45 -0
- package/src/menuRow.spec.ts +32 -0
- package/src/menuRow.ts +31 -0
- package/src/theme/FontKnobStyles.native.tsx +24 -0
- package/src/theme/FontKnobStyles.tsx +256 -0
- package/src/theme/animations/reactNative.ts +6 -1
- package/src/theme/chartPalette.spec.ts +159 -0
- package/src/theme/chartPalette.ts +170 -0
- package/src/theme/colorRules.ts +33 -1
- package/src/theme/cookies.spec.ts +32 -0
- package/src/theme/cookiesPersistence.spec.ts +86 -0
- package/src/theme/cornerSmoothing.native.ts +16 -0
- package/src/theme/cornerSmoothing.spec.ts +27 -0
- package/src/theme/cornerSmoothing.ts +46 -0
- package/src/theme/createDefaultThemeConfig.ts +32 -8
- package/src/theme/createThemeConfig.spec.ts +137 -0
- package/src/theme/createThemes.ts +77 -2
- package/src/theme/defaults/accent.ts +39 -0
- package/src/theme/defaults/base.ts +63 -0
- package/src/theme/defaults/builderOptions.ts +174 -0
- package/src/theme/defaults/fonts.spec.ts +87 -0
- package/src/theme/defaults/fonts.ts +89 -0
- package/src/theme/defaults/index.ts +4 -0
- package/src/theme/devtools/ThemeDevtoolsPanel.tsx +196 -2
- package/src/theme/devtools/buildSnapshot.ts +11 -0
- package/src/theme/devtools/knobIcons.tsx +141 -0
- package/src/theme/devtools/vizConstants.ts +1 -1
- package/src/theme/focusState.spec.ts +174 -0
- package/src/theme/focusState.ts +112 -0
- package/src/theme/fontKnobStyles.spec.ts +98 -0
- package/src/theme/hairline.native.ts +43 -0
- package/src/theme/hairline.spec.ts +63 -0
- package/src/theme/hairline.ts +101 -0
- package/src/theme/index.ts +8 -0
- package/src/theme/intent.spec.tsx +2 -2
- package/src/theme/intents.ts +6 -2
- package/src/theme/knobs.ts +134 -2
- package/src/theme/layoutTokens.spec.ts +75 -0
- package/src/theme/layoutTokens.ts +213 -0
- package/src/theme/layoutTokensHooks.spec.tsx +157 -0
- package/src/theme/presets.spec.ts +17 -0
- package/src/theme/presets.ts +22 -2
- package/src/theme/readableColor.ts +101 -0
- package/src/theme/recipes.ts +130 -7
- package/src/theme/resolveKnobs.spec.ts +560 -21
- package/src/theme/resolveKnobs.ts +267 -23
- package/src/theme/shared.tsx +26 -2
- package/src/theme/useResolvedKnobs.ts +67 -26
- package/src/theme/useResolvedKnobsBehavior.spec.tsx +166 -0
- package/types/audit/constraintAudit.d.ts +83 -0
- package/types/audit/constraintAudit.d.ts.map +1 -0
- package/types/audit/diffReport.d.ts +45 -0
- package/types/audit/diffReport.d.ts.map +1 -0
- package/types/audit/index.d.ts +5 -0
- package/types/audit/index.d.ts.map +1 -0
- package/types/dates.d.ts +52 -0
- package/types/dates.d.ts.map +1 -0
- package/types/devWarn.d.ts +104 -0
- package/types/devWarn.d.ts.map +1 -0
- package/types/figma/figmaTokens.d.ts +168 -0
- package/types/figma/figmaTokens.d.ts.map +1 -0
- package/types/font.d.ts +5 -0
- package/types/font.d.ts.map +1 -0
- package/types/fonts/createFontLoader.d.ts +3 -0
- package/types/fonts/createFontLoader.d.ts.map +1 -0
- package/types/fonts/createFontLoader.web.d.ts +3 -0
- package/types/fonts/createFontLoader.web.d.ts.map +1 -0
- package/types/fonts/index.d.ts +3 -0
- package/types/fonts/index.d.ts.map +1 -0
- package/types/fonts/types.d.ts +12 -0
- package/types/fonts/types.d.ts.map +1 -0
- package/types/index.d.ts +9 -0
- package/types/index.d.ts.map +1 -0
- package/types/keyboardFocusRing.d.ts +32 -0
- package/types/keyboardFocusRing.d.ts.map +1 -0
- package/types/menuRow.d.ts +32 -0
- package/types/menuRow.d.ts.map +1 -0
- package/types/theme/FontKnobStyles.d.ts +49 -0
- package/types/theme/FontKnobStyles.d.ts.map +1 -0
- package/types/theme/FontKnobStyles.native.d.ts +12 -0
- package/types/theme/FontKnobStyles.native.d.ts.map +1 -0
- package/types/theme/Intent.d.ts +20 -0
- package/types/theme/Intent.d.ts.map +1 -0
- package/types/theme/Preset.d.ts +15 -0
- package/types/theme/Preset.d.ts.map +1 -0
- package/types/theme/PresetContext.d.ts +18 -0
- package/types/theme/PresetContext.d.ts.map +1 -0
- package/types/theme/Tint.d.ts +19 -0
- package/types/theme/Tint.d.ts.map +1 -0
- package/types/theme/animations/css.d.ts +24 -0
- package/types/theme/animations/css.d.ts.map +1 -0
- package/types/theme/animations/index.d.ts +2 -0
- package/types/theme/animations/index.d.ts.map +1 -0
- package/types/theme/animations/index.web.d.ts +2 -0
- package/types/theme/animations/index.web.d.ts.map +1 -0
- package/types/theme/animations/reactNative.d.ts +104 -0
- package/types/theme/animations/reactNative.d.ts.map +1 -0
- package/types/theme/chartPalette.d.ts +62 -0
- package/types/theme/chartPalette.d.ts.map +1 -0
- package/types/theme/colorRules.d.ts +69 -0
- package/types/theme/colorRules.d.ts.map +1 -0
- package/types/theme/cookies.d.ts +76 -0
- package/types/theme/cookies.d.ts.map +1 -0
- package/types/theme/cornerSmoothing.d.ts +31 -0
- package/types/theme/cornerSmoothing.d.ts.map +1 -0
- package/types/theme/cornerSmoothing.native.d.ts +14 -0
- package/types/theme/cornerSmoothing.native.d.ts.map +1 -0
- package/types/theme/createDefaultThemeConfig.d.ts +37 -0
- package/types/theme/createDefaultThemeConfig.d.ts.map +1 -0
- package/types/theme/createThemes.d.ts +38 -0
- package/types/theme/createThemes.d.ts.map +1 -0
- package/types/theme/defaults/accent.d.ts +3 -0
- package/types/theme/defaults/accent.d.ts.map +1 -0
- package/types/theme/defaults/base.d.ts +3 -0
- package/types/theme/defaults/base.d.ts.map +1 -0
- package/types/theme/defaults/builderOptions.d.ts +3 -0
- package/types/theme/defaults/builderOptions.d.ts.map +1 -0
- package/types/theme/defaults/fonts.d.ts +7 -0
- package/types/theme/defaults/fonts.d.ts.map +1 -0
- package/types/theme/defaults/index.d.ts +5 -0
- package/types/theme/defaults/index.d.ts.map +1 -0
- package/types/theme/devtools/ColorLineVisualizer.d.ts +17 -0
- package/types/theme/devtools/ColorLineVisualizer.d.ts.map +1 -0
- package/types/theme/devtools/ThemeDevtoolsPanel.d.ts +87 -0
- package/types/theme/devtools/ThemeDevtoolsPanel.d.ts.map +1 -0
- package/types/theme/devtools/buildSnapshot.d.ts +12 -0
- package/types/theme/devtools/buildSnapshot.d.ts.map +1 -0
- package/types/theme/devtools/knobIcons.d.ts +33 -0
- package/types/theme/devtools/knobIcons.d.ts.map +1 -0
- package/types/theme/devtools/vizConstants.d.ts +5 -0
- package/types/theme/devtools/vizConstants.d.ts.map +1 -0
- package/types/theme/focusState.d.ts +42 -0
- package/types/theme/focusState.d.ts.map +1 -0
- package/types/theme/hairline.d.ts +88 -0
- package/types/theme/hairline.d.ts.map +1 -0
- package/types/theme/hairline.native.d.ts +42 -0
- package/types/theme/hairline.native.d.ts.map +1 -0
- package/types/theme/index.d.ts +29 -0
- package/types/theme/index.d.ts.map +1 -0
- package/types/theme/intents.d.ts +3 -0
- package/types/theme/intents.d.ts.map +1 -0
- package/types/theme/knobs.d.ts +236 -0
- package/types/theme/knobs.d.ts.map +1 -0
- package/types/theme/layoutTokens.d.ts +104 -0
- package/types/theme/layoutTokens.d.ts.map +1 -0
- package/types/theme/preset.types.d.ts +21 -0
- package/types/theme/preset.types.d.ts.map +1 -0
- package/types/theme/presets.d.ts +4 -0
- package/types/theme/presets.d.ts.map +1 -0
- package/types/theme/readableColor.d.ts +17 -0
- package/types/theme/readableColor.d.ts.map +1 -0
- package/types/theme/recipes.d.ts +200 -0
- package/types/theme/recipes.d.ts.map +1 -0
- package/types/theme/resolveKnobs.d.ts +22 -0
- package/types/theme/resolveKnobs.d.ts.map +1 -0
- package/types/theme/shared.d.ts +40 -0
- package/types/theme/shared.d.ts.map +1 -0
- package/types/theme/theme.d.ts +19 -0
- package/types/theme/theme.d.ts.map +1 -0
- package/types/theme/theme.native.d.ts +10 -0
- package/types/theme/theme.native.d.ts.map +1 -0
- package/types/theme/useColorScale.d.ts +7 -0
- package/types/theme/useColorScale.d.ts.map +1 -0
- package/types/theme/useColorScale.native.d.ts +6 -0
- package/types/theme/useColorScale.native.d.ts.map +1 -0
- package/types/theme/useResolvedKnobs.d.ts +32 -0
- package/types/theme/useResolvedKnobs.d.ts.map +1 -0
- package/types/theme/useTheme.d.ts +31 -0
- package/types/theme/useTheme.d.ts.map +1 -0
- package/types/theme/useTheme.native.d.ts +10 -0
- package/types/theme/useTheme.native.d.ts.map +1 -0
- package/CHANGELOG.md +0 -53
- package/src/theme/__snapshots__/resolveKnobs.spec.ts.snap +0 -69
- package/src/theme/pokemonScreen.spec.ts +0 -109
- package/tsconfig.json +0 -11
- package/vitest.config.mjs +0 -9
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useResolvedKnobs behavior specs — the resolution rules consumers feel but
|
|
3
|
+
* that aren't covered by the pure resolveKnobs specs: Tamagui size-token →
|
|
4
|
+
* knob-size mapping, OS reduced-motion forcing animation off, the legacy
|
|
5
|
+
* addListener matchMedia branch, and the semantic-intent Button label color
|
|
6
|
+
* rule (filled binds $color, outlined pins $color11).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { renderHook } from "@testing-library/react";
|
|
10
|
+
import type { ReactNode } from "react";
|
|
11
|
+
import { createElement } from "react";
|
|
12
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
13
|
+
import type { ThemeName } from "@tamagui/web";
|
|
14
|
+
import { defaultKnobs } from "./knobs";
|
|
15
|
+
import type { Preset as PresetType } from "./preset.types";
|
|
16
|
+
import { PresetContext, type PresetContextValue } from "./PresetContext";
|
|
17
|
+
import { useResolvedKnobs } from "./useResolvedKnobs";
|
|
18
|
+
|
|
19
|
+
let originalMatchMedia: typeof window.matchMedia;
|
|
20
|
+
|
|
21
|
+
function stubMatchMedia(
|
|
22
|
+
impl: (query: string) => Partial<MediaQueryList> & Record<string, unknown>,
|
|
23
|
+
) {
|
|
24
|
+
window.matchMedia = vi.fn(
|
|
25
|
+
(query: string) => impl(query) as MediaQueryList,
|
|
26
|
+
) as typeof window.matchMedia;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function modernMq(matches: boolean) {
|
|
30
|
+
return {
|
|
31
|
+
matches,
|
|
32
|
+
addEventListener: vi.fn(),
|
|
33
|
+
removeEventListener: vi.fn(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
originalMatchMedia = window.matchMedia;
|
|
39
|
+
stubMatchMedia(() => modernMq(false));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
window.matchMedia = originalMatchMedia;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
function presetWrapper(preset: PresetType) {
|
|
47
|
+
const ctx: PresetContextValue = { preset };
|
|
48
|
+
return ({ children }: { children: ReactNode }) =>
|
|
49
|
+
createElement(PresetContext.Provider, { value: ctx }, children);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function makePreset(overrides: Partial<PresetType> = {}): PresetType {
|
|
53
|
+
return {
|
|
54
|
+
theme: "light" as ThemeName,
|
|
55
|
+
knobs: { ...defaultKnobs },
|
|
56
|
+
intents: {},
|
|
57
|
+
tints: [],
|
|
58
|
+
...overrides,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe("size token mapping", () => {
|
|
63
|
+
it.each([
|
|
64
|
+
["$1", "small"],
|
|
65
|
+
["$3", "small"],
|
|
66
|
+
["$4", "medium"],
|
|
67
|
+
["$5", "large"],
|
|
68
|
+
["$6", "large"],
|
|
69
|
+
["$true", "medium"],
|
|
70
|
+
] as const)("maps Tamagui size %s to knob size %s", (token, expected) => {
|
|
71
|
+
const { result } = renderHook(() => useResolvedKnobs({ size: token as never }));
|
|
72
|
+
expect(result.current.knobProps.size).toBe(expected);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("keeps the knob size for unmapped tokens", () => {
|
|
76
|
+
const { result } = renderHook(() => useResolvedKnobs({ size: "$11" as never }));
|
|
77
|
+
expect(result.current.knobProps.size).toBe(defaultKnobs.size);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("reduced motion", () => {
|
|
82
|
+
it("keeps the animation knob's transition when the OS does not prefer reduced motion", () => {
|
|
83
|
+
const { result } = renderHook(() => useResolvedKnobs());
|
|
84
|
+
expect(result.current.knobProps.transition).toBe(defaultKnobs.animation);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("forces the transition off when prefers-reduced-motion matches", () => {
|
|
88
|
+
stubMatchMedia((query) => modernMq(query === "(prefers-reduced-motion: reduce)"));
|
|
89
|
+
const { result } = renderHook(() => useResolvedKnobs());
|
|
90
|
+
expect(result.current.knobProps.transition).toBeUndefined();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("supports legacy MediaQueryList hosts exposing only addListener", () => {
|
|
94
|
+
const addListener = vi.fn();
|
|
95
|
+
const removeListener = vi.fn();
|
|
96
|
+
stubMatchMedia(() => ({ matches: true, addListener, removeListener }));
|
|
97
|
+
const { result, unmount } = renderHook(() => useResolvedKnobs());
|
|
98
|
+
expect(result.current.knobProps.transition).toBeUndefined();
|
|
99
|
+
expect(addListener).toHaveBeenCalledWith(expect.any(Function));
|
|
100
|
+
unmount();
|
|
101
|
+
expect(removeListener).toHaveBeenCalledWith(expect.any(Function));
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe("semantic-intent Button label color (LC-05)", () => {
|
|
106
|
+
it("binds filled error Buttons to $color (the on-fill foreground)", () => {
|
|
107
|
+
// defaultIntents.error sets Button.fillStyle = "filled".
|
|
108
|
+
const { result } = renderHook(() => useResolvedKnobs({ intent: "error", component: "Button" }));
|
|
109
|
+
expect(result.current.knobProps.body.color).toBe("$color");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("pins outlined error Buttons to $color11 (readable on page surfaces)", () => {
|
|
113
|
+
const preset = makePreset({
|
|
114
|
+
intents: { error: { Button: { fillStyle: "outlined" } } },
|
|
115
|
+
});
|
|
116
|
+
const { result } = renderHook(
|
|
117
|
+
() => useResolvedKnobs({ intent: "error", component: "Button" }),
|
|
118
|
+
{ wrapper: presetWrapper(preset) },
|
|
119
|
+
);
|
|
120
|
+
expect(result.current.knobProps.body.color).toBe("$color11");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("leaves non-semantic intents without the label override", () => {
|
|
124
|
+
const { result } = renderHook(() =>
|
|
125
|
+
useResolvedKnobs({ intent: "accent", component: "Button" }),
|
|
126
|
+
);
|
|
127
|
+
const plain = renderHook(() => useResolvedKnobs());
|
|
128
|
+
expect(result.current.knobProps.body.color).toBe(plain.result.current.knobProps.body.color);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe("intent + component knob merging", () => {
|
|
133
|
+
it("applies intent-level string overrides and component-level objects", () => {
|
|
134
|
+
const preset = makePreset({
|
|
135
|
+
intents: {
|
|
136
|
+
error: {
|
|
137
|
+
borderRadius: "small",
|
|
138
|
+
Card: { elevation: "large" },
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
const withComponent = renderHook(
|
|
143
|
+
() => useResolvedKnobs({ intent: "error", component: "Card" }),
|
|
144
|
+
{ wrapper: presetWrapper(preset) },
|
|
145
|
+
);
|
|
146
|
+
const withoutComponent = renderHook(() => useResolvedKnobs({ intent: "error" }), {
|
|
147
|
+
wrapper: presetWrapper(preset),
|
|
148
|
+
});
|
|
149
|
+
// Component-scoped override only applies when the component matches.
|
|
150
|
+
expect(withComponent.result.current.knobProps.elevation).not.toBe(
|
|
151
|
+
withoutComponent.result.current.knobProps.elevation,
|
|
152
|
+
);
|
|
153
|
+
// Intent-level knob override applies to both.
|
|
154
|
+
expect(withComponent.result.current.knobProps.borderRadius).toEqual(
|
|
155
|
+
withoutComponent.result.current.knobProps.borderRadius,
|
|
156
|
+
);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("compact option steps sizing down regardless of the density knob", () => {
|
|
160
|
+
const comfortable = renderHook(() => useResolvedKnobs());
|
|
161
|
+
const compact = renderHook(() => useResolvedKnobs({ compact: true }));
|
|
162
|
+
// default medium comfort → small under compact stepping
|
|
163
|
+
expect(comfortable.result.current.knobProps.size).toBe("medium");
|
|
164
|
+
expect(compact.result.current.knobProps.size).toBe("small");
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constraint Audit System
|
|
3
|
+
*
|
|
4
|
+
* Audits the rendered DOM to verify all structural CSS values land on valid
|
|
5
|
+
* Tamagui token steps defined by the knob system. Off-scale values indicate
|
|
6
|
+
* styles that bypassed the constraint system.
|
|
7
|
+
*
|
|
8
|
+
* Token values are from @tamagui/themes v5 + resolveKnobs.ts mappings.
|
|
9
|
+
* Run this in-browser via Playwright's page.evaluate(runConstraintAudit).
|
|
10
|
+
*/
|
|
11
|
+
export interface PropertyAudit {
|
|
12
|
+
value: number;
|
|
13
|
+
unit: string;
|
|
14
|
+
knob: string;
|
|
15
|
+
offScale: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface TextPropertyAudit {
|
|
18
|
+
value: string;
|
|
19
|
+
knob: string;
|
|
20
|
+
offScale: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface ElementAudit {
|
|
23
|
+
/** Human-readable element descriptor */
|
|
24
|
+
label: string;
|
|
25
|
+
/** Tag name */
|
|
26
|
+
tag: string;
|
|
27
|
+
/** id attribute if present */
|
|
28
|
+
id: string;
|
|
29
|
+
/** Non-hash class names (for readability) */
|
|
30
|
+
classes: string[];
|
|
31
|
+
/** Audited properties (only populated when value is non-default/non-zero) */
|
|
32
|
+
borderRadius?: PropertyAudit;
|
|
33
|
+
borderWidth?: PropertyAudit;
|
|
34
|
+
gap?: PropertyAudit;
|
|
35
|
+
rowGap?: PropertyAudit;
|
|
36
|
+
columnGap?: PropertyAudit;
|
|
37
|
+
paddingTop?: PropertyAudit;
|
|
38
|
+
paddingRight?: PropertyAudit;
|
|
39
|
+
paddingBottom?: PropertyAudit;
|
|
40
|
+
paddingLeft?: PropertyAudit;
|
|
41
|
+
fontWeight?: PropertyAudit;
|
|
42
|
+
fontFamily?: TextPropertyAudit;
|
|
43
|
+
/** Inline color bypasses (hardcoded color/backgroundColor not from theme) */
|
|
44
|
+
inlineColor?: TextPropertyAudit;
|
|
45
|
+
/** Violations found on this element */
|
|
46
|
+
violations: string[];
|
|
47
|
+
}
|
|
48
|
+
export interface AuditSummary {
|
|
49
|
+
totalElements: number;
|
|
50
|
+
auditedElements: number;
|
|
51
|
+
totalViolations: number;
|
|
52
|
+
byProperty: {
|
|
53
|
+
borderRadius: number;
|
|
54
|
+
borderWidth: number;
|
|
55
|
+
gap: number;
|
|
56
|
+
padding: number;
|
|
57
|
+
fontWeight: number;
|
|
58
|
+
fontFamily: number;
|
|
59
|
+
inlineColor: number;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export interface AuditReport {
|
|
63
|
+
url: string;
|
|
64
|
+
timestamp: string;
|
|
65
|
+
preset: string;
|
|
66
|
+
scheme: string;
|
|
67
|
+
summary: AuditSummary;
|
|
68
|
+
violations: ElementAudit[];
|
|
69
|
+
/** All audited elements (including compliant ones) */
|
|
70
|
+
elements: ElementAudit[];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Runs the constraint audit in the browser.
|
|
74
|
+
*
|
|
75
|
+
* This function is completely self-contained — no imports or external refs.
|
|
76
|
+
* Pass it directly to Playwright's page.evaluate():
|
|
77
|
+
*
|
|
78
|
+
* const report = await page.evaluate(runConstraintAudit);
|
|
79
|
+
*
|
|
80
|
+
* Returns an AuditReport object describing all structural CSS violations.
|
|
81
|
+
*/
|
|
82
|
+
export declare function runConstraintAudit(): AuditReport;
|
|
83
|
+
//# sourceMappingURL=constraintAudit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraintAudit.d.ts","sourceRoot":"","sources":["../../src/audit/constraintAudit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,eAAe;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,6CAA6C;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,uCAAuC;IACvC,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE;QACV,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,sDAAsD;IACtD,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAkPD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,WAAW,CAgiBhD"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Diff Reporter
|
|
3
|
+
*
|
|
4
|
+
* Compares two AuditReport snapshots (pre/post change) and produces
|
|
5
|
+
* a human-readable delta in constraint terms.
|
|
6
|
+
*/
|
|
7
|
+
import type { AuditReport, PropertyAudit, TextPropertyAudit } from "./constraintAudit";
|
|
8
|
+
export interface PropertyDiff {
|
|
9
|
+
property: string;
|
|
10
|
+
before: PropertyAudit | TextPropertyAudit | undefined;
|
|
11
|
+
after: PropertyAudit | TextPropertyAudit | undefined;
|
|
12
|
+
changed: boolean;
|
|
13
|
+
becameViolation: boolean;
|
|
14
|
+
fixedViolation: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface ElementDiff {
|
|
17
|
+
label: string;
|
|
18
|
+
tag: string;
|
|
19
|
+
status: "added" | "removed" | "changed" | "unchanged";
|
|
20
|
+
propertyDiffs: PropertyDiff[];
|
|
21
|
+
newViolations: string[];
|
|
22
|
+
fixedViolations: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface AuditDiff {
|
|
25
|
+
baselineUrl: string;
|
|
26
|
+
currentUrl: string;
|
|
27
|
+
baselineTimestamp: string;
|
|
28
|
+
currentTimestamp: string;
|
|
29
|
+
baselinePreset: string;
|
|
30
|
+
currentPreset: string;
|
|
31
|
+
summary: {
|
|
32
|
+
elementsAdded: number;
|
|
33
|
+
elementsRemoved: number;
|
|
34
|
+
elementsChanged: number;
|
|
35
|
+
newViolations: number;
|
|
36
|
+
fixedViolations: number;
|
|
37
|
+
netViolationChange: number;
|
|
38
|
+
};
|
|
39
|
+
elementDiffs: ElementDiff[];
|
|
40
|
+
/** Human-readable report text */
|
|
41
|
+
report: string;
|
|
42
|
+
}
|
|
43
|
+
export declare function diffAuditReports(baseline: AuditReport, current: AuditReport): AuditDiff;
|
|
44
|
+
export declare function formatAuditReport(report: AuditReport): string;
|
|
45
|
+
//# sourceMappingURL=diffReport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diffReport.d.ts","sourceRoot":"","sources":["../../src/audit/diffReport.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,WAAW,EAEX,aAAa,EACb,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAI3B,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACtD,KAAK,EAAE,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;IACtD,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE;QACP,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,kBAAkB,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB;AAoCD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,GAAG,SAAS,CAmMvF;AAID,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAwD7D"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { AuditReport, AuditSummary, ElementAudit, PropertyAudit, TextPropertyAudit, } from "./constraintAudit";
|
|
2
|
+
export { runConstraintAudit } from "./constraintAudit";
|
|
3
|
+
export type { AuditDiff, ElementDiff, PropertyDiff } from "./diffReport";
|
|
4
|
+
export { diffAuditReports, formatAuditReport } from "./diffReport";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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"}
|
package/types/dates.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical timestamp/date registers (LC-12 TIMESTAMP-REGISTER, Axiom 9).
|
|
3
|
+
*
|
|
4
|
+
* One formatter owns every absolute date the catalog renders — Timeline
|
|
5
|
+
* timestamps, table date cells (FieldDisplay), DatePicker display values —
|
|
6
|
+
* so the same data class never speaks in multiple voices ("2026-07-01" vs
|
|
7
|
+
* "Aug 9, 3:30 PM" vs "11/01/2026").
|
|
8
|
+
*
|
|
9
|
+
* Content class picks the register (paired with the `timestampStyle` knob):
|
|
10
|
+
* - feeds/social → relative ("2h ago") via `formatRelativeTimestamp`
|
|
11
|
+
* - tables/system → compact absolute ("Jul 1" / "Aug 9, 3:30 PM"),
|
|
12
|
+
* current year elided (`year: "auto"`)
|
|
13
|
+
* - editing surfaces → compact absolute with the year always shown
|
|
14
|
+
* ("Jul 1, 2026") — pickers are precision contexts
|
|
15
|
+
* No default may emit verbose locale output with seconds.
|
|
16
|
+
*/
|
|
17
|
+
export type DateInput = Date | string | number | null | undefined;
|
|
18
|
+
export interface AbsoluteDateFormatOptions {
|
|
19
|
+
/**
|
|
20
|
+
* `"auto"` (default) elides the current year — the display register for
|
|
21
|
+
* tables, feeds, and system events. `"always"` keeps it — the editing
|
|
22
|
+
* register for picker display values.
|
|
23
|
+
*/
|
|
24
|
+
year?: "auto" | "always";
|
|
25
|
+
/** Include the time component ("Aug 9, 3:30 PM"). Default false. */
|
|
26
|
+
withTime?: boolean;
|
|
27
|
+
/** BCP-47 locale forwarded to Intl. Default: system locale. */
|
|
28
|
+
locale?: string;
|
|
29
|
+
/** Reference date for current-year elision (injectable for tests). */
|
|
30
|
+
now?: Date;
|
|
31
|
+
}
|
|
32
|
+
/** ISO date-only shape ("YYYY-MM-DD"). */
|
|
33
|
+
export declare const ISO_DATE_ONLY: RegExp;
|
|
34
|
+
/**
|
|
35
|
+
* Compact absolute date — the house register for every absolute date.
|
|
36
|
+
* "Jul 1" / "Jul 1, 2025" (year auto-elided when current), or with
|
|
37
|
+
* `withTime` "Aug 9, 3:30 PM". Empty input renders "" and an unparseable
|
|
38
|
+
* string passes through unchanged (honest passthrough — never invents).
|
|
39
|
+
*/
|
|
40
|
+
export declare function formatAbsoluteDate(value: DateInput, options?: AbsoluteDateFormatOptions): string;
|
|
41
|
+
/**
|
|
42
|
+
* Compact absolute date-time ("Aug 9, 3:30 PM"; year added when not
|
|
43
|
+
* current). The system-event register (LC-12) and the tooltip form for
|
|
44
|
+
* relative timestamps.
|
|
45
|
+
*/
|
|
46
|
+
export declare function formatAbsoluteDateTime(value: DateInput, options?: Omit<AbsoluteDateFormatOptions, "withTime">): string;
|
|
47
|
+
/**
|
|
48
|
+
* Relative timestamp ("just now", "5m ago", "2h ago", "10 days ago") — the
|
|
49
|
+
* feed/social register (LC-12), selected by `timestampStyle: "relative"`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function formatRelativeTimestamp(value: DateInput, now?: number): string;
|
|
52
|
+
//# sourceMappingURL=dates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../src/dates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAElE,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,0CAA0C;AAC1C,eAAO,MAAM,aAAa,QAAwB,CAAC;AAyBnD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,yBAA8B,GACtC,MAAM,CA0BR;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,IAAI,CAAC,yBAAyB,EAAE,UAAU,CAAM,GACxD,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,CAgB1F"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tree-shaken DEV guardrails (blueprint §5).
|
|
3
|
+
* No-ops when `NODE_ENV === "production"`.
|
|
4
|
+
*
|
|
5
|
+
* W12 owns `outline-none` + `positive-tabindex`. Other codes are catalogued
|
|
6
|
+
* here so consumers share one tree-shaken entry point.
|
|
7
|
+
*/
|
|
8
|
+
export type DevWarnCode = "placeholder-as-label" | "two-primaries" | "banned-error-word" | "bare-disabled" | "cancel-disabled" | "dialog-too-many-actions" | "select-too-few-options" | "positive-tabindex" | "tooltip-on-disabled" | "outline-none" | "multiple-h1";
|
|
9
|
+
export type DevWarnDetail = {
|
|
10
|
+
component?: string;
|
|
11
|
+
id?: string;
|
|
12
|
+
value?: unknown;
|
|
13
|
+
word?: string;
|
|
14
|
+
count?: number;
|
|
15
|
+
suggest?: string;
|
|
16
|
+
region?: string;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Emit a once-per-key console warning in non-production builds.
|
|
21
|
+
*/
|
|
22
|
+
export declare function devWarn(code: DevWarnCode, detail?: DevWarnDetail): void;
|
|
23
|
+
/** @internal test helper */
|
|
24
|
+
export declare function __resetDevWarnSeen(): void;
|
|
25
|
+
/** Alias kept for callers that imported the W12-era name. */
|
|
26
|
+
export declare const themeDevWarn: typeof devWarn;
|
|
27
|
+
export declare const __resetThemeDevWarnSeen: typeof __resetDevWarnSeen;
|
|
28
|
+
/**
|
|
29
|
+
* DG-FORM-02 / DG-FORM-11: placeholder must not be the only label.
|
|
30
|
+
*/
|
|
31
|
+
export declare function warnPlaceholderAsLabel(args: {
|
|
32
|
+
placeholder?: string | null;
|
|
33
|
+
label?: unknown;
|
|
34
|
+
ariaLabel?: string | null;
|
|
35
|
+
id?: string;
|
|
36
|
+
component?: string;
|
|
37
|
+
}): void;
|
|
38
|
+
/** DG-COPY-02 / DG-VAL-03 — banned words in error copy. */
|
|
39
|
+
export declare function warnBannedErrorWords(message: string | null | undefined, detail?: DevWarnDetail): void;
|
|
40
|
+
/** DG-ST-03 — bare `disabled` without reason / explain. */
|
|
41
|
+
export declare function warnBareDisabled(args: {
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
disabledReason?: string | null;
|
|
44
|
+
skip?: boolean;
|
|
45
|
+
component?: string;
|
|
46
|
+
id?: string;
|
|
47
|
+
}): void;
|
|
48
|
+
/**
|
|
49
|
+
* DG-ACT-05 — the cancel/dismiss action never renders disabled (while confirm
|
|
50
|
+
* may be). Enforcing callers strip the prop and report the attempt here.
|
|
51
|
+
*/
|
|
52
|
+
export declare function warnCancelDisabled(args: {
|
|
53
|
+
disabled?: boolean;
|
|
54
|
+
component?: string;
|
|
55
|
+
id?: string;
|
|
56
|
+
}): void;
|
|
57
|
+
/** DG-OVL-04 — dialog action rows cap at this many actions by default. */
|
|
58
|
+
export declare const DIALOG_MAX_ACTIONS = 2;
|
|
59
|
+
/**
|
|
60
|
+
* DG-OVL-04 — max 2 actions in a dialog by default. Warn-only (never a hard
|
|
61
|
+
* block); `allowManyActions` is the explicit eject acknowledging the extra
|
|
62
|
+
* actions.
|
|
63
|
+
*/
|
|
64
|
+
export declare function warnDialogTooManyActions(args: {
|
|
65
|
+
count: number;
|
|
66
|
+
allowManyActions?: boolean;
|
|
67
|
+
component?: string;
|
|
68
|
+
id?: string;
|
|
69
|
+
}): void;
|
|
70
|
+
/**
|
|
71
|
+
* DG-CTRL — Select with too few options; suggest RadioGroup / ToggleGroup.
|
|
72
|
+
*/
|
|
73
|
+
export declare function warnSelectTooFewOptions(args: {
|
|
74
|
+
count: number;
|
|
75
|
+
multiple?: boolean;
|
|
76
|
+
component?: string;
|
|
77
|
+
id?: string;
|
|
78
|
+
}): void;
|
|
79
|
+
/** DG-A11Y-03 — never `tabIndex` > 0. */
|
|
80
|
+
export declare function warnPositiveTabIndex(args: {
|
|
81
|
+
value?: number | string | null;
|
|
82
|
+
component?: string;
|
|
83
|
+
id?: string;
|
|
84
|
+
}): void;
|
|
85
|
+
/** DG-OVL-05 — no hover tooltip on disabled controls. */
|
|
86
|
+
export declare function warnTooltipOnDisabled(args: {
|
|
87
|
+
childDisabled?: boolean;
|
|
88
|
+
component?: string;
|
|
89
|
+
id?: string;
|
|
90
|
+
}): void;
|
|
91
|
+
type OutlineLike = {
|
|
92
|
+
outline?: string | number;
|
|
93
|
+
outlineStyle?: string;
|
|
94
|
+
outlineWidth?: number;
|
|
95
|
+
outlineColor?: string;
|
|
96
|
+
} | null | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* DG-A11Y-01 / W12 — warn when a focus style strips the outline.
|
|
99
|
+
* Call on `focusVisibleStyle` / `focusStyle` only — not resting
|
|
100
|
+
* `outlineWidth: 0` + transparent (border-flicker rest).
|
|
101
|
+
*/
|
|
102
|
+
export declare function warnOutlineNone(style: OutlineLike, detail?: DevWarnDetail): void;
|
|
103
|
+
export {};
|
|
104
|
+
//# sourceMappingURL=devWarn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devWarn.d.ts","sourceRoot":"","sources":["../src/devWarn.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Figma token export transform — the code→Figma projection for
|
|
3
|
+
* `agent-os/specs/2026-05-08-figma-v2-token-migration`.
|
|
4
|
+
*
|
|
5
|
+
* Everything here is DERIVED from the canonical theme sources at call time
|
|
6
|
+
* (no hand-copied values):
|
|
7
|
+
*
|
|
8
|
+
* - Palette ramps + shadows: `createThemesBuilder(defaultBaseTheme,
|
|
9
|
+
* defaultAccentTheme, defaultBuilderOptions).themes()` — the exact themes
|
|
10
|
+
* apps run, including tint text neutralization and computed tokens like
|
|
11
|
+
* `outlineColor`.
|
|
12
|
+
* - Semantic aliases: reverse-matched per scheme against the ramp steps of
|
|
13
|
+
* the built base themes (a key only becomes a `colorN` alias when light
|
|
14
|
+
* AND dark agree on the step index; otherwise raw per-scheme values are
|
|
15
|
+
* exported).
|
|
16
|
+
* - Sizing: `tokens` from `@tamagui/themes` (the tokens
|
|
17
|
+
* `createDefaultThemeConfig` installs).
|
|
18
|
+
* - Knob outputs: `resolveKnobs()` is executed per knob mode — the export
|
|
19
|
+
* shows exactly what the runtime resolver produces.
|
|
20
|
+
* - Typography: the built `defaultHeadingFont` / `defaultBodyFont` tables
|
|
21
|
+
* (size / lineHeight / letterSpacing / weight).
|
|
22
|
+
*
|
|
23
|
+
* The transform is pure and deterministic (no Date, no I/O) so it can be
|
|
24
|
+
* golden-tested; the runner script (`scripts/export-figma-tokens.mts`)
|
|
25
|
+
* stamps `generatedAt` when writing to disk.
|
|
26
|
+
*/
|
|
27
|
+
import { type Knobs } from "../theme/knobs";
|
|
28
|
+
/**
|
|
29
|
+
* Theme modes of the `Palette/Theme` Figma collection (spec.md §Variable
|
|
30
|
+
* Collection Structure): semantic intents take the red/yellow/green slots;
|
|
31
|
+
* the remaining stock tints are manual designer picks. 9 modes — inside
|
|
32
|
+
* Figma Pro's 10-modes-per-collection cap with 1 slot of headroom.
|
|
33
|
+
*/
|
|
34
|
+
export declare const FIGMA_THEME_MODES: readonly ["base", "accent", "error", "success", "warning", "orange", "blue", "purple", "pink"];
|
|
35
|
+
export type FigmaThemeMode = (typeof FIGMA_THEME_MODES)[number];
|
|
36
|
+
/**
|
|
37
|
+
* Figma's per-node corner-smoothing dial value per `cornerSmoothing` knob.
|
|
38
|
+
* `smooth` = 0.6 ≈ `corner-shape: squircle` ≡ superellipse(2) ≈ Apple's
|
|
39
|
+
* continuous corners (see cornerSmoothing.ts). This is a Figma rendering
|
|
40
|
+
* constant, not a Variable — Figma cannot bind cornerSmoothing to Variables.
|
|
41
|
+
*/
|
|
42
|
+
export declare const FIGMA_CORNER_SMOOTHING: Record<string, number>;
|
|
43
|
+
/** Tamagui token key (`1.5`, `true`) → Figma-safe variable name segment. */
|
|
44
|
+
export declare function figmaTokenName(prefix: string, key: string): string;
|
|
45
|
+
export interface FigmaPaletteTheme {
|
|
46
|
+
light: string[];
|
|
47
|
+
dark: string[];
|
|
48
|
+
}
|
|
49
|
+
export interface FigmaShadows {
|
|
50
|
+
light: Record<string, string>;
|
|
51
|
+
dark: Record<string, string>;
|
|
52
|
+
}
|
|
53
|
+
export type FigmaSemanticEntry = {
|
|
54
|
+
alias: string;
|
|
55
|
+
light: string;
|
|
56
|
+
dark: string;
|
|
57
|
+
} | {
|
|
58
|
+
alias: null;
|
|
59
|
+
light: string;
|
|
60
|
+
dark: string;
|
|
61
|
+
};
|
|
62
|
+
export interface FigmaRadiusMode {
|
|
63
|
+
/** Tamagui radius token resolveKnobs emits for this knob mode (e.g. `$4`). */
|
|
64
|
+
token: string;
|
|
65
|
+
/** `Sizing` collection variable to alias (e.g. `radius-4`). */
|
|
66
|
+
figmaName: string;
|
|
67
|
+
px: number;
|
|
68
|
+
/** Outer/nested radius fragment (`knobProps.borderRadiusOuter`). */
|
|
69
|
+
outerToken: string;
|
|
70
|
+
outerFigmaName: string;
|
|
71
|
+
outerPx: number;
|
|
72
|
+
}
|
|
73
|
+
export interface FigmaElevationMode {
|
|
74
|
+
/** Tamagui size token backing the elevation shadow scale (null = none). */
|
|
75
|
+
sizeToken: string | null;
|
|
76
|
+
px: number | null;
|
|
77
|
+
}
|
|
78
|
+
export interface FigmaSpaceMode {
|
|
79
|
+
paddingToken: string;
|
|
80
|
+
paddingFigmaName: string;
|
|
81
|
+
gapToken: string;
|
|
82
|
+
gapFigmaName: string;
|
|
83
|
+
gapLgToken: string;
|
|
84
|
+
gapLgFigmaName: string;
|
|
85
|
+
}
|
|
86
|
+
export interface FigmaKnobsExport {
|
|
87
|
+
borderRadius: {
|
|
88
|
+
default: Knobs["borderRadius"];
|
|
89
|
+
modes: Record<string, FigmaRadiusMode>;
|
|
90
|
+
};
|
|
91
|
+
borderWidth: {
|
|
92
|
+
default: Knobs["borderWidth"];
|
|
93
|
+
modes: Record<string, number>;
|
|
94
|
+
};
|
|
95
|
+
elevation: {
|
|
96
|
+
default: Knobs["elevation"];
|
|
97
|
+
modes: Record<string, FigmaElevationMode>;
|
|
98
|
+
};
|
|
99
|
+
fontWeight: {
|
|
100
|
+
default: Knobs["fontWeight"];
|
|
101
|
+
modes: Record<string, string>;
|
|
102
|
+
};
|
|
103
|
+
space: {
|
|
104
|
+
default: Knobs["space"];
|
|
105
|
+
modes: Record<string, FigmaSpaceMode>;
|
|
106
|
+
};
|
|
107
|
+
size: {
|
|
108
|
+
default: Knobs["size"];
|
|
109
|
+
modes: Record<string, {
|
|
110
|
+
token: string;
|
|
111
|
+
figmaName: string;
|
|
112
|
+
}>;
|
|
113
|
+
};
|
|
114
|
+
cornerSmoothing: {
|
|
115
|
+
default: string;
|
|
116
|
+
modes: Record<string, number>;
|
|
117
|
+
};
|
|
118
|
+
density: {
|
|
119
|
+
default: Knobs["density"];
|
|
120
|
+
/** compact steps size/space down one level (applyDensity). */
|
|
121
|
+
compact: {
|
|
122
|
+
size: Record<string, string>;
|
|
123
|
+
space: Record<string, string>;
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export interface FigmaFontExport {
|
|
128
|
+
family: string;
|
|
129
|
+
size: Record<string, number>;
|
|
130
|
+
lineHeight: Record<string, number>;
|
|
131
|
+
letterSpacing: Record<string, number>;
|
|
132
|
+
weight: Record<string, string>;
|
|
133
|
+
}
|
|
134
|
+
export interface FigmaTypographyExport {
|
|
135
|
+
heading: FigmaFontExport;
|
|
136
|
+
body: FigmaFontExport;
|
|
137
|
+
/**
|
|
138
|
+
* Category font stacks (the `headingFont`/`bodyFont` knob targets), as
|
|
139
|
+
* supplied by the app config (`packages/config/fonts.ts` in this repo).
|
|
140
|
+
* `figmaFamily` is the first family of the stack — Figma cannot resolve
|
|
141
|
+
* CSS fallback chains.
|
|
142
|
+
*/
|
|
143
|
+
categories: Record<string, {
|
|
144
|
+
stack: string;
|
|
145
|
+
figmaFamily: string;
|
|
146
|
+
}>;
|
|
147
|
+
}
|
|
148
|
+
export interface FigmaTokensExport {
|
|
149
|
+
$meta: {
|
|
150
|
+
generator: string;
|
|
151
|
+
spec: string;
|
|
152
|
+
note: string;
|
|
153
|
+
};
|
|
154
|
+
palette: {
|
|
155
|
+
themes: Record<string, FigmaPaletteTheme>;
|
|
156
|
+
shadows: FigmaShadows;
|
|
157
|
+
};
|
|
158
|
+
semantic: Record<string, FigmaSemanticEntry>;
|
|
159
|
+
sizing: Record<string, number>;
|
|
160
|
+
knobs: FigmaKnobsExport;
|
|
161
|
+
typography: FigmaTypographyExport;
|
|
162
|
+
}
|
|
163
|
+
export interface BuildFigmaTokensOptions {
|
|
164
|
+
/** Category font stacks to export (e.g. `fontFamilies` from app config). */
|
|
165
|
+
fontFamilies?: Record<string, string>;
|
|
166
|
+
}
|
|
167
|
+
export declare function buildFigmaTokens(options?: BuildFigmaTokensOptions): FigmaTokensExport;
|
|
168
|
+
//# sourceMappingURL=figmaTokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figmaTokens.d.ts","sourceRoot":"","sources":["../../src/figma/figmaTokens.ts"],"names":[],"mappings":"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"}
|
package/types/font.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font.d.ts","sourceRoot":"","sources":["../src/font.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAiChD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW,EACrD,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG;IAAE,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAA;CAAE,GACzC,CAAC,CAWH"}
|