From f790d5a6ce32e54f46290e156baefa0500c9f515 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Thu, 30 Jul 2026 00:17:26 -0500 Subject: [PATCH] fix(desktop): stop the checkbox painting the check and dash at once codicon.css styles glyphs through `.codicon[class*='codicon-']`, a two-class selector that outranks Tailwind's single-class `hidden`. The indicator stacks a check and a dash and hides one per state, so neither was ever hidden and the box rendered both glyphs side by side, spilling past its 16px bounds in every state including unchecked. Use the important modifier on both display utilities so state, not stylesheet order, decides which glyph shows. --- .../src/components/ui/checkbox.test.tsx | 62 +++++++++++++++++++ apps/desktop/src/components/ui/checkbox.tsx | 6 +- 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 apps/desktop/src/components/ui/checkbox.test.tsx diff --git a/apps/desktop/src/components/ui/checkbox.test.tsx b/apps/desktop/src/components/ui/checkbox.test.tsx new file mode 100644 index 00000000000..2ed48ea0ac2 --- /dev/null +++ b/apps/desktop/src/components/ui/checkbox.test.tsx @@ -0,0 +1,62 @@ +import { cleanup, render } from '@testing-library/react' +import { afterEach, beforeAll, describe, expect, it } from 'vitest' + +import { Checkbox } from './checkbox' + +/** + * The indicator stacks both glyphs and hides one with a utility class, so the + * cascade — not the markup — decides what the user sees. codicon.css sets + * `display: inline-block` on `.codicon[class*='codicon-']`, which outranks a + * single-class utility and paints the check and the dash at the same time. + * That specificity race is the real contract, so the test carries both + * stylesheets rather than asserting on class strings. Tailwind's nested output + * is flattened to the equivalent descendant selector because jsdom does not + * implement CSS nesting. + */ +const CODICON_CSS = `.codicon[class*='codicon-'] { display: inline-block; }` + +const TAILWIND_CSS = ` + .hidden\\! { display: none !important; } + :where(.group)[data-state="checked"] .group-data-\\[state\\=checked\\]\\:block\\! { + display: block !important; + } + :where(.group)[data-state="indeterminate"] .group-data-\\[state\\=indeterminate\\]\\:block\\! { + display: block !important; + } +` + +function shownGlyphs(container: HTMLElement) { + return [...container.querySelectorAll('.codicon')] + .filter(glyph => getComputedStyle(glyph).display !== 'none') + .map(glyph => (glyph.classList.contains('codicon-check') ? 'check' : 'dash')) +} + +beforeAll(() => { + // eslint-disable-next-line no-restricted-globals -- the cascade is the assertion; it needs a real stylesheet + const style = document.createElement('style') + style.textContent = `${CODICON_CSS}\n${TAILWIND_CSS}` + // eslint-disable-next-line no-restricted-globals -- see above + document.head.append(style) +}) + +afterEach(cleanup) + +describe('Checkbox', () => { + it('paints the check alone when checked', () => { + const { container } = render() + + expect(shownGlyphs(container)).toEqual(['check']) + }) + + it('paints the dash alone when indeterminate', () => { + const { container } = render() + + expect(shownGlyphs(container)).toEqual(['dash']) + }) + + it('paints no glyph when unchecked', () => { + const { container } = render() + + expect(shownGlyphs(container)).toEqual([]) + }) +}) diff --git a/apps/desktop/src/components/ui/checkbox.tsx b/apps/desktop/src/components/ui/checkbox.tsx index 357560fd2cb..31c8e356586 100644 --- a/apps/desktop/src/components/ui/checkbox.tsx +++ b/apps/desktop/src/components/ui/checkbox.tsx @@ -18,8 +18,10 @@ function Checkbox({ className, ...props }: React.ComponentProps - - + {/* codicon.css sets `display: inline-block` at higher specificity than a bare + `hidden`, so both glyphs paint at once without the important modifier. */} + + )