kopia lustrzana https://github.com/shoelace-style/shoelace
Light DOM variation
rodzic
1546b53d40
commit
ad9de54752
|
@ -4,7 +4,71 @@
|
|||
|
||||
Alerts are used to display important messages.
|
||||
|
||||
Alerts are designed to be shown dynamically, so you need to include the `open` attribute to display them.
|
||||
Alerts are designed to be shown dynamically, so you must include the `open` attribute to display them.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```html preview
|
||||
<div class="toast-example">
|
||||
<sl-button type="primary">Primary</sl-button>
|
||||
<sl-button type="success">Success</sl-button>
|
||||
<sl-button type="info">Info</sl-button>
|
||||
<sl-button type="warning">Warning</sl-button>
|
||||
<sl-button type="danger">Danger</sl-button>
|
||||
|
||||
<sl-alert type="primary" placement="top-end" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="info-circle"></sl-icon>
|
||||
<strong>This is super informative</strong><br>
|
||||
You can tell by how pretty the alert is.
|
||||
</sl-alert>
|
||||
|
||||
<sl-alert type="success" placement="top-end" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="check2-circle"></sl-icon>
|
||||
<strong>Your changes have been saved</strong><br>
|
||||
You can safely exit the app now.
|
||||
</sl-alert>
|
||||
|
||||
<sl-alert type="info" placement="top-end" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="gear"></sl-icon>
|
||||
<strong>Your settings have been updated</strong><br>
|
||||
Some settings will take affect the next time you log in.
|
||||
</sl-alert>
|
||||
|
||||
<sl-alert type="warning" placement="top-end" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="exclamation-triangle"></sl-icon>
|
||||
<strong>Your session has ended</strong><br>
|
||||
Please login again to continue.
|
||||
</sl-alert>
|
||||
|
||||
<sl-alert type="danger" placement="bottom" duration="3000" closable>
|
||||
<sl-icon slot="icon" name="exclamation-octagon"></sl-icon>
|
||||
<strong>Your account has been deleted</strong><br>
|
||||
We're very sorry to see you go!
|
||||
</sl-alert>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.toast-example');
|
||||
|
||||
['primary', 'success', 'info', 'warning', 'danger'].map(type => {
|
||||
const button = container.querySelector(`sl-button[type="${type}"]`);
|
||||
const alert = container.querySelector(`sl-alert[type="${type}"]`);
|
||||
|
||||
button.addEventListener('click', () => alert.show());
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```html preview
|
||||
<sl-alert open>
|
||||
|
@ -46,16 +110,16 @@ Set the `type` attribute to change the alert's type.
|
|||
|
||||
<sl-alert type="warning" open>
|
||||
<sl-icon slot="icon" name="exclamation-triangle"></sl-icon>
|
||||
<strong>This will end your session</strong><br>
|
||||
You will be logged out until you log in again.
|
||||
<strong>Your session has ended</strong><br>
|
||||
Please login again to continue.
|
||||
</sl-alert>
|
||||
|
||||
<br>
|
||||
|
||||
<sl-alert type="danger" open>
|
||||
<sl-icon slot="icon" name="exclamation-octagon"></sl-icon>
|
||||
<strong>Delete this file?</strong><br>
|
||||
This is permanent, which means forever!
|
||||
<strong>Your account has been deleted</strong><br>
|
||||
We're very sorry to see you go!
|
||||
</sl-alert>
|
||||
```
|
||||
|
||||
|
|
|
@ -7,4 +7,5 @@ Z-indexes are used to stack components in a logical manner.
|
|||
| `--sl-z-index-drawer` | 700 |
|
||||
| `--sl-z-index-dialog` | 800 |
|
||||
| `--sl-z-index-dropdown` | 900 |
|
||||
| `--sl-z-index-alert-group` | 950 |
|
||||
| `--sl-z-index-tooltip` | 1000 |
|
||||
|
|
|
@ -11,6 +11,10 @@ export namespace Components {
|
|||
* Set to true to make the alert closable.
|
||||
*/
|
||||
"closable": boolean;
|
||||
/**
|
||||
* The length of time, in milliseconds, the alert will show before closing itself.
|
||||
*/
|
||||
"duration": number;
|
||||
/**
|
||||
* Hides the alert
|
||||
*/
|
||||
|
@ -19,6 +23,10 @@ export namespace Components {
|
|||
* Indicates whether or not the alert is open. You can use this in lieu of the show/hide methods.
|
||||
*/
|
||||
"open": boolean;
|
||||
/**
|
||||
* Determines how the alert will be shown. If this is anything other than `inline`, the alert will be shown in a stack as a "toast" notification. When the alert is shown as a notification, it will be hoisted to a stack and removed from the DOM when hidden. (You can reuse alerts that have been removed by storing a reference to the element.)
|
||||
*/
|
||||
"placement": 'inline' | 'top-start' | 'top' | 'top-end' | 'bottom-start' | 'bottom' | 'bottom-end';
|
||||
/**
|
||||
* Shows the alert.
|
||||
*/
|
||||
|
@ -1418,6 +1426,10 @@ declare namespace LocalJSX {
|
|||
* Set to true to make the alert closable.
|
||||
*/
|
||||
"closable"?: boolean;
|
||||
/**
|
||||
* The length of time, in milliseconds, the alert will show before closing itself.
|
||||
*/
|
||||
"duration"?: number;
|
||||
/**
|
||||
* Emitted after the alert closes and all transitions are complete.
|
||||
*/
|
||||
|
@ -1438,6 +1450,10 @@ declare namespace LocalJSX {
|
|||
* Indicates whether or not the alert is open. You can use this in lieu of the show/hide methods.
|
||||
*/
|
||||
"open"?: boolean;
|
||||
/**
|
||||
* Determines how the alert will be shown. If this is anything other than `inline`, the alert will be shown in a stack as a "toast" notification. When the alert is shown as a notification, it will be hoisted to a stack and removed from the DOM when hidden. (You can reuse alerts that have been removed by storing a reference to the element.)
|
||||
*/
|
||||
"placement"?: 'inline' | 'top-start' | 'top' | 'top-end' | 'bottom-start' | 'bottom' | 'bottom-end';
|
||||
/**
|
||||
* The type of alert.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
:root {
|
||||
--width: 28rem;
|
||||
--spacing: var(--sl-spacing-medium);
|
||||
}
|
||||
|
||||
.sl-alert-stack {
|
||||
position: fixed;
|
||||
z-index: var(--sl-z-index-toast);
|
||||
width: var(--width);
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
padding: 0 var(--spacing);
|
||||
|
||||
sl-alert {
|
||||
--box-shadow: var(--sl-shadow-large);
|
||||
margin: var(--spacing) 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sl-alert-stack[data-placement='top-start'] {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.sl-alert-stack[data-placement='top'] {
|
||||
top: 0;
|
||||
left: calc(50% - var(--width) / 2);
|
||||
}
|
||||
|
||||
.sl-alert-stack[data-placement='top-end'] {
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.sl-alert-stack[data-placement='bottom-start'] {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.sl-alert-stack[data-placement='bottom'] {
|
||||
bottom: 0;
|
||||
left: calc(50% - var(--width) / 2);
|
||||
}
|
||||
|
||||
.sl-alert-stack[data-placement='bottom-end'] {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
|
@ -1,6 +1,11 @@
|
|||
@import 'component';
|
||||
|
||||
/**
|
||||
* @prop --box-shadow: The alert's box shadow.
|
||||
*/
|
||||
:host {
|
||||
--box-shadow: none;
|
||||
|
||||
display: block;
|
||||
|
||||
&[hidden] {
|
||||
|
@ -16,17 +21,20 @@
|
|||
border: solid 1px var(--sl-color-gray-90);
|
||||
border-top-width: 3px;
|
||||
border-radius: var(--sl-border-radius-medium);
|
||||
box-shadow: var(--box-shadow);
|
||||
font-family: var(--sl-font-sans);
|
||||
font-size: var(--sl-font-size-small);
|
||||
font-weight: var(--sl-font-weight-normal);
|
||||
line-height: 1.6;
|
||||
color: var(--sl-color-gray-30);
|
||||
opacity: 0;
|
||||
transition: var(--sl-transition-medium) opacity ease;
|
||||
transform: scale(0.9);
|
||||
transition: var(--sl-transition-medium) opacity ease, var(--sl-transition-medium) transform ease;
|
||||
}
|
||||
|
||||
.alert--open {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.alert__icon {
|
||||
|
@ -91,5 +99,5 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
font-size: var(--sl-font-size-large);
|
||||
padding: 0 var(--sl-spacing-medium);
|
||||
padding-right: var(--sl-spacing-medium);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ import { Component, Element, Event, EventEmitter, Host, Method, Prop, Watch, h }
|
|||
* @part close-button - The close button.
|
||||
*/
|
||||
|
||||
const stack = Object.assign(document.createElement('div'), { className: 'sl-alert-stack' });
|
||||
|
||||
@Component({
|
||||
tag: 'sl-alert',
|
||||
styleUrl: 'alert.scss',
|
||||
|
@ -20,6 +22,7 @@ import { Component, Element, Event, EventEmitter, Host, Method, Prop, Watch, h }
|
|||
})
|
||||
export class Alert {
|
||||
alert: HTMLElement;
|
||||
autoHideTimeout: any;
|
||||
isShowing = false;
|
||||
|
||||
@Element() host: HTMLSlAlertElement;
|
||||
|
@ -33,11 +36,31 @@ export class Alert {
|
|||
/** The type of alert. */
|
||||
@Prop() type: 'primary' | 'success' | 'info' | 'warning' | 'danger' = 'primary';
|
||||
|
||||
/**
|
||||
* Determines how the alert will be shown. If this is anything other than `inline`, the alert will be shown in a stack
|
||||
* as a "toast" notification. When the alert is shown as a notification, it will be hoisted to a stack and removed
|
||||
* from the DOM when hidden. (You can reuse alerts that have been removed by storing a reference to the element.)
|
||||
*/
|
||||
@Prop() placement: 'inline' | 'top-start' | 'top' | 'top-end' | 'bottom-start' | 'bottom' | 'bottom-end' = 'inline';
|
||||
|
||||
/** The length of time, in milliseconds, the alert will show before closing itself. */
|
||||
@Prop() duration = Infinity;
|
||||
|
||||
@Watch('open')
|
||||
handleOpenChange() {
|
||||
this.open ? this.show() : this.hide();
|
||||
}
|
||||
|
||||
@Watch('duration')
|
||||
handleDurationChange() {
|
||||
clearTimeout(this.autoHideTimeout);
|
||||
|
||||
// Restart the timeout if the duration changes and the alert is open
|
||||
if (this.open && this.duration < Infinity) {
|
||||
this.autoHideTimeout = setTimeout(() => this.hide(), this.duration);
|
||||
}
|
||||
}
|
||||
|
||||
/** Emitted when the alert opens. Calling `event.preventDefault()` will prevent it from being opened. */
|
||||
@Event() slShow: EventEmitter;
|
||||
|
||||
|
@ -80,6 +103,14 @@ export class Alert {
|
|||
this.host.clientWidth; // force a reflow
|
||||
this.isShowing = true;
|
||||
this.open = true;
|
||||
|
||||
if (this.placement !== 'inline') {
|
||||
this.appendToStack();
|
||||
}
|
||||
|
||||
if (this.duration < Infinity) {
|
||||
this.autoHideTimeout = setTimeout(() => this.hide(), this.duration);
|
||||
}
|
||||
}
|
||||
|
||||
/** Hides the alert */
|
||||
|
@ -96,6 +127,7 @@ export class Alert {
|
|||
return;
|
||||
}
|
||||
|
||||
clearTimeout(this.autoHideTimeout);
|
||||
this.isShowing = false;
|
||||
this.open = false;
|
||||
}
|
||||
|
@ -110,10 +142,34 @@ 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;
|
||||
|
||||
if (this.placement !== 'inline' && !this.open) {
|
||||
this.removeFromStack();
|
||||
}
|
||||
|
||||
this.open ? this.slAfterShow.emit() : this.slAfterHide.emit();
|
||||
}
|
||||
}
|
||||
|
||||
appendToStack() {
|
||||
if (!stack.parentElement) {
|
||||
document.body.append(stack);
|
||||
}
|
||||
|
||||
stack.dataset.placement = this.placement;
|
||||
stack.append(this.host);
|
||||
}
|
||||
|
||||
removeFromStack() {
|
||||
this.host.remove();
|
||||
|
||||
// Remove the stack from the DOM when there are no more alerts
|
||||
const openAlerts = [...stack.querySelectorAll('sl-alert')].filter((el: HTMLSlAlertElement) => el.open === true);
|
||||
if (openAlerts.length === 0) {
|
||||
stack.remove();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Host hidden>
|
||||
|
@ -145,7 +201,9 @@ export class Alert {
|
|||
</span>
|
||||
|
||||
{this.closable && (
|
||||
<sl-icon-button part="close-button" class="alert__close" name="x" onClick={this.handleCloseClick} />
|
||||
<span class="alert__close">
|
||||
<sl-icon-button part="close-button" name="x" onClick={this.handleCloseClick} />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</Host>
|
||||
|
|
|
@ -249,6 +249,7 @@
|
|||
--sl-z-index-drawer: 700;
|
||||
--sl-z-index-dialog: 800;
|
||||
--sl-z-index-dropdown: 900;
|
||||
--sl-z-index-toast: 950;
|
||||
--sl-z-index-tooltip: 1000;
|
||||
}
|
||||
|
||||
|
@ -268,4 +269,5 @@
|
|||
// Component light DOM styles - only follow this pattern when absolutely necessary!
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@import '../components/alert/alert.light-dom';
|
||||
@import '../components/button-group/button-group.light-dom';
|
||||
|
|
Ładowanie…
Reference in New Issue