diff --git a/audit/component_map/toggle_group.yml b/audit/component_map/toggle_group.yml new file mode 100644 index 000000000..57e25cf2b --- /dev/null +++ b/audit/component_map/toggle_group.yml @@ -0,0 +1,36 @@ +shadcn: toggle-group +shadcn_sha: 8a3536678a528cc012b9e62484290e79d0be410f +kind: form_control +docs_view: toggle_group +parts: + ToggleGroup: toggle-group + ToggleGroupItem: toggle-group-item +selectors: + ToggleGroup: '[data-slot="toggle-group"]' + ToggleGroupItem: '[data-slot="toggle-group-item"]' +props: + # shadcn's own props (variant, size, spacing, orientation) + Base UI ToggleGroup.Props. + ToggleGroup: + variant: variant + size: size + spacing: spacing + orientation: orientation + multiple: type + # Base UI defaultValue is always an array; RubyUI value is a scalar for type: :single + # and an array for :multiple. + defaultValue: value + value: null + onValueChange: null + disabled: disabled + loopFocus: loop_focus + # shadcn's variant/size + Base UI Toggle.Props. + ToggleGroupItem: + variant: variant + size: size + value: value + disabled: disabled # item kwarg reaches Toggle and overrides the group value + pressed: null + defaultPressed: null + onPressedChange: null +rubyui_only: + ToggleGroup: [name] diff --git a/audit/divergences/toggle_group.yml b/audit/divergences/toggle_group.yml new file mode 100644 index 000000000..fc951ee56 --- /dev/null +++ b/audit/divergences/toggle_group.yml @@ -0,0 +1,12 @@ +- component: toggle_group + dimension: Behavior + rubyui: "With a selection, Tab enters the group on the first pressed item" + shadcn: "Base UI makes the first item the tab stop whatever is pressed" + reason: "Landing on the current choice tells keyboard users the group's value at once and saves arrow presses; with no selection both enter on the first item." + since: "2026-11-04" +- component: toggle_group + dimension: Props + rubyui: "value sets the initial state; the state reaches forms through hidden inputs (name)" + shadcn: "value/onValueChange, and pressed/defaultPressed/onPressedChange on items (controlled React state)" + reason: "Server-rendered Phlex has no controlled state or JS callbacks; listen to clicks on the items or read the hidden inputs." + since: "2026-11-04" diff --git a/audit/fixtures/toggle_group/content.yml b/audit/fixtures/toggle_group/content.yml new file mode 100644 index 000000000..667e2e021 --- /dev/null +++ b/audit/fixtures/toggle_group/content.yml @@ -0,0 +1,12 @@ +# Four groups, same strings and options on both sides: +# - Alignment: single, outline, spacing 0 (joined), nothing pressed. data-audit-trigger +# sits on Left: with no selection both libraries make the first item the tab stop +# (with a selection RubyUI picks the pressed item, Base UI the first one). +# - Formatting: multiple, default variant, spacing 1, Bold pressed. +# - Size: single, vertical, outline, size sm, spacing 0, Medium pressed. +# - Range: multiple, outline, spacing 2, whole group disabled. +groups: [Alignment, Formatting, Size, Range] +alignment: [Left, Center, Right] +formatting: [Bold, Italic, Underline] +size: [Small, Medium, Large] +range: [Day, Week] diff --git a/audit/fixtures/toggle_group/rubyui.rb b/audit/fixtures/toggle_group/rubyui.rb new file mode 100644 index 000000000..850557b8e --- /dev/null +++ b/audit/fixtures/toggle_group/rubyui.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module ShadcnAuditFixtures + # RubyUI side of audit/fixtures/toggle_group (strings in content.yml). + class ToggleGroup < Phlex::HTML + include RubyUI + + def view_template + div(id: "toggle-group-fixture", class: "flex flex-col items-start gap-6") do + ToggleGroup(type: :single, name: "alignment", variant: :outline, spacing: 0, aria: {label: "Alignment"}) do |g| + g.ToggleGroupItem(value: "left", data: {audit_trigger: true}) { "Left" } + g.ToggleGroupItem(value: "center") { "Center" } + g.ToggleGroupItem(value: "right") { "Right" } + end + ToggleGroup(type: :multiple, name: "formatting", value: %w[bold], spacing: 1, aria: {label: "Formatting"}) do |g| + g.ToggleGroupItem(value: "bold") { "Bold" } + g.ToggleGroupItem(value: "italic") { "Italic" } + g.ToggleGroupItem(value: "underline") { "Underline" } + end + ToggleGroup(type: :single, name: "size", value: "medium", variant: :outline, size: :sm, spacing: 0, orientation: :vertical, aria: {label: "Size"}) do |g| + g.ToggleGroupItem(value: "small") { "Small" } + g.ToggleGroupItem(value: "medium") { "Medium" } + g.ToggleGroupItem(value: "large") { "Large" } + end + ToggleGroup(type: :multiple, name: "range", variant: :outline, spacing: 2, disabled: true, aria: {label: "Range"}) do |g| + g.ToggleGroupItem(value: "day") { "Day" } + g.ToggleGroupItem(value: "week") { "Week" } + end + end + end + end +end diff --git a/audit/fixtures/toggle_group/shadcn.tsx b/audit/fixtures/toggle_group/shadcn.tsx new file mode 100644 index 000000000..5708ce851 --- /dev/null +++ b/audit/fixtures/toggle_group/shadcn.tsx @@ -0,0 +1,27 @@ +import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group" + +export default function ToggleGroupFixture() { + return ( +