Skip to content

Commit

Permalink
add radio group component
Browse files Browse the repository at this point in the history
  • Loading branch information
woylie committed Jan 4, 2024
1 parent 3cc15d7 commit 650fad7
Show file tree
Hide file tree
Showing 4 changed files with 297 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Added

- New component: `Doggo.radio_group/1`.
- New component: `Doggo.tabs/1`.
- Storybook page about modifier classes.
- Mix task `mix dog.modifiers` to list all modifier classes.
Expand Down
129 changes: 129 additions & 0 deletions lib/doggo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3322,6 +3322,135 @@ defmodule Doggo do
"""
end

@doc """
Renders a group of radio buttons, for example for a toolbar.
To render radio buttons within a regular form, use `input/1` with the
`"radio-group"` type instead.
## Example
```heex
<Doggo.radio_group
id="favorite_dog"
name="favorite_dog"
label="Favorite Dog"
options={[
{"Labrador Retriever", "labrador"},
{"German Shepherd", "german_shepherd"},
{"Golden Retriever", "golden_retriever"},
{"French Bulldog", "french_bulldog"},
{"Beagle", "beagle"}
]}
/>
```
## CSS
To target the wrapper, use an attribute selector:
```css
[role="radio-group"] {}
```
"""

@doc type: :form

attr :id, :string, required: true

attr :name, :string,
required: true,
doc: "The `name` attribute for the `input` elements."

attr :label, :string,
default: nil,
doc: """
A accessibility label for the radio group. Set as `aria-label` attribute.
You should ensure that either the `label` or the `labelledby` attribute is
set.
"""

attr :labelledby, :string,
default: nil,
doc: """
The DOM ID of an element that labels this radio group.
Example:
```html
<h3 id="dog-rg-label">Favorite Dog</h3>
<.radio_group labelled_by="dog-rg-label"></.radio_group>
```
You should ensure that either the `label` or the `labelledby` attribute is
set.
"""

attr :options, :list,
required: true,
doc: """
A list of options. It can be given a list values or as a list of
`{label, value}` tuples.
"""

attr :value, :any,
default: nil,
doc: """
The currently selected value, which is compared with the option value to
determine whether a radio button is checked.
"""

attr :class, :any,
default: [],
doc: "Additional CSS classes. Can be a string or a list of strings."

attr :rest, :global, doc: "Any additional HTML attributes."

def radio_group(assigns) do
label = assigns[:label]
labelledby = assigns[:labelledby]

if (label && labelledby) || !(label || labelledby) do
raise """
invalid label attributes for radio_group
Doggo.radio_group requires either 'label' or 'labelledby' set for
accessibility, but not both.
## Examples
With label:
<Doggo.radio_group label="Favorite Dog" ... />
<h3 id="favorite_dog_label">Favorite Dog</h3>
<Doggo.radio_group labelledby="favorite_dog_label" ... />
"""
end

~H"""
<div
id={@id}
role="radiogroup"
aria-label={@label}
aria-labelledby={@labelledby}
class={@class}
{@rest}
>
<.radio
:for={option <- @options}
option={option}
name={@name}
id={@id}
value={@value}
errors={[]}
description={[]}
/>
</div>
"""
end

@doc """
Renders a skeleton loader, a placeholder for content that is in the process of
loading.
Expand Down
26 changes: 26 additions & 0 deletions priv/storybook/components/radio_group.story.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Storybook.Components.RadioGroup do
use PhoenixStorybook.Story, :component

def function, do: &Doggo.radio_group/1

def variations do
[
%Variation{
id: :default,
attributes: %{
id: "favorite_dog_rg",
name: "favorite_dog",
label: "Favorite Dog",
value: "golden_retriever",
options: [
{"Labrador Retriever", "labrador"},
{"German Shepherd", "german_shepherd"},
{"Golden Retriever", "golden_retriever"},
{"French Bulldog", "french_bulldog"},
{"Beagle", "beagle"}
]
}
}
]
end
end
141 changes: 141 additions & 0 deletions test/doggo_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3644,6 +3644,147 @@ defmodule DoggoTest do
end
end

describe "radio_group/1" do
test "with label" do
assigns = %{}

html =
parse_heex(~H"""
<Doggo.radio_group
id="favorite_dog_rg"
name="favorite_dog_name"
label="Favorite Dog"
value="german_shepherd"
options={[
{"Labrador Retriever", "labrador"},
{"German Shepherd", "german_shepherd"}
]}
/>
""")

assert attribute(html, "div:root", "role") == "radiogroup"
assert attribute(html, ":root", "id") == "favorite_dog_rg"
assert attribute(html, ":root", "aria-label") == "Favorite Dog"

input = find_one(html, "label:first-child input")
assert attribute(input, "type") == "radio"
assert attribute(input, "id") == "favorite_dog_rg_labrador"
assert attribute(input, "name") == "favorite_dog_name"
assert attribute(input, "checked") == nil
assert text(html, "label:first-child") == "Labrador Retriever"

input = find_one(html, "label:last-child input")
assert attribute(input, "type") == "radio"
assert attribute(input, "id") == "favorite_dog_rg_german_shepherd"
assert attribute(input, "name") == "favorite_dog_name"
assert attribute(input, "checked") == "checked"
assert text(html, "label:last-child") == "German Shepherd"
end

test "with labelledby" do
assigns = %{}

html =
parse_heex(~H"""
<Doggo.radio_group
id="favorite_dog_rg"
name="favorite_dog"
labelledby="rg-label"
options={[{"Labrador Retriever", "labrador"}]}
/>
""")

assert attribute(html, ":root", "aria-labelledby") == "rg-label"
end

test "raises if both label and labelledby are set" do
error =
assert_raise RuntimeError, fn ->
assigns = %{}

parse_heex(~H"""
<Doggo.radio_group
id="favorite_dog_rg"
name="favorite_dog"
label="Favorite Dog"
labelledby="rg-label"
options={[{"Labrador Retriever", "labrador"}]}
/>
""")
end

assert error.message =~ "invalid label attributes"
end

test "raises if neither label nor labelledby are set" do
error =
assert_raise RuntimeError, fn ->
assigns = %{}

parse_heex(~H"""
<Doggo.radio_group
id="favorite_dog_rg"
name="favorite_dog"
options={[{"Labrador Retriever", "labrador"}]}
/>
""")
end

assert error.message =~ "invalid label attributes"
end

test "with additional class as string" do
assigns = %{}

html =
parse_heex(~H"""
<Doggo.radio_group
id="favorite_dog_rg"
name="favorite_dog"
labelledby="rg-label"
options={[{"Labrador Retriever", "labrador"}]}
class="is-buttons"
/>
""")

assert attribute(html, ":root", "class") == "is-buttons"
end

test "with additional classes as list" do
assigns = %{}

html =
parse_heex(~H"""
<Doggo.radio_group
id="favorite_dog_rg"
name="favorite_dog"
labelledby="rg-label"
options={[{"Labrador Retriever", "labrador"}]}
class={["is-buttons", "is-small"]}
/>
""")

assert attribute(html, ":root", "class") == "is-buttons is-small"
end

test "with global attribute" do
assigns = %{}

html =
parse_heex(~H"""
<Doggo.radio_group
id="favorite_dog_rg"
name="favorite_dog"
labelledby="rg-label"
options={[{"Labrador Retriever", "labrador"}]}
data-test="hi"
/>
""")

assert attribute(html, ":root", "data-test") == "hi"
end
end

describe "skeleton/1" do
test "default" do
assigns = %{}
Expand Down

0 comments on commit 650fad7

Please sign in to comment.