Skip to content

Commit

Permalink
Align action_list_item label with checkbox
Browse files Browse the repository at this point in the history
  • Loading branch information
ArthurClemens committed Jul 9, 2023
1 parent 28645d2 commit 9b8cf74
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 3 deletions.
6 changes: 5 additions & 1 deletion lib/component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,10 @@ defmodule PrimerLive.Component do
end

def action_list_item(assigns) do
%{
input_id: input_id
} = AttributeHelpers.common_input_attrs(assigns, :checkbox)

is_selected = assigns.is_selected
is_form_input = assigns[:form] || assigns[:field]
# Get the first link slot, if any
Expand Down Expand Up @@ -1043,7 +1047,7 @@ defmodule PrimerLive.Component do

attributes =
AttributeHelpers.append_attributes([
[class: classes.content],
[class: classes.content, for: input_id],
!is_nil(is_expanded) &&
["aria-expanded": is_expanded |> Atom.to_string()]
])
Expand Down
1 change: 1 addition & 0 deletions lib/helpers/attribute_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ defmodule PrimerLive.Helpers.AttributeHelpers do
def input_id(_input_id, _id, _input_type, "", _value_for_derived_label), do: nil
def input_id(_input_id, _id, _input_type, input_name, _value_for_derived_label), do: input_name

@spec cleanup_id(nil | binary) :: nil | binary
def cleanup_id(id) when is_nil(id), do: nil

def cleanup_id(id) do
Expand Down
9 changes: 9 additions & 0 deletions lib/test_helpers/todos/todo.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule PrimerLive.TestHelpers.Repo.Todo do
use Ecto.Schema

schema "todos" do
field(:statuses, {:array, :string}, default: [])

timestamps()
end
end
55 changes: 55 additions & 0 deletions lib/test_helpers/todos/todos.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
defmodule PrimerLive.TestHelpers.Repo.Todos do
import Ecto.Changeset, except: [change: 1]
alias PrimerLive.TestHelpers.Repo.Todo

@doc """
Returns an `%Ecto.Changeset{}` for tracking to do item changes.
## Examples
iex> change(to do item)
%Ecto.Changeset{data: %Todo{}}
"""
def change(%Todo{} = todo, attrs \\ %{}) do
todo
|> changeset(attrs)
end

def init() do
change(%Todo{})
end

@status_options [
{"In progress", "in-progress"},
{"Needs review", "needs-review"},
{"Complete", "complete"}
]

def status_options, do: @status_options

@allowed_fields [
:statuses
]

@required_fields [
:statuses
]

defp changeset(todo, attrs) do
todo
|> cast(attrs, @allowed_fields)
|> validate_required(@required_fields)
|> validate_empty(:statuses, "must select a status")
end

defp validate_empty(changeset, field, message) do
values = get_field(changeset, field)

if Enum.empty?(values) do
add_error(changeset, field, message)
else
changeset
end
end
end
6 changes: 4 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ defmodule PrimerLive.MixProject do
defp deps do
[
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:ecto_sql, "~> 3.9"},
{:ecto, "~> 3.10", only: [:dev, :test], runtime: false},
{:ecto_sql, "~> 3.10", only: [:dev, :test], runtime: false},
{:esbuild, "~> 0.7", only: :dev},
{:ex_doc, "~> 0.29", only: :dev},
{:ex_doc, "~> 0.29", only: [:dev, :test], runtime: false},
{:phoenix_ecto, "~> 4.4", only: [:dev, :test], runtime: false},
{:phoenix_html, "~> 3.3"},
{:phoenix_live_view, ">= 0.18.3"},
{:jason, "~> 1.4"}
Expand Down
1 change: 1 addition & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"},
"phoenix": {:hex, :phoenix, "1.7.3", "4d8eca2c020c9ed81a28e7a8c60e0a4f6f9f7f6e12eb91dfd01301eac07424c1", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "6b1bc308758f95ecf3e0d795389440a2ca88a903e0fda1f921c780918c16d640"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.2", "b21bd01fdeffcfe2fab49e4942aa938b6d3e89e93a480d4aee58085560a0bc0d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "70242edd4601d50b69273b057ecf7b684644c19ee750989fd555625ae4ce8f5d"},
"phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.19.0", "de5643d03e3cdf5ff19cd45b5d14543a3b1ad8551d529f6b24246e88a6c6f1b8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a650b6f814c4f386314b98f1aebf92f8652649166612f84ef2e60a20894addfa"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.2", "a4950b63ace57720b0fc1c6da083c53346b36f99021de89595cc4f026288ff51", [:mix], [], "hexpm", "45741676a94c71f9afdfed9d22d49b6856c026ff504db04e3dc03a1d86f8201c"},
Expand Down
105 changes: 105 additions & 0 deletions test/components/action_list_test.exs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
defmodule PrimerLive.TestComponents.ActionListTest do
use ExUnit.Case
use PrimerLive

import PrimerLive.Helpers.TestHelpers

import Phoenix.Component
import Phoenix.LiveViewTest

alias PrimerLive.TestHelpers.Repo.Todos

test "Content slot" do
assigns = %{}

Expand Down Expand Up @@ -113,4 +116,106 @@ defmodule PrimerLive.TestComponents.ActionListTest do
"""
|> format_html()
end

test "With form" do
changeset = Todos.init()
options = Todos.status_options()
values = changeset.changes |> Map.get(:statuses) || []

assigns = %{
changeset: changeset,
options: options,
values: values
}

assert rendered_to_string(~H"""
<.form :let={f} for={@changeset} phx-change="validate" phx-submit="save">
<.action_list is_multiple_select>
<%= for {label, value} <- @options do %>
<.action_list_item
form={f}
field={:statuses}
checked_value={value}
is_selected={value in @values}
>
<%= label %>
</.action_list_item>
<% end %>
</.action_list>
</.form>
""")
|> format_html() ==
"""
<form method="post" phx-change="validate" phx-submit="save">
<ul class="ActionList" role="listbox" aria-multiselectable="true">
<li class="ActionList-item"><label class="ActionList-content" for="todo_statuses_in-progress"><span
class="ActionList-item-label">In progress</span></label></li>
<li class="ActionList-item"><label class="ActionList-content" for="todo_statuses_needs-review"><span
class="ActionList-item-label">Needs review</span></label></li>
<li class="ActionList-item"><label class="ActionList-content" for="todo_statuses_complete"><span
class="ActionList-item-label">Complete</span></label></li>
</ul>
</form>
"""
|> format_html()
end

test "With form, is_multiple_select" do
changeset = Todos.init()
options = Todos.status_options()
values = changeset.changes |> Map.get(:statuses) || []

assigns = %{
changeset: changeset,
options: options,
values: values
}

assert rendered_to_string(~H"""
<.form :let={f} for={@changeset} phx-change="validate" phx-submit="save">
<.action_list is_multiple_select>
<%= for {label, value} <- @options do %>
<.action_list_item
form={f}
field={:statuses}
checked_value={value}
is_multiple_select
is_selected={value in @values}
>
<%= label %>
</.action_list_item>
<% end %>
</.action_list>
</.form>
""")
|> format_html() ==
"""
<form method="post" phx-change="validate" phx-submit="save">
<ul class="ActionList" role="listbox" aria-multiselectable="true">
<li class="ActionList-item" role="option"><label class="ActionList-content" for="todo_statuses_in-progress"><span
class="ActionList-item-visual ActionList-item-visual--leading"><span
class="FormControl-checkbox-wrap pl-invalid ActionList-item-multiSelectIcon"><input name="todo[statuses][]"
type="hidden" value="false" /><input class="FormControl-checkbox" id="todo_statuses_in-progress"
name="todo[statuses][]" type="checkbox" value="in-progress" /></span></span><span
class="ActionList-item-label">In
progress</span></label></li>
<li class="ActionList-item" role="option"><label class="ActionList-content" for="todo_statuses_needs-review"><span
class="ActionList-item-visual ActionList-item-visual--leading"><span
class="FormControl-checkbox-wrap pl-invalid ActionList-item-multiSelectIcon"><input name="todo[statuses][]"
type="hidden" value="false" /><input class="FormControl-checkbox" id="todo_statuses_needs-review"
name="todo[statuses][]" type="checkbox" value="needs-review" /></span></span><span
class="ActionList-item-label">Needs
review</span></label></li>
<li class="ActionList-item" role="option"><label class="ActionList-content" for="todo_statuses_complete"><span
class="ActionList-item-visual ActionList-item-visual--leading"><span
class="FormControl-checkbox-wrap pl-invalid ActionList-item-multiSelectIcon"><input name="todo[statuses][]"
type="hidden" value="false" /><input class="FormControl-checkbox" id="todo_statuses_complete"
name="todo[statuses][]" type="checkbox" value="complete" /></span></span><span
class="ActionList-item-label">Complete</span></label>
</li>
</ul>
</form>
"""
|> format_html()
end
end
1 change: 1 addition & 0 deletions test/components/radio_button_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ defmodule PrimerLive.TestComponents.RadioButtonTest do
valid?: true
}
}

test "Called without options or inner_block: should render the component" do
assigns = %{}

Expand Down

0 comments on commit 9b8cf74

Please sign in to comment.