Skip to content

feat: ToggleGroup/ToggleGroupItem compound component (binary-toggle refactor)#288

Open
maxnoller wants to merge 2 commits intomainfrom
feat/toggle-group-component
Open

feat: ToggleGroup/ToggleGroupItem compound component (binary-toggle refactor)#288
maxnoller wants to merge 2 commits intomainfrom
feat/toggle-group-component

Conversation

@maxnoller
Copy link
Copy Markdown
Member

Summary

Replaces the hand-rolled SegmentedToggle / BooleanToggle / BooleanField stack with a clean ToggleGroup + ToggleGroupItem primitive modelled after the shadcn/Radix compound-component pattern.

Old pattern

SegmentedToggle rendered a <fieldset class="binary-toggle"> directly, applying active-state purely through CSS class names (active is-on / active is-off). No shared context, no data-state attribute, no size variant.

New component

console/src/components/ui/toggle-group.tsx

Feature Detail
Structure <ToggleGroup> root + <ToggleGroupItem> children (shadcn/Radix compound pattern)
Root element <fieldset> — carries implicit role="group", biome-compliant semantic HTML
value / onValueChange shadcn naming, on the root
Context ToggleGroupContext wires value, onValueChange, disabled, size from root to items
data-state "on" / "off" on every item, matching Radix behaviour exactly
aria-pressed Preserved on each item for backward compat and correct button semantics
size prop "sm" / "default" on root; .toggle-group--sm reduces padding for dense table rows
activeTone Preserved on items — 'is-on' (success green) / 'is-off' (muted grey)
CSS Existing .binary-toggle / .binary-toggle-button classes retained; additive [data-state="on"] selectors added alongside the existing .active.is-on / .active.is-off rules

Existing wrappers updated

  • SegmentedToggle → thin wrapper around ToggleGroup + ToggleGroupItem (options-array convenience API unchanged)
  • BooleanToggle → gains size prop, forwards to SegmentedToggleToggleGroup
  • BooleanField — no change needed (always form/default size)

Pages updated

Page Change
Channels BooleanFieldBooleanToggleSegmentedToggleToggleGroup (17 toggles, automatic)
Config Same chain (2 toggles, automatic)
Scheduler Same chain (1 toggle + BooleanPill unchanged)
Sessions BooleanPill only — read-only display, no change
Skills Same chain for form toggles; table row toggle gets size="sm" explicitly

No behaviour changes

All existing CSS classes, visual styling, aria-pressed semantics, and onChange APIs are preserved. The only observable difference is data-state on toggle items and the Skills table toggle being slightly smaller.

…le stack

Introduces a compound-component ToggleGroup + ToggleGroupItem following
shadcn/Radix naming and API conventions (context-based, value + onValueChange,
data-state on every item):

- New file console/src/components/ui/toggle-group.tsx exports ToggleGroup
  (root, <fieldset> with implicit role=group) and ToggleGroupItem (<button
  aria-pressed>) with React context wiring so size/disabled flow from root
  to items without prop-drilling.
- data-state="on"/"off" on every item, mirroring Radix behaviour; CSS
  selectors added in styles.css alongside the existing .active.is-on/is-off
  rules to provide a data-attribute hook for future transitions.
- size prop ("sm" | "default") on ToggleGroup; .toggle-group--sm reduces
  padding for dense table rows.
- SegmentedToggle and BooleanToggle are now thin wrappers that delegate to
  ToggleGroup/ToggleGroupItem; BooleanToggle gains and forwards size prop.
- ToggleGroup/ToggleGroupItem re-exported from ui.tsx for a single import
  path.
- Skills table toggle gains size="sm" for compact display in table rows.
- No behaviour changes; all existing CSS classes, active-state visual
  styling, and aria-pressed semantics are preserved.
- Use cx() from lib/cx instead of hand-rolled class string concatenation
- Remove size from ToggleGroupContextValue: items never read it; the size
  class is applied on the fieldset in ToggleGroup itself
- Wrap context value in useMemo to avoid unnecessary re-renders of all
  ToggleGroupItems when the parent re-renders with unchanged props
- Consolidate export+import in ui.tsx to import + export {} (single source)
@maxnoller
Copy link
Copy Markdown
Member Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant