mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
* fix(ui): restore hover feedback and dark-mode variants lost in the token migration PR #37576 mapped hardcoded Tailwind palette classes onto semantic tokens. Two-tone hover pairs collapsed onto a single token, so 116 hover utilities across 49 files became identical to their base class and produced no visible feedback, and in seven files a dark: variant was dropped while its hardcoded light partner survived, leaving those elements stuck light in dark mode. Hover states now follow the alpha-step idiom the shadcn primitives already use (hover:bg-primary/80, hover:bg-success/20): a duplicated hover:text-X or hover:bg-X becomes /80, hover:border-border becomes hover:border-ring, and a duplicate is dropped where another hover utility on the element already carries the change. One transition-colors that no longer animated anything is removed. For the dark-mode gaps, indigo maps onto info and amber onto warning. There is no purple token in globals.css, so the purple sites keep their palette classes and get their dark: partner back. * fix(ui): add an eslint rule that fails a hover: utility identical to its base The token migration collapsed two-tone hover pairs by hand, so nothing catches the next one. `local/no-noop-hover-variant` reads every string literal and template chunk and errors when a `hover:X` sits alongside a bare `X`, which is exactly the shape that renders no hover feedback. It ships at error with no suppression baseline, so the eleven sites that already carried a dead hover before the migration are fixed here too. The rule reads one class string at a time, so a base class supplied by a different ternary branch than its hover partner is left alone: a selected row whose resting colour already matches its hover colour is deliberate, not a bug.
50 lines
2 KiB
TypeScript
50 lines
2 KiB
TypeScript
import { RuleTester } from "eslint";
|
|
import rule from "../../scripts/eslint-rules/no-noop-hover-variant.mjs";
|
|
|
|
const ruleTester = new RuleTester({
|
|
languageOptions: { ecmaVersion: "latest", sourceType: "module" },
|
|
});
|
|
|
|
ruleTester.run("no-noop-hover-variant", rule as never, {
|
|
valid: [
|
|
'const c = "text-info hover:text-info/80";',
|
|
'const c = "bg-success hover:bg-success/80 text-white";',
|
|
'const c = "border-border hover:border-ring";',
|
|
'const c = "text-info hover:underline";',
|
|
'const c = "bg-info/10 hover:bg-info/20";',
|
|
'const c = "hover:bg-muted";',
|
|
'const c = "text-info focus:text-info";',
|
|
"const c = `cursor-pointer hover:bg-info/10 ${isSelected ? 'bg-info/10' : ''}`;",
|
|
"const c = `border-2 ${isSelected ? 'border-info bg-info/10' : 'border-border hover:border-ring'}`;",
|
|
],
|
|
invalid: [
|
|
{
|
|
code: 'const c = "text-info hover:text-info";',
|
|
errors: [{ messageId: "noop", data: { hover: "hover:text-info", base: "text-info" } }],
|
|
},
|
|
{
|
|
code: 'const c = "text-xs bg-success hover:bg-success text-white transition-colors";',
|
|
errors: [{ messageId: "noop", data: { hover: "hover:bg-success", base: "bg-success" } }],
|
|
},
|
|
{
|
|
code: 'const c = "border border-border hover:border-border";',
|
|
errors: [{ messageId: "noop", data: { hover: "hover:border-border", base: "border-border" } }],
|
|
},
|
|
{
|
|
code: 'const c = "text-destructive border-destructive hover:text-destructive hover:border-destructive";',
|
|
errors: [{ messageId: "noop" }, { messageId: "noop" }],
|
|
},
|
|
{
|
|
code: 'const c = "text-info underline hover:underline";',
|
|
errors: [{ messageId: "noop", data: { hover: "hover:underline", base: "underline" } }],
|
|
},
|
|
{
|
|
code: "const c = `text-info hover:text-info ${extra}`;",
|
|
errors: [{ messageId: "noop" }],
|
|
},
|
|
{
|
|
code: "const c = `p-2 ${active ? 'bg-info/15 text-info' : 'text-success hover:text-success'}`;",
|
|
errors: [{ messageId: "noop", data: { hover: "hover:text-success", base: "text-success" } }],
|
|
},
|
|
],
|
|
});
|