diff --git a/lib/live_select.ex b/lib/live_select.ex
index 4385fcc..75d19ae 100644
--- a/lib/live_select.ex
+++ b/lib/live_select.ex
@@ -418,6 +418,11 @@ defmodule LiveSelect do
doc:
~s(if `true`, the current list of selectable options and the content of the input text field are preserved upon selection)
+ attr :keep_label_on_select, :boolean,
+ default: Component.default_opts()[:keep_label_on_select],
+ doc:
+ ~s(if `true`, when in single mode, the input text field is preserved to the active label upon selection.)
+
attr :value, :any, doc: "used to manually set a selection - overrides any values from the form.
Must be a single element in `:single` mode, or a list of elements in `:tags` mode."
diff --git a/lib/live_select/component.ex b/lib/live_select/component.ex
index c08e452..9cadd07 100644
--- a/lib/live_select/component.ex
+++ b/lib/live_select/component.ex
@@ -20,6 +20,7 @@ defmodule LiveSelect.Component do
clear_tag_button_class: nil,
clear_tag_button_extra_class: nil,
keep_options_on_select: false,
+ keep_label_on_select: false,
current_text: "",
user_defined_options: false,
container_class: nil,
@@ -218,12 +219,25 @@ defmodule LiveSelect.Component do
@impl true
def handle_event(event, _params, socket) when event in ~w(focus click) do
+ keep_label_on_select =
+ socket.assigns.keep_label_on_select &&
+ socket.assigns.mode == :single &&
+ socket.assigns.selection != []
+
+ display_text =
+ if keep_label_on_select do
+ List.first(socket.assigns.selection).label
+ else
+ socket.assigns.current_text
+ end
+
socket =
socket
+ |> assign(current_text: if(keep_label_on_select, do: "", else: socket.assigns.current_text))
|> client_select(%{
input_event: false,
parent_event: socket.assigns[:"phx-focus"],
- current_text: socket.assigns.current_text
+ current_text: display_text
})
|> assign(hide_dropdown: false)
@@ -542,8 +556,8 @@ defmodule LiveSelect.Component do
defp clear(socket, params) do
socket
- |> assign(selection: [])
- |> client_select(params)
+ |> assign(selection: [], current_text: "")
+ |> client_select(Map.put(params, :current_text, ""))
end
defp clear_options(socket) do
diff --git a/lib/support/live_select_web/live/showcase_live.ex b/lib/support/live_select_web/live/showcase_live.ex
index cf49fa7..c5571e0 100644
--- a/lib/support/live_select_web/live/showcase_live.ex
+++ b/lib/support/live_select_web/live/showcase_live.ex
@@ -76,6 +76,10 @@ defmodule LiveSelectWeb.ShowcaseLive do
default: Component.default_opts()[:keep_options_on_select]
)
+ field(:keep_label_on_select, :boolean,
+ default: Component.default_opts()[:keep_label_on_select]
+ )
+
field(:mode, Ecto.Enum,
values: [:single, :tags, :quick_tags],
default: Component.default_opts()[:mode]
@@ -106,6 +110,7 @@ defmodule LiveSelectWeb.ShowcaseLive do
:disabled,
:options_styled_as_checkboxes,
:keep_options_on_select,
+ :keep_label_on_select,
:max_selectable,
:user_defined_options,
:mode,
@@ -145,7 +150,8 @@ defmodule LiveSelectWeb.ShowcaseLive do
(remove_defaults && value == Keyword.get(default_opts, option)) ||
(settings.mode == :single && option == :max_selectable) ||
(settings.mode != :single && option == :allow_clear) ||
- (settings.mode == :quick_tags && option == :keep_options_on_select)
+ (settings.mode == :quick_tags && option == :keep_options_on_select) ||
+ (settings.mode != :single && option == :keep_label_on_select)
end)
|> Keyword.new()
end
diff --git a/lib/support/live_select_web/live/showcase_live.html.heex b/lib/support/live_select_web/live/showcase_live.html.heex
index d1f9ef7..25a9581 100644
--- a/lib/support/live_select_web/live/showcase_live.html.heex
+++ b/lib/support/live_select_web/live/showcase_live.html.heex
@@ -74,6 +74,13 @@
disabled: to_string(@settings_form[:mode].value) == "quick_tags"
)}
+
<%= label class: "label cursor-pointer" do %>
Disabled:
{checkbox(@settings_form, :disabled, class: "toggle")}
diff --git a/test/live_select_test.exs b/test/live_select_test.exs
index ab55024..d508d2d 100644
--- a/test/live_select_test.exs
+++ b/test/live_select_test.exs
@@ -1213,4 +1213,92 @@ defmodule LiveSelectTest do
refute_selected(live)
end
+
+ describe "when keep_label_on_select = true" do
+ setup %{conn: conn} do
+ stub_options(A: 1, B: 2, C: 3)
+
+ {:ok, live, _html} = live(conn, "/?keep_label_on_select=true")
+
+ type(live, "ABC")
+ select_nth_option(live, 2)
+ assert_selected(live, :B, 2)
+
+ %{live: live}
+ end
+
+ test "on focus, the text input displays the selected label", %{live: live} do
+ element(live, selectors()[:text_input])
+ |> render_focus()
+
+ assert_set_text_field(live, :B)
+ end
+
+ test "on click, the text input displays the selected label", %{live: live} do
+ element(live, selectors()[:text_input])
+ |> render_click()
+
+ assert_set_text_field(live, :B)
+ end
+
+ test "on blur, the text input is restored to the selected label", %{live: live} do
+ element(live, selectors()[:text_input])
+ |> render_focus()
+
+ element(live, selectors()[:text_input])
+ |> render_blur()
+
+ assert_set_text_field(live, :B)
+ end
+
+ test "blur then focus cycle preserves the selected label", %{live: live} do
+ element(live, selectors()[:text_input])
+ |> render_blur()
+
+ assert_set_text_field(live, :B)
+
+ element(live, selectors()[:text_input])
+ |> render_focus()
+
+ assert_set_text_field(live, :B)
+
+ element(live, selectors()[:text_input])
+ |> render_blur()
+
+ assert_selected_static(live, :B, 2)
+ end
+
+ test "without a selection, focus behaves as default", %{conn: conn} do
+ stub_options(A: 1, B: 2, C: 3)
+
+ {:ok, live, _html} = live(conn, "/?keep_label_on_select=true")
+
+ type(live, "ABC")
+
+ element(live, selectors()[:text_input])
+ |> render_focus()
+
+ assert_set_text_field(live, "ABC")
+ end
+
+ test "phx-focus parent_event fires normally on focus", %{conn: conn} do
+ stub_options(A: 1, B: 2, C: 3)
+
+ {:ok, live, _html} =
+ live(conn, "/?keep_label_on_select=true&phx-focus=focus-event-for-parent")
+
+ type(live, "ABC")
+ select_nth_option(live, 2)
+ assert_selected(live, :B, 2)
+
+ element(live, selectors()[:text_input])
+ |> render_focus()
+
+ assert_push_event(live, "select", %{
+ id: "my_form_city_search_live_select_component",
+ current_text: :B,
+ parent_event: "focus-event-for-parent"
+ })
+ end
+ end
end