Modal
Are you sure, you don't want it to be another page instead?
bin/rails g quicksilver_ui:component Modal
Default
render UI::Modal.new(heading: "Title", text: "Qui in quis Lorem velit esse tempor laboris enim id sint commodo Lorem. Magna voluptate dolore ex elit anim. Aliqua fugiat qui incididunt incididunt sit deserunt mollit labore eiusmod elit officia est nisi. Elit est nostrud ut adipisicing ex esse aliquip incididunt minim ad ex sit. Ut aliqua adipisicing esse reprehenderit sit sit incididunt duis consectetur ad. Laborum ea consectetur pariatur aliqua sit cupidatat pariatur consectetur aute reprehenderit eiusmod veniam. Laboris deserunt consequat occaecat enim eiusmod et aliquip minim.") do |modal|
modal.trigger(class: "ui-button") do
"Pop pop!"
end
modal.footer do
div(class: "flex justify-between") do
button(class: "ui-button") { "Button #3" }
div(class: "flex gap-x-3") do
button(class: "ui-button") { "Button #1" }
button(class: "ui-button ui-button-primary") { "Button #2" }
end
end
end
end
With yielded content
render UI::Modal.new(heading: "Title") do |modal|
modal.trigger(class: "ui-button") do
"Pop pop!"
end
render UI::Alert.new(
icon: "exclamation-triangle",
heading: "You can render anything here",
description: "Like other components",
variant: :warning
)
p { "Or just plain HTML" }
end
Not backdrop closeable
render UI::Modal.new(heading: "Title", text: "Qui in quis Lorem velit esse tempor laboris enim id sint commodo Lorem. Magna voluptate dolore ex elit anim. Aliqua fugiat qui incididunt incididunt sit deserunt mollit labore eiusmod elit officia est nisi. Elit est nostrud ut adipisicing ex esse aliquip incididunt minim ad ex sit. Ut aliqua adipisicing esse reprehenderit sit sit incididunt duis consectetur ad. Laborum ea consectetur pariatur aliqua sit cupidatat pariatur consectetur aute reprehenderit eiusmod veniam. Laboris deserunt consequat occaecat enim eiusmod et aliquip minim.", backdrop_closeable: false) do |modal|
modal.trigger(class: "ui-button") do
"Pop pop!"
end
end
Implementation
# frozen_string_literal: true
class UI::Modal < UI::Base
prop :open, _Boolean, default: false, reader: :private
prop :heading, String, reader: :private
prop :text, _Nilable(String), reader: :private
prop :backdrop_closeable, _Boolean, default: true, reader: :private
def initialize(**props)
super
@trigger_block = nil
@footer_block = nil
end
def view_template(&block)
vanish(&block) if block_given?
div data: {controller: "modal", modal_open_value: open}.merge(backdrop_closeable_attributes) do
dialog(data: {modal_target: "dialog"}, class: classes) do
div(class: "ui-modal-body") do
div(class: "flex justify-between items-start") do
render_heading
render_close_trigger
end
render_text
yield
end
render_footer
end
render_trigger
end
end
def trigger(class: nil, &block)
@trigger_block = block
@trigger_classes = grab(class:)
nil
end
def footer(class: nil, &block)
@footer_block = block
@footer_classes = grab(class:)
nil
end
private
def render_close_trigger
button(data: {action: "modal#close"}, class: "cursor-pointer hover:text-gray-700") do
render UI::Icon.new(name: :x_mark)
end
end
def render_heading
h2(class: "ui-display-md") { heading }
end
def render_text
p(class: "ui-text-md") { text }
end
def render_footer
return if @footer_block.nil?
div(class: footer_classes) do
@footer_block.call
end
end
def render_trigger
button(class: @trigger_classes, data: {action: "modal#open"}) do
@trigger_block.call
end
end
def backdrop_closeable_attributes
return {action: "click->modal#backdropClose"} if backdrop_closeable?
{}
end
def backdrop_closeable?
backdrop_closeable
end
def default_classes
"ui-modal"
end
def footer_classes
TAILWIND_MERGER.merge ["ui-modal-footer", @footer_classes].join(" ")
end
end