From 970ea21f35549c509c63ea8ef45512ec5d0f7aab Mon Sep 17 00:00:00 2001 From: PAMulligan Date: Mon, 24 Aug 2026 20:34:10 -0400 Subject: [PATCH] fix(ui): stop tailwind-merge from dropping text colors on custom font-size tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The design system's fontSize tokens (text-button, text-body, ...) are unknown to tailwind-merge's default config, so they fell into the text-color group and cancelled real color classes in the same cn() call — the primary Button lost text-brand-fg to text-button, rendering dark inherited ink on the indigo background. Extend twMerge with the custom font-size class group so size and color merge independently. Fixes #62 Co-Authored-By: Claude Fable 5 --- app/src/lib/utils.ts | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/app/src/lib/utils.ts b/app/src/lib/utils.ts index a5ef193..13530a0 100644 --- a/app/src/lib/utils.ts +++ b/app/src/lib/utils.ts @@ -1,5 +1,33 @@ import { clsx, type ClassValue } from "clsx"; -import { twMerge } from "tailwind-merge"; +import { extendTailwindMerge } from "tailwind-merge"; + +// tailwind-merge only knows Tailwind's stock scale, so the design system's +// fontSize tokens (text-button, text-body, …) fall through to the text-color +// group and cancel real color classes in the same cn() call — e.g. text-button +// silently dropped text-brand-fg from the primary Button (#62). Declaring them +// as font-size classes keeps size and color merging independently. +const twMerge = extendTailwindMerge({ + extend: { + classGroups: { + "font-size": [ + { + text: [ + "display", + "h1", + "h2", + "body", + "body-semibold", + "body-16", + "body-12", + "button", + "label", + "caption", + ], + }, + ], + }, + }, +}); export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs));