Module: Layered::Ui::ModalHelper
- Defined in:
- app/helpers/layered/ui/modal_helper.rb
Defined Under Namespace
Classes: ModalBuilder
Instance Method Summary collapse
-
#l_ui_modal(title:, id: nil, heading_level: :h3, container: {}, &block) ⇒ Object
Renders a modal as a <dialog> wired up to the
l-ui--modalStimulus controller.
Instance Method Details
#l_ui_modal(title:, id: nil, heading_level: :h3, container: {}, &block) ⇒ Object
Renders a modal as a <dialog> wired up to the l-ui--modal Stimulus controller. The block’s content is the modal body; call m.trigger to render a colocated trigger button.
<%= l_ui_modal(title: "Socials") do |m| %>
<% m.trigger(class: "l-ui-button l-ui-button--outline") do %>
Open socials
<% end %>
<p>Body content.</p>
<% end %>
To open the modal from elsewhere on the page (or to have multiple triggers), give it a known id: and add data-l-ui-modal-open=“<id>” to any button. The button does not need to live inside the helper’s wrapper; the l-ui--modal controller listens at the document level for matching clicks.
<button type="button" data-l-ui-modal-open="confirm-modal">Open</button>
Calling dialog.showModal() directly is not supported: it bypasses the l-ui--modal controller and skips scroll lock, focus restoration, open- count tracking, and the screen-reader announcement.
Note: use <% m.trigger %> (without the equals sign) so its content is captured by the builder rather than written to the body buffer.
Options:
title: (String) Required. Modal heading; also used for aria-labelledby.
id: (String) DOM id for the <dialog>; defaults to an auto-generated id.
heading_level: (Symbol) Heading tag for the title (e.g. :h2, :h3). Defaults to :h3.
container: (Hash) Extra HTML attributes for the wrapping <div>.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'app/helpers/layered/ui/modal_helper.rb', line 35 def l_ui_modal(title:, id: nil, heading_level: :h3, container: {}, &block) id ||= "l-ui-modal-#{SecureRandom.hex(4)}" builder = ModalBuilder.new(self, title: title, id: id, heading_level: heading_level) body_content = capture { block.call(builder) } container_attrs = container.deep_dup container_data = container_attrs[:data] || {} existing_controller = container_data.delete(:controller) || container_data.delete("controller") container_data[:controller] = [existing_controller, "l-ui--modal"].compact.reject(&:empty?).join(" ") container_attrs[:data] = container_data tag.div(**container_attrs) do safe_join([ builder.trigger_html || ActiveSupport::SafeBuffer.new, render_modal_dialog(builder, body_content) ]) end end |