mirror of
https://github.com/we-promise/sure.git
synced 2026-06-08 12:19:03 +00:00
feat(ds): DS::SegmentedControl — fix invisible dark selected pill (#2145)
* feat(ds): DS::SegmentedControl; fix invisible dark selected pill (#2137) Ships DS::SegmentedControl — a single-select pill group (filters, mode switches) — plus a Lookbook preview, tests, and an exemplar migration of the budget filter tabs. The audit flagged the dark selected pill as invisible: the bespoke controls paired a container-inset track (gray-800) with a gray-700 active pill, barely a step apart. The primitive uses the DS tab-token values (tab-bg-group -> a near-black alpha-black-700 track in dark), against which the gray-700 active pill clearly reads. Values are inlined with @variant theme-dark because @apply-ing the custom tab utilities drops their dark override. - app/components/DS/segmented_control.rb: slot-based with_segment(label, active:, href:, **opts); link or button; full_width: for equal footprint; selected style isolated in .segmented-control__segment--active so a controller can toggle it as one class. - .segmented-control recipe in components.css. - Migrate budgets/_budget_tabs; budget_filter_controller now toggles the single --active class instead of five raw utility classes. Verified in-browser: dark active pill reads (gray-700 on near-black track); filter toggle still works. Tests + rubocop clean. Deferred (follow-up): auth sign-in/up switch, transaction-type tabs, and other bespoke segmented controls — same primitive, one migration each. * fix(a11y): expose segmented-control selection + derive active from filter param - DS::SegmentedControl: set aria-current (links) / aria-pressed (buttons) from the segment's active state so screen readers announce the selection. - budget_filter_controller: mirror aria-pressed when it toggles the active class. - _budget_tabs: compute each segment's initial active: from params[:filter] so a ?filter=over_budget request server-renders the correct pill (no flash before Stimulus runs). Addresses CodeRabbit reviews on #2145. * fix(ds): close unterminated segmented-control CSS rule The --active rule swallowed the table-scroll block's comment opener and never closed, so the Tailwind build died with 'Missing closing } at @layer components' and both test jobs failed at boot. Restore the closing brace and the /* opener. Also add the budgets.show.filter.aria_label locale key the budget tabs view referenced only through its inline default. --------- Signed-off-by: Juan José Mata <juanjo.mata@gmail.com> Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
This commit is contained in:
committed by
GitHub
parent
f7be206c55
commit
0fe81cefe6
51
test/components/DS/segmented_control_test.rb
Normal file
51
test/components/DS/segmented_control_test.rb
Normal file
@@ -0,0 +1,51 @@
|
||||
require "test_helper"
|
||||
|
||||
class DS::SegmentedControlTest < ViewComponent::TestCase
|
||||
test "renders segments as buttons by default with the base + active classes" do
|
||||
render_inline(DS::SegmentedControl.new) do |sc|
|
||||
sc.with_segment("All", active: true)
|
||||
sc.with_segment("Over Budget")
|
||||
end
|
||||
|
||||
assert_selector "div.segmented-control[role=group]"
|
||||
assert_selector "button.segmented-control__segment", count: 2
|
||||
assert_selector "button.segmented-control__segment--active", text: "All", count: 1
|
||||
refute_selector "button.segmented-control__segment--active", text: "Over Budget"
|
||||
end
|
||||
|
||||
test "href renders a segment as a link" do
|
||||
render_inline(DS::SegmentedControl.new) do |sc|
|
||||
sc.with_segment("Sign in", href: "/login", active: true)
|
||||
sc.with_segment("Sign up", href: "/join")
|
||||
end
|
||||
|
||||
assert_selector "a.segmented-control__segment--active[href='/login']", text: "Sign in"
|
||||
assert_selector "a.segmented-control__segment[href='/join']", text: "Sign up"
|
||||
end
|
||||
|
||||
test "full_width stretches the track and each segment" do
|
||||
render_inline(DS::SegmentedControl.new(full_width: true)) do |sc|
|
||||
sc.with_segment("One", active: true)
|
||||
sc.with_segment("Two")
|
||||
end
|
||||
|
||||
assert_selector "div.segmented-control.w-full"
|
||||
assert_selector "button.segmented-control__segment.flex-1", count: 2
|
||||
end
|
||||
|
||||
test "aria_label and passthrough attrs land on the wrapper" do
|
||||
render_inline(DS::SegmentedControl.new(aria_label: "Filter", data: { controller: "x" })) do |sc|
|
||||
sc.with_segment("A", active: true)
|
||||
end
|
||||
|
||||
assert_selector "div.segmented-control[aria-label='Filter'][data-controller='x']"
|
||||
end
|
||||
|
||||
test "per-segment passthrough class and data merge onto the segment" do
|
||||
render_inline(DS::SegmentedControl.new) do |sc|
|
||||
sc.with_segment("A", active: true, class: "custom-x", data: { id: "a" })
|
||||
end
|
||||
|
||||
assert_selector "button.segmented-control__segment--active.custom-x[data-id='a']"
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user