@multiplatform.one/theme 7.6.3 → 7.7.1
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 +5 -6
- package/src/theme/colorRules.spec.ts +2 -1
- package/src/theme/createDefaultThemeConfig.ts +7 -1
- package/src/theme/focusState.spec.ts +99 -0
- package/src/theme/focusState.ts +55 -0
- package/src/theme/index.ts +1 -0
- package/src/theme/readableColor.spec.ts +54 -1
- package/src/theme/readableColor.ts +105 -0
- package/src/theme/recipeInputs.ts +27 -0
- package/src/theme/sizeLadder.spec.ts +20 -0
- package/src/theme/sizeRecipes.ts +2 -0
- package/src/theme/themeValue.spec.ts +98 -0
- package/src/theme/themeValue.ts +108 -0
- package/types/theme/createDefaultThemeConfig.d.ts.map +1 -1
- package/types/theme/focusState.d.ts +48 -0
- package/types/theme/focusState.d.ts.map +1 -1
- package/types/theme/index.d.ts +1 -0
- package/types/theme/index.d.ts.map +1 -1
- package/types/theme/readableColor.d.ts +39 -0
- package/types/theme/readableColor.d.ts.map +1 -1
- package/types/theme/recipeInputs.d.ts +19 -0
- package/types/theme/recipeInputs.d.ts.map +1 -1
- package/types/theme/sizeRecipes.d.ts +1 -1
- package/types/theme/sizeRecipes.d.ts.map +1 -1
- package/types/theme/themeValue.d.ts +30 -0
- package/types/theme/themeValue.d.ts.map +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplatform.one/theme",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.7.1",
|
|
4
4
|
"description": "Tamagui theme system for multiplatform.one",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"multiplatform",
|
|
@@ -53,15 +53,14 @@
|
|
|
53
53
|
"@tamagui/toast": "2.7.6",
|
|
54
54
|
"@tamagui/web": "2.7.6",
|
|
55
55
|
"react-cookie": "^8.1.2",
|
|
56
|
-
"@multiplatform.one/platform": "7.
|
|
57
|
-
"@multiplatform.one/store": "7.
|
|
56
|
+
"@multiplatform.one/platform": "7.7.1",
|
|
57
|
+
"@multiplatform.one/store": "7.7.1"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@tamagui/animations-css": "2.7.6",
|
|
61
61
|
"@tamagui/animations-reanimated": "2.7.6",
|
|
62
62
|
"@tamagui/font-inter": "2.7.6",
|
|
63
63
|
"@testing-library/react": "^16.3.2",
|
|
64
|
-
"@types/react": "~19.2.14",
|
|
65
64
|
"@vitejs/plugin-react": "^6.0.1",
|
|
66
65
|
"@vitest/coverage-v8": "^4.1.5",
|
|
67
66
|
"react": "19.2.5",
|
|
@@ -69,8 +68,8 @@
|
|
|
69
68
|
"tamagui": "2.7.6",
|
|
70
69
|
"typescript": "~5.9.3",
|
|
71
70
|
"vitest": "^4.1.5",
|
|
72
|
-
"@multiplatform.one/config": "7.
|
|
73
|
-
"@multiplatform.one/test-utils": "7.
|
|
71
|
+
"@multiplatform.one/config": "7.7.1",
|
|
72
|
+
"@multiplatform.one/test-utils": "7.7.1"
|
|
74
73
|
},
|
|
75
74
|
"peerDependencies": {
|
|
76
75
|
"@tamagui/animations-css": "^2.0.0-rc",
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
resolveThemeContrast,
|
|
13
13
|
$color,
|
|
14
14
|
semanticGroups,
|
|
15
|
+
type ContrastPair,
|
|
15
16
|
} from "./colorRules";
|
|
16
17
|
import { createThemesBuilder } from "./createThemes";
|
|
17
18
|
import { defaultAccentTheme } from "./defaults/accent";
|
|
@@ -339,7 +340,7 @@ describe("contrast floor on built themes (DG-A11Y-01 / DG-COL-01)", () => {
|
|
|
339
340
|
).themes() as Record<string, Record<string, string>>;
|
|
340
341
|
|
|
341
342
|
it("base text tiers clear AA on page surfaces in both schemes", () => {
|
|
342
|
-
const pairs = [];
|
|
343
|
+
const pairs: ContrastPair[] = [];
|
|
343
344
|
for (const scheme of ["light", "dark"] as const) {
|
|
344
345
|
for (const foreground of ["color", "color11", "color12"]) {
|
|
345
346
|
for (const background of ["background", "color1", "color2"]) {
|
|
@@ -16,6 +16,7 @@ import { defaultFonts } from "./defaults/fonts";
|
|
|
16
16
|
import type { Preset } from "./preset.types";
|
|
17
17
|
import { type SizeRecipeInputs } from "./recipeInputs";
|
|
18
18
|
import { type ThemeConfig, createThemeConfig } from "./shared";
|
|
19
|
+
import { assertResolvableThemeValues } from "./themeValue";
|
|
19
20
|
import { getGeneratedSizeRecipes, getSizeRecipeInputs, setSizeRecipeInputs } from "./sizeRecipes";
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -87,7 +88,12 @@ function composeGetTheme(
|
|
|
87
88
|
if (!custom) return base;
|
|
88
89
|
return (props: GetThemeProps) => {
|
|
89
90
|
const merged: Record<string, string | number> = { ...base(props) };
|
|
90
|
-
|
|
91
|
+
const consumer = custom(props);
|
|
92
|
+
// MPO-23 / 10 B.3 item 3. Dropping nullish is not enough: a misspelled
|
|
93
|
+
// colour is not nullish, survives the merge, and resolves to nothing at
|
|
94
|
+
// paint. Fail here, while there is a stack that names the getTheme.
|
|
95
|
+
assertResolvableThemeValues(consumer, props.name);
|
|
96
|
+
for (const [key, value] of Object.entries(consumer)) {
|
|
91
97
|
if (value != null) merged[key] = value;
|
|
92
98
|
}
|
|
93
99
|
return merged;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
4
|
import { __resetDevWarnSeen, warnOutlineNone, warnPositiveTabIndex } from "../devWarn";
|
|
3
5
|
import { compositeFocusRingCss, keyboardFocusRingProps } from "../keyboardFocusRing";
|
|
@@ -9,10 +11,15 @@ import { defaultBuilderOptions } from "./defaults/builderOptions";
|
|
|
9
11
|
import {
|
|
10
12
|
ensureFocusVisibleRing,
|
|
11
13
|
focusRingColorMeetsContrast,
|
|
14
|
+
FOCUS_RING_CLIPPED_OFFSET,
|
|
15
|
+
FOCUS_RING_HALO_OFFSET,
|
|
12
16
|
FOCUS_RING_MIN_CONTRAST,
|
|
13
17
|
FOCUS_RING_MIN_WIDTH,
|
|
14
18
|
FOCUS_VISIBLE_RING,
|
|
19
|
+
FOCUS_VISIBLE_RING_HALO,
|
|
15
20
|
FOCUS_VISIBLE_RING_INSET,
|
|
21
|
+
isSanctionedFocusRingOffset,
|
|
22
|
+
SANCTIONED_FOCUS_RING_OFFSETS,
|
|
16
23
|
STATE_LAYER_HOVER,
|
|
17
24
|
STATE_LAYER_PRESS,
|
|
18
25
|
withDefaultStateLayer,
|
|
@@ -290,3 +297,95 @@ describe("theme DEV warn (outline-none / positive-tabindex)", () => {
|
|
|
290
297
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
291
298
|
});
|
|
292
299
|
});
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* MPO-92 AC-3 — the offset set is CLOSED, and a tenth site cannot open it.
|
|
303
|
+
*
|
|
304
|
+
* Two layers. The unit layer pins the three sanctioned numbers and the halo's
|
|
305
|
+
* geometry. The source layer is the one that actually bites: it walks every
|
|
306
|
+
* package's `src` and fails on any `outlineOffset` literal outside the set, so
|
|
307
|
+
* a new call site that invents `outlineOffset: 3` fails here rather than
|
|
308
|
+
* shipping and being found in a later audit.
|
|
309
|
+
*/
|
|
310
|
+
describe("LC-71 §4: the sanctioned focus-ring offset set is closed (MPO-92)", () => {
|
|
311
|
+
it("is exactly three offsets — clipping inset, default, shape halo", () => {
|
|
312
|
+
expect([...SANCTIONED_FOCUS_RING_OFFSETS]).toEqual([-2, 0, 2]);
|
|
313
|
+
expect(FOCUS_RING_CLIPPED_OFFSET).toBe(-2);
|
|
314
|
+
expect(FOCUS_VISIBLE_RING.outlineOffset).toBe(0);
|
|
315
|
+
expect(FOCUS_RING_HALO_OFFSET).toBe(2);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it("isSanctionedFocusRingOffset accepts the three and rejects everything else", () => {
|
|
319
|
+
for (const offset of SANCTIONED_FOCUS_RING_OFFSETS) {
|
|
320
|
+
expect(isSanctionedFocusRingOffset(offset)).toBe(true);
|
|
321
|
+
}
|
|
322
|
+
for (const offset of [-4, -3, -1, 1, 3, 4, 8]) {
|
|
323
|
+
expect(isSanctionedFocusRingOffset(offset)).toBe(false);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it("FOCUS_VISIBLE_RING_HALO is the same ring, pushed wholly outside the border box", () => {
|
|
328
|
+
expect(FOCUS_VISIBLE_RING_HALO).toMatchObject({
|
|
329
|
+
outlineWidth: FOCUS_RING_MIN_WIDTH,
|
|
330
|
+
outlineStyle: "solid",
|
|
331
|
+
outlineColor: "$outlineColor",
|
|
332
|
+
outlineOffset: FOCUS_RING_HALO_OFFSET,
|
|
333
|
+
});
|
|
334
|
+
// The band spans [outlineOffset, outlineOffset + outlineWidth] from the
|
|
335
|
+
// border edge — here [2, 4]. Inner edge ≥ 0 means it paints entirely on the
|
|
336
|
+
// surface BEHIND the control, exactly like the default offset 0, so it
|
|
337
|
+
// measures against the page ground and cannot reproduce the 1.17–1.31:1
|
|
338
|
+
// inside-the-fill failure MPO-41 retired.
|
|
339
|
+
expect(FOCUS_VISIBLE_RING_HALO.outlineOffset).toBeGreaterThanOrEqual(0);
|
|
340
|
+
expect(ensureFocusVisibleRing({ outlineOffset: FOCUS_RING_HALO_OFFSET }).outlineOffset).toBe(2);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it("no source file paints an outlineOffset outside the sanctioned set", () => {
|
|
344
|
+
// Scoped to the JS/TS object form (`outlineOffset:`), numeric or "Npx"
|
|
345
|
+
// string — that is the form every focus ring in the repo goes through, via
|
|
346
|
+
// FOCUS_VISIBLE_RING* / ensureFocusVisibleRing / keyboardFocusRingProps.
|
|
347
|
+
// Raw `outline-offset:` inside CSS template strings is deliberately out of
|
|
348
|
+
// scope: it also carries non-focus decoration (the forced-colors skeleton
|
|
349
|
+
// hairline at -1px), so folding it in would assert a rule §4 does not make.
|
|
350
|
+
const packagesDir = path.resolve(__dirname, "../../..");
|
|
351
|
+
const skipDirs = new Set(["node_modules", "dist", "build", ".turbo", "types", "__snapshots__"]);
|
|
352
|
+
const files: string[] = [];
|
|
353
|
+
const walk = (dir: string) => {
|
|
354
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
355
|
+
if (entry.isDirectory()) {
|
|
356
|
+
if (skipDirs.has(entry.name)) continue;
|
|
357
|
+
walk(path.join(dir, entry.name));
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const name = entry.name;
|
|
361
|
+
if (!/\.tsx?$/.test(name)) continue;
|
|
362
|
+
if (/\.(spec|test|stories)\./.test(name)) continue;
|
|
363
|
+
if (name.endsWith(".d.ts")) continue;
|
|
364
|
+
files.push(path.join(dir, name));
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
walk(packagesDir);
|
|
368
|
+
expect(files.length).toBeGreaterThan(200);
|
|
369
|
+
|
|
370
|
+
const violations: string[] = [];
|
|
371
|
+
const literal = /outlineOffset\s*:\s*(?:"(-?\d+)px"|'(-?\d+)px'|(-?\d+))\b/;
|
|
372
|
+
for (const file of files) {
|
|
373
|
+
const lines = fs.readFileSync(file, "utf-8").split("\n");
|
|
374
|
+
lines.forEach((line, index) => {
|
|
375
|
+
const trimmed = line.trim();
|
|
376
|
+
if (trimmed.startsWith("//") || trimmed.startsWith("*")) return;
|
|
377
|
+
const match = literal.exec(line);
|
|
378
|
+
if (!match) return;
|
|
379
|
+
const value = Number.parseInt(match[1] ?? match[2] ?? match[3], 10);
|
|
380
|
+
if (isSanctionedFocusRingOffset(value)) return;
|
|
381
|
+
violations.push(
|
|
382
|
+
`${path.relative(packagesDir, file)}:${index + 1} paints outlineOffset ${value}`,
|
|
383
|
+
);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
expect(
|
|
387
|
+
violations,
|
|
388
|
+
`unsanctioned focus-ring offsets (LC-71 §4 closes the set at -2/0/2):\n${violations.join("\n")}`,
|
|
389
|
+
).toEqual([]);
|
|
390
|
+
});
|
|
391
|
+
});
|
package/src/theme/focusState.ts
CHANGED
|
@@ -59,6 +59,13 @@ export function focusRingColorMeetsContrast(ringColor: string, surfaceColor: str
|
|
|
59
59
|
* The inset did not die — it moved to `FOCUS_VISIBLE_RING_INSET`, an
|
|
60
60
|
* explicit per-call-site carve-out for clipping ancestors. MPO-19 X7 names
|
|
61
61
|
* the same offset `FOCUS_RING_CLIPPED_OFFSET` so call sites do not type `-2`.
|
|
62
|
+
*
|
|
63
|
+
* MPO-92 ratified a second, shape-scoped carve-out on the other side:
|
|
64
|
+
* `FOCUS_VISIBLE_RING_HALO` (+2) for pill/circular thumbs and inline text
|
|
65
|
+
* links. The F1 "not +2" reading was about the DEFAULT — a blanket +2 on
|
|
66
|
+
* every control — and it stands. The halo is a named carve-out with a written
|
|
67
|
+
* shape scope, exactly as the inset is; `SANCTIONED_FOCUS_RING_OFFSETS` below
|
|
68
|
+
* is the closed set of all three.
|
|
62
69
|
*/
|
|
63
70
|
export const FOCUS_RING_CLIPPED_OFFSET = -2;
|
|
64
71
|
export const FOCUS_VISIBLE_RING = {
|
|
@@ -86,6 +93,54 @@ export const FOCUS_VISIBLE_RING_INSET = {
|
|
|
86
93
|
outlineOffset: FOCUS_RING_CLIPPED_OFFSET,
|
|
87
94
|
} satisfies ControlStateProps;
|
|
88
95
|
|
|
96
|
+
/**
|
|
97
|
+
* The LC-71 §4 halo carve-out (MPO-92, ratified 2026-09-02): the SAME ring,
|
|
98
|
+
* pushed 2px clear of the border box, for the two shapes where a band hugging
|
|
99
|
+
* the edge reads as part of the glyph instead of around it.
|
|
100
|
+
*
|
|
101
|
+
* Scope is by SHAPE, not by instance, and it is closed at two:
|
|
102
|
+
* - **pill / circular thumbs** — a round handle the user drags (Slider
|
|
103
|
+
* thumb, Rating star, TimeRangeScrubber handle). At offset 0 the band is
|
|
104
|
+
* concentric with the glyph's own edge and reads as a thicker glyph.
|
|
105
|
+
* - **inline text links** — a link inside a run of prose (markdown/mdx
|
|
106
|
+
* `Link`, ErrorSummary's summary link, backoffice "View All"). At offset 0
|
|
107
|
+
* the band crosses the line box and collides with ascenders/descenders of
|
|
108
|
+
* the surrounding text.
|
|
109
|
+
*
|
|
110
|
+
* NOT for standalone rectangles on the page ground — cards, tiles, rows,
|
|
111
|
+
* fields. Those are the default `FOCUS_VISIBLE_RING` (offset 0), which is
|
|
112
|
+
* what makes the Axiom 12 ≥3:1 floor computable against the page ground.
|
|
113
|
+
*
|
|
114
|
+
* Contrast is unaffected: like offset 0 the halo paints OUTSIDE the border
|
|
115
|
+
* box, on the surface behind the control, so it measures against the same
|
|
116
|
+
* page ground the default does — the 1.17–1.31:1 failures MPO-41 retired were
|
|
117
|
+
* the INSET painting inside solid intent fills, a defect the halo cannot have.
|
|
118
|
+
*/
|
|
119
|
+
export const FOCUS_RING_HALO_OFFSET = 2;
|
|
120
|
+
export const FOCUS_VISIBLE_RING_HALO = {
|
|
121
|
+
...FOCUS_VISIBLE_RING,
|
|
122
|
+
outlineOffset: FOCUS_RING_HALO_OFFSET,
|
|
123
|
+
} satisfies ControlStateProps;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The CLOSED set of sanctioned focus-ring offsets (LC-71 §4). Three, and only
|
|
127
|
+
* three: the default 0, the clipping inset −2, the shape halo +2. A call site
|
|
128
|
+
* that wants any other number is a rule gap, not a preference — file it and
|
|
129
|
+
* amend §4, do not type the number. `focusState.spec.ts` asserts this set is
|
|
130
|
+
* exactly what the repo paints, so a fourth offset fails a test instead of
|
|
131
|
+
* shipping (MPO-92 AC-3).
|
|
132
|
+
*/
|
|
133
|
+
export const SANCTIONED_FOCUS_RING_OFFSETS = [
|
|
134
|
+
FOCUS_RING_CLIPPED_OFFSET,
|
|
135
|
+
FOCUS_VISIBLE_RING.outlineOffset,
|
|
136
|
+
FOCUS_RING_HALO_OFFSET,
|
|
137
|
+
] as const;
|
|
138
|
+
|
|
139
|
+
/** True when `offset` is one of the three offsets LC-71 §4 sanctions. */
|
|
140
|
+
export function isSanctionedFocusRingOffset(offset: number): boolean {
|
|
141
|
+
return (SANCTIONED_FOCUS_RING_OFFSETS as readonly number[]).includes(offset);
|
|
142
|
+
}
|
|
143
|
+
|
|
89
144
|
/**
|
|
90
145
|
* DG-STATE-01 — Material-style state layers as theme tokens.
|
|
91
146
|
* Ramp lives in `defaults/builderOptions` (hover/press background steps);
|
package/src/theme/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { resolveAccentTintedSurface } from "./readableColor";
|
|
2
|
+
import { resolveAaSolidFill, resolveAccentTintedSurface } from "./readableColor";
|
|
3
3
|
import { contrastRatio, normalizeToHex, relativeLuminance } from "./colorRules";
|
|
4
4
|
|
|
5
5
|
// The stock accent ramp (defaults/accent.ts) as the theme resolves it.
|
|
@@ -113,3 +113,56 @@ describe("resolveAccentTintedSurface", () => {
|
|
|
113
113
|
).toBeUndefined();
|
|
114
114
|
});
|
|
115
115
|
});
|
|
116
|
+
|
|
117
|
+
describe("resolveAaSolidFill", () => {
|
|
118
|
+
it("keeps the preferred solid when it already clears the text floor", () => {
|
|
119
|
+
const solids = lightAccent.slice(0, 10).map((value, i) => ({
|
|
120
|
+
token: `$accent${i + 1}`,
|
|
121
|
+
value,
|
|
122
|
+
}));
|
|
123
|
+
// Stock light accentBackground is the mid solid (step 3, 6.09:1 on paper).
|
|
124
|
+
expect(
|
|
125
|
+
resolveAaSolidFill({
|
|
126
|
+
preferred: { token: "$accentBackground", value: lightAccent[2] },
|
|
127
|
+
solids,
|
|
128
|
+
paper: lightPaper,
|
|
129
|
+
ink: lightInk,
|
|
130
|
+
}),
|
|
131
|
+
).toBe("$accentBackground");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("walks off the dark mid-solid that tops out at 4.02:1", () => {
|
|
135
|
+
const solids = darkAccent.slice(0, 10).map((value, i) => ({
|
|
136
|
+
token: `$accent${i + 1}`,
|
|
137
|
+
value,
|
|
138
|
+
}));
|
|
139
|
+
const token = resolveAaSolidFill({
|
|
140
|
+
preferred: { token: "$accentBackground", value: darkAccent[9] },
|
|
141
|
+
solids,
|
|
142
|
+
paper: darkPaper,
|
|
143
|
+
ink: darkInk,
|
|
144
|
+
});
|
|
145
|
+
expect(token).not.toBe("$accentBackground");
|
|
146
|
+
const picked = solids.find((s) => s.token === token);
|
|
147
|
+
expect(picked?.value).toBeTruthy();
|
|
148
|
+
const fillLum = lum(picked!.value!);
|
|
149
|
+
const best = Math.max(
|
|
150
|
+
contrastRatio(fillLum, lum(darkPaper)),
|
|
151
|
+
contrastRatio(fillLum, lum(darkInk)),
|
|
152
|
+
);
|
|
153
|
+
expect(best).toBeGreaterThanOrEqual(4.5);
|
|
154
|
+
// Nearest passing solid to the 60% mid is accent9 (57%, 4.60:1).
|
|
155
|
+
expect(token).toBe("$accent9");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("returns the preferred token when anchors cannot be parsed", () => {
|
|
159
|
+
expect(
|
|
160
|
+
resolveAaSolidFill({
|
|
161
|
+
preferred: { token: "$accentBackground", value: darkAccent[9] },
|
|
162
|
+
solids: [],
|
|
163
|
+
paper: undefined,
|
|
164
|
+
ink: darkInk,
|
|
165
|
+
}),
|
|
166
|
+
).toBe("$accentBackground");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
@@ -161,3 +161,108 @@ export function useAccentTintedSurface(): string | undefined {
|
|
|
161
161
|
[paper, ink, steps.join("|")],
|
|
162
162
|
);
|
|
163
163
|
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* A named solid in the accent ramp. `token` is what a caller paints
|
|
167
|
+
* (`$accentBackground`, `$accent9`); `value` is the resolved color.
|
|
168
|
+
*/
|
|
169
|
+
export interface AaSolidCandidate {
|
|
170
|
+
token: string;
|
|
171
|
+
value: string | undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface ResolveAaSolidFillInput {
|
|
175
|
+
/** The LC-05 selected solid, usually `$accentBackground`. */
|
|
176
|
+
preferred: AaSolidCandidate;
|
|
177
|
+
/**
|
|
178
|
+
* Accent solids (steps 1–10). Pale anchors 11–12 are tinted surfaces, not
|
|
179
|
+
* selection solids — they would pass AA as chips and fail LC-05 as marks.
|
|
180
|
+
*/
|
|
181
|
+
solids: AaSolidCandidate[];
|
|
182
|
+
paper?: string;
|
|
183
|
+
ink?: string;
|
|
184
|
+
/** Defaults to {@link aaTextContrastRatio} (4.5). */
|
|
185
|
+
floor?: number;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function bestAnchorContrast(fill: string, paperLum: number, inkLum: number): number {
|
|
189
|
+
const hex = normalizeToHex(fill);
|
|
190
|
+
if (!hex) return 0;
|
|
191
|
+
const fillLum = relativeLuminance(hex);
|
|
192
|
+
return Math.max(contrastRatio(fillLum, paperLum), contrastRatio(fillLum, inkLum));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Pick an accent solid that can carry AA text (paper or ink ≥ 4.5).
|
|
197
|
+
*
|
|
198
|
+
* `$accentBackground` in the stock dark ramp is a mid-chroma solid whose
|
|
199
|
+
* better scheme-anchor pair measures 4.02:1 — over the graphic 3:1 tier and
|
|
200
|
+
* under the in-repo text floor. Walking to the nearest passing solid keeps
|
|
201
|
+
* the mark on the accent channel (LC-05) instead of dropping to ink or a
|
|
202
|
+
* tinted surface.
|
|
203
|
+
*
|
|
204
|
+
* Returns the preferred token when it already clears the floor, otherwise
|
|
205
|
+
* the solid token whose resolved luminance is closest to the preferred fill.
|
|
206
|
+
*/
|
|
207
|
+
export function resolveAaSolidFill({
|
|
208
|
+
preferred,
|
|
209
|
+
solids,
|
|
210
|
+
paper,
|
|
211
|
+
ink,
|
|
212
|
+
floor = aaTextContrastRatio,
|
|
213
|
+
}: ResolveAaSolidFillInput): string {
|
|
214
|
+
const paperHex = paper ? normalizeToHex(paper) : null;
|
|
215
|
+
const inkHex = ink ? normalizeToHex(ink) : null;
|
|
216
|
+
if (!paperHex || !inkHex) return preferred.token;
|
|
217
|
+
const paperLum = relativeLuminance(paperHex);
|
|
218
|
+
const inkLum = relativeLuminance(inkHex);
|
|
219
|
+
|
|
220
|
+
if (preferred.value && bestAnchorContrast(preferred.value, paperLum, inkLum) >= floor) {
|
|
221
|
+
return preferred.token;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const preferredHex = preferred.value ? normalizeToHex(preferred.value) : null;
|
|
225
|
+
const preferredLum = preferredHex ? relativeLuminance(preferredHex) : undefined;
|
|
226
|
+
let bestToken: string | undefined;
|
|
227
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
228
|
+
for (const { token, value } of solids) {
|
|
229
|
+
if (!value || bestAnchorContrast(value, paperLum, inkLum) < floor) continue;
|
|
230
|
+
const hex = normalizeToHex(value);
|
|
231
|
+
if (!hex) continue;
|
|
232
|
+
const dist = preferredLum === undefined ? 0 : Math.abs(relativeLuminance(hex) - preferredLum);
|
|
233
|
+
if (dist < bestDist) {
|
|
234
|
+
bestDist = dist;
|
|
235
|
+
bestToken = token;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return bestToken ?? preferred.token;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Token to paint as a selected/current solid so on-fill text clears AA.
|
|
243
|
+
* See {@link resolveAaSolidFill}.
|
|
244
|
+
*/
|
|
245
|
+
export function useAaSolidFill(preferredToken: string): string {
|
|
246
|
+
const theme = useTamaguiTheme() as unknown as Record<string, { val?: unknown } | undefined>;
|
|
247
|
+
const paper = resolveTokenValue(theme, "color1");
|
|
248
|
+
const ink = resolveTokenValue(theme, "color12");
|
|
249
|
+
const preferredValue = preferredToken.startsWith("$")
|
|
250
|
+
? resolveTokenValue(theme, preferredToken)
|
|
251
|
+
: preferredToken;
|
|
252
|
+
const solids: AaSolidCandidate[] = [];
|
|
253
|
+
for (let i = 1; i <= 10; i++) {
|
|
254
|
+
solids.push({ token: `$accent${i}`, value: resolveTokenValue(theme, `accent${i}`) });
|
|
255
|
+
}
|
|
256
|
+
const solidsKey = solids.map((s) => s.value ?? "").join("|");
|
|
257
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
258
|
+
return useMemo(
|
|
259
|
+
() =>
|
|
260
|
+
resolveAaSolidFill({
|
|
261
|
+
preferred: { token: preferredToken, value: preferredValue },
|
|
262
|
+
solids,
|
|
263
|
+
paper,
|
|
264
|
+
ink,
|
|
265
|
+
}),
|
|
266
|
+
[preferredToken, preferredValue, paper, ink, solidsKey],
|
|
267
|
+
);
|
|
268
|
+
}
|
|
@@ -459,6 +459,33 @@ export function applyRadiusStop<T extends { gap: number }>(
|
|
|
459
459
|
return { ...recipe, gap: SIZE_RECIPE_RADIUS_STOPS[stop] };
|
|
460
460
|
}
|
|
461
461
|
|
|
462
|
+
/** Knob fragment token → stop name. Default medium is `$4`. */
|
|
463
|
+
export const SIZE_RECIPE_RADIUS_TOKEN_TO_STOP = {
|
|
464
|
+
$0: "none",
|
|
465
|
+
$2: "small",
|
|
466
|
+
$4: "medium",
|
|
467
|
+
$6: "large",
|
|
468
|
+
$12: "full",
|
|
469
|
+
} as const;
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Painted control radius + inner gap.
|
|
473
|
+
*
|
|
474
|
+
* Default `medium` follows the size table (gap == radius at that token).
|
|
475
|
+
* Any other borderRadius knob stop is an override: both values become
|
|
476
|
+
* that stop's px so gap == radius there too (MPO-46).
|
|
477
|
+
*/
|
|
478
|
+
export function resolveControlRadius(
|
|
479
|
+
recipe: SizeRecipe,
|
|
480
|
+
stop: SizeRecipeRadiusStop = "medium",
|
|
481
|
+
): { radius: number; gap: number } {
|
|
482
|
+
if (stop === "medium") {
|
|
483
|
+
return { radius: recipe.gap, gap: recipe.gap };
|
|
484
|
+
}
|
|
485
|
+
const px = SIZE_RECIPE_RADIUS_STOPS[stop];
|
|
486
|
+
return { radius: px, gap: px };
|
|
487
|
+
}
|
|
488
|
+
|
|
462
489
|
function generateTouchHeights(
|
|
463
490
|
heights: Record<string, number>,
|
|
464
491
|
inputs: SizeRecipeInputs,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
applyRadiusStop,
|
|
16
16
|
generateSizeRecipes,
|
|
17
17
|
recipeFamilies,
|
|
18
|
+
resolveControlRadius,
|
|
18
19
|
sizeRecipeForToken,
|
|
19
20
|
sizeRecipes,
|
|
20
21
|
type SizeRecipeRadiusStop,
|
|
@@ -82,3 +83,22 @@ describe("MPO-46 gap == radius", () => {
|
|
|
82
83
|
}
|
|
83
84
|
});
|
|
84
85
|
});
|
|
86
|
+
|
|
87
|
+
describe("MPO-46 resolveControlRadius", () => {
|
|
88
|
+
it("default medium follows the size table, not the 9px knob", () => {
|
|
89
|
+
const two = resolveControlRadius(sizeRecipeForToken("$2"), "medium");
|
|
90
|
+
expect(two.radius).toBe(5);
|
|
91
|
+
expect(two.gap).toBe(5);
|
|
92
|
+
const six = resolveControlRadius(sizeRecipeForToken("$6"), "medium");
|
|
93
|
+
expect(six.radius).toBe(16);
|
|
94
|
+
expect(six.gap).toBe(16);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("non-medium knob stops retarget both radius and gap", () => {
|
|
98
|
+
const recipe = sizeRecipeForToken("$2");
|
|
99
|
+
expect(resolveControlRadius(recipe, "none")).toEqual({ radius: 0, gap: 0 });
|
|
100
|
+
expect(resolveControlRadius(recipe, "small")).toEqual({ radius: 5, gap: 5 });
|
|
101
|
+
expect(resolveControlRadius(recipe, "large")).toEqual({ radius: 16, gap: 16 });
|
|
102
|
+
expect(resolveControlRadius(recipe, "full")).toEqual({ radius: 50, gap: 50 });
|
|
103
|
+
});
|
|
104
|
+
});
|
package/src/theme/sizeRecipes.ts
CHANGED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPO-23 / 10 B.3 item 3: a consumer `getTheme` that returns something CSS
|
|
3
|
+
* cannot resolve must fail at BUILD, not at paint.
|
|
4
|
+
*
|
|
5
|
+
* Two halves, and both are the acceptance criterion: a deliberate violation in
|
|
6
|
+
* a fixture fails, and the mpo tree's own defaults pass. A check that only
|
|
7
|
+
* does the first is a check nobody can keep.
|
|
8
|
+
*/
|
|
9
|
+
import { describe, expect, it, vi } from "vitest";
|
|
10
|
+
|
|
11
|
+
vi.mock("tamagui", () => ({
|
|
12
|
+
createTamagui: vi.fn((config: Record<string, unknown>) => config),
|
|
13
|
+
}));
|
|
14
|
+
// The reanimated driver imports react-native, which has no Node build.
|
|
15
|
+
vi.mock("./animations/index", () => ({ animations: {} }));
|
|
16
|
+
|
|
17
|
+
import { createDefaultThemeConfig } from "./createDefaultThemeConfig";
|
|
18
|
+
import { isResolvableThemeValue } from "./themeValue";
|
|
19
|
+
|
|
20
|
+
describe("isResolvableThemeValue", () => {
|
|
21
|
+
it.each([
|
|
22
|
+
["$color5", "token reference"],
|
|
23
|
+
["#fff", "3-digit hex"],
|
|
24
|
+
["#ff00aa", "6-digit hex"],
|
|
25
|
+
["#ff00aa80", "8-digit hex"],
|
|
26
|
+
["rgba(0, 0, 0, 0.5)", "rgba()"],
|
|
27
|
+
["hsla(210, 50%, 40%, 0.2)", "hsla()"],
|
|
28
|
+
["oklch(0.7 0.1 200)", "oklch()"],
|
|
29
|
+
["color-mix(in srgb, red 50%, blue)", "color-mix()"],
|
|
30
|
+
["var(--fb-wall)", "var()"],
|
|
31
|
+
["transparent", "keyword"],
|
|
32
|
+
["currentColor", "keyword"],
|
|
33
|
+
["rebeccapurple", "named colour"],
|
|
34
|
+
[0.5, "number"],
|
|
35
|
+
])("accepts %s (%s)", (value) => {
|
|
36
|
+
expect(isResolvableThemeValue(value)).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it.each([
|
|
40
|
+
["", "empty string"],
|
|
41
|
+
[" ", "whitespace"],
|
|
42
|
+
["undefined", "the literal string undefined"],
|
|
43
|
+
["vaR(--x)", "a misspelled function"],
|
|
44
|
+
["reddish", "a word that is not a colour"],
|
|
45
|
+
["bakcground", "a typo"],
|
|
46
|
+
["$", "a bare dollar"],
|
|
47
|
+
[{}, "an object"],
|
|
48
|
+
])("rejects %s (%s)", (value) => {
|
|
49
|
+
expect(isResolvableThemeValue(value)).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("does not accept an arbitrary bare word — the typo case is the whole point", () => {
|
|
53
|
+
// A `/^[a-z]+$/` shortcut would pass all three of these.
|
|
54
|
+
expect(isResolvableThemeValue("backgroundd")).toBe(false);
|
|
55
|
+
expect(isResolvableThemeValue("greeen")).toBe(false);
|
|
56
|
+
expect(isResolvableThemeValue("green")).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe("composeGetTheme validates at build (10 B.3 item 3)", () => {
|
|
61
|
+
it("throws on a deliberate fixture violation, naming theme, key and value", () => {
|
|
62
|
+
expect(() =>
|
|
63
|
+
createDefaultThemeConfig({
|
|
64
|
+
builderOptions: { getTheme: () => ({ borderColor: "vaR(--x)" }) },
|
|
65
|
+
}),
|
|
66
|
+
).toThrow(/unresolvable value for "borderColor".*vaR\(--x\)/s);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("throws on the literal string 'undefined', which nullish-dropping lets through", () => {
|
|
70
|
+
expect(() =>
|
|
71
|
+
createDefaultThemeConfig({
|
|
72
|
+
builderOptions: { getTheme: () => ({ backgroundPress: "undefined" }) },
|
|
73
|
+
}),
|
|
74
|
+
).toThrow(/unresolvable value for "backgroundPress"/);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("still drops nullish rather than failing on it (DF-03 is unchanged)", () => {
|
|
78
|
+
expect(() =>
|
|
79
|
+
createDefaultThemeConfig({
|
|
80
|
+
builderOptions: {
|
|
81
|
+
getTheme: () => ({ borderColor: undefined, outlineColor: undefined }),
|
|
82
|
+
},
|
|
83
|
+
}),
|
|
84
|
+
).not.toThrow();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("passes on a real consumer override", () => {
|
|
88
|
+
expect(() =>
|
|
89
|
+
createDefaultThemeConfig({
|
|
90
|
+
builderOptions: { getTheme: () => ({ borderColor: "#ff00aa" }) },
|
|
91
|
+
}),
|
|
92
|
+
).not.toThrow();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("passes on the mpo tree's own defaults, with no consumer getTheme", () => {
|
|
96
|
+
expect(() => createDefaultThemeConfig()).not.toThrow();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is a theme value one a renderer can actually resolve? (MPO-23, 10 B.3 item 3.)
|
|
3
|
+
*
|
|
4
|
+
* `composeGetTheme` drops nullish consumer entries so a partial override does
|
|
5
|
+
* not erase a framework derivation (DF-03). It did nothing else, so a consumer
|
|
6
|
+
* `getTheme` that returned a MISSPELLED colour handed the string straight to
|
|
7
|
+
* paint: `borderColor: "vaR(--x)"` is not nullish, survives the merge, reaches
|
|
8
|
+
* CSS, resolves to nothing, and the element falls back to `currentColor`.
|
|
9
|
+
* That is the same near-black-border failure DF-03's comment describes, only
|
|
10
|
+
* with a slower fuse — it surfaces in someone's browser rather than in a build.
|
|
11
|
+
*
|
|
12
|
+
* So: validate at build. The predicate is deliberately PERMISSIVE. A false
|
|
13
|
+
* negative here fails an app's whole theme construction, which is far worse
|
|
14
|
+
* than the paint bug it prevents, so anything CSS could plausibly resolve
|
|
15
|
+
* passes and only the clearly-unresolvable fails.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Tamagui resolves a `$`-prefixed value against the token table, not CSS. */
|
|
19
|
+
const TOKEN_REFERENCE = /^\$[\w.-]+$/;
|
|
20
|
+
|
|
21
|
+
/** #rgb, #rgba, #rrggbb, #rrggbbaa. */
|
|
22
|
+
const HEX = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Every CSS colour FUNCTION, plus `var()`. Only the head is checked: the
|
|
26
|
+
* argument grammar is CSS's job and re-implementing it here would be a second
|
|
27
|
+
* parser to keep in step with the spec.
|
|
28
|
+
*/
|
|
29
|
+
const COLOR_FUNCTION = /^(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color|color-mix|light-dark|var)\(/;
|
|
30
|
+
|
|
31
|
+
/** CSS-wide keywords plus the two the theme layer actually writes. */
|
|
32
|
+
const KEYWORDS = new Set([
|
|
33
|
+
"transparent",
|
|
34
|
+
"currentColor",
|
|
35
|
+
"currentcolor",
|
|
36
|
+
"inherit",
|
|
37
|
+
"initial",
|
|
38
|
+
"revert",
|
|
39
|
+
"revert-layer",
|
|
40
|
+
"unset",
|
|
41
|
+
"none",
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The 148 CSS named colours. Spelled out rather than matched with `/^[a-z]+$/`
|
|
46
|
+
* on purpose: a bare-word pattern accepts `reddish` and `bakcground`, which are
|
|
47
|
+
* exactly the typos this check exists to catch.
|
|
48
|
+
*/
|
|
49
|
+
const NAMED_COLORS = new Set(
|
|
50
|
+
(
|
|
51
|
+
"aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue " +
|
|
52
|
+
"blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk " +
|
|
53
|
+
"crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki " +
|
|
54
|
+
"darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen " +
|
|
55
|
+
"darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue " +
|
|
56
|
+
"dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite " +
|
|
57
|
+
"gold goldenrod gray green greenyellow grey honeydew hotpink indianred indigo ivory khaki " +
|
|
58
|
+
"lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan " +
|
|
59
|
+
"lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen " +
|
|
60
|
+
"lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen linen " +
|
|
61
|
+
"magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen " +
|
|
62
|
+
"mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream " +
|
|
63
|
+
"mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid " +
|
|
64
|
+
"palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum " +
|
|
65
|
+
"powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown " +
|
|
66
|
+
"seagreen seashell sienna silver skyblue slateblue slategray slategrey snow springgreen " +
|
|
67
|
+
"steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen"
|
|
68
|
+
).split(" "),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* True when a renderer can resolve `value` to a colour.
|
|
73
|
+
*
|
|
74
|
+
* Numbers pass: a theme carries numeric values (z-index, opacity-ish steps)
|
|
75
|
+
* that are not colours at all and are not this check's business.
|
|
76
|
+
*/
|
|
77
|
+
export function isResolvableThemeValue(value: unknown): boolean {
|
|
78
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
79
|
+
if (typeof value !== "string") return false;
|
|
80
|
+
const text = value.trim();
|
|
81
|
+
if (text === "") return false;
|
|
82
|
+
if (TOKEN_REFERENCE.test(text)) return true;
|
|
83
|
+
if (HEX.test(text)) return true;
|
|
84
|
+
if (COLOR_FUNCTION.test(text)) return true;
|
|
85
|
+
if (KEYWORDS.has(text)) return true;
|
|
86
|
+
return NAMED_COLORS.has(text.toLowerCase());
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Throw on the first unresolvable entry, naming the theme, the key and the
|
|
91
|
+
* value. The message has to carry all three: a `getTheme` runs once per theme
|
|
92
|
+
* name, so "bad value" alone leaves the author grepping.
|
|
93
|
+
*/
|
|
94
|
+
export function assertResolvableThemeValues(
|
|
95
|
+
entries: Record<string, unknown>,
|
|
96
|
+
themeName: string,
|
|
97
|
+
): void {
|
|
98
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
99
|
+
if (value == null) continue;
|
|
100
|
+
if (isResolvableThemeValue(value)) continue;
|
|
101
|
+
throw new Error(
|
|
102
|
+
`getTheme returned an unresolvable value for "${key}" in theme "${themeName}": ` +
|
|
103
|
+
`${JSON.stringify(value)}. A theme value must be a $token, a hex colour, a CSS ` +
|
|
104
|
+
`colour function, a CSS-wide keyword or a named colour — anything else resolves to ` +
|
|
105
|
+
`nothing at paint and the element falls back to currentColor (10 B.3 item 3, MPO-23).`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createDefaultThemeConfig.d.ts","sourceRoot":"","sources":["../../src/theme/createDefaultThemeConfig.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,EAE/B,KAAK,sBAAsB,EAE5B,MAAM,gBAAgB,CAAC;AAKxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"createDefaultThemeConfig.d.ts","sourceRoot":"","sources":["../../src/theme/createDefaultThemeConfig.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,EAE/B,KAAK,sBAAsB,EAE5B,MAAM,gBAAgB,CAAC;AAKxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,UAAU,CAAC;AAI/D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,WAAW,EAAG,IAAa,CAAC;AACzC,sDAAsD;AACtD,eAAO,MAAM,UAAU,MAAc,CAAC;AAEtC,MAAM,WAAW,+BAA+B;IAC9C,oGAAoG;IACpG,IAAI,CAAC,EAAE,0BAA0B,CAAC;IAClC,mEAAmE;IACnE,MAAM,CAAC,EAAE,sBAAsB,CAAC;IAChC,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAC1D,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,qEAAqE;IACrE,UAAU,CAAC,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAC9C,oEAAoE;IACpE,cAAc,CAAC,EAAE,0BAA0B,CAAC;IAC5C,gCAAgC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAChE,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtC,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC1C;AAkCD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,+BAAoC,GAC5C,WAAW,CA8Db"}
|
|
@@ -27,6 +27,13 @@ export declare function focusRingColorMeetsContrast(ringColor: string, surfaceCo
|
|
|
27
27
|
* The inset did not die — it moved to `FOCUS_VISIBLE_RING_INSET`, an
|
|
28
28
|
* explicit per-call-site carve-out for clipping ancestors. MPO-19 X7 names
|
|
29
29
|
* the same offset `FOCUS_RING_CLIPPED_OFFSET` so call sites do not type `-2`.
|
|
30
|
+
*
|
|
31
|
+
* MPO-92 ratified a second, shape-scoped carve-out on the other side:
|
|
32
|
+
* `FOCUS_VISIBLE_RING_HALO` (+2) for pill/circular thumbs and inline text
|
|
33
|
+
* links. The F1 "not +2" reading was about the DEFAULT — a blanket +2 on
|
|
34
|
+
* every control — and it stands. The halo is a named carve-out with a written
|
|
35
|
+
* shape scope, exactly as the inset is; `SANCTIONED_FOCUS_RING_OFFSETS` below
|
|
36
|
+
* is the closed set of all three.
|
|
30
37
|
*/
|
|
31
38
|
export declare const FOCUS_RING_CLIPPED_OFFSET = -2;
|
|
32
39
|
export declare const FOCUS_VISIBLE_RING: {
|
|
@@ -54,6 +61,47 @@ export declare const FOCUS_VISIBLE_RING_INSET: {
|
|
|
54
61
|
outlineStyle: "solid";
|
|
55
62
|
outlineColor: string;
|
|
56
63
|
};
|
|
64
|
+
/**
|
|
65
|
+
* The LC-71 §4 halo carve-out (MPO-92, ratified 2026-09-02): the SAME ring,
|
|
66
|
+
* pushed 2px clear of the border box, for the two shapes where a band hugging
|
|
67
|
+
* the edge reads as part of the glyph instead of around it.
|
|
68
|
+
*
|
|
69
|
+
* Scope is by SHAPE, not by instance, and it is closed at two:
|
|
70
|
+
* - **pill / circular thumbs** — a round handle the user drags (Slider
|
|
71
|
+
* thumb, Rating star, TimeRangeScrubber handle). At offset 0 the band is
|
|
72
|
+
* concentric with the glyph's own edge and reads as a thicker glyph.
|
|
73
|
+
* - **inline text links** — a link inside a run of prose (markdown/mdx
|
|
74
|
+
* `Link`, ErrorSummary's summary link, backoffice "View All"). At offset 0
|
|
75
|
+
* the band crosses the line box and collides with ascenders/descenders of
|
|
76
|
+
* the surrounding text.
|
|
77
|
+
*
|
|
78
|
+
* NOT for standalone rectangles on the page ground — cards, tiles, rows,
|
|
79
|
+
* fields. Those are the default `FOCUS_VISIBLE_RING` (offset 0), which is
|
|
80
|
+
* what makes the Axiom 12 ≥3:1 floor computable against the page ground.
|
|
81
|
+
*
|
|
82
|
+
* Contrast is unaffected: like offset 0 the halo paints OUTSIDE the border
|
|
83
|
+
* box, on the surface behind the control, so it measures against the same
|
|
84
|
+
* page ground the default does — the 1.17–1.31:1 failures MPO-41 retired were
|
|
85
|
+
* the INSET painting inside solid intent fills, a defect the halo cannot have.
|
|
86
|
+
*/
|
|
87
|
+
export declare const FOCUS_RING_HALO_OFFSET = 2;
|
|
88
|
+
export declare const FOCUS_VISIBLE_RING_HALO: {
|
|
89
|
+
outlineOffset: number;
|
|
90
|
+
outlineWidth: number;
|
|
91
|
+
outlineStyle: "solid";
|
|
92
|
+
outlineColor: string;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* The CLOSED set of sanctioned focus-ring offsets (LC-71 §4). Three, and only
|
|
96
|
+
* three: the default 0, the clipping inset −2, the shape halo +2. A call site
|
|
97
|
+
* that wants any other number is a rule gap, not a preference — file it and
|
|
98
|
+
* amend §4, do not type the number. `focusState.spec.ts` asserts this set is
|
|
99
|
+
* exactly what the repo paints, so a fourth offset fails a test instead of
|
|
100
|
+
* shipping (MPO-92 AC-3).
|
|
101
|
+
*/
|
|
102
|
+
export declare const SANCTIONED_FOCUS_RING_OFFSETS: readonly [-2, number, 2];
|
|
103
|
+
/** True when `offset` is one of the three offsets LC-71 §4 sanctions. */
|
|
104
|
+
export declare function isSanctionedFocusRingOffset(offset: number): boolean;
|
|
57
105
|
/**
|
|
58
106
|
* DG-STATE-01 — Material-style state layers as theme tokens.
|
|
59
107
|
* Ramp lives in `defaults/builderOptions` (hover/press background steps);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"focusState.d.ts","sourceRoot":"","sources":["../../src/theme/focusState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAuBzC;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAO5F;AAED
|
|
1
|
+
{"version":3,"file":"focusState.d.ts","sourceRoot":"","sources":["../../src/theme/focusState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAuBzC;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAO5F;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,eAAO,MAAM,kBAAkB;;;;;CAKF,CAAC;AAE9B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB;;;;;CAGR,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AACxC,eAAO,MAAM,uBAAuB;;;;;CAGP,CAAC;AAE9B;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,0BAIhC,CAAC;AAEX,yEAAyE;AACzE,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;CAED,CAAC;AAE9B,eAAO,MAAM,iBAAiB;;CAED,CAAC;AAE9B;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,iBAAiB,EAChE,QAAQ,CAAC,EAAE,CAAC,CAAC,GAAG,iBAAiB,CAAC,GAAG,IAAI,GACxC,CAAC,GAAG,iBAAiB,CAyBvB;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,iBAAiB,GACvB,iBAAiB,CAKnB"}
|
package/types/theme/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,YAAY,EAAE,MAAM,IAAI,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACjF,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAE5B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,YAAY,EAAE,MAAM,IAAI,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACjF,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAE5B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC"}
|
|
@@ -26,4 +26,43 @@ export interface ResolveAccentTintedSurfaceInput {
|
|
|
26
26
|
/** Pure resolver behind {@link useAccentTintedSurface} — see its docs. */
|
|
27
27
|
export declare function resolveAccentTintedSurface({ steps, paper, ink, }: ResolveAccentTintedSurfaceInput): string | undefined;
|
|
28
28
|
export declare function useAccentTintedSurface(): string | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* A named solid in the accent ramp. `token` is what a caller paints
|
|
31
|
+
* (`$accentBackground`, `$accent9`); `value` is the resolved color.
|
|
32
|
+
*/
|
|
33
|
+
export interface AaSolidCandidate {
|
|
34
|
+
token: string;
|
|
35
|
+
value: string | undefined;
|
|
36
|
+
}
|
|
37
|
+
export interface ResolveAaSolidFillInput {
|
|
38
|
+
/** The LC-05 selected solid, usually `$accentBackground`. */
|
|
39
|
+
preferred: AaSolidCandidate;
|
|
40
|
+
/**
|
|
41
|
+
* Accent solids (steps 1–10). Pale anchors 11–12 are tinted surfaces, not
|
|
42
|
+
* selection solids — they would pass AA as chips and fail LC-05 as marks.
|
|
43
|
+
*/
|
|
44
|
+
solids: AaSolidCandidate[];
|
|
45
|
+
paper?: string;
|
|
46
|
+
ink?: string;
|
|
47
|
+
/** Defaults to {@link aaTextContrastRatio} (4.5). */
|
|
48
|
+
floor?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Pick an accent solid that can carry AA text (paper or ink ≥ 4.5).
|
|
52
|
+
*
|
|
53
|
+
* `$accentBackground` in the stock dark ramp is a mid-chroma solid whose
|
|
54
|
+
* better scheme-anchor pair measures 4.02:1 — over the graphic 3:1 tier and
|
|
55
|
+
* under the in-repo text floor. Walking to the nearest passing solid keeps
|
|
56
|
+
* the mark on the accent channel (LC-05) instead of dropping to ink or a
|
|
57
|
+
* tinted surface.
|
|
58
|
+
*
|
|
59
|
+
* Returns the preferred token when it already clears the floor, otherwise
|
|
60
|
+
* the solid token whose resolved luminance is closest to the preferred fill.
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveAaSolidFill({ preferred, solids, paper, ink, floor, }: ResolveAaSolidFillInput): string;
|
|
63
|
+
/**
|
|
64
|
+
* Token to paint as a selected/current solid so on-fill text clears AA.
|
|
65
|
+
* See {@link resolveAaSolidFill}.
|
|
66
|
+
*/
|
|
67
|
+
export declare function useAaSolidFill(preferredToken: string): string;
|
|
29
68
|
//# sourceMappingURL=readableColor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readableColor.d.ts","sourceRoot":"","sources":["../../src/theme/readableColor.ts"],"names":[],"mappings":"AA4CA;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAU/E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CA8B3C;AA0BD,MAAM,WAAW,+BAA+B;IAC9C,mEAAmE;IACnE,KAAK,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;IAC9B,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,0EAA0E;AAC1E,wBAAgB,0BAA0B,CAAC,EACzC,KAAK,EACL,KAAK,EACL,GAAG,GACJ,EAAE,+BAA+B,GAAG,MAAM,GAAG,SAAS,CAQtD;AAED,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAW3D"}
|
|
1
|
+
{"version":3,"file":"readableColor.d.ts","sourceRoot":"","sources":["../../src/theme/readableColor.ts"],"names":[],"mappings":"AA4CA;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAU/E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CA8B3C;AA0BD,MAAM,WAAW,+BAA+B;IAC9C,mEAAmE;IACnE,KAAK,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;IAC9B,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,0EAA0E;AAC1E,wBAAgB,0BAA0B,CAAC,EACzC,KAAK,EACL,KAAK,EACL,GAAG,GACJ,EAAE,+BAA+B,GAAG,MAAM,GAAG,SAAS,CAQtD;AAED,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAW3D;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,6DAA6D;IAC7D,SAAS,EAAE,gBAAgB,CAAC;IAC5B;;;OAGG;IACH,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AASD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,MAAM,EACN,KAAK,EACL,GAAG,EACH,KAA2B,GAC5B,EAAE,uBAAuB,GAAG,MAAM,CA0BlC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAuB7D"}
|
|
@@ -185,6 +185,25 @@ export declare function recipeFromTokenChannels(height: number, channels: SizeRe
|
|
|
185
185
|
export declare function applyRadiusStop<T extends {
|
|
186
186
|
gap: number;
|
|
187
187
|
}>(recipe: T, stop: SizeRecipeRadiusStop): T;
|
|
188
|
+
/** Knob fragment token → stop name. Default medium is `$4`. */
|
|
189
|
+
export declare const SIZE_RECIPE_RADIUS_TOKEN_TO_STOP: {
|
|
190
|
+
readonly $0: "none";
|
|
191
|
+
readonly $2: "small";
|
|
192
|
+
readonly $4: "medium";
|
|
193
|
+
readonly $6: "large";
|
|
194
|
+
readonly $12: "full";
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Painted control radius + inner gap.
|
|
198
|
+
*
|
|
199
|
+
* Default `medium` follows the size table (gap == radius at that token).
|
|
200
|
+
* Any other borderRadius knob stop is an override: both values become
|
|
201
|
+
* that stop's px so gap == radius there too (MPO-46).
|
|
202
|
+
*/
|
|
203
|
+
export declare function resolveControlRadius(recipe: SizeRecipe, stop?: SizeRecipeRadiusStop): {
|
|
204
|
+
radius: number;
|
|
205
|
+
gap: number;
|
|
206
|
+
};
|
|
188
207
|
export declare function generateSizeRecipeTables(inputs: SizeRecipeInputs, ratios?: SizeRecipeRatios, table?: SizeRecipeTokenTable | undefined): SizeRecipeTables;
|
|
189
208
|
export declare function createRecipeFamilies(inputs?: SizeRecipeInputs | Partial<SizeRecipeInputs>): RecipeFamilies;
|
|
190
209
|
export declare function generateSizeRecipes(partial?: Partial<SizeRecipeInputs>): GeneratedSizeRecipes;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recipeInputs.d.ts","sourceRoot":"","sources":["../../src/theme/recipeInputs.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"recipeInputs.d.ts","sourceRoot":"","sources":["../../src/theme/recipeInputs.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* desktop table — runtime fragments carry the floor; consumers spread
|
|
29
29
|
* `knobProps.control` after `size`.
|
|
30
30
|
*/
|
|
31
|
-
export { DEFAULT_SIZE_RECIPE_INPUTS, SIZE_RECIPE_RADIUS_STOPS, SIZE_RECIPE_TOKENS, SIZE_TOKEN_EXPONENTS, TAMAGUI_COMPACT_SIZE_TABLE, TAMAGUI_CONTROL_SIZE_TABLE, TAMAGUI_INPUT_PADX, TOUCH_HEIGHT_FLOOR, applyRadiusStop, cloneSizeRecipeInputs, createRecipeFamilies, defaultRecipeInputs, defaultSizeFactors, generateSizeRecipeTables, generateSizeRecipes, mergeRecipeInputs, recipeFromTokenChannels, resolveSizeRecipeInputs, } from "./recipeInputs";
|
|
31
|
+
export { DEFAULT_SIZE_RECIPE_INPUTS, SIZE_RECIPE_RADIUS_STOPS, SIZE_RECIPE_TOKENS, SIZE_TOKEN_EXPONENTS, TAMAGUI_COMPACT_SIZE_TABLE, TAMAGUI_CONTROL_SIZE_TABLE, TAMAGUI_INPUT_PADX, TOUCH_HEIGHT_FLOOR, applyRadiusStop, SIZE_RECIPE_RADIUS_TOKEN_TO_STOP, cloneSizeRecipeInputs, resolveControlRadius, createRecipeFamilies, defaultRecipeInputs, defaultSizeFactors, generateSizeRecipeTables, generateSizeRecipes, mergeRecipeInputs, recipeFromTokenChannels, resolveSizeRecipeInputs, } from "./recipeInputs";
|
|
32
32
|
export type { GeneratedSizeRecipes, RecipeFamilies, RecipeFamilyName, RecipeInputs, SizeRecipe, SizeRecipeBoxVariant, SizeRecipeFamily, SizeRecipeFamilyName, SizeRecipeIconVariant, SizeRecipeInputs, SizeRecipeRadiusStop, SizeRecipeRatios, SizeRecipeTables, SizeRecipeToken, SizeRecipeTokenChannels, SizeRecipeTokenTable, SizeRecipeTypeVariant, } from "./recipeInputs";
|
|
33
33
|
import { type GeneratedSizeRecipes, type RecipeFamilyName, type RecipeInputs, type SizeRecipe, type SizeRecipeFamily } from "./recipeInputs";
|
|
34
34
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sizeRecipes.d.ts","sourceRoot":"","sources":["../../src/theme/sizeRecipes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,kBAAkB,EAClB,oBAAoB,EACpB,0BAA0B,EAC1B,0BAA0B,EAC1B,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,EACxB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAKL,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,gBAAgB,EAEtB,MAAM,gBAAgB,CAAC;AA0BxB;;;GAGG;AACH,eAAO,MAAM,cAAc,yCAAmB,CAAC;AAE/C,oFAAoF;AACpF,eAAO,MAAM,WAAW,4BAAiC,CAAC;AAC1D,eAAO,MAAM,qBAAqB,+DAAqC,CAAC;AACxE,eAAO,MAAM,sBAAsB,gEAAsC,CAAC;AAC1E,eAAO,MAAM,sBAAsB,gEAAsC,CAAC;AAC1E,eAAO,MAAM,mBAAmB,wBAAiC,CAAC;AAClE,eAAO,MAAM,yBAAyB,wBAAsC,CAAC;AAC7E,eAAO,MAAM,iBAAiB,wBAA+B,CAAC;AAC9D,eAAO,MAAM,kBAAkB,2CAAgC,CAAC;AAChE,eAAO,MAAM,0BAA0B,2CAAuC,CAAC;AAE/E,eAAO,MAAM,wBAAwB,wCAAyC,CAAC;AAE/E;;;;GAIG;AACH,eAAO,MAAM,cAAc,sCAAgB,CAAC;AAE5C,wBAAgB,iBAAiB,IAAI,OAAO,cAAc,CAEzD;AAyBD,oGAAoG;AACpG,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,OAAO,CAAC,YAAY,CAAM,GAAG,oBAAoB,CAE7F;AAED,wBAAgB,mBAAmB,IAAI,YAAY,CAElD;AAED,wBAAgB,uBAAuB,IAAI,oBAAoB,CAE9D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,gBAA4B,GAAG,gBAAgB,CAExF;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,YAAY,CAAC,QAAQ,CAAyB,GACrD,UAAU,CAEZ;AAOD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,GAC3C,UAAU,CAQZ;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,CAAA;CAAE,GAC1E,UAAU,CAKZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAE/C;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,GAAG,mBAAmB,GAAG,UAAU,CAAC,GACpE,MAAM,CAER"}
|
|
1
|
+
{"version":3,"file":"sizeRecipes.d.ts","sourceRoot":"","sources":["../../src/theme/sizeRecipes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,kBAAkB,EAClB,oBAAoB,EACpB,0BAA0B,EAC1B,0BAA0B,EAC1B,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,gCAAgC,EAChC,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,EACxB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAKL,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,gBAAgB,EAEtB,MAAM,gBAAgB,CAAC;AA0BxB;;;GAGG;AACH,eAAO,MAAM,cAAc,yCAAmB,CAAC;AAE/C,oFAAoF;AACpF,eAAO,MAAM,WAAW,4BAAiC,CAAC;AAC1D,eAAO,MAAM,qBAAqB,+DAAqC,CAAC;AACxE,eAAO,MAAM,sBAAsB,gEAAsC,CAAC;AAC1E,eAAO,MAAM,sBAAsB,gEAAsC,CAAC;AAC1E,eAAO,MAAM,mBAAmB,wBAAiC,CAAC;AAClE,eAAO,MAAM,yBAAyB,wBAAsC,CAAC;AAC7E,eAAO,MAAM,iBAAiB,wBAA+B,CAAC;AAC9D,eAAO,MAAM,kBAAkB,2CAAgC,CAAC;AAChE,eAAO,MAAM,0BAA0B,2CAAuC,CAAC;AAE/E,eAAO,MAAM,wBAAwB,wCAAyC,CAAC;AAE/E;;;;GAIG;AACH,eAAO,MAAM,cAAc,sCAAgB,CAAC;AAE5C,wBAAgB,iBAAiB,IAAI,OAAO,cAAc,CAEzD;AAyBD,oGAAoG;AACpG,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,OAAO,CAAC,YAAY,CAAM,GAAG,oBAAoB,CAE7F;AAED,wBAAgB,mBAAmB,IAAI,YAAY,CAElD;AAED,wBAAgB,uBAAuB,IAAI,oBAAoB,CAE9D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,gBAA4B,GAAG,gBAAgB,CAExF;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,YAAY,CAAC,QAAQ,CAAyB,GACrD,UAAU,CAEZ;AAOD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,GAC3C,UAAU,CAQZ;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,CAAA;CAAE,GAC1E,UAAU,CAKZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAE/C;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,GAAG,mBAAmB,GAAG,UAAU,CAAC,GACpE,MAAM,CAER"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is a theme value one a renderer can actually resolve? (MPO-23, 10 B.3 item 3.)
|
|
3
|
+
*
|
|
4
|
+
* `composeGetTheme` drops nullish consumer entries so a partial override does
|
|
5
|
+
* not erase a framework derivation (DF-03). It did nothing else, so a consumer
|
|
6
|
+
* `getTheme` that returned a MISSPELLED colour handed the string straight to
|
|
7
|
+
* paint: `borderColor: "vaR(--x)"` is not nullish, survives the merge, reaches
|
|
8
|
+
* CSS, resolves to nothing, and the element falls back to `currentColor`.
|
|
9
|
+
* That is the same near-black-border failure DF-03's comment describes, only
|
|
10
|
+
* with a slower fuse — it surfaces in someone's browser rather than in a build.
|
|
11
|
+
*
|
|
12
|
+
* So: validate at build. The predicate is deliberately PERMISSIVE. A false
|
|
13
|
+
* negative here fails an app's whole theme construction, which is far worse
|
|
14
|
+
* than the paint bug it prevents, so anything CSS could plausibly resolve
|
|
15
|
+
* passes and only the clearly-unresolvable fails.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* True when a renderer can resolve `value` to a colour.
|
|
19
|
+
*
|
|
20
|
+
* Numbers pass: a theme carries numeric values (z-index, opacity-ish steps)
|
|
21
|
+
* that are not colours at all and are not this check's business.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isResolvableThemeValue(value: unknown): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Throw on the first unresolvable entry, naming the theme, the key and the
|
|
26
|
+
* value. The message has to carry all three: a `getTheme` runs once per theme
|
|
27
|
+
* name, so "bad value" alone leaves the author grepping.
|
|
28
|
+
*/
|
|
29
|
+
export declare function assertResolvableThemeValues(entries: Record<string, unknown>, themeName: string): void;
|
|
30
|
+
//# sourceMappingURL=themeValue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"themeValue.d.ts","sourceRoot":"","sources":["../../src/theme/themeValue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAuDH;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAU9D;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,EAAE,MAAM,GAChB,IAAI,CAWN"}
|