@@ -47,6 +47,7 @@ defmodule PeekAppSDK.UI.Odyssey.ToggleButton do
4747 attr ( :selected , :string , required: false , doc: "the currently selected option (not needed when using field)" )
4848 attr ( :on_change , :string , required: false , doc: "event name to fire on change (not needed when using field)" )
4949 attr ( :field , Phoenix.HTML.FormField , required: false , doc: "optional form field for automatic form integration" )
50+ attr ( :label , :string , required: false , doc: "optional label to wrap the toggle button in a fieldset" )
5051 attr ( :phx_target , :any , required: false , doc: "optional phx-target for LiveComponent integration" )
5152 attr ( :rest , :global )
5253
@@ -66,10 +67,47 @@ defmodule PeekAppSDK.UI.Odyssey.ToggleButton do
6667
6768 # Standalone mode - regular component without form integration
6869 def odyssey_toggle_button ( assigns ) do
69- assigns = assign_new ( assigns , :phx_target , fn -> nil end )
70+ assigns =
71+ assigns
72+ |> assign_new ( :phx_target , fn -> nil end )
73+ |> assign_new ( :label , fn -> nil end )
7074
7175 ~H"""
72- < div class = "inline-flex rounded-lg " role = "group " >
76+ < fieldset :if = { @ label } class = "fieldset mb-2 " >
77+ < label >
78+ < span class = "label mb-1 " > { @ label } </ span >
79+ < div class = "inline-flex rounded-lg " role = "group " >
80+ < button
81+ :for = { { option , index } <- Enum . with_index ( @ options ) }
82+ type = "button "
83+ value = { to_string ( option_value ( option ) ) }
84+ phx-click = { @ on_change }
85+ phx-target = { @ phx_target }
86+ class = {
87+ [
88+ "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium transition-colors border border-gray-200" ,
89+ # Rounded corners only on first and last buttons
90+ index == 0 && "rounded-l-lg" ,
91+ index == length ( @ options ) - 1 && "rounded-r-lg" ,
92+ # Remove left border on all buttons except the first to avoid double borders
93+ index > 0 && "-ml-px" ,
94+ to_string ( @ selected ) == to_string ( option_value ( option ) ) &&
95+ "bg-gray-50 text-blue-600 z-10 relative" ,
96+ to_string ( @ selected ) != to_string ( option_value ( option ) ) &&
97+ "bg-white text-gray-600 hover:text-gray-900 cursor-pointer"
98+ ]
99+ }
100+ { @ rest }
101+ >
102+ <%= if option_icon ( option ) do %>
103+ < . odyssey_icon name = { option_icon ( option ) } class = "size-4 " />
104+ <% end %>
105+ { option_text ( option ) }
106+ </ button >
107+ </ div >
108+ </ label >
109+ </ fieldset >
110+ < div :if = { ! @ label } class = "inline-flex rounded-lg " role = "group " >
73111 < button
74112 :for = { { option , index } <- Enum . with_index ( @ options ) }
75113 type = "button "
0 commit comments