@lmb-it/kitsconcerto-native 0.1.291 → 0.1.292
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.
|
@@ -9,17 +9,56 @@ function useSeverityColors(severity) {
|
|
|
9
9
|
return React.useMemo(() => {
|
|
10
10
|
const slots = theme.severity?.[severity] ?? theme.severity?.secondary;
|
|
11
11
|
if (!slots) {
|
|
12
|
-
const
|
|
13
|
-
|
|
12
|
+
const isDark = colorMode === "dark";
|
|
13
|
+
const pick = (token, backstop) => {
|
|
14
|
+
const value = resolveToken(token);
|
|
15
|
+
return !value || value === token ? resolveToken(backstop) : value;
|
|
16
|
+
};
|
|
17
|
+
const ink = pick("text-secondary", isDark ? "gray.300" : "gray.600");
|
|
18
|
+
const ground = pick("surface", isDark ? "gray.800" : "gray.50");
|
|
19
|
+
const tint = pick("surface-muted", isDark ? "gray.700" : "gray.100");
|
|
20
|
+
return {
|
|
21
|
+
solid: ink,
|
|
22
|
+
solidText: ground,
|
|
23
|
+
bgTint: tint,
|
|
24
|
+
iconFg: ink,
|
|
25
|
+
iconBg: tint,
|
|
26
|
+
text: ink,
|
|
27
|
+
border: ink
|
|
28
|
+
};
|
|
14
29
|
}
|
|
15
|
-
const
|
|
30
|
+
const relativeLuminance = (css) => {
|
|
31
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(css.trim());
|
|
32
|
+
if (!m) return null;
|
|
33
|
+
const channel = (v) => v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
34
|
+
const [r, g, b] = [0, 2, 4].map(
|
|
35
|
+
(i) => channel(parseInt(m[1].substr(i, 2), 16) / 255)
|
|
36
|
+
);
|
|
37
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
38
|
+
};
|
|
39
|
+
const whiteOn = (fill) => {
|
|
40
|
+
const l = relativeLuminance(fill);
|
|
41
|
+
return l === null ? null : 1.05 / (l + 0.05);
|
|
42
|
+
};
|
|
43
|
+
const resolveSolidText = (fill) => {
|
|
44
|
+
if (slots.solidText) return resolveToken(slots.solidText);
|
|
45
|
+
const ratio = fill ? whiteOn(fill) : null;
|
|
46
|
+
if (ratio !== null && ratio < 4.5) {
|
|
47
|
+
const ink = resolveToken("text-inverse");
|
|
48
|
+
if (ink && ink !== "text-inverse") return ink;
|
|
49
|
+
const surface = resolveToken("surface");
|
|
50
|
+
if (surface && surface !== "surface") return surface;
|
|
51
|
+
return resolveToken("gray.900");
|
|
52
|
+
}
|
|
53
|
+
return WHITE;
|
|
54
|
+
};
|
|
16
55
|
if (severity === "brand") {
|
|
17
56
|
const primary = resolveToken("primary");
|
|
18
57
|
if (colorMode === "dark") {
|
|
19
58
|
const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
|
|
20
59
|
return {
|
|
21
60
|
solid: primary,
|
|
22
|
-
solidText: resolveSolidText(),
|
|
61
|
+
solidText: resolveSolidText(primary),
|
|
23
62
|
bgTint: swapShade(slots.solid, "900", slots.bgTint),
|
|
24
63
|
iconFg: primary,
|
|
25
64
|
iconBg: swapShade(slots.solid, "800", slots.iconBg),
|
|
@@ -29,7 +68,7 @@ function useSeverityColors(severity) {
|
|
|
29
68
|
}
|
|
30
69
|
return {
|
|
31
70
|
solid: primary,
|
|
32
|
-
solidText: resolveSolidText(),
|
|
71
|
+
solidText: resolveSolidText(primary),
|
|
33
72
|
bgTint: resolveToken(slots.bgTint),
|
|
34
73
|
iconFg: primary,
|
|
35
74
|
iconBg: resolveToken(slots.iconBg),
|
|
@@ -41,7 +80,7 @@ function useSeverityColors(severity) {
|
|
|
41
80
|
const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
|
|
42
81
|
return {
|
|
43
82
|
solid: resolveToken(slots.solid),
|
|
44
|
-
solidText: resolveSolidText(),
|
|
83
|
+
solidText: resolveSolidText(resolveToken(slots.solid)),
|
|
45
84
|
bgTint: swapShade(slots.solid, "900", slots.bgTint),
|
|
46
85
|
iconFg: swapShade(slots.solid, "300", slots.iconFg),
|
|
47
86
|
iconBg: swapShade(slots.solid, "800", slots.iconBg),
|
|
@@ -51,7 +90,7 @@ function useSeverityColors(severity) {
|
|
|
51
90
|
}
|
|
52
91
|
return {
|
|
53
92
|
solid: resolveToken(slots.solid),
|
|
54
|
-
solidText: resolveSolidText(),
|
|
93
|
+
solidText: resolveSolidText(resolveToken(slots.solid)),
|
|
55
94
|
bgTint: resolveToken(slots.bgTint),
|
|
56
95
|
iconFg: resolveToken(slots.iconFg),
|
|
57
96
|
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 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 * ⛔ 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 // 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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"}
|
|
@@ -7,17 +7,56 @@ function useSeverityColors(severity) {
|
|
|
7
7
|
return useMemo(() => {
|
|
8
8
|
const slots = theme.severity?.[severity] ?? theme.severity?.secondary;
|
|
9
9
|
if (!slots) {
|
|
10
|
-
const
|
|
11
|
-
|
|
10
|
+
const isDark = colorMode === "dark";
|
|
11
|
+
const pick = (token, backstop) => {
|
|
12
|
+
const value = resolveToken(token);
|
|
13
|
+
return !value || value === token ? resolveToken(backstop) : value;
|
|
14
|
+
};
|
|
15
|
+
const ink = pick("text-secondary", isDark ? "gray.300" : "gray.600");
|
|
16
|
+
const ground = pick("surface", isDark ? "gray.800" : "gray.50");
|
|
17
|
+
const tint = pick("surface-muted", isDark ? "gray.700" : "gray.100");
|
|
18
|
+
return {
|
|
19
|
+
solid: ink,
|
|
20
|
+
solidText: ground,
|
|
21
|
+
bgTint: tint,
|
|
22
|
+
iconFg: ink,
|
|
23
|
+
iconBg: tint,
|
|
24
|
+
text: ink,
|
|
25
|
+
border: ink
|
|
26
|
+
};
|
|
12
27
|
}
|
|
13
|
-
const
|
|
28
|
+
const relativeLuminance = (css) => {
|
|
29
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(css.trim());
|
|
30
|
+
if (!m) return null;
|
|
31
|
+
const channel = (v) => v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
32
|
+
const [r, g, b] = [0, 2, 4].map(
|
|
33
|
+
(i) => channel(parseInt(m[1].substr(i, 2), 16) / 255)
|
|
34
|
+
);
|
|
35
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
36
|
+
};
|
|
37
|
+
const whiteOn = (fill) => {
|
|
38
|
+
const l = relativeLuminance(fill);
|
|
39
|
+
return l === null ? null : 1.05 / (l + 0.05);
|
|
40
|
+
};
|
|
41
|
+
const resolveSolidText = (fill) => {
|
|
42
|
+
if (slots.solidText) return resolveToken(slots.solidText);
|
|
43
|
+
const ratio = fill ? whiteOn(fill) : null;
|
|
44
|
+
if (ratio !== null && ratio < 4.5) {
|
|
45
|
+
const ink = resolveToken("text-inverse");
|
|
46
|
+
if (ink && ink !== "text-inverse") return ink;
|
|
47
|
+
const surface = resolveToken("surface");
|
|
48
|
+
if (surface && surface !== "surface") return surface;
|
|
49
|
+
return resolveToken("gray.900");
|
|
50
|
+
}
|
|
51
|
+
return WHITE;
|
|
52
|
+
};
|
|
14
53
|
if (severity === "brand") {
|
|
15
54
|
const primary = resolveToken("primary");
|
|
16
55
|
if (colorMode === "dark") {
|
|
17
56
|
const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
|
|
18
57
|
return {
|
|
19
58
|
solid: primary,
|
|
20
|
-
solidText: resolveSolidText(),
|
|
59
|
+
solidText: resolveSolidText(primary),
|
|
21
60
|
bgTint: swapShade(slots.solid, "900", slots.bgTint),
|
|
22
61
|
iconFg: primary,
|
|
23
62
|
iconBg: swapShade(slots.solid, "800", slots.iconBg),
|
|
@@ -27,7 +66,7 @@ function useSeverityColors(severity) {
|
|
|
27
66
|
}
|
|
28
67
|
return {
|
|
29
68
|
solid: primary,
|
|
30
|
-
solidText: resolveSolidText(),
|
|
69
|
+
solidText: resolveSolidText(primary),
|
|
31
70
|
bgTint: resolveToken(slots.bgTint),
|
|
32
71
|
iconFg: primary,
|
|
33
72
|
iconBg: resolveToken(slots.iconBg),
|
|
@@ -39,7 +78,7 @@ function useSeverityColors(severity) {
|
|
|
39
78
|
const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
|
|
40
79
|
return {
|
|
41
80
|
solid: resolveToken(slots.solid),
|
|
42
|
-
solidText: resolveSolidText(),
|
|
81
|
+
solidText: resolveSolidText(resolveToken(slots.solid)),
|
|
43
82
|
bgTint: swapShade(slots.solid, "900", slots.bgTint),
|
|
44
83
|
iconFg: swapShade(slots.solid, "300", slots.iconFg),
|
|
45
84
|
iconBg: swapShade(slots.solid, "800", slots.iconBg),
|
|
@@ -49,7 +88,7 @@ function useSeverityColors(severity) {
|
|
|
49
88
|
}
|
|
50
89
|
return {
|
|
51
90
|
solid: resolveToken(slots.solid),
|
|
52
|
-
solidText: resolveSolidText(),
|
|
91
|
+
solidText: resolveSolidText(resolveToken(slots.solid)),
|
|
53
92
|
bgTint: resolveToken(slots.bgTint),
|
|
54
93
|
iconFg: resolveToken(slots.iconFg),
|
|
55
94
|
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 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 * ⛔ 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 // 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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"}
|