UNPKG

tailwindcss-stimulus-components

Version:

A set of Stimulus components (tabs, dropdowns, modals, toggles, autosave, etc) for TailwindCSS users

104 lines (84 loc) 3.14 kB
import { Controller } from '@hotwired/stimulus' import { transition } from './transition.js' export default class extends Controller { static targets = ['menu', 'button', 'menuItem'] static values = { open: { type: Boolean, default: false }, closeOnEscape: { type: Boolean, default: true }, closeOnClickOutside: { type: Boolean, default: true } } static classes = ['enter', 'enterFrom', 'enterTo', 'leave', 'leaveFrom', 'leaveTo', 'toggle'] connect() { this.boundBeforeCache = this.beforeCache.bind(this) document.addEventListener('turbo:before-cache', this.boundBeforeCache) } disconnect() { document.removeEventListener('turbo:before-cache', this.boundBeforeCache) } openValueChanged() { transition(this.menuTarget, this.openValue, this.transitionOptions) if (this.openValue === true && this.hasMenuItemTarget) { this.menuItemTargets[0].focus() } } show() { this.openValue = true } close() { this.openValue = false } // Closes dropdown from outside click or keyboard hide(event) { // if the event is a click and the target is not inside the dropdown, then close it if ( this.closeOnClickOutsideValue && event.target.nodeType && this.element.contains(event.target) === false && this.openValue ) { this.openValue = false } // if the event is a keydown and the key is escape, then close it if (this.closeOnEscapeValue && event.key === 'Escape' && this.openValue) { this.openValue = false } } toggle() { this.openValue = !this.openValue } nextItem(event) { event.preventDefault() this.menuItemTargets[this.nextIndex].focus() } previousItem(event) { event.preventDefault() this.menuItemTargets[this.previousIndex].focus() } // getters and setters get currentItemIndex() { return this.menuItemTargets.indexOf(document.activeElement) } get nextIndex() { return Math.min(this.currentItemIndex + 1, this.menuItemTargets.length - 1) } get previousIndex() { return Math.max(this.currentItemIndex - 1, 0) } get transitionOptions() { // once the Class API default values are available, we can simplify this return { enter: this.hasEnterClass ? this.enterClasses.join(' ') : 'transition ease-out duration-100', enterFrom: this.hasEnterFromClass ? this.enterFromClasses.join(' ') : 'transform opacity-0 scale-95', enterTo: this.hasEnterToClass ? this.enterToClasses.join(' ') : 'transform opacity-100 scale-100', leave: this.hasLeaveClass ? this.leaveClasses.join(' ') : 'transition ease-in duration-75', leaveFrom: this.hasLeaveFromClass ? this.leaveFromClasses.join(' ') : 'transform opacity-100 scale-100', leaveTo: this.hasLeaveToClass ? this.leaveToClasses.join(' ') : 'transform opacity-0 scale-95', toggleClass: this.hasToggleClass ? this.toggleClasses.join(' ') : 'hidden', } } // Ensures the menu is hidden before Turbo caches the page beforeCache() { this.openValue = false this.menuTarget.classList.add(this.transitionOptions.toggleClass) } }