Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Unreleased

* Fix premeture closing of modals and slideovers (#284, #289)
* Update Tailwind v4 documentation


# 6.1.3

* Support multiple classes for dropdown transitions
Expand Down
5 changes: 4 additions & 1 deletion src/slideover.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ export default class extends Controller {
}

backdropClose(event) {
if (event.target.nodeName == "DIALOG") this.close()
if (event.target.nodeName !== "DIALOG") return;
if (window.getSelection().toString().length > 0) return;

this.close();
}

show() {
Expand Down
3 changes: 2 additions & 1 deletion test/fixtures/slideover.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<div data-controller="slideover">
<dialog data-slideover-target="dialog" class="slideover h-full max-h-full m-0 w-96 p-8 backdrop:bg-black/80">
<dialog data-slideover-target="dialog" data-action="click->slideover#backdropClose" class="slideover h-full max-h-full m-0 w-96 p-8 backdrop:bg-black/80">
<p>This slideover dialog has a groovy backdrop!</p>
<input type="text" value="Select this text" class="border p-1" data-testid="slideover-input">
<button autofocus data-action="slideover#close" class="px-2.5 py-1 bg-blue-500 text-white text-sm rounded">Close</button>
</dialog>
<button data-action="slideover#open" class="bg-blue-500 hover:bg-blue-700 text-white text-sm font-bold py-1 px-2.5 rounded">Open slideover</button>
Expand Down
58 changes: 55 additions & 3 deletions test/slideover_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,62 @@ describe('SlideoverController', () => {
})

it('opens dialog', () => {
const dialog = document.querySelector("dialog")
expect(dialog.hasAttribute("open")).to.equal(false)
const dialog = document.querySelector('dialog')
expect(dialog.hasAttribute('open')).to.equal(false)
document.querySelector("[data-action='slideover#open']").click()
expect(dialog.hasAttribute("open")).to.equal(true)
expect(dialog.hasAttribute('open')).to.equal(true)
})

it('closes the slideover when clicking on the backdrop', async () => {
const dialog = document.querySelector('dialog')
const openSlideoverButton = document.querySelector("[data-action='slideover#open']")
openSlideoverButton.click()
expect(dialog.hasAttribute('open')).to.equal(true)

// Simulate clicking on the dialog element itself (the backdrop)
const clickEvent = new MouseEvent('click', { bubbles: true })
Object.defineProperty(clickEvent, 'target', { value: dialog })
dialog.dispatchEvent(clickEvent)

expect(dialog.hasAttribute('closing')).to.equal(true)
})

it('does not close the slideover when clicking inside slideover content', async () => {
const dialog = document.querySelector('dialog')
const openSlideoverButton = document.querySelector("[data-action='slideover#open']")
const input = document.querySelector("[data-testid='slideover-input']")
openSlideoverButton.click()
expect(dialog.hasAttribute('open')).to.equal(true)

// Simulate clicking on the input inside the modal
input.click()

expect(dialog.hasAttribute('closing')).to.equal(false)
expect(dialog.hasAttribute('open')).to.equal(true)
})

it('does not close the slideover when text is selected', async () => {
const dialog = document.querySelector('dialog')
const openSlideoverButton = document.querySelector("[data-action='slideover#open']")
openSlideoverButton.click()
expect(dialog.hasAttribute('open')).to.equal(true)

// Simulate text selection
const selection = window.getSelection()
const input = document.querySelector("[data-testid='slideover-input']")
input.select()

// Simulate clicking on the backdrop while text is selected
const clickEvent = new MouseEvent('click', { bubbles: true })
Object.defineProperty(clickEvent, 'target', { value: dialog })
dialog.dispatchEvent(clickEvent)

// Modal should stay open because text is selected
expect(dialog.hasAttribute('closing')).to.equal(false)
expect(dialog.hasAttribute('open')).to.equal(true)

// Clear selection
selection.removeAllRanges()
})
})
})
Loading