fix(dees-input-dropdown): improve dropdown popup lifecycle with window layer overlay and animated visibility transitions
This commit is contained in:
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@design.estate/dees-catalog',
|
||||
version: '3.56.0',
|
||||
version: '3.56.1',
|
||||
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@ import {
|
||||
cssManager,
|
||||
DeesElement,
|
||||
} from '@design.estate/dees-element';
|
||||
import * as domtools from '@design.estate/dees-domtools';
|
||||
import { zIndexRegistry } from '../../00zindex.js';
|
||||
import { cssGeistFontFamily } from '../../00fonts.js';
|
||||
import { themeDefaultStyles } from '../../00theme.js';
|
||||
import { DeesWindowLayer } from '../../00group-overlay/dees-windowlayer/dees-windowlayer.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
@@ -47,6 +49,12 @@ export class DeesInputDropdownPopup extends DeesElement {
|
||||
@state()
|
||||
accessor menuZIndex: number = 1000;
|
||||
|
||||
@state()
|
||||
accessor visible: boolean = false;
|
||||
|
||||
private windowLayer: DeesWindowLayer | null = null;
|
||||
private isDestroying: boolean = false;
|
||||
|
||||
public static styles = [
|
||||
themeDefaultStyles,
|
||||
cssManager.defaultStyles,
|
||||
@@ -182,7 +190,7 @@ export class DeesInputDropdownPopup extends DeesElement {
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="selectionBox show ${this.opensToTop ? 'top' : 'bottom'}"
|
||||
class="selectionBox ${this.visible ? 'show' : ''} ${this.opensToTop ? 'top' : 'bottom'}"
|
||||
style="${posStyle}; z-index: ${this.menuZIndex};"
|
||||
>
|
||||
${this.enableSearch
|
||||
@@ -233,30 +241,43 @@ export class DeesInputDropdownPopup extends DeesElement {
|
||||
}
|
||||
}
|
||||
|
||||
public show(): void {
|
||||
public async show(): Promise<void> {
|
||||
this.filteredOptions = this.options;
|
||||
this.highlightedIndex = 0;
|
||||
this.searchValue = '';
|
||||
|
||||
// Create window layer (transparent, no blur)
|
||||
this.windowLayer = await DeesWindowLayer.createAndShow();
|
||||
this.windowLayer.addEventListener('click', () => {
|
||||
this.dispatchEvent(new CustomEvent('close-request'));
|
||||
});
|
||||
|
||||
// Set z-index above the window layer
|
||||
this.menuZIndex = zIndexRegistry.getNextZIndex();
|
||||
zIndexRegistry.register(this, this.menuZIndex);
|
||||
this.style.zIndex = this.menuZIndex.toString();
|
||||
|
||||
document.body.appendChild(this);
|
||||
|
||||
// Add listeners
|
||||
// Animate in on next frame
|
||||
await domtools.plugins.smartdelay.delayFor(0);
|
||||
this.visible = true;
|
||||
|
||||
// Add scroll/resize listeners for repositioning
|
||||
window.addEventListener('scroll', this.handleScrollOrResize, { capture: true, passive: true });
|
||||
window.addEventListener('resize', this.handleScrollOrResize, { passive: true });
|
||||
setTimeout(() => {
|
||||
document.addEventListener('mousedown', this.handleOutsideClick);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
// Remove listeners
|
||||
public async hide(): Promise<void> {
|
||||
// Guard against double-destruction
|
||||
if (this.isDestroying) {
|
||||
return;
|
||||
}
|
||||
this.isDestroying = true;
|
||||
|
||||
// Remove scroll/resize listeners
|
||||
window.removeEventListener('scroll', this.handleScrollOrResize, { capture: true } as EventListenerOptions);
|
||||
window.removeEventListener('resize', this.handleScrollOrResize);
|
||||
document.removeEventListener('mousedown', this.handleOutsideClick);
|
||||
|
||||
zIndexRegistry.unregister(this);
|
||||
|
||||
@@ -264,9 +285,21 @@ export class DeesInputDropdownPopup extends DeesElement {
|
||||
this.filteredOptions = this.options;
|
||||
this.highlightedIndex = 0;
|
||||
|
||||
// Don't await - let window layer cleanup happen in background for instant visual feedback
|
||||
if (this.windowLayer) {
|
||||
this.windowLayer.destroy();
|
||||
this.windowLayer = null;
|
||||
}
|
||||
|
||||
// Animate out via CSS transition
|
||||
this.visible = false;
|
||||
await domtools.plugins.smartdelay.delayFor(150);
|
||||
|
||||
if (this.parentElement) {
|
||||
this.parentElement.removeChild(this);
|
||||
}
|
||||
|
||||
this.isDestroying = false;
|
||||
}
|
||||
|
||||
public async focusSearchInput(): Promise<void> {
|
||||
@@ -328,13 +361,6 @@ export class DeesInputDropdownPopup extends DeesElement {
|
||||
}
|
||||
};
|
||||
|
||||
private handleOutsideClick = (event: MouseEvent): void => {
|
||||
const path = event.composedPath();
|
||||
if (!path.includes(this) && (!this.ownerComponent || !path.includes(this.ownerComponent))) {
|
||||
this.dispatchEvent(new CustomEvent('close-request'));
|
||||
}
|
||||
};
|
||||
|
||||
private handleScrollOrResize = (): void => {
|
||||
this.dispatchEvent(new CustomEvent('reposition-request'));
|
||||
};
|
||||
@@ -343,7 +369,6 @@ export class DeesInputDropdownPopup extends DeesElement {
|
||||
await super.disconnectedCallback();
|
||||
window.removeEventListener('scroll', this.handleScrollOrResize, { capture: true } as EventListenerOptions);
|
||||
window.removeEventListener('resize', this.handleScrollOrResize);
|
||||
document.removeEventListener('mousedown', this.handleOutsideClick);
|
||||
zIndexRegistry.unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,12 +205,12 @@ export class DeesInputDropdown extends DeesInputBase<DeesInputDropdown> {
|
||||
this.popupInstance.addEventListener('close-request', this.handleCloseRequest);
|
||||
this.popupInstance.addEventListener('reposition-request', this.handleRepositionRequest);
|
||||
|
||||
// Show popup (appends to document.body)
|
||||
this.popupInstance.show();
|
||||
// Show popup (creates window layer, appends to document.body)
|
||||
await this.popupInstance.show();
|
||||
|
||||
// Focus search input
|
||||
if (this.enableSearch) {
|
||||
this.popupInstance.focusSearchInput();
|
||||
await this.popupInstance.focusSearchInput();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user