@lmb-it/kitsconcerto-native 0.1.291 → 0.1.293

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.
@@ -7,19 +7,78 @@ const WHITE = "#ffffff";
7
7
  function useSeverityColors(severity) {
8
8
  const { theme, resolveToken, colorMode } = KitsThemeProvider_native.useKitsTheme();
9
9
  return React.useMemo(() => {
10
+ const relativeLuminance = (css) => {
11
+ const m = /^#?([0-9a-f]{6})$/i.exec(css.trim());
12
+ if (!m) return null;
13
+ const channel = (v) => v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
14
+ const [r, g, b] = [0, 2, 4].map(
15
+ (i) => channel(parseInt(m[1].substr(i, 2), 16) / 255)
16
+ );
17
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
18
+ };
19
+ const whiteOn = (fill) => {
20
+ const l = relativeLuminance(fill);
21
+ return l === null ? null : 1.05 / (l + 0.05);
22
+ };
23
+ const resolveSolidText = (fill) => {
24
+ if (slots.solidText) return resolveToken(slots.solidText);
25
+ const ratio = fill ? whiteOn(fill) : null;
26
+ if (ratio !== null && ratio < 4.5) {
27
+ const ink = resolveToken("text-inverse");
28
+ if (ink && ink !== "text-inverse") return ink;
29
+ const surface = resolveToken("surface");
30
+ if (surface && surface !== "surface") return surface;
31
+ return resolveToken("gray.900");
32
+ }
33
+ return WHITE;
34
+ };
35
+ if (severity === "primary-interactive") {
36
+ const known = (token) => {
37
+ const value = resolveToken(token);
38
+ return value && value !== token ? value : null;
39
+ };
40
+ const fill = known("primary-interactive") ?? resolveToken("primary");
41
+ const ink = known("on-primary-interactive") ?? resolveSolidText(fill);
42
+ return {
43
+ solid: fill,
44
+ solidText: ink,
45
+ /* The soft slots have no token of their own; the brand's tint is
46
+ the nearest thing a product has already chosen, and it is only
47
+ used by outlined/soft treatments, never under `ink`. */
48
+ bgTint: known("primary-subtle") ?? resolveToken("surface-muted"),
49
+ iconFg: fill,
50
+ iconBg: known("primary-subtle") ?? resolveToken("surface-muted"),
51
+ text: fill,
52
+ border: fill
53
+ };
54
+ }
10
55
  const slots = theme.severity?.[severity] ?? theme.severity?.secondary;
11
56
  if (!slots) {
12
- const fallback = resolveToken("gray.500");
13
- return { solid: fallback, solidText: WHITE, bgTint: fallback, iconFg: fallback, iconBg: fallback, text: fallback, border: fallback };
57
+ const isDark = colorMode === "dark";
58
+ const pick = (token, backstop) => {
59
+ const value = resolveToken(token);
60
+ return !value || value === token ? resolveToken(backstop) : value;
61
+ };
62
+ const ink = pick("text-secondary", isDark ? "gray.300" : "gray.600");
63
+ const ground = pick("surface", isDark ? "gray.800" : "gray.50");
64
+ const tint = pick("surface-muted", isDark ? "gray.700" : "gray.100");
65
+ return {
66
+ solid: ink,
67
+ solidText: ground,
68
+ bgTint: tint,
69
+ iconFg: ink,
70
+ iconBg: tint,
71
+ text: ink,
72
+ border: ink
73
+ };
14
74
  }
15
- const resolveSolidText = () => slots.solidText ? resolveToken(slots.solidText) : WHITE;
16
75
  if (severity === "brand") {
17
76
  const primary = resolveToken("primary");
18
77
  if (colorMode === "dark") {
19
78
  const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
20
79
  return {
21
80
  solid: primary,
22
- solidText: resolveSolidText(),
81
+ solidText: resolveSolidText(primary),
23
82
  bgTint: swapShade(slots.solid, "900", slots.bgTint),
24
83
  iconFg: primary,
25
84
  iconBg: swapShade(slots.solid, "800", slots.iconBg),
@@ -29,7 +88,7 @@ function useSeverityColors(severity) {
29
88
  }
30
89
  return {
31
90
  solid: primary,
32
- solidText: resolveSolidText(),
91
+ solidText: resolveSolidText(primary),
33
92
  bgTint: resolveToken(slots.bgTint),
34
93
  iconFg: primary,
35
94
  iconBg: resolveToken(slots.iconBg),
@@ -41,7 +100,7 @@ function useSeverityColors(severity) {
41
100
  const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
42
101
  return {
43
102
  solid: resolveToken(slots.solid),
44
- solidText: resolveSolidText(),
103
+ solidText: resolveSolidText(resolveToken(slots.solid)),
45
104
  bgTint: swapShade(slots.solid, "900", slots.bgTint),
46
105
  iconFg: swapShade(slots.solid, "300", slots.iconFg),
47
106
  iconBg: swapShade(slots.solid, "800", slots.iconBg),
@@ -51,7 +110,7 @@ function useSeverityColors(severity) {
51
110
  }
52
111
  return {
53
112
  solid: resolveToken(slots.solid),
54
- solidText: resolveSolidText(),
113
+ solidText: resolveSolidText(resolveToken(slots.solid)),
55
114
  bgTint: resolveToken(slots.bgTint),
56
115
  iconFg: resolveToken(slots.iconFg),
57
116
  iconBg: resolveToken(slots.iconBg),
@@ -1 +1 @@
1
- {"version":3,"file":"useSeverityColors.cjs","sources":["../../../src/hooks/useSeverityColors.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\nimport type {Severity, ISeverityColorSlots} from '@lmb-it/kitsconcerto-types';\n\nexport interface ResolvedSeverityColors {\n solid: string;\n solidText: string;\n bgTint: string;\n iconFg: string;\n iconBg: string;\n text: string;\n border: string;\n}\n\nconst WHITE = '#ffffff';\n\n/**\n * Resolves all severity color slots for a given severity using the current theme.\n * All slot values go through resolveToken() — so they support:\n * - Raw values: '#ff0000', 'black', 'rgb(..)'\n * - Semantic tokens: 'primary', 'danger'\n * - Dot-notation: 'red.700', 'blue.500'\n * - Prefixed tokens: '$spacing.4'\n *\n * solidText defaults to white if not explicitly set by the consumer.\n */\n/**\n * ⛔ SHADE-SWAPPING ONLY WORKS ON A SHADED TOKEN, AND FOUR OF THIS LIBRARY'S\n * SEVEN SEVERITIES DO NOT HAVE ONE.\n *\n * Dark mode derives its tint and its text from the severity's `solid` value by\n * replacing the shade — `amber.500` → `amber.900` for the background and\n * `amber.200` for the text. That is only meaningful when `solid` LOOKS like\n * `name.NNN`. In `defaultTheme.ts` it often does not:\n *\n * brand brand.500 shaded → swap works\n * success green.500 shaded → swap works\n * secondary gray.500 shaded → swap works\n * danger #E3595B RAW HEX → swap is a no-op\n * warning #F59E0B RAW HEX → swap is a no-op\n * info #4F5BD5 RAW HEX → swap is a no-op\n * help #4F5BD5 RAW HEX → swap is a no-op\n *\n * ⛔ AND A NO-OP HERE IS NOT \"NO CHANGE\" — IT IS A COLLISION. The regex matches\n * nothing, so BOTH the background and the text resolve to the SAME raw hex, and\n * the text becomes invisible on its own background. Measured on the device\n * (AlphaMatch, Me tab, warning banner, dark): the action row was 6,923 sampled\n * pixels of #F59E0B with no text ink in it at all — the label and its reason\n * had vanished while the banner still looked like a banner.\n *\n * ⚠️ IT HITS THE FOUR SEVERITIES PEOPLE SEE MOST — errors, warnings, info and\n * help — and this hook is SHARED, not native-only, so web surfaces have it too.\n *\n * 💡 THE FALLBACK IS THE DESIGNED LIGHT PAIR. When there is no shade to swap,\n * the light slots are used instead: they are a pair someone chose to be legible\n * together, which is the one thing that must be true here. A dark-mode tint\n * would look better and is a palette decision, not a correctness one.\n */\nexport function useSeverityColors(severity: Severity): ResolvedSeverityColors {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const slots: ISeverityColorSlots = theme.severity?.[severity] ?? theme.severity?.secondary;\n if (!slots) {\n const fallback = resolveToken('gray.500');\n return {solid: fallback, solidText: WHITE, bgTint: fallback, iconFg: fallback, iconBg: fallback, text: fallback, border: fallback};\n }\n\n // solidText: resolve if consumer provided it, otherwise default to white\n const resolveSolidText = () =>\n slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n // Brand severity: solid/border/iconFg dynamically follow the primary token\n if (severity === 'brand') {\n const primary = resolveToken('primary');\n if (colorMode === 'dark') {\n // Same shade-guard as below: a `solid` with no shade cannot be\n // swapped, and collapsing it would put the text on its own colour.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: primary,\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: primary,\n };\n }\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: primary,\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: primary,\n };\n }\n\n if (colorMode === 'dark') {\n // `fallbackSlot` is used when `token` carries no shade to swap —\n // see the note above this function.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: resolveToken(slots.border),\n };\n }\n\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: resolveToken(slots.border),\n };\n }, [theme.severity, severity, resolveToken, colorMode]);\n}\n\n/**\n * Returns the full resolved map for all severities.\n */\nexport function useAllSeverityColors(): Record<Severity, ResolvedSeverityColors> {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const severities: Severity[] = ['success', 'info', 'warning', 'danger', 'help', 'secondary', 'brand'];\n const result = {} as Record<Severity, ResolvedSeverityColors>;\n const primary = resolveToken('primary');\n\n for (const key of severities) {\n const slots = theme.severity?.[key];\n if (!slots) continue;\n\n const isBrand = key === 'brand';\n const solidText = slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n if (colorMode === 'dark') {\n // Same shade-guard as useSeverityColors — four of the seven\n // default severities carry a raw hex, which cannot be swapped.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: isBrand ? primary : swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n } else {\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: resolveToken(slots.bgTint),\n iconFg: isBrand ? primary : resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n }\n }\n\n return result;\n }, [theme.severity, resolveToken, colorMode]);\n}\n"],"names":["useKitsTheme","useMemo"],"mappings":"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"}
1
+ {"version":3,"file":"useSeverityColors.cjs","sources":["../../../src/hooks/useSeverityColors.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\nimport type {Severity, ISeverityColorSlots} from '@lmb-it/kitsconcerto-types';\n\nexport interface ResolvedSeverityColors {\n solid: string;\n solidText: string;\n bgTint: string;\n iconFg: string;\n iconBg: string;\n text: string;\n border: string;\n}\n\nconst WHITE = '#ffffff';\n\n/**\n * Resolves all severity color slots for a given severity using the current theme.\n * All slot values go through resolveToken() — so they support:\n * - Raw values: '#ff0000', 'black', 'rgb(..)'\n * - Semantic tokens: 'primary', 'danger'\n * - Dot-notation: 'red.700', 'blue.500'\n * - Prefixed tokens: '$spacing.4'\n *\n * solidText defaults to white if not explicitly set by the consumer.\n */\n/**\n * ⛔ SHADE-SWAPPING ONLY WORKS ON A SHADED TOKEN, AND FOUR OF THIS LIBRARY'S\n * SEVEN SEVERITIES DO NOT HAVE ONE.\n *\n * Dark mode derives its tint and its text from the severity's `solid` value by\n * replacing the shade — `amber.500` → `amber.900` for the background and\n * `amber.200` for the text. That is only meaningful when `solid` LOOKS like\n * `name.NNN`. In `defaultTheme.ts` it often does not:\n *\n * brand brand.500 shaded → swap works\n * success green.500 shaded → swap works\n * secondary gray.500 shaded → swap works\n * danger #E3595B RAW HEX → swap is a no-op\n * warning #F59E0B RAW HEX → swap is a no-op\n * info #4F5BD5 RAW HEX → swap is a no-op\n * help #4F5BD5 RAW HEX → swap is a no-op\n *\n * ⛔ AND A NO-OP HERE IS NOT \"NO CHANGE\" — IT IS A COLLISION. The regex matches\n * nothing, so BOTH the background and the text resolve to the SAME raw hex, and\n * the text becomes invisible on its own background. Measured on the device\n * (AlphaMatch, Me tab, warning banner, dark): the action row was 6,923 sampled\n * pixels of #F59E0B with no text ink in it at all — the label and its reason\n * had vanished while the banner still looked like a banner.\n *\n * ⚠️ IT HITS THE FOUR SEVERITIES PEOPLE SEE MOST — errors, warnings, info and\n * help — and this hook is SHARED, not native-only, so web surfaces have it too.\n *\n * 💡 THE FALLBACK IS THE DESIGNED LIGHT PAIR. When there is no shade to swap,\n * the light slots are used instead: they are a pair someone chose to be legible\n * together, which is the one thing that must be true here. A dark-mode tint\n * would look better and is a palette decision, not a correctness one.\n */\nexport function useSeverityColors(severity: Severity): ResolvedSeverityColors {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n /*\n * ⛔ THE HELPERS AND THE `primary-interactive` BRANCH SIT ABOVE THE\n * NO-SLOTS RETURN ON PURPOSE. They used to sit below it, which meant a\n * product shipping no `theme.severity` at all never reached them and got\n * a grey secondary button while explicitly asking for an interactive\n * one. The helpers are pure definitions, so hoisting them changes\n * nothing for any other severity.\n */\n /*\n * ⛔ WHITE IS NOT A SAFE DEFAULT ON A FILL THAT FOLLOWS THE THEME —\n * R49, 25 October 2026, and this is the same fault as the no-slots\n * fallback above, one branch along.\n *\n * `solidText` defaulted to white unconditionally while `solid` for\n * the brand severity follows the `primary` token, which moves with\n * the colour mode. In the AlphaMatch Portal `primary` is #20AAB0 in\n * light and **#26C6DA in dark**, so a filled brand button measured\n * **2.82:1** and then **2.06:1** — the worst reading in the product.\n * Found on `/verification`: \"Verify on phone\", white on bright teal.\n *\n * ⛔ IT PICKS BY LUMINANCE RATHER THAN BY MODE, deliberately. Keying\n * on `colorMode === 'dark'` would be wrong for any product whose\n * primary is DARK in dark mode, and it was a guess about palettes\n * this library does not own. Relative luminance asks the only\n * question that matters — is white readable on this exact colour —\n * and answers it for a palette nobody here has seen.\n *\n * ⚠️ A CONSUMER'S OWN `solidText` STILL WINS. This changes the\n * DEFAULT only; a product that has stated what the ink should be is\n * not second-guessed.\n */\n const relativeLuminance = (css: string): number | null => {\n const m = /^#?([0-9a-f]{6})$/i.exec(css.trim());\n if (!m) return null;\n const channel = (v: number) =>\n v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);\n const [r, g, b] = [0, 2, 4].map(i =>\n channel(parseInt(m[1].substr(i, 2), 16) / 255),\n );\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n };\n /** White on `fill`, as a WCAG contrast ratio. */\n const whiteOn = (fill: string): number | null => {\n const l = relativeLuminance(fill);\n return l === null ? null : 1.05 / (l + 0.05);\n };\n const resolveSolidText = (fill?: string) => {\n if (slots.solidText) return resolveToken(slots.solidText);\n // ⚠️ UNKNOWN SHAPES KEEP THE OLD BEHAVIOUR. A gradient, a CSS\n // variable or a named colour returns null here, and white stays —\n // this must not start guessing at values it cannot read.\n const ratio = fill ? whiteOn(fill) : null;\n if (ratio !== null && ratio < 4.5) {\n const ink = resolveToken('text-inverse');\n if (ink && ink !== 'text-inverse') return ink;\n const surface = resolveToken('surface');\n if (surface && surface !== 'surface') return surface;\n return resolveToken('gray.900');\n }\n return WHITE;\n };\n\n /*\n * ⛔ `primary-interactive` RESOLVES FROM TOKENS, NOT FROM `theme.severity`,\n * for the same reason `brand` does below: the colour belongs to the\n * consuming product's palette, and this library ships no default for it.\n *\n * ⛔ IT IS PLACED BEFORE THE SLOTS LOOKUP DELIBERATELY. A product that has\n * not defined `theme.severity['primary-interactive']` — which is every\n * product today — would otherwise fall into the no-slots fallback and get\n * a grey secondary button while asking for an interactive one.\n *\n * ⛔ AND THE INK IS ITS OWN TOKEN, WHICH IS THE WHOLE POINT. `solidText`\n * here is `on-primary-interactive`, not white and not a luminance guess.\n * The fill is designed to flip between modes (AlphaMatch: #157C82 light,\n * #4DD0E1 dark) and white on the dark value measures 1.84:1 — the exact\n * failure R49 fixed for `brand`. A pair that was chosen together cannot\n * be re-derived here as reliably as it can be stated.\n *\n * ⚠️ A PRODUCT WITHOUT THE TOKENS DEGRADES TO `primary` RATHER THAN TO A\n * TOKEN NAME. `resolveToken` returns its argument unchanged when it knows\n * nothing, so the guard below treats that as absent. The Portal is\n * therefore unaffected unless it both defines the tokens and asks for\n * this severity.\n */\n if (severity === 'primary-interactive') {\n const known = (token: string): string | null => {\n const value = resolveToken(token);\n return value && value !== token ? value : null;\n };\n const fill = known('primary-interactive') ?? resolveToken('primary');\n const ink = known('on-primary-interactive') ?? resolveSolidText(fill);\n return {\n solid: fill,\n solidText: ink,\n /* The soft slots have no token of their own; the brand's tint is\n the nearest thing a product has already chosen, and it is only\n used by outlined/soft treatments, never under `ink`. */\n bgTint: known('primary-subtle') ?? resolveToken('surface-muted'),\n iconFg: fill,\n iconBg: known('primary-subtle') ?? resolveToken('surface-muted'),\n text: fill,\n border: fill,\n };\n }\n\n const slots: ISeverityColorSlots = theme.severity?.[severity] ?? theme.severity?.secondary;\n if (!slots) {\n /*\n * ⛔ THE FALLBACK MUST FOLLOW THE COLOUR MODE, AND `gray.500` DID\n * NOT — R49, 25 October 2026. This branch is not an edge case: a\n * product that ships `severity: {}` lands here for every severity\n * except `brand`, which has its own dynamic path above. The\n * AlphaMatch Client Portal does exactly that, so EVERY outlined\n * secondary control in it was inked `#6B7280`.\n *\n * A scale step is a fixed point on a ramp; it is the same colour\n * in both palettes, while everything around it moves. Measured in\n * the Portal:\n *\n * outlined label, light page #F5F7F6 **4.49:1** (already failing)\n * outlined label, dark page #111827 **3.67:1**\n * outlined label, dark card #1F2937 **3.04:1**\n *\n * ⚠️ THIS IS THE SECOND TIME THE SAME MISTAKE HAS BEEN FOUND HERE.\n * `Tabs` defaulted `inactiveBackground` to `gray.100` while\n * labelling it with a token that flips, and four chips measured\n * 1.34:1 on a dark page; that was fixed at source in 0.1.290. The\n * rule it produced — a default that pairs a scale value with a\n * semantic one will be wrong in one mode — was not carried across\n * to this function.\n *\n * ⛔ AND `solid` DOES TWO JOBS, WHICH IS WHY IT NEEDS A PAIR.\n * `Button` uses it as the FILL when solid and as the INK when\n * outlined; `Chip` does the same. A value dark enough for white\n * text is unreadable as ink on a dark page, and vice versa. So\n * the ink follows the mode and `solidText` is the surface behind\n * it, which moves the opposite way:\n *\n * filled light #FFFFFF on #546067 6.47:1\n * filled dark #1F2937 on #D1D5DB 9.96:1\n * outlined light #546067 on #F5F7F6 6.01:1\n * outlined dark #D1D5DB on #111827 12.04:1\n *\n * ⚠️ AND IT DEGRADES RATHER THAN BREAKING. This library ships no\n * default semantic tokens — consumers supply them — so a product\n * without `text-secondary` or `surface` would get the token name\n * back instead of a colour. `pick()` keeps a mode-aware scale\n * step behind each one: still better than today, because the\n * backstop flips even though a scale value normally cannot.\n */\n const isDark = colorMode === 'dark';\n const pick = (token: string, backstop: string) => {\n const value = resolveToken(token);\n return !value || value === token ? resolveToken(backstop) : value;\n };\n const ink = pick('text-secondary', isDark ? 'gray.300' : 'gray.600');\n const ground = pick('surface', isDark ? 'gray.800' : 'gray.50');\n const tint = pick('surface-muted', isDark ? 'gray.700' : 'gray.100');\n return {\n solid: ink,\n solidText: ground,\n bgTint: tint,\n iconFg: ink,\n iconBg: tint,\n text: ink,\n border: ink,\n };\n }\n\n\n // Brand severity: solid/border/iconFg dynamically follow the primary token\n if (severity === 'brand') {\n const primary = resolveToken('primary');\n if (colorMode === 'dark') {\n // Same shade-guard as below: a `solid` with no shade cannot be\n // swapped, and collapsing it would put the text on its own colour.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: primary,\n solidText: resolveSolidText(primary),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: primary,\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: primary,\n };\n }\n return {\n solid: primary,\n solidText: resolveSolidText(primary),\n bgTint: resolveToken(slots.bgTint),\n iconFg: primary,\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: primary,\n };\n }\n\n if (colorMode === 'dark') {\n // `fallbackSlot` is used when `token` carries no shade to swap —\n // see the note above this function.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(resolveToken(slots.solid)),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: resolveToken(slots.border),\n };\n }\n\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(resolveToken(slots.solid)),\n bgTint: resolveToken(slots.bgTint),\n iconFg: resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: resolveToken(slots.border),\n };\n }, [theme.severity, severity, resolveToken, colorMode]);\n}\n\n/**\n * Returns the full resolved map for all severities.\n */\nexport function useAllSeverityColors(): Record<Severity, ResolvedSeverityColors> {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const severities: Severity[] = ['success', 'info', 'warning', 'danger', 'help', 'secondary', 'brand'];\n const result = {} as Record<Severity, ResolvedSeverityColors>;\n const primary = resolveToken('primary');\n\n for (const key of severities) {\n const slots = theme.severity?.[key];\n if (!slots) continue;\n\n const isBrand = key === 'brand';\n const solidText = slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n if (colorMode === 'dark') {\n // Same shade-guard as useSeverityColors — four of the seven\n // default severities carry a raw hex, which cannot be swapped.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: isBrand ? primary : swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n } else {\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: resolveToken(slots.bgTint),\n iconFg: isBrand ? primary : resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n }\n }\n\n return result;\n }, [theme.severity, resolveToken, colorMode]);\n}\n"],"names":["useKitsTheme","useMemo"],"mappings":"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"}
@@ -5,19 +5,78 @@ const WHITE = "#ffffff";
5
5
  function useSeverityColors(severity) {
6
6
  const { theme, resolveToken, colorMode } = useKitsTheme();
7
7
  return useMemo(() => {
8
+ const relativeLuminance = (css) => {
9
+ const m = /^#?([0-9a-f]{6})$/i.exec(css.trim());
10
+ if (!m) return null;
11
+ const channel = (v) => v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
12
+ const [r, g, b] = [0, 2, 4].map(
13
+ (i) => channel(parseInt(m[1].substr(i, 2), 16) / 255)
14
+ );
15
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
16
+ };
17
+ const whiteOn = (fill) => {
18
+ const l = relativeLuminance(fill);
19
+ return l === null ? null : 1.05 / (l + 0.05);
20
+ };
21
+ const resolveSolidText = (fill) => {
22
+ if (slots.solidText) return resolveToken(slots.solidText);
23
+ const ratio = fill ? whiteOn(fill) : null;
24
+ if (ratio !== null && ratio < 4.5) {
25
+ const ink = resolveToken("text-inverse");
26
+ if (ink && ink !== "text-inverse") return ink;
27
+ const surface = resolveToken("surface");
28
+ if (surface && surface !== "surface") return surface;
29
+ return resolveToken("gray.900");
30
+ }
31
+ return WHITE;
32
+ };
33
+ if (severity === "primary-interactive") {
34
+ const known = (token) => {
35
+ const value = resolveToken(token);
36
+ return value && value !== token ? value : null;
37
+ };
38
+ const fill = known("primary-interactive") ?? resolveToken("primary");
39
+ const ink = known("on-primary-interactive") ?? resolveSolidText(fill);
40
+ return {
41
+ solid: fill,
42
+ solidText: ink,
43
+ /* The soft slots have no token of their own; the brand's tint is
44
+ the nearest thing a product has already chosen, and it is only
45
+ used by outlined/soft treatments, never under `ink`. */
46
+ bgTint: known("primary-subtle") ?? resolveToken("surface-muted"),
47
+ iconFg: fill,
48
+ iconBg: known("primary-subtle") ?? resolveToken("surface-muted"),
49
+ text: fill,
50
+ border: fill
51
+ };
52
+ }
8
53
  const slots = theme.severity?.[severity] ?? theme.severity?.secondary;
9
54
  if (!slots) {
10
- const fallback = resolveToken("gray.500");
11
- return { solid: fallback, solidText: WHITE, bgTint: fallback, iconFg: fallback, iconBg: fallback, text: fallback, border: fallback };
55
+ const isDark = colorMode === "dark";
56
+ const pick = (token, backstop) => {
57
+ const value = resolveToken(token);
58
+ return !value || value === token ? resolveToken(backstop) : value;
59
+ };
60
+ const ink = pick("text-secondary", isDark ? "gray.300" : "gray.600");
61
+ const ground = pick("surface", isDark ? "gray.800" : "gray.50");
62
+ const tint = pick("surface-muted", isDark ? "gray.700" : "gray.100");
63
+ return {
64
+ solid: ink,
65
+ solidText: ground,
66
+ bgTint: tint,
67
+ iconFg: ink,
68
+ iconBg: tint,
69
+ text: ink,
70
+ border: ink
71
+ };
12
72
  }
13
- const resolveSolidText = () => slots.solidText ? resolveToken(slots.solidText) : WHITE;
14
73
  if (severity === "brand") {
15
74
  const primary = resolveToken("primary");
16
75
  if (colorMode === "dark") {
17
76
  const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
18
77
  return {
19
78
  solid: primary,
20
- solidText: resolveSolidText(),
79
+ solidText: resolveSolidText(primary),
21
80
  bgTint: swapShade(slots.solid, "900", slots.bgTint),
22
81
  iconFg: primary,
23
82
  iconBg: swapShade(slots.solid, "800", slots.iconBg),
@@ -27,7 +86,7 @@ function useSeverityColors(severity) {
27
86
  }
28
87
  return {
29
88
  solid: primary,
30
- solidText: resolveSolidText(),
89
+ solidText: resolveSolidText(primary),
31
90
  bgTint: resolveToken(slots.bgTint),
32
91
  iconFg: primary,
33
92
  iconBg: resolveToken(slots.iconBg),
@@ -39,7 +98,7 @@ function useSeverityColors(severity) {
39
98
  const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
40
99
  return {
41
100
  solid: resolveToken(slots.solid),
42
- solidText: resolveSolidText(),
101
+ solidText: resolveSolidText(resolveToken(slots.solid)),
43
102
  bgTint: swapShade(slots.solid, "900", slots.bgTint),
44
103
  iconFg: swapShade(slots.solid, "300", slots.iconFg),
45
104
  iconBg: swapShade(slots.solid, "800", slots.iconBg),
@@ -49,7 +108,7 @@ function useSeverityColors(severity) {
49
108
  }
50
109
  return {
51
110
  solid: resolveToken(slots.solid),
52
- solidText: resolveSolidText(),
111
+ solidText: resolveSolidText(resolveToken(slots.solid)),
53
112
  bgTint: resolveToken(slots.bgTint),
54
113
  iconFg: resolveToken(slots.iconFg),
55
114
  iconBg: resolveToken(slots.iconBg),
@@ -1 +1 @@
1
- {"version":3,"file":"useSeverityColors.js","sources":["../../../src/hooks/useSeverityColors.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\nimport type {Severity, ISeverityColorSlots} from '@lmb-it/kitsconcerto-types';\n\nexport interface ResolvedSeverityColors {\n solid: string;\n solidText: string;\n bgTint: string;\n iconFg: string;\n iconBg: string;\n text: string;\n border: string;\n}\n\nconst WHITE = '#ffffff';\n\n/**\n * Resolves all severity color slots for a given severity using the current theme.\n * All slot values go through resolveToken() — so they support:\n * - Raw values: '#ff0000', 'black', 'rgb(..)'\n * - Semantic tokens: 'primary', 'danger'\n * - Dot-notation: 'red.700', 'blue.500'\n * - Prefixed tokens: '$spacing.4'\n *\n * solidText defaults to white if not explicitly set by the consumer.\n */\n/**\n * ⛔ SHADE-SWAPPING ONLY WORKS ON A SHADED TOKEN, AND FOUR OF THIS LIBRARY'S\n * SEVEN SEVERITIES DO NOT HAVE ONE.\n *\n * Dark mode derives its tint and its text from the severity's `solid` value by\n * replacing the shade — `amber.500` → `amber.900` for the background and\n * `amber.200` for the text. That is only meaningful when `solid` LOOKS like\n * `name.NNN`. In `defaultTheme.ts` it often does not:\n *\n * brand brand.500 shaded → swap works\n * success green.500 shaded → swap works\n * secondary gray.500 shaded → swap works\n * danger #E3595B RAW HEX → swap is a no-op\n * warning #F59E0B RAW HEX → swap is a no-op\n * info #4F5BD5 RAW HEX → swap is a no-op\n * help #4F5BD5 RAW HEX → swap is a no-op\n *\n * ⛔ AND A NO-OP HERE IS NOT \"NO CHANGE\" — IT IS A COLLISION. The regex matches\n * nothing, so BOTH the background and the text resolve to the SAME raw hex, and\n * the text becomes invisible on its own background. Measured on the device\n * (AlphaMatch, Me tab, warning banner, dark): the action row was 6,923 sampled\n * pixels of #F59E0B with no text ink in it at all — the label and its reason\n * had vanished while the banner still looked like a banner.\n *\n * ⚠️ IT HITS THE FOUR SEVERITIES PEOPLE SEE MOST — errors, warnings, info and\n * help — and this hook is SHARED, not native-only, so web surfaces have it too.\n *\n * 💡 THE FALLBACK IS THE DESIGNED LIGHT PAIR. When there is no shade to swap,\n * the light slots are used instead: they are a pair someone chose to be legible\n * together, which is the one thing that must be true here. A dark-mode tint\n * would look better and is a palette decision, not a correctness one.\n */\nexport function useSeverityColors(severity: Severity): ResolvedSeverityColors {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const slots: ISeverityColorSlots = theme.severity?.[severity] ?? theme.severity?.secondary;\n if (!slots) {\n const fallback = resolveToken('gray.500');\n return {solid: fallback, solidText: WHITE, bgTint: fallback, iconFg: fallback, iconBg: fallback, text: fallback, border: fallback};\n }\n\n // solidText: resolve if consumer provided it, otherwise default to white\n const resolveSolidText = () =>\n slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n // Brand severity: solid/border/iconFg dynamically follow the primary token\n if (severity === 'brand') {\n const primary = resolveToken('primary');\n if (colorMode === 'dark') {\n // Same shade-guard as below: a `solid` with no shade cannot be\n // swapped, and collapsing it would put the text on its own colour.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: primary,\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: primary,\n };\n }\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: primary,\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: primary,\n };\n }\n\n if (colorMode === 'dark') {\n // `fallbackSlot` is used when `token` carries no shade to swap —\n // see the note above this function.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: resolveToken(slots.border),\n };\n }\n\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: resolveToken(slots.border),\n };\n }, [theme.severity, severity, resolveToken, colorMode]);\n}\n\n/**\n * Returns the full resolved map for all severities.\n */\nexport function useAllSeverityColors(): Record<Severity, ResolvedSeverityColors> {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const severities: Severity[] = ['success', 'info', 'warning', 'danger', 'help', 'secondary', 'brand'];\n const result = {} as Record<Severity, ResolvedSeverityColors>;\n const primary = resolveToken('primary');\n\n for (const key of severities) {\n const slots = theme.severity?.[key];\n if (!slots) continue;\n\n const isBrand = key === 'brand';\n const solidText = slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n if (colorMode === 'dark') {\n // Same shade-guard as useSeverityColors — four of the seven\n // default severities carry a raw hex, which cannot be swapped.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: isBrand ? primary : swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n } else {\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: resolveToken(slots.bgTint),\n iconFg: isBrand ? primary : resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n }\n }\n\n return result;\n }, [theme.severity, resolveToken, colorMode]);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useSeverityColors.js","sources":["../../../src/hooks/useSeverityColors.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\nimport type {Severity, ISeverityColorSlots} from '@lmb-it/kitsconcerto-types';\n\nexport interface ResolvedSeverityColors {\n solid: string;\n solidText: string;\n bgTint: string;\n iconFg: string;\n iconBg: string;\n text: string;\n border: string;\n}\n\nconst WHITE = '#ffffff';\n\n/**\n * Resolves all severity color slots for a given severity using the current theme.\n * All slot values go through resolveToken() — so they support:\n * - Raw values: '#ff0000', 'black', 'rgb(..)'\n * - Semantic tokens: 'primary', 'danger'\n * - Dot-notation: 'red.700', 'blue.500'\n * - Prefixed tokens: '$spacing.4'\n *\n * solidText defaults to white if not explicitly set by the consumer.\n */\n/**\n * ⛔ SHADE-SWAPPING ONLY WORKS ON A SHADED TOKEN, AND FOUR OF THIS LIBRARY'S\n * SEVEN SEVERITIES DO NOT HAVE ONE.\n *\n * Dark mode derives its tint and its text from the severity's `solid` value by\n * replacing the shade — `amber.500` → `amber.900` for the background and\n * `amber.200` for the text. That is only meaningful when `solid` LOOKS like\n * `name.NNN`. In `defaultTheme.ts` it often does not:\n *\n * brand brand.500 shaded → swap works\n * success green.500 shaded → swap works\n * secondary gray.500 shaded → swap works\n * danger #E3595B RAW HEX → swap is a no-op\n * warning #F59E0B RAW HEX → swap is a no-op\n * info #4F5BD5 RAW HEX → swap is a no-op\n * help #4F5BD5 RAW HEX → swap is a no-op\n *\n * ⛔ AND A NO-OP HERE IS NOT \"NO CHANGE\" — IT IS A COLLISION. The regex matches\n * nothing, so BOTH the background and the text resolve to the SAME raw hex, and\n * the text becomes invisible on its own background. Measured on the device\n * (AlphaMatch, Me tab, warning banner, dark): the action row was 6,923 sampled\n * pixels of #F59E0B with no text ink in it at all — the label and its reason\n * had vanished while the banner still looked like a banner.\n *\n * ⚠️ IT HITS THE FOUR SEVERITIES PEOPLE SEE MOST — errors, warnings, info and\n * help — and this hook is SHARED, not native-only, so web surfaces have it too.\n *\n * 💡 THE FALLBACK IS THE DESIGNED LIGHT PAIR. When there is no shade to swap,\n * the light slots are used instead: they are a pair someone chose to be legible\n * together, which is the one thing that must be true here. A dark-mode tint\n * would look better and is a palette decision, not a correctness one.\n */\nexport function useSeverityColors(severity: Severity): ResolvedSeverityColors {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n /*\n * ⛔ THE HELPERS AND THE `primary-interactive` BRANCH SIT ABOVE THE\n * NO-SLOTS RETURN ON PURPOSE. They used to sit below it, which meant a\n * product shipping no `theme.severity` at all never reached them and got\n * a grey secondary button while explicitly asking for an interactive\n * one. The helpers are pure definitions, so hoisting them changes\n * nothing for any other severity.\n */\n /*\n * ⛔ WHITE IS NOT A SAFE DEFAULT ON A FILL THAT FOLLOWS THE THEME —\n * R49, 25 October 2026, and this is the same fault as the no-slots\n * fallback above, one branch along.\n *\n * `solidText` defaulted to white unconditionally while `solid` for\n * the brand severity follows the `primary` token, which moves with\n * the colour mode. In the AlphaMatch Portal `primary` is #20AAB0 in\n * light and **#26C6DA in dark**, so a filled brand button measured\n * **2.82:1** and then **2.06:1** — the worst reading in the product.\n * Found on `/verification`: \"Verify on phone\", white on bright teal.\n *\n * ⛔ IT PICKS BY LUMINANCE RATHER THAN BY MODE, deliberately. Keying\n * on `colorMode === 'dark'` would be wrong for any product whose\n * primary is DARK in dark mode, and it was a guess about palettes\n * this library does not own. Relative luminance asks the only\n * question that matters — is white readable on this exact colour —\n * and answers it for a palette nobody here has seen.\n *\n * ⚠️ A CONSUMER'S OWN `solidText` STILL WINS. This changes the\n * DEFAULT only; a product that has stated what the ink should be is\n * not second-guessed.\n */\n const relativeLuminance = (css: string): number | null => {\n const m = /^#?([0-9a-f]{6})$/i.exec(css.trim());\n if (!m) return null;\n const channel = (v: number) =>\n v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);\n const [r, g, b] = [0, 2, 4].map(i =>\n channel(parseInt(m[1].substr(i, 2), 16) / 255),\n );\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n };\n /** White on `fill`, as a WCAG contrast ratio. */\n const whiteOn = (fill: string): number | null => {\n const l = relativeLuminance(fill);\n return l === null ? null : 1.05 / (l + 0.05);\n };\n const resolveSolidText = (fill?: string) => {\n if (slots.solidText) return resolveToken(slots.solidText);\n // ⚠️ UNKNOWN SHAPES KEEP THE OLD BEHAVIOUR. A gradient, a CSS\n // variable or a named colour returns null here, and white stays —\n // this must not start guessing at values it cannot read.\n const ratio = fill ? whiteOn(fill) : null;\n if (ratio !== null && ratio < 4.5) {\n const ink = resolveToken('text-inverse');\n if (ink && ink !== 'text-inverse') return ink;\n const surface = resolveToken('surface');\n if (surface && surface !== 'surface') return surface;\n return resolveToken('gray.900');\n }\n return WHITE;\n };\n\n /*\n * ⛔ `primary-interactive` RESOLVES FROM TOKENS, NOT FROM `theme.severity`,\n * for the same reason `brand` does below: the colour belongs to the\n * consuming product's palette, and this library ships no default for it.\n *\n * ⛔ IT IS PLACED BEFORE THE SLOTS LOOKUP DELIBERATELY. A product that has\n * not defined `theme.severity['primary-interactive']` — which is every\n * product today — would otherwise fall into the no-slots fallback and get\n * a grey secondary button while asking for an interactive one.\n *\n * ⛔ AND THE INK IS ITS OWN TOKEN, WHICH IS THE WHOLE POINT. `solidText`\n * here is `on-primary-interactive`, not white and not a luminance guess.\n * The fill is designed to flip between modes (AlphaMatch: #157C82 light,\n * #4DD0E1 dark) and white on the dark value measures 1.84:1 — the exact\n * failure R49 fixed for `brand`. A pair that was chosen together cannot\n * be re-derived here as reliably as it can be stated.\n *\n * ⚠️ A PRODUCT WITHOUT THE TOKENS DEGRADES TO `primary` RATHER THAN TO A\n * TOKEN NAME. `resolveToken` returns its argument unchanged when it knows\n * nothing, so the guard below treats that as absent. The Portal is\n * therefore unaffected unless it both defines the tokens and asks for\n * this severity.\n */\n if (severity === 'primary-interactive') {\n const known = (token: string): string | null => {\n const value = resolveToken(token);\n return value && value !== token ? value : null;\n };\n const fill = known('primary-interactive') ?? resolveToken('primary');\n const ink = known('on-primary-interactive') ?? resolveSolidText(fill);\n return {\n solid: fill,\n solidText: ink,\n /* The soft slots have no token of their own; the brand's tint is\n the nearest thing a product has already chosen, and it is only\n used by outlined/soft treatments, never under `ink`. */\n bgTint: known('primary-subtle') ?? resolveToken('surface-muted'),\n iconFg: fill,\n iconBg: known('primary-subtle') ?? resolveToken('surface-muted'),\n text: fill,\n border: fill,\n };\n }\n\n const slots: ISeverityColorSlots = theme.severity?.[severity] ?? theme.severity?.secondary;\n if (!slots) {\n /*\n * ⛔ THE FALLBACK MUST FOLLOW THE COLOUR MODE, AND `gray.500` DID\n * NOT — R49, 25 October 2026. This branch is not an edge case: a\n * product that ships `severity: {}` lands here for every severity\n * except `brand`, which has its own dynamic path above. The\n * AlphaMatch Client Portal does exactly that, so EVERY outlined\n * secondary control in it was inked `#6B7280`.\n *\n * A scale step is a fixed point on a ramp; it is the same colour\n * in both palettes, while everything around it moves. Measured in\n * the Portal:\n *\n * outlined label, light page #F5F7F6 **4.49:1** (already failing)\n * outlined label, dark page #111827 **3.67:1**\n * outlined label, dark card #1F2937 **3.04:1**\n *\n * ⚠️ THIS IS THE SECOND TIME THE SAME MISTAKE HAS BEEN FOUND HERE.\n * `Tabs` defaulted `inactiveBackground` to `gray.100` while\n * labelling it with a token that flips, and four chips measured\n * 1.34:1 on a dark page; that was fixed at source in 0.1.290. The\n * rule it produced — a default that pairs a scale value with a\n * semantic one will be wrong in one mode — was not carried across\n * to this function.\n *\n * ⛔ AND `solid` DOES TWO JOBS, WHICH IS WHY IT NEEDS A PAIR.\n * `Button` uses it as the FILL when solid and as the INK when\n * outlined; `Chip` does the same. A value dark enough for white\n * text is unreadable as ink on a dark page, and vice versa. So\n * the ink follows the mode and `solidText` is the surface behind\n * it, which moves the opposite way:\n *\n * filled light #FFFFFF on #546067 6.47:1\n * filled dark #1F2937 on #D1D5DB 9.96:1\n * outlined light #546067 on #F5F7F6 6.01:1\n * outlined dark #D1D5DB on #111827 12.04:1\n *\n * ⚠️ AND IT DEGRADES RATHER THAN BREAKING. This library ships no\n * default semantic tokens — consumers supply them — so a product\n * without `text-secondary` or `surface` would get the token name\n * back instead of a colour. `pick()` keeps a mode-aware scale\n * step behind each one: still better than today, because the\n * backstop flips even though a scale value normally cannot.\n */\n const isDark = colorMode === 'dark';\n const pick = (token: string, backstop: string) => {\n const value = resolveToken(token);\n return !value || value === token ? resolveToken(backstop) : value;\n };\n const ink = pick('text-secondary', isDark ? 'gray.300' : 'gray.600');\n const ground = pick('surface', isDark ? 'gray.800' : 'gray.50');\n const tint = pick('surface-muted', isDark ? 'gray.700' : 'gray.100');\n return {\n solid: ink,\n solidText: ground,\n bgTint: tint,\n iconFg: ink,\n iconBg: tint,\n text: ink,\n border: ink,\n };\n }\n\n\n // Brand severity: solid/border/iconFg dynamically follow the primary token\n if (severity === 'brand') {\n const primary = resolveToken('primary');\n if (colorMode === 'dark') {\n // Same shade-guard as below: a `solid` with no shade cannot be\n // swapped, and collapsing it would put the text on its own colour.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: primary,\n solidText: resolveSolidText(primary),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: primary,\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: primary,\n };\n }\n return {\n solid: primary,\n solidText: resolveSolidText(primary),\n bgTint: resolveToken(slots.bgTint),\n iconFg: primary,\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: primary,\n };\n }\n\n if (colorMode === 'dark') {\n // `fallbackSlot` is used when `token` carries no shade to swap —\n // see the note above this function.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(resolveToken(slots.solid)),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: resolveToken(slots.border),\n };\n }\n\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(resolveToken(slots.solid)),\n bgTint: resolveToken(slots.bgTint),\n iconFg: resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: resolveToken(slots.border),\n };\n }, [theme.severity, severity, resolveToken, colorMode]);\n}\n\n/**\n * Returns the full resolved map for all severities.\n */\nexport function useAllSeverityColors(): Record<Severity, ResolvedSeverityColors> {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const severities: Severity[] = ['success', 'info', 'warning', 'danger', 'help', 'secondary', 'brand'];\n const result = {} as Record<Severity, ResolvedSeverityColors>;\n const primary = resolveToken('primary');\n\n for (const key of severities) {\n const slots = theme.severity?.[key];\n if (!slots) continue;\n\n const isBrand = key === 'brand';\n const solidText = slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n if (colorMode === 'dark') {\n // Same shade-guard as useSeverityColors — four of the seven\n // default severities carry a raw hex, which cannot be swapped.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: isBrand ? primary : swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n } else {\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: resolveToken(slots.bgTint),\n iconFg: isBrand ? primary : resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n }\n }\n\n return result;\n }, [theme.severity, resolveToken, colorMode]);\n}\n"],"names":[],"mappings":"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"}