UNPKG

@csedl/stimulus-dropdown

Version:

Dropdown and Tooltip with stimulus and floating-ui

99 lines (81 loc) 4.03 kB
import {Controller} from "@hotwired/stimulus" import {positionAllPanels, getAllOpenPanels} from "./floating-ui-functions"; import {debugLog} from "./utils.js"; export default class extends Controller { elements_to_place = null connect() { const on = this.element.getAttribute('data-on') if (on.includes('scroll')) { this.element.addEventListener('scroll', () => { this.handle_placement('scroll') }) } if (on.includes('resize-observer')) { var resize_observer = new ResizeObserver(entries => { for (let entry of entries) { this.handle_placement('resize-observer') } }); resize_observer.observe(this.element) } } handle_placement(trigger_label) { if (this.elements_to_place === null) { this.elements_to_place = getAllOpenPanels(this.element) this.element.setAttribute('csedl-place-all-first-done-time', performance.now()) } if (this.elements_to_place.length === 0) { this.cleanup() } else { const c = Number(this.element.getAttribute('csedl-place-all-counter')) this.element.setAttribute('csedl-place-all-counter', c + 1) const first_run = Number(this.element.getAttribute('csedl-place-all-first-done-time')) debugLog(`place panels by ${trigger_label} ${c} / ${performance.now() - first_run}ms: x: ${this.element.offsetWidth} y: ${this.element.offsetHeight}`) positionAllPanels(this.elements_to_place) this.element.setAttribute('csedl-place-all-done-time', performance.now()) this.setup_run_after_event() } } setup_run_after_event() { if (this.element.hasAttribute('data-run-after')) { const run_after_str = this.element.getAttribute('data-run-after') const run_after = Number(run_after_str) if (isNaN(run_after)) { console.error(`the data-run-after attribute must be a valid positive number (integer for milliseconds) but is: «${run_after_str}»`, this.element) } else if (run_after < 0.0) { console.error(`the data-run-after attribute must be a positive number (integer for milliseconds) but is: «${run_after_str}»`, this.element) } else { if (this.element.getAttribute('csedl-run-after-is-active')) { debugLog('place-panel run-after is already installed (nothing to do)') } else { this.element.setAttribute('csedl-run-after-is-active', true) this.element.setAttribute('csedl-place-all-counter', 0) setTimeout(() => this.handle_placement_after(), 50); debugLog('place-panel run-after INSTALLED') } } } } handle_placement_after() { const run_after = Number(this.element.getAttribute('data-run-after')) const last_run = Number(this.element.getAttribute('csedl-place-all-done-time')) const c = Number(this.element.getAttribute('csedl-place-all-counter')) this.element.setAttribute('csedl-place-all-counter', c + 1) const running_time = performance.now() - last_run positionAllPanels(this.elements_to_place) debugLog(`PLACEMENT FOLLOW-UP ${c}: ${running_time}ms / ${run_after}ms`) if (running_time < run_after) { setTimeout(() => this.handle_placement_after(), 50); } else { this.cleanup() } } cleanup() { this.element.removeAttribute('csedl-place-all-done-time') this.element.removeAttribute('csedl-place-all-first-done-time') this.element.removeAttribute('csedl-place-all-counter') this.element.removeAttribute('csedl-run-after-is-active') this.elements_to_place = null debugLog('FINISHED placement follow-up') } }