Rework show/hide logic; #fixes 170

pull/186/head
Cory LaViska 2020-08-13 10:29:31 -04:00
rodzic fba34699c6
commit 573552b457
7 zmienionych plików z 114 dodań i 49 usunięć

24
src/components.d.ts vendored
Wyświetl plik

@ -14,7 +14,7 @@ export namespace Components {
/**
* Hides the alert
*/
"hide": () => Promise<boolean>;
"hide": () => Promise<void>;
/**
* Indicates whether or not the alert is open. You can use this in lieu of the show/hide methods.
*/
@ -22,7 +22,7 @@ export namespace Components {
/**
* Shows the alert.
*/
"show": () => Promise<boolean>;
"show": () => Promise<void>;
/**
* The type of alert.
*/
@ -276,7 +276,7 @@ export namespace Components {
/**
* Hides the alert
*/
"hide": () => Promise<boolean>;
"hide": () => Promise<void>;
/**
* Indicates whether or not the details is open. You can use this in lieu of the show/hide methods.
*/
@ -284,7 +284,7 @@ export namespace Components {
/**
* Shows the alert.
*/
"show": () => Promise<boolean>;
"show": () => Promise<void>;
/**
* The summary to show in the details header. If you need to display HTML, use the `summary` slot instead.
*/
@ -294,7 +294,7 @@ export namespace Components {
/**
* Hides the dialog
*/
"hide": () => Promise<boolean>;
"hide": () => Promise<void>;
/**
* The dialog's label as displayed in the header. You should always include a relevant label even when using `no-header`, as it is required for proper accessibility.
*/
@ -310,7 +310,7 @@ export namespace Components {
/**
* Shows the dialog
*/
"show": () => Promise<boolean>;
"show": () => Promise<void>;
}
interface SlDrawer {
/**
@ -320,7 +320,7 @@ export namespace Components {
/**
* Hides the drawer
*/
"hide": () => Promise<boolean>;
"hide": () => Promise<void>;
/**
* The drawer's label as displayed in the header. You should always include a relevant label even when using `no-header`, as it is required for proper accessibility.
*/
@ -340,7 +340,7 @@ export namespace Components {
/**
* Shows the drawer
*/
"show": () => Promise<boolean>;
"show": () => Promise<void>;
}
interface SlDropdown {
/**
@ -358,7 +358,7 @@ export namespace Components {
/**
* Hides the dropdown panel
*/
"hide": () => Promise<boolean>;
"hide": () => Promise<void>;
/**
* Indicates whether or not the dropdown is open. You can use this in lieu of the show/hide methods.
*/
@ -381,7 +381,7 @@ export namespace Components {
/**
* Shows the dropdown panel
*/
"show": () => Promise<boolean>;
"show": () => Promise<void>;
/**
* The distance in pixels from which to offset the panel along its trigger.
*/
@ -963,7 +963,7 @@ export namespace Components {
/**
* Shows the tooltip.
*/
"hide": () => Promise<boolean>;
"hide": () => Promise<void>;
/**
* Indicates whether or not the tooltip is open. You can use this in lieu of the show/hide methods.
*/
@ -986,7 +986,7 @@ export namespace Components {
/**
* Shows the tooltip.
*/
"show": () => Promise<boolean>;
"show": () => Promise<void>;
/**
* The distance in pixels from which to offset the tooltip along its target.
*/

Wyświetl plik

@ -20,6 +20,7 @@ import { Component, Element, Event, EventEmitter, Host, Method, Prop, Watch, h }
})
export class Tab {
alert: HTMLElement;
isShowing = false;
@Element() host: HTMLSlAlertElement;
@ -64,28 +65,38 @@ export class Tab {
/** Shows the alert. */
@Method()
async show() {
if (this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (this.isShowing) {
return;
}
const slShow = this.slShow.emit();
if (slShow.defaultPrevented) {
return false;
this.open = false;
return;
}
this.host.hidden = false;
this.host.clientWidth; // force a reflow
this.isShowing = true;
this.open = true;
}
/** Hides the alert */
@Method()
async hide() {
if (!this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (!this.isShowing) {
return;
}
const slHide = this.slHide.emit();
if (slHide.defaultPrevented) {
return false;
this.open = true;
return;
}
this.isShowing = false;
this.open = false;
}

Wyświetl plik

@ -23,10 +23,11 @@ let id = 0;
shadow: true
})
export class Details {
body: HTMLElement;
componentId = `details-${++id}`;
details: HTMLElement;
header: HTMLElement;
componentId = `details-${++id}`;
body: HTMLElement;
isShowing = false;
/** Indicates whether or not the details is open. You can use this in lieu of the show/hide methods. */
@Prop({ mutable: true, reflect: true }) open = false;
@ -76,11 +77,15 @@ export class Details {
/** Shows the alert. */
@Method()
async show() {
if (this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (this.isShowing) {
return;
}
const slShow = this.slShow.emit();
if (slShow.defaultPrevented) {
return false;
this.open = false;
return;
}
if (this.body.scrollHeight === 0) {
@ -93,17 +98,22 @@ export class Details {
this.body.style.overflow = 'hidden';
}
this.isShowing = true;
this.open = true;
}
/** Hides the alert */
@Method()
async hide() {
if (!this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (!this.isShowing) {
return;
}
const slHide = this.slHide.emit();
if (slHide.defaultPrevented) {
return false;
this.open = true;
return;
}
// We can't transition out of `height: auto`, so let's set it to the current height first
@ -115,6 +125,7 @@ export class Details {
this.body.style.height = '0';
});
this.isShowing = false;
this.open = false;
}

Wyświetl plik

@ -27,9 +27,10 @@ let id = 0;
shadow: true
})
export class Dialog {
panel: HTMLElement;
dialog: HTMLElement;
componentId = `dialog-${++id}`;
dialog: HTMLElement;
isShowing = false;
panel: HTMLElement;
@Element() host: HTMLSlDialogElement;
@ -99,16 +100,21 @@ export class Dialog {
/** Shows the dialog */
@Method()
async show() {
if (this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (this.isShowing) {
return;
}
const slShow = this.slShow.emit();
if (slShow.defaultPrevented) {
return false;
this.open = false;
return;
}
this.dialog.hidden = false;
this.host.clientWidth; // force a reflow
requestAnimationFrame(() => (this.open = true));
this.isShowing = true;
this.open = true;
lockBodyScrolling(this.host);
document.addEventListener('focusin', this.handleDocumentFocusIn);
@ -117,13 +123,18 @@ export class Dialog {
/** Hides the dialog */
@Method()
async hide() {
if (!this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (!this.isShowing) {
return;
}
const slHide = this.slHide.emit();
if (slHide.defaultPrevented) {
return false;
this.open = true;
return;
}
this.isShowing = false;
this.open = false;
unlockBodyScrolling(this.host);

Wyświetl plik

@ -26,9 +26,10 @@ let id = 0;
shadow: true
})
export class Drawer {
panel: HTMLElement;
drawer: HTMLElement;
componentId = `drawer-${++id}`;
drawer: HTMLElement;
isShowing = false;
panel: HTMLElement;
@Element() host: HTMLSlDrawerElement;
@ -107,16 +108,21 @@ export class Drawer {
/** Shows the drawer */
@Method()
async show() {
if (this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (this.isShowing) {
return;
}
const slShow = this.slShow.emit();
if (slShow.defaultPrevented) {
return false;
this.open = false;
return;
}
this.drawer.hidden = false;
this.host.clientWidth; // force a reflow
requestAnimationFrame(() => (this.open = true));
this.isShowing = true;
this.open = true;
// Lock body scrolling only if the drawer isn't contained
if (!this.contained) {
@ -129,17 +135,21 @@ export class Drawer {
/** Hides the drawer */
@Method()
async hide() {
if (!this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (!this.isShowing) {
return;
}
const slHide = this.slHide.emit();
if (slHide.defaultPrevented) {
return false;
this.open = true;
return;
}
this.isShowing = false;
this.open = false;
unlockBodyScrolling(this.host);
document.removeEventListener('focusin', this.handleDocumentFocusIn);
}

Wyświetl plik

@ -23,6 +23,7 @@ let id = 0;
})
export class Dropdown {
componentId = `dropdown-${++id}`;
isShowing = false;
panel: HTMLElement;
popover: Popover;
trigger: HTMLElement;
@ -123,11 +124,15 @@ export class Dropdown {
/** Shows the dropdown panel */
@Method()
async show() {
if (this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (this.isShowing) {
return;
}
const slShow = this.slShow.emit();
if (slShow.defaultPrevented) {
return false;
this.open = false;
return;
}
this.panel.addEventListener('slActivate', this.handleMenuItemActivate);
@ -135,18 +140,23 @@ export class Dropdown {
document.addEventListener('mousedown', this.handleDocumentMouseDown);
document.addEventListener('keydown', this.handleDocumentKeyDown);
this.popover.show();
this.isShowing = true;
this.open = true;
this.popover.show();
}
/** Hides the dropdown panel */
@Method()
async hide() {
if (!this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (!this.isShowing) {
return;
}
const slHide = this.slHide.emit();
if (slHide.defaultPrevented) {
return false;
this.open = true;
return;
}
this.panel.removeEventListener('slActivate', this.handleMenuItemActivate);
@ -154,8 +164,9 @@ export class Dropdown {
document.removeEventListener('mousedown', this.handleDocumentMouseDown);
document.removeEventListener('keydown', this.handleDocumentKeyDown);
this.popover.hide();
this.isShowing = false;
this.open = false;
this.popover.hide();
}
focusOnTrigger() {

Wyświetl plik

@ -19,6 +19,7 @@ let id = 0;
})
export class Tooltip {
componentId = `tooltip-${++id}`;
isShowing = false;
popover: Popover;
target: HTMLElement;
tooltip: any;
@ -126,29 +127,39 @@ export class Tooltip {
/** Shows the tooltip. */
@Method()
async show() {
if (this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (this.isShowing) {
return;
}
const slShow = this.slShow.emit();
if (slShow.defaultPrevented) {
return false;
this.open = false;
return;
}
this.popover.show();
this.isShowing = true;
this.open = true;
this.popover.show();
}
/** Shows the tooltip. */
@Method()
async hide() {
if (!this.open) return;
// Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
if (!this.isShowing) {
return;
}
const slHide = this.slHide.emit();
if (slHide.defaultPrevented) {
return false;
this.open = true;
return;
}
this.popover.hide();
this.isShowing = false;
this.open = false;
this.popover.hide();
}
getTarget() {