Rework alert show/hide logic; #247

pull/261/head
Cory LaViska 2020-10-13 12:41:57 -04:00
rodzic 4f7496b6be
commit 5e8db633b9
4 zmienionych plików z 57 dodań i 48 usunięć

Wyświetl plik

@ -11,6 +11,8 @@ Alerts are used to display important messages either inline or as toast notifica
</sl-alert>
```
?> Alerts will not be visible if the `open` attribute is not present.
## Examples
### Types
@ -93,7 +95,7 @@ Set the `duration` prop to automatically hide an alert after a period of time. T
<div class="alert-duration">
<sl-button type="primary">Show Alert</sl-button>
<sl-alert type="primary" duration="3000" closable style="margin-top: var(--sl-spacing-medium);">
<sl-alert type="primary" duration="3000" closable>
<sl-icon slot="icon" name="info-circle"></sl-icon>
This alert will automatically hide itself after three seconds, unless you interact with it.
</sl-alert>
@ -106,6 +108,12 @@ Set the `duration` prop to automatically hide an alert after a period of time. T
button.addEventListener('click', () => alert.show());
</script>
<style>
.alert-duration sl-alert {
margin-top: var(--sl-spacing-medium);
}
</style>
```
### Toast Notifications

Wyświetl plik

@ -10,6 +10,7 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
- Fixed a bug where initial transitions didn't show in `sl-dialog` and `sl-drawer` [#247](https://github.com/shoelace-style/shoelace/issues/247)
- Improved `sl-color-picker` grid and slider handles [#246](https://github.com/shoelace-style/shoelace/issues/246)
- Reworked show/hide logic in `sl-alert`, `sl-dialog`, and `sl-drawer` to not use reflow hacks and the `hidden` attribute
- Updated to Popper 2.5.3 to address a fixed position bug in Firefox
## 2.0.0-beta.20

Wyświetl plik

@ -1,16 +1,14 @@
@import 'component';
@import 'mixins/visually-hidden';
/**
* @prop --box-shadow: The alert's box shadow.
*/
:host {
--box-shadow: none;
display: contents;
display: block;
&[hidden] {
display: none;
}
// For better DX, we'll reset the margin here so the base part can inherit it
margin: 0;
}
.alert {
@ -30,6 +28,11 @@
opacity: 0;
transform: scale(0.9);
transition: var(--sl-transition-medium) opacity ease, var(--sl-transition-medium) transform ease;
margin: inherit;
&:not(.alert--visible) {
@include visually-hidden;
}
}
.alert--open {

Wyświetl plik

@ -1,4 +1,4 @@
import { Component, Element, Event, EventEmitter, Host, Method, Prop, Watch, h } from '@stencil/core';
import { Component, Element, Event, EventEmitter, Method, Prop, State, Watch, h } from '@stencil/core';
const toastStack = Object.assign(document.createElement('div'), { className: 'sl-toast-stack' });
@ -23,10 +23,11 @@ const toastStack = Object.assign(document.createElement('div'), { className: 'sl
export class Alert {
alert: HTMLElement;
autoHideTimeout: any;
isVisible = false;
@Element() host: HTMLSlAlertElement;
@State() isVisible = false;
/** Indicates whether or not the alert is open. You can use this in lieu of the show/hide methods. */
@Prop({ mutable: true, reflect: true }) open = false;
@ -91,8 +92,6 @@ export class Alert {
return;
}
this.host.hidden = false;
this.host.clientWidth; // force a reflow
this.isVisible = true;
this.open = true;
@ -116,7 +115,6 @@ export class Alert {
}
clearTimeout(this.autoHideTimeout);
this.isVisible = false;
this.open = false;
}
@ -133,7 +131,7 @@ export class Alert {
}
toastStack.append(this.host);
this.show();
requestAnimationFrame(() => this.show());
this.host.addEventListener(
'sl-after-hide',
@ -164,7 +162,7 @@ export class Alert {
// Ensure we only emit one event when the target element is no longer visible
if (event.propertyName === 'opacity' && target.classList.contains('alert')) {
this.host.hidden = !this.open;
this.isVisible = this.open;
this.open ? this.slAfterShow.emit() : this.slAfterHide.emit();
}
}
@ -178,42 +176,41 @@ export class Alert {
render() {
return (
<Host hidden>
<div
ref={el => (this.alert = el)}
part="base"
class={{
alert: true,
'alert--open': this.open,
'alert--closable': this.closable,
'alert--primary': this.type === 'primary',
'alert--success': this.type === 'success',
'alert--info': this.type === 'info',
'alert--warning': this.type === 'warning',
'alert--danger': this.type === 'danger'
}}
role="alert"
aria-live="assertive"
aria-atomic="true"
aria-hidden={!this.open}
onMouseMove={this.handleMouseMove}
onTransitionEnd={this.handleTransitionEnd}
>
<span part="icon" class="alert__icon">
<slot name="icon" />
</span>
<div
ref={el => (this.alert = el)}
part="base"
class={{
alert: true,
'alert--open': this.open,
'alert--visible': this.isVisible,
'alert--closable': this.closable,
'alert--primary': this.type === 'primary',
'alert--success': this.type === 'success',
'alert--info': this.type === 'info',
'alert--warning': this.type === 'warning',
'alert--danger': this.type === 'danger'
}}
role="alert"
aria-live="assertive"
aria-atomic="true"
aria-hidden={!this.open}
onMouseMove={this.handleMouseMove}
onTransitionEnd={this.handleTransitionEnd}
>
<span part="icon" class="alert__icon">
<slot name="icon" />
</span>
<span part="message" class="alert__message">
<slot />
</span>
<span part="message" class="alert__message">
<slot />
</span>
{this.closable && (
<span class="alert__close">
<sl-icon-button part="close-button" name="x" onClick={this.handleCloseClick} />
</span>
)}
</div>
</Host>
{this.closable && (
<span class="alert__close">
<sl-icon-button part="close-button" name="x" onClick={this.handleCloseClick} />
</span>
)}
</div>
);
}
}