Revert "feat(ui): support icon-only segmented controls"

This reverts commit 2e05fcf524.
This commit is contained in:
teknium1
2026-09-18 23:50:35 -07:00
committed by Teknium
parent 8bd0da2b8c
commit 086628ad8a
3 changed files with 4 additions and 64 deletions

View File

@@ -231,8 +231,7 @@ blurred backdrop.
Empty lists hide their search field.
- **`SegmentedControl`** — the choice control for small mutually-exclusive sets
(color mode, tool-call display, usage period). Replaces radio piles and
pill rows. `iconOnly` renders compact icon buttons with label tooltips and
accessible names; use `codiconIcon()` for Codicon options.
pill rows.
- **`Switch`** (`size="xs"`) — bare, with `aria-label`. No bordered text wrapper.
- **`FanMenu`** (`src/components/ui/fan-menu.tsx`) — one hub control that
fans sibling toggles out on hover: `direction` `vertical` | `horizontal`

View File

@@ -1,51 +0,0 @@
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { codiconIcon } from './codicon'
import { SegmentedControl } from './segmented-control'
const options = [
{ id: 'list', label: 'List view', icon: codiconIcon('list-unordered') },
{ id: 'cards', label: 'Card view', icon: codiconIcon('extensions') }
]
afterEach(cleanup)
describe('SegmentedControl', () => {
it('preserves visible labels by default', () => {
render(<SegmentedControl onChange={vi.fn()} options={options} value="cards" />)
expect(screen.getByRole('button', { name: 'Card view', pressed: true }).textContent).toBe('Card view')
expect(screen.getByRole('button', { name: 'List view', pressed: false }).textContent).toBe('List view')
})
it('keeps accessible labels and selection behavior for icon-only controls', () => {
const onChange = vi.fn()
render(<SegmentedControl iconOnly onChange={onChange} options={options} value="cards" />)
const list = screen.getByRole('button', { name: 'List view', pressed: false })
const cards = screen.getByRole('button', { name: 'Card view', pressed: true })
expect(list.textContent).toBe('')
expect(cards.textContent).toBe('')
expect(list.querySelector('.codicon-list-unordered')).not.toBeNull()
expect(cards.querySelector('.codicon-extensions')).not.toBeNull()
fireEvent.click(list)
expect(onChange).toHaveBeenCalledExactlyOnceWith('list')
})
it('retains a visible label when an icon-only option has no icon', () => {
render(<SegmentedControl iconOnly onChange={vi.fn()} options={[{ id: 'list', label: 'List view' }]} value="list" />)
expect(screen.getByRole('button', { name: 'List view' }).textContent).toBe('List view')
})
it('does not change a disabled icon-only control', () => {
const onChange = vi.fn()
render(<SegmentedControl disabled iconOnly onChange={onChange} options={options} value="cards" />)
const list = screen.getByRole<HTMLButtonElement>('button', { name: 'List view' })
expect(list.disabled).toBe(true)
fireEvent.click(list)
expect(onChange).not.toHaveBeenCalled()
})
})

View File

@@ -1,4 +1,3 @@
import { Tip } from '@/components/ui/tooltip'
import type { IconComponent } from '@/lib/icons'
import { cn } from '@/lib/utils'
@@ -13,8 +12,6 @@ interface SegmentedControlProps<T extends string> {
value: T
onChange: (id: T) => void
className?: string
/** Icon buttons retain localized labels for tooltips and screen readers. */
iconOnly?: boolean
/** Dims the whole track and blocks selection (e.g. gated behind a prerequisite). */
disabled?: boolean
}
@@ -27,7 +24,6 @@ interface SegmentedControlProps<T extends string> {
export function SegmentedControl<T extends string>({
className,
disabled = false,
iconOnly = false,
onChange,
options,
value
@@ -43,14 +39,12 @@ export function SegmentedControl<T extends string>({
{options.map(({ id, label, icon: Icon }) => {
const active = value === id
const button = (
return (
<button
aria-label={iconOnly ? label : undefined}
aria-pressed={active}
className={cn(
'flex items-center justify-center gap-1 rounded-[3px] px-2.5 py-0.5 text-[0.6875rem] font-medium transition-colors disabled:cursor-default',
active ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground',
iconOnly && Icon && 'size-6 p-0 text-sm'
active ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'
)}
disabled={disabled}
key={id}
@@ -58,11 +52,9 @@ export function SegmentedControl<T extends string>({
type="button"
>
{Icon && <Icon className="size-3" />}
{(!iconOnly || !Icon) && label}
{label}
</button>
)
return iconOnly && Icon ? <Tip key={id} label={label}>{button}</Tip> : button
})}
</div>
)