Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/live_ui/lib/live_ui/renderer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1705,6 +1705,7 @@ defmodule LiveUi.Renderer do
value: value,
label: Map.get(option, :label, Map.get(option, "label", "")),
disabled?: disabled?,
count: Map.get(option, :count, Map.get(option, "count")),
attrs: segmented_button_group_option_attrs(element, event_target, value, disabled?)
}
end)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ defmodule LiveUi.Widgets.SegmentedButtonGroup do
{option_attrs(option)}
>
{option_label(option)}
<span
:if={option_count(option) != nil}
class="live-ui-segmented-button-group-option-count"
aria-hidden="true"
>{option_count(option)}</span>
</button>
</div>
"""
Expand All @@ -56,6 +61,7 @@ defmodule LiveUi.Widgets.SegmentedButtonGroup do
defp option_value(option), do: fetch_option(option, :value)
defp option_label(option), do: fetch_option(option, :label, "")
defp option_attrs(option), do: fetch_option(option, :attrs, %{})
defp option_count(option), do: fetch_option(option, :count)

defp option_disabled?(option) do
fetch_option(option, :disabled?) || fetch_option(option, :disabled) || false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,83 @@ defmodule LiveUi.Widgets.SegmentedButtonGroupTest do
assert metadata.mountable?
end
end

describe "count badge" do
test "option with count renders count badge span" do
html =
render_component(&SegmentedButtonGroup.component/1, %{
id: "test-sbg",
options: [
%{value: "adrs", label: "ADRs", count: 12},
%{value: "specs", label: "Specs", count: 8}
],
label: "Document type"
})

assert html =~ ~s(class="live-ui-segmented-button-group-option-count")
assert html =~ "12"
assert html =~ "8"
end

test "count badge has aria-hidden=true" do
html =
render_component(&SegmentedButtonGroup.component/1, %{
id: "test-sbg",
options: [%{value: "a", label: "All", count: 5}],
label: "Test group"
})

assert html =~ ~s(aria-hidden="true")
end

test "option without count does not render count badge span" do
html =
render_component(&SegmentedButtonGroup.component/1, %{
id: "test-sbg",
options: @options,
label: "Test group"
})

refute html =~ ~s(live-ui-segmented-button-group-option-count)
end

test "option with count nil does not render count badge span" do
html =
render_component(&SegmentedButtonGroup.component/1, %{
id: "test-sbg",
options: [%{value: "a", label: "Option A", count: nil}],
label: "Test group"
})

refute html =~ ~s(live-ui-segmented-button-group-option-count)
end

test "count of zero renders a badge with '0'" do
html =
render_component(&SegmentedButtonGroup.component/1, %{
id: "test-sbg",
options: [%{value: "plans", label: "Plans", count: 0}],
label: "Test group"
})

assert html =~ ~s(live-ui-segmented-button-group-option-count)
assert html =~ ">0<"
end

test "mixed options: some with count, some without" do
html =
render_component(&SegmentedButtonGroup.component/1, %{
id: "test-sbg",
options: [
%{value: "adrs", label: "ADRs", count: 12},
%{value: "specs", label: "Specs"}
],
label: "Document type"
})

assert html =~ "12"
assert html =~ "ADRs"
assert html =~ "Specs"
end
end
end
10 changes: 10 additions & 0 deletions packages/unified_iur/lib/unified_iur/widgets/components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -851,9 +851,19 @@ defmodule UnifiedIUR.Widgets.Components do
|> maybe_put(:value, option(option_value, :value))
|> maybe_put(:label, option(option_value, :label))
|> maybe_put(:disabled?, option(option_value, :disabled?))
|> maybe_put(:count, normalize_option_count(option(option_value, :count)))
end)
end

defp normalize_option_count(nil), do: nil

defp normalize_option_count(count) when is_integer(count) and count >= 0, do: count

defp normalize_option_count(count) do
raise ArgumentError,
"option :count must be a non-negative integer or nil, got: #{inspect(count)}"
end

defp normalize_maps(values) when is_list(values) do
Enum.map(values, &normalize_map/1)
end
Expand Down
55 changes: 55 additions & 0 deletions packages/unified_iur/test/unified_iur/widgets/components_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -379,4 +379,59 @@ defmodule UnifiedIUR.Widgets.ComponentsTest do

assert [%{slot: :default, element: %Element{id: :sources_body, kind: :text}}] = rail.children
end

describe "segmented_button_group count prop" do
test "passes count through to normalized options when present" do
element =
Components.segmented_button_group(
[
%{value: :adrs, label: "ADRs", count: 12},
%{value: :specs, label: "Specs", count: 8},
%{value: :plans, label: "Plans"}
],
active_value: :adrs
)

[adrs, specs, plans] = element.attributes.selection.options

assert adrs == %{value: :adrs, label: "ADRs", count: 12}
assert specs == %{value: :specs, label: "Specs", count: 8}
# no count key when absent (maybe_put drops nil)
refute Map.has_key?(plans, :count)
end

test "count of zero is preserved in normalized options" do
element =
Components.segmented_button_group([%{value: :empty, label: "Empty", count: 0}])

[opt] = element.attributes.selection.options
assert opt.count == 0
end

test "explicit count nil is omitted from normalized options" do
element =
Components.segmented_button_group([%{value: :a, label: "A", count: nil}])

[opt] = element.attributes.selection.options
refute Map.has_key?(opt, :count)
end

test "negative count raises ArgumentError" do
assert_raise ArgumentError, ~r/non-negative integer/, fn ->
Components.segmented_button_group([%{value: :a, label: "A", count: -1}])
end
end

test "non-integer count raises ArgumentError" do
assert_raise ArgumentError, ~r/non-negative integer/, fn ->
Components.segmented_button_group([%{value: :a, label: "A", count: "12"}])
end
end

test "float count raises ArgumentError" do
assert_raise ArgumentError, ~r/non-negative integer/, fn ->
Components.segmented_button_group([%{value: :a, label: "A", count: 3.5}])
end
end
end
end
Loading