Skip to content

Commit

Permalink
Use <dialog> element for modals
Browse files Browse the repository at this point in the history
  • Loading branch information
excid3 committed Mar 15, 2024
1 parent 64275eb commit 8117bdd
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 151 deletions.
2 changes: 1 addition & 1 deletion dist/tailwindcss-stimulus-components.cjs

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/tailwindcss-stimulus-components.cjs.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/tailwindcss-stimulus-components.module.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/tailwindcss-stimulus-components.module.js.map

Large diffs are not rendered by default.

40 changes: 7 additions & 33 deletions docs/modal.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,13 @@ application.register('modal', Modal)
```

```html
<div data-controller="modal" data-action="keydown.esc->modal#close" tabindex="-1" class="relative z-10">
<button type="button" data-action="click->modal#open" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Open Modal</button>

<!-- Modal Background -->
<div class="hidden fixed inset-0 bg-black bg-opacity-80 overflow-y-auto flex items-center justify-center"
data-modal-target="background"
data-action="click->modal#closeBackground"
data-transition-enter="transition-all ease-in-out duration-300"
data-transition-enter-from="bg-opacity-0"
data-transition-enter-to="bg-opacity-80"
data-transition-leave="transition-all ease-in-out duration-300"
data-transition-leave-from="bg-opacity-80"
data-transition-leave-to="bg-opacity-0">

<!-- Modal Container -->
<div data-modal-target="container" class="max-h-screen w-full max-w-lg relative">
<!-- Modal Card -->
<div class="m-1 bg-white rounded shadow">
<div class="p-8">
<h2 class="text-xl mb-4">Large Modal Content</h2>
<p class="mb-4">This is an example modal dialog box.</p>

<div class="flex justify-end items-center flex-wrap mt-6">
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" data-action="click->modal#close:prevent">Close</button>
</div>
</div>
</div>
</div>
</div>
<div data-controller="dialog">
<dialog data-dialog-target="dialog" class="p-8 rounded-lg backdrop:bg-black/80">
<p>This modal dialog has a groovy backdrop!</p>
<button autofocus data-action="dialog#close" class="px-2.5 py-1 bg-blue-500 text-white text-sm rounded">Close</button>
</dialog>
<button data-action="dialog#showModal" class="bg-blue-500 hover:bg-blue-700 text-white text-sm font-bold py-1 px-2.5 rounded">Open modal</button>
</div>
```

`data-modal-restore-scroll-value` may be set to `false` to disable
restoring scroll position.

`data-modal-open-value` may be set to `true` to open modal on page load.
`data-modal-open-value` may be set to `true` to open modal on connect.
49 changes: 13 additions & 36 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@

<script type="module">
import { Application } from "@hotwired/stimulus";
import { Alert, ColorPreview, Dropdown, Modal, Popover, Slideover, Tabs, Toggle } from "tailwindcss-stimulus-components";
import { Alert, ColorPreview, Dropdown, Dialog, Modal, Popover, Slideover, Tabs, Toggle } from "tailwindcss-stimulus-components";

(() => {
const application = Application.start();
application.register('alert', Alert);
application.register('color-preview', ColorPreview);
application.register('dropdown', Dropdown);
application.register('dialog', Dialog);
application.register('modal', Modal);
application.register('popover', Popover);
application.register('slideover', Slideover);
Expand Down Expand Up @@ -90,7 +91,7 @@ <h1 class="text-3xl font-semibold mb-2">Tailwind Stimulus Components Examples</h

<div class="my-12">
<h2 class="text-2xl text-gray-800 font-semibold mb-4">Slideovers</h2>
<button data-action="click->slideover#toggle click@window->slideover#hide" class="inline-block bg-blue-500 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded">Open Slideover</button>
<button data-action="click->slideover#toggle click@window->slideover#hide" class="inline-block bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2.5 rounded text-sm">Open Slideover</button>
</div>

<div class="my-12">
Expand Down Expand Up @@ -120,38 +121,14 @@ <h2 class="text-2xl text-gray-800 font-semibold mb-4">Dropdowns</h2>

<div class="my-12">
<h2 class="text-2xl text-gray-800 font-semibold mb-4">Modals</h2>

<div data-controller="modal" data-action="keydown.esc->modal#close" tabindex="-1" class="relative">
<p class="mb-4 text-gray-700">This modal can be closed with the "esc" key or by clicking the backdrop.</p>
<a href="#" data-action="click->modal#open:prevent" class="inline-block bg-blue-500 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded">Open Modal</a>

<!-- Modal Background -->
<div class="hidden fixed inset-0 bg-black bg-opacity-80 overflow-y-auto flex items-center justify-center"
data-modal-target="background"
data-action="click->modal#closeBackground"
data-transition-enter="transition-all ease-in-out duration-300"
data-transition-enter-from="bg-opacity-0"
data-transition-enter-to="bg-opacity-80"
data-transition-leave="transition-all ease-in-out duration-300"
data-transition-leave-from="bg-opacity-80"
data-transition-leave-to="bg-opacity-0">

<!-- Modal Container -->
<div data-modal-target="container" class="max-h-screen w-full max-w-lg relative">
<!-- Modal Card -->
<div class="m-1 bg-white rounded shadow">
<div class="p-8">
<h2 class="text-xl mb-4">Large Modal Content</h2>
<p class="mb-4">This is an example modal dialog box.</p>

<div class="flex justify-end items-center flex-wrap mt-6">
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" data-action="click->modal#close:prevent">Close</button>
</div>
</div>
</div>
</div>

</div>
<p>Modals use the <code>&lt;dialog&gt;</code> html element and can be closed with <kbd>Esc</kbd> or a button. See the <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog#accessibility_concerns" target="_blank" class="underline text-blue-500">dialog element MDN docs</a>.</p>

<div data-controller="dialog">
<dialog data-dialog-target="dialog" class="p-8 rounded-lg backdrop:bg-black/80">
<p>This modal dialog has a groovy backdrop!</p>
<button autofocus data-action="dialog#close" class="px-2.5 py-1 bg-blue-500 text-white text-sm rounded">Close</button>
</dialog>
<button data-action="dialog#showModal" class="bg-blue-500 hover:bg-blue-700 text-white text-sm font-bold py-1 px-2.5 rounded">Open modal</button>
</div>
</div>

Expand Down Expand Up @@ -276,7 +253,7 @@ <h2 class="text-2xl text-gray-800 font-semibold mb-4">Radios as Tabs</h2>
<div class="my-12">
<h2 class="text-2xl text-gray-800 font-semibold">Toggle</h2>
<div data-controller='toggle' class="m-2 p-6 border flex items-center gap-4">
<button data-action='click->toggle#toggle:prevent touch->toggle#toggle:prevent' class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded">
<button data-action='click->toggle#toggle:prevent touch->toggle#toggle:prevent' class="bg-blue-500 hover:bg-blue-700 text-white text-sm font-bold py-1 px-2.5 rounded">
Toggle button
</button>
<div class="hidden bg-yellow-500/20"
Expand Down Expand Up @@ -310,7 +287,7 @@ <h2 class="text-2xl text-gray-800 font-semibold">Toggle</h2>
</div>

<div data-controller='toggle' class="m-2 p-6 border flex items-center gap-4">
<button data-action='click->toggle#toggle:prevent touch->toggle#toggle:prevent' class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded">
<button data-action='click->toggle#toggle:prevent touch->toggle#toggle:prevent' class="bg-blue-500 hover:bg-blue-700 text-white text-sm font-bold py-1 px-2.5 rounded">
Toggle button with custom classes
</button>
<div class="opacity-50 bg-yellow-500/20"
Expand Down
82 changes: 8 additions & 74 deletions src/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,90 +2,24 @@ import { Controller } from "@hotwired/stimulus"
import { enter, leave } from "./transition"

export default class extends Controller {
static targets = ['container', 'background']
static targets = ["dialog"]
static values = {
open: { type: Boolean, default: false },
restoreScroll: { type: Boolean, default: true }
open: Boolean
}

connect() {
document.addEventListener("turbo:before-cache", this.beforeCache.bind(this))
if (this.openValue) this.showModal()
}

disconnect() {
document.removeEventListener("turbo:before-cache", this.beforeCache.bind(this))
showModal() {
this.dialogTarget.showModal()
}

open() {
this.openValue = true
show() {
this.dialogTarget.show()
}

close() {
this.openValue = false
}

closeBackground(event) {
if (event.target === this.backgroundTarget) this.close()
}

async openValueChanged() {
if (this.openValue) {
this.containerTarget.focus()
this.lockScroll()
enter(this.backgroundTarget)
enter(this.containerTarget)
} else {
leave(this.containerTarget)
await leave(this.backgroundTarget)
this.unlockScroll()
}
}

lockScroll() {
// Save the scroll position before we hide the scrollbar
if (this.restoreScrollValue) {
this.saveScrollPosition()
// Add negative top position in order for body to stay in place
document.body.style.top = `-${this.scrollPosition}px`
}

// Add right padding to the body so the page doesn't shift
// when we disable scrolling
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth
document.body.style.paddingRight = `${scrollbarWidth}px`

// Add classes to body to fix its position
document.body.classList.add('fixed', 'inset-x-0', 'overflow-hidden')
}

unlockScroll() {
// Remove tweaks for scrollbar
document.body.style.paddingRight = null;

// Remove classes from body to unfix position
document.body.classList.remove('fixed', 'inset-x-0', 'overflow-hidden')

// Restore the scroll position of the body before it got locked
if (this.restoreScrollValue) {
this.restoreScrollPosition()

// Remove the negative top inline style from body
document.body.style.top = null
}
}

saveScrollPosition() {
this.scrollPosition = window.pageYOffset || document.body.scrollTop
}

restoreScrollPosition() {
if (this.scrollPosition === undefined) return
document.documentElement.scrollTop = this.scrollPosition
}

beforeCache() {
this.close()
this.backgroundTarget.classList.add("hidden")
this.containerTarget.classList.add("hidden")
this.dialogTarget.close()
}
}

0 comments on commit 8117bdd

Please sign in to comment.