diff --git a/gem/lib/ruby_ui/dialog/dialog_content.rb b/gem/lib/ruby_ui/dialog/dialog_content.rb index d6df40b06..5ed38a0e5 100644 --- a/gem/lib/ruby_ui/dialog/dialog_content.rb +++ b/gem/lib/ruby_ui/dialog/dialog_content.rb @@ -17,14 +17,9 @@ def initialize(size: :md, **attrs) end def view_template - template(data: {ruby_ui__dialog_target: "content"}) do - div(data_controller: "ruby-ui--dialog") do - backdrop - div(**attrs) do - yield - close_button - end - end + dialog(**attrs) do + yield + close_button end end @@ -32,9 +27,10 @@ def view_template def default_attrs { - data_state: "open", + data_ruby_ui__dialog_target: "dialog", + data_action: "click->ruby-ui--dialog#backdropClick", class: [ - "fixed flex flex-col pointer-events-auto left-[50%] top-[50%] z-50 w-full max-h-screen overflow-y-auto translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:rounded-lg md:w-full", + "fixed flex flex-col pointer-events-auto left-[50%] top-[50%] z-50 w-full max-h-screen overflow-y-auto translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 backdrop:bg-background/80 backdrop:backdrop-blur-sm open:animate-in open:fade-in-0 open:zoom-in-95 sm:rounded-lg md:w-full", SIZES[@size] ] } @@ -43,7 +39,7 @@ def default_attrs def close_button button( type: "button", - class: "absolute end-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", + class: "absolute end-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", data_action: "click->ruby-ui--dialog#dismiss" ) do svg( @@ -65,13 +61,5 @@ def close_button span(class: "sr-only") { "Close" } end end - - def backdrop - div( - data_state: "open", - data_action: "click->ruby-ui--dialog#dismiss esc->ruby-ui--dialog#dismiss", - class: "fixed pointer-events-auto inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=open]:fade-in-0" - ) - end end end diff --git a/gem/lib/ruby_ui/dialog/dialog_controller.js b/gem/lib/ruby_ui/dialog/dialog_controller.js index 26bf1fa00..7b7e368cc 100644 --- a/gem/lib/ruby_ui/dialog/dialog_controller.js +++ b/gem/lib/ruby_ui/dialog/dialog_controller.js @@ -1,8 +1,8 @@ import { Controller } from "@hotwired/stimulus" -// Connects to data-controller="dialog" +// Connects to data-controller="ruby-ui--dialog" export default class extends Controller { - static targets = ["content"] + static targets = ["dialog"] static values = { open: { type: Boolean, @@ -11,22 +11,34 @@ export default class extends Controller { } connect() { + this.dialogTarget.addEventListener("close", this.handleClose) if (this.openValue) { this.open() } } + disconnect() { + this.dialogTarget.removeEventListener("close", this.handleClose) + document.body.classList.remove("overflow-hidden") + } + open(e) { - e?.preventDefault(); - document.body.insertAdjacentHTML('beforeend', this.contentTarget.innerHTML) - // prevent scroll on body - document.body.classList.add('overflow-hidden') + e?.preventDefault() + this.dialogTarget.showModal() + document.body.classList.add("overflow-hidden") } dismiss() { - // allow scroll on body - document.body.classList.remove('overflow-hidden') - // remove the element - this.element.remove() + this.dialogTarget.close() + } + + backdropClick(e) { + if (e.target === this.dialogTarget) { + this.dismiss() + } + } + + handleClose = () => { + document.body.classList.remove("overflow-hidden") } } diff --git a/gem/test/ruby_ui/dialog_test.rb b/gem/test/ruby_ui/dialog_test.rb index b6814feb4..19307ba06 100644 --- a/gem/test/ruby_ui/dialog_test.rb +++ b/gem/test/ruby_ui/dialog_test.rb @@ -33,4 +33,92 @@ def test_render_with_all_items assert_match(/Open Dialog/, output) end + + # Regression test for #343: Dialog content must use native element, not
+ def test_dialog_content_renders_native_dialog_element + output = phlex do + RubyUI.Dialog do + RubyUI.DialogContent { "Content" } + end + end + + assert_match(/]/, output, "DialogContent must render a native element") + refute_match(/]/, output, "DialogContent must not use a