Module: Basecoat::FormHelper
- Defined in:
- lib/basecoat/form_helper.rb
Instance Method Summary collapse
-
#basecoat_country_select_tag(name, options = {}) ⇒ Object
Renders a country select component with flag emojis.
-
#basecoat_remote_search_tag(url, options = {}) ⇒ Object
Renders a remote search component with Turbo Stream support.
-
#basecoat_select_tag(name, choices, options = {}) ⇒ Object
Renders a select component outside of a form context.
Instance Method Details
#basecoat_country_select_tag(name, options = {}) ⇒ Object
Renders a country select component with flag emojis.
Parameters
name- The name attribute for the hidden input field (required)-
options- Hash of optional parameters::selected- The initially selected country code (e.g., "US"):countries- Array of country codes to include (defaults to all countries):priority- Array of priority country codes to show at the top:except- Array of country codes to exclude- All other basecoat_select_tag options (placeholder, scrollable, etc.)
Examples
<%= basecoat_country_select_tag :country %> <%= basecoat_country_select_tag :country, selected: "US" %> <%= basecoat_country_select_tag :country, priority: ["US", "CA", "GB"] %> <%= basecoat_country_select_tag :country, countries: ["US", "CA", "MX"] %>
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/basecoat/form_helper.rb', line 120 def basecoat_country_select_tag(name, = {}) require 'countries' # Extract country-specific options country_codes = .delete(:countries) priority_codes = .delete(:priority) || [] except_codes = .delete(:except) || [] # Get all countries or filtered list all_countries = if country_codes country_codes.map { |code| ISO3166::Country[code] }.compact else ISO3166::Country.all end # Remove excluded countries all_countries.reject! { |country| except_codes.include?(country.alpha2) } if except_codes.any? # Build choices with flag emoji choices = all_countries.map do |country| ["#{country.emoji_flag} #{country.iso_short_name}", country.alpha2] end # Sort alphabetically by country name choices.sort_by! { |label, _| label } # Add priority countries at the top if priority_codes.any? priority_choices = priority_codes.map do |code| country = ISO3166::Country[code] next unless country ["#{country.emoji_flag} #{country.iso_short_name}", country.alpha2] end.compact choices.reject! { |_, code| priority_codes.include?(code) } choices = priority_choices + [["---", nil]] + choices end # Update selected_label if a country is selected if [:selected] country = ISO3166::Country[[:selected]] [:selected_label] = "#{country.emoji_flag} #{country.iso_short_name}" if country end # Set defaults [:placeholder] ||= "Search countries..." [:group_label] ||= "Countries" [:scrollable] = true unless .key?(:scrollable) basecoat_select_tag(name, choices, ) rescue LoadError content_tag :div, class: "alert", "data-variant": "destructive" do lucide_icon("circle-alert") + tag.section("gem 'countries' required") end end |
#basecoat_remote_search_tag(url, options = {}) ⇒ Object
Renders a remote search component with Turbo Stream support.
Parameters
url- The URL to fetch search results from (required)-
options- Hash of optional parameters::turbo_frame- Custom turbo frame name (defaults to underscored URL):placeholder- Custom placeholder text (defaults to "Type a command or search..."):data_empty- Message shown when no results found (defaults to "No results found."):classes- Additional CSS classes to apply to the component
Examples
<%= basecoat_remote_search_tag("/posts/search") %> <%= basecoat_remote_search_tag("/posts/search", turbo_frame: "custom_frame") %> <%= basecoat_remote_search_tag("/posts/search", placeholder: "Search posts...", classes: "rounded-lg border shadow-md") %>
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/basecoat/form_helper.rb', line 18 def basecoat_remote_search_tag(url, = {}) turbo_frame = [:turbo_frame] || url.gsub("/", "_") placeholder = [:placeholder] || "Type a command or search..." data_empty = [:data_empty] || "No results found." classes = [:classes] || "" search_id = "search-#{SecureRandom.random_number(1000000)}" content_tag(:div, id: search_id, data: { controller: "search", search_url_value: url }, class: "command #{classes}", "aria-label": "Command menu") do content_tag(:header) do lucide_icon("search").html_safe + tag(:input, type: "search", id: "#{search_id}-input", placeholder: placeholder, autocomplete: "off", autocorrect: "off", spellcheck: "false", "aria-autocomplete": "list", role: "combobox", "aria-expanded": "true", "aria-controls": "#{search_id}-menu", data: { search_target: "input", action: "input->search#search" } ) end + content_tag(:div, role: "menu", id: "#{search_id}-menu", "aria-orientation": "vertical", data: { empty: data_empty }, class: "scrollbar") do turbo_frame_tag(turbo_frame) end end end |
#basecoat_select_tag(name, choices, options = {}) ⇒ Object
Renders a select component outside of a form context.
Parameters
name- The name attribute for the hidden input field (required)choices- Array of [label, value] pairs for select options (required)-
options- Hash of optional parameters::selected- The initially selected value (defaults to first choice):group_label- Label for the option group (defaults to titleized and pluralized name):placeholder- Placeholder text for the search input (defaults to "Search entries..."):url- URL for remote search via Turbo Stream:turbo_frame- Custom turbo frame name when using:url(defaults to underscored URL):scrollable- Whether to make the listbox scrollable with max height (defaults to false)
Examples
<%= basecoat_select_tag "fruit", [["Apple", 1], ["Pear", 2]] %> <%= basecoat_select_tag "fruit", [["Apple", 1], ["Pear", 2]], selected: 2, placeholder: "Search fruits..." %> <%= basecoat_select_tag "fruit", [], url: "/fruits/search", turbo_frame: "custom_frame", scrollable: true %>
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/basecoat/form_helper.rb', line 69 def basecoat_select_tag(name, choices, = {}) select_id = "select-#{SecureRandom.random_number(1000000)}" url = [:url] if url || choices.empty? selected_value = [:selected] selected_label = [:selected_label] || "Select..." else selected_value = [:selected] || choices.first[1] selected_choice = choices.find { |label, val| val.to_s == selected_value.to_s } selected_label = selected_choice ? selected_choice[0] : choices.first[0] end group_label = [:group_label] || name.to_s.titleize.pluralize placeholder = [:placeholder] || "Search entries..." scrollable = [:scrollable] || false turbo_frame = [:turbo_frame] || (url ? url.gsub("/", "_") : nil) select_attrs = { id: select_id, class: "combobox" } if url select_attrs[:data] = { controller: "search", search_url_value: url, filter: "manual" # filtering happens server-side, tell basecoat not to filter } end content_tag(:div, select_attrs) do (select_id, selected_label) + basecoat_select_popover(select_id, choices, group_label, placeholder, selected_value, url, scrollable, turbo_frame) + tag(:input, type: "hidden", name: name, value: selected_value) end end |