From dd79faf14fd7f6eb3a3b9dd03f3529f396cdcdf7 Mon Sep 17 00:00:00 2001 From: A-PachecoT Date: Sat, 22 Aug 2026 09:37:55 -0500 Subject: [PATCH] fix(button,badge): la tinta de la variante de marca se deriva, no se fija MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `variant="default"` pintaba `bg-[var(--primary)] text-white`. El relleno es reasignable por la app que consume el paquete —Fovente lo ata al color que el cliente elige en Ajustes → Marca— y la tinta era una constante, así que sobre un relleno claro el rótulo desaparecía. Medido en el DOM vivo de Fovente (Chromium, ratio compuesto sobre el fondo real apilado): · tema oscuro, marca por defecto: blanco sobre #D98D7D = 2.61:1 ✗ AA · tema claro, marca amarilla: blanco sobre #F2C230 = 1.68:1 ✗ AA `--primary-foreground` ya existe en `styles/index.css` y vale `#ffffff` en los dos temas, así que para quien no lo reasigne (TimelyAI, Landing) esto no mueve un píxel: el par sigue siendo exactamente el mismo. Para quien sí lo reasigne, la tinta pasa a seguir al relleno. Las demás variantes conservan `text-white` a propósito: `--secondary`, `--destructive` y las de estado/canal son colores FIJOS del sistema, no de marca, y su par ya está verificado. El test lo afirma explícitamente para que un barrido de `text-white` no se lleve puesta esa distinción. `brand-ink-derives.test.tsx` se escribió contra la versión rota primero y falló ahí (2 de 3), con el control de no-vacuidad en verde. Nota: `ChatInput.test.tsx` falla en `main` desde antes de este cambio — reproducido sobre el árbol limpio. Ref: cofoundy/inbox-ai#617 --- .../components/brand-ink-derives.test.tsx | 45 +++++++++++++++++++ src/components/ui/badge.tsx | 6 ++- src/components/ui/button.tsx | 10 ++++- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 src/__tests__/components/brand-ink-derives.test.tsx diff --git a/src/__tests__/components/brand-ink-derives.test.tsx b/src/__tests__/components/brand-ink-derives.test.tsx new file mode 100644 index 0000000..3c10162 --- /dev/null +++ b/src/__tests__/components/brand-ink-derives.test.tsx @@ -0,0 +1,45 @@ +import { describe, it, expect } from "vitest"; +import { buttonVariants } from "../../components/ui/button"; +import { badgeVariants } from "../../components/ui/badge"; + +/** + * La tinta de una variante de MARCA se deriva; no se fija. + * + * `--primary` es reasignable por la app que consume el paquete. Fovente lo ata + * al color que el cliente elige en Ajustes → Marca, así que un `text-white` + * clavado acá deja el relleno variable y la tinta constante — y sobre un + * relleno claro el rótulo desaparece. Medido en el DOM vivo de Fovente antes + * del arreglo: **1.68:1** con una marca amarilla, **2.61:1** en tema oscuro con + * la marca por defecto. → inbox-ai#617 + * + * Este test se escribió contra la versión ROTA primero y falló ahí; si alguna + * vez pasa sobre un `text-white` reintroducido, es este test el que está mal. + * + * Las OTRAS variantes conservan `text-white` a propósito y el test lo afirma: + * sus rellenos (`--secondary`, `--destructive`, los de estado y canal) son + * colores FIJOS del sistema, no de marca, y su par ya está verificado. Sin esa + * mitad, el test premiaría con verde a quien borre todos los `text-white`. + */ +describe("la tinta de las variantes de marca se deriva del relleno", () => { + it("Button variant=default toma la tinta de --primary-foreground, no de un literal", () => { + const cls = buttonVariants({ variant: "default" }); + expect(cls).toContain("bg-[var(--primary)]"); + expect(cls).toContain("text-[var(--primary-foreground)]"); + expect(cls).not.toContain("text-white"); + }); + + it("Badge variant=default idem", () => { + const cls = badgeVariants({ variant: "default" }); + expect(cls).toContain("bg-[var(--primary)]"); + expect(cls).toContain("text-[var(--primary-foreground)]"); + expect(cls).not.toContain("text-white"); + }); + + it("las variantes de relleno FIJO sí conservan su tinta literal", () => { + // Control de no-vacuidad: si esto se pusiera verde con todo el paquete + // vaciado de `text-white`, las dos aserciones de arriba no probarían nada. + expect(buttonVariants({ variant: "destructive" })).toContain("text-white"); + expect(buttonVariants({ variant: "secondary" })).toContain("text-white"); + expect(badgeVariants({ variant: "destructive" })).toContain("text-white"); + }); +}); diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx index e75847e..0d0fd6a 100644 --- a/src/components/ui/badge.tsx +++ b/src/components/ui/badge.tsx @@ -9,8 +9,12 @@ const badgeVariants = cva( { variants: { variant: { + // Mismo motivo que en `button.tsx`: `--primary` es reasignable por la app + // (Fovente lo ata al color del tenant), así que la tinta se deriva de él. + // Las demás variantes conservan `text-white` a propósito — sus rellenos + // son colores FIJOS del sistema, no de marca. → inbox-ai#617 default: - "border-transparent bg-[var(--primary)] text-white [a&]:hover:bg-[var(--primary)]/90", + "border-transparent bg-[var(--primary)] text-[var(--primary-foreground)] [a&]:hover:bg-[var(--primary)]/90", secondary: "border-transparent bg-[var(--secondary)] text-white [a&]:hover:bg-[var(--secondary)]/90", destructive: diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index d4ecf28..f6a49d4 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -9,7 +9,15 @@ const buttonVariants = cva( { variants: { variant: { - default: "bg-[var(--primary)] text-white hover:bg-[var(--primary)]/90", + // La tinta se DERIVA del relleno, no se fija. `--primary` es el color de + // marca y una app puede reasignarlo (Fovente lo ata al color del tenant), + // así que un `text-white` clavado acá deja el relleno variable y la tinta + // constante: sobre un relleno claro el rótulo desaparece. Medido en el DOM + // vivo de Fovente, tema oscuro: blanco sobre #D98D7D = 2.61:1, reprueba AA + // en TODA acción primaria de la app. `--primary-foreground` ya existe en + // `styles/index.css` y vale `#ffffff` en los dos temas, así que para quien + // no lo reasigne (TimelyAI, Landing) esto no mueve un píxel. → inbox-ai#617 + default: "bg-[var(--primary)] text-[var(--primary-foreground)] hover:bg-[var(--primary)]/90", destructive: "bg-[var(--destructive)] text-white hover:bg-[var(--destructive)]/90", outline: "border border-[var(--border)] bg-transparent text-[var(--foreground)] shadow-xs hover:bg-[var(--accent)]",