feat(combox): Introduce singleton SioCombox attached to document.body with open/close/toggle API and animated show/hide; integrate SioFab to use the singleton and update styles/positioning
This commit is contained in:
@@ -36,6 +36,27 @@ declare global {
|
||||
export class SioCombox extends DeesElement {
|
||||
public static demo = () => html` <sio-combox></sio-combox> `;
|
||||
|
||||
// Singleton instance
|
||||
private static instance: SioCombox | null = null;
|
||||
|
||||
/**
|
||||
* Creates and appends a singleton combox to document.body
|
||||
*/
|
||||
public static createOnBody(): SioCombox {
|
||||
if (!SioCombox.instance) {
|
||||
SioCombox.instance = new SioCombox();
|
||||
document.body.appendChild(SioCombox.instance);
|
||||
}
|
||||
return SioCombox.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the singleton instance if it exists
|
||||
*/
|
||||
public static getInstance(): SioCombox | null {
|
||||
return SioCombox.instance;
|
||||
}
|
||||
|
||||
@property({ type: Object })
|
||||
public accessor referenceObject: HTMLElement;
|
||||
|
||||
@@ -45,6 +66,9 @@ export class SioCombox extends DeesElement {
|
||||
@state()
|
||||
private accessor isKeyboardVisible: boolean = false;
|
||||
|
||||
@state()
|
||||
private accessor isOpen: boolean = false;
|
||||
|
||||
private keyboardBlurTimeout?: number;
|
||||
|
||||
@state()
|
||||
@@ -174,6 +198,48 @@ export class SioCombox extends DeesElement {
|
||||
this.removeAttribute('keyboard-visible');
|
||||
}
|
||||
}
|
||||
if (changedProperties.has('isOpen')) {
|
||||
if (this.isOpen) {
|
||||
this.classList.add('open');
|
||||
this.dispatchEvent(new CustomEvent('opened', { bubbles: true, composed: true }));
|
||||
} else {
|
||||
this.classList.remove('open');
|
||||
this.dispatchEvent(new CustomEvent('closed', { bubbles: true, composed: true }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the combox
|
||||
*/
|
||||
public open() {
|
||||
this.isOpen = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the combox
|
||||
*/
|
||||
public close() {
|
||||
this.isOpen = false;
|
||||
this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the combox open/closed state
|
||||
*/
|
||||
public toggle() {
|
||||
if (this.isOpen) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the combox is currently open
|
||||
*/
|
||||
public getIsOpen(): boolean {
|
||||
return this.isOpen;
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
@@ -181,6 +247,9 @@ export class SioCombox extends DeesElement {
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
position: fixed;
|
||||
bottom: 100px;
|
||||
right: 20px;
|
||||
height: 600px;
|
||||
width: 800px;
|
||||
background: ${bdTheme('background')};
|
||||
@@ -189,25 +258,22 @@ export class SioCombox extends DeesElement {
|
||||
box-shadow: ${unsafeCSS(shadows.xl)};
|
||||
overflow: hidden;
|
||||
font-family: ${unsafeCSS(fontFamilies.sans)};
|
||||
position: relative;
|
||||
transform-origin: bottom right;
|
||||
z-index: 10001;
|
||||
|
||||
/* Hidden by default */
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transform: scale(0.95) translateY(10px);
|
||||
transition: opacity 200ms ease, transform 200ms ease;
|
||||
}
|
||||
|
||||
:host(.animate-in) {
|
||||
animation: scaleIn 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
|
||||
:host(.open) {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
|
||||
@keyframes scaleIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9) translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
:host::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
@@ -243,9 +309,19 @@ export class SioCombox extends DeesElement {
|
||||
// Mobile responsive layout - full screen with sliding mechanics
|
||||
cssManager.cssForPhablet(css`
|
||||
:host {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
border-radius: 0;
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
:host(.open) {
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
|
||||
:host::before {
|
||||
|
||||
Reference in New Issue
Block a user