add sl-request-close event

This commit is contained in:
Cory LaViska
2021-06-21 09:40:11 -04:00
parent 95ba1b5849
commit 1c010ffe5a
5 changed files with 71 additions and 42 deletions

View File

@@ -76,27 +76,29 @@ By design, a dialog's height will never exceed that of the viewport. As such, di
</script>
```
### Ignoring Clicks on the Overlay
### Preventing the Dialog from Closing
By default, dialogs are closed when the user clicks or taps on the overlay. To prevent this behavior, cancel the `sl-overlay-dismiss` event.
By default, dialogs will close when the user clicks the close button, clicks the overlay, or presses the <kbd>Escape</kbd> key. In most cases, the default behavior is the best behavior in terms of UX. However, there are situations where this may be undesirable, such as when data loss will occur.
To keep the dialog open in such cases, you can cancel the `sl-request-close` event. When canceled, the dialog will remain open and pulse briefly to draw the user's attention to it.
```html preview
<sl-dialog label="Dialog" class="dialog-no-overlay-dismiss">
This dialog will not be closed when you click outside of it.
<sl-button slot="footer" type="primary">Close</sl-button>
<sl-dialog label="Dialog" class="dialog-deny-close">
This dialog will not close unless you use the button below.
<sl-button slot="footer" type="primary">Save &amp; Close</sl-button>
</sl-dialog>
<sl-button>Open Dialog</sl-button>
<script>
const dialog = document.querySelector('.dialog-no-overlay-dismiss');
const dialog = document.querySelector('.dialog-deny-close');
const openButton = dialog.nextElementSibling;
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
const saveButton = dialog.querySelector('sl-button[slot="footer"]');
openButton.addEventListener('click', () => dialog.show());
closeButton.addEventListener('click', () => dialog.hide());
saveButton.addEventListener('click', () => dialog.hide());
dialog.addEventListener('sl-overlay-dismiss', event => event.preventDefault());
dialog.addEventListener('sl-request-close', event => event.preventDefault());
</script>
```

View File

@@ -164,27 +164,30 @@ By design, a drawer's height will never exceed 100% of its container. As such, d
</script>
```
### Ignoring Clicks on the Overlay
### Preventing the Drawer from Closing
By default, drawers will close when the user clicks the close button, clicks the overlay, or presses the <kbd>Escape</kbd> key. In most cases, the default behavior is the best behavior in terms of UX. However, there are situations where this may be undesirable, such as when data loss will occur.
To keep the drawer open in such cases, you can cancel the `sl-request-close` event. When canceled, the drawer will remain open and pulse briefly to draw the user's attention to it.
By default, drawers are closed when the user clicks or taps on the overlay. To prevent this behavior, cancel the `sl-overlay-dismiss` event.
```html preview
<sl-drawer label="Drawer" class="drawer-no-overlay-dismiss">
This drawer will not be closed when you click outside of it.
<sl-button slot="footer" type="primary">Close</sl-button>
<sl-drawer label="Drawer" class="drawer-deny-close">
This dialog will not close unless you use the button below.
<sl-button slot="footer" type="primary">Save &amp; Close</sl-button>
</sl-drawer>
<sl-button>Open Drawer</sl-button>
<script>
const drawer = document.querySelector('.drawer-no-overlay-dismiss');
const drawer = document.querySelector('.drawer-deny-close');
const openButton = drawer.nextElementSibling;
const closeButton = drawer.querySelector('sl-button[type="primary"]');
openButton.addEventListener('click', () => drawer.show());
closeButton.addEventListener('click', () => drawer.hide());
drawer.addEventListener('sl-overlay-dismiss', event => event.preventDefault());
drawer.addEventListener('sl-request-close', event => event.preventDefault());
</script>
```

View File

@@ -8,6 +8,9 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
## Next
- 🚨 BREAKING: removed the `sl-overlay-click` event from `sl-dialog` and `sl-drawer` (use `sl-request-close` instead) [#471](https://github.com/shoelace-style/shoelace/discussions/471)
- Added `sl-request-close` event to `sl-dialog` and `sl-drawer`
- Added `dialog.denyClose` and `drawer.denyClose` animations
- Fixed a bug in `sl-color-picker` where setting `value` immediately wouldn't trigger an update
## 2.0.0-beta.44

View File

@@ -42,6 +42,7 @@ let id = 0;
*
* @animation dialog.show - The animation to use when showing the dialog.
* @animation dialog.hide - The animation to use when hiding the dialog.
* @animation dialog.denyClose - The animation to use when a request to close the dialog is denied.
* @animation dialog.overlay.show - The animation to use when showing the dialog's overlay.
* @animation dialog.overlay.hide - The animation to use when hiding the dialog's overlay.
*/
@@ -92,8 +93,12 @@ export default class SlDialog extends LitElement {
*/
@event('sl-initial-focus') slInitialFocus: EventEmitter<void>;
/** Emitted when the overlay is clicked. Calling `event.preventDefault()` will prevent the dialog from closing. */
@event('sl-overlay-dismiss') slOverlayDismiss: EventEmitter<void>;
/**
* Emitted when the user attempts to close the dialog by clicking the close button, clicking the overlay, or pressing
* the escape key. Calling `event.preventDefault()` will prevent the dialog from closing. Avoid using this unless
* closing the dialog will result in destructive behavior such as data loss.
*/
@event('sl-request-close') slRequestClose: EventEmitter<void>;
connectedCallback() {
super.connectedCallback();
@@ -131,14 +136,21 @@ export default class SlDialog extends LitElement {
return waitForEvent(this, 'sl-after-hide');
}
handleCloseClick() {
private requestClose() {
const slRequestClose = this.slRequestClose.emit({ cancelable: true });
if (slRequestClose.defaultPrevented) {
const animation = getAnimation(this, 'dialog.denyClose');
animateTo(this.panel, animation.keyframes, animation.options);
return;
}
this.hide();
}
handleKeyDown(event: KeyboardEvent) {
if (event.key === 'Escape') {
event.stopPropagation();
this.hide();
this.requestClose();
}
}
@@ -206,13 +218,6 @@ export default class SlDialog extends LitElement {
}
}
handleOverlayClick() {
const slOverlayDismiss = this.slOverlayDismiss.emit({ cancelable: true });
if (!slOverlayDismiss.defaultPrevented) {
this.hide();
}
}
handleSlotChange() {
this.hasFooter = hasSlot(this, 'footer');
}
@@ -228,7 +233,7 @@ export default class SlDialog extends LitElement {
})}
@keydown=${this.handleKeyDown}
>
<div part="overlay" class="dialog__overlay" @click=${this.handleOverlayClick} tabindex="-1"></div>
<div part="overlay" class="dialog__overlay" @click=${this.requestClose} tabindex="-1"></div>
<div
part="panel"
@@ -251,7 +256,7 @@ export default class SlDialog extends LitElement {
class="dialog__close"
name="x"
library="system"
@click="${this.handleCloseClick}"
@click="${this.requestClose}"
></sl-icon-button>
</header>
`
@@ -286,6 +291,11 @@ setDefaultAnimation('dialog.hide', {
options: { duration: 250, easing: 'ease' }
});
setDefaultAnimation('dialog.denyClose', {
keyframes: [{ transform: 'scale(1)' }, { transform: 'scale(1.02)' }, { transform: 'scale(1)' }],
options: { duration: 250 }
});
setDefaultAnimation('dialog.overlay.show', {
keyframes: [{ opacity: 0 }, { opacity: 1 }],
options: { duration: 250 }

View File

@@ -50,6 +50,7 @@ let id = 0;
* @animation drawer.hideEnd - The animation to use when hiding a drawer with `end` placement.
* @animation drawer.hideBottom - The animation to use when hiding a drawer with `bottom` placement.
* @animation drawer.hideStart - The animation to use when hiding a drawer with `start` placement.
* @animation drawer.denyClose - The animation to use when a request to close the drawer is denied.
* @animation drawer.overlay.show - The animation to use when showing the drawer's overlay.
* @animation drawer.overlay.hide - The animation to use when hiding the drawer's overlay.
*/
@@ -106,8 +107,12 @@ export default class SlDrawer extends LitElement {
/** Emitted when the drawer opens and the panel gains focus. Calling `event.preventDefault()` will prevent focus and allow you to set it on a different element in the drawer, such as an input or button. */
@event('sl-initial-focus') slInitialFocus: EventEmitter<void>;
/** Emitted when the overlay is clicked. Calling `event.preventDefault()` will prevent the drawer from closing. */
@event('sl-overlay-dismiss') slOverlayDismiss: EventEmitter<void>;
/**
* Emitted when the user attempts to close the drawer by clicking the close button, clicking the overlay, or pressing
* the escape key. Calling `event.preventDefault()` will prevent the drawer from closing. Avoid using this unless
* closing the drawer will result in destructive behavior such as data loss.
*/
@event('sl-request-close') slRequestClose: EventEmitter<void>;
connectedCallback() {
super.connectedCallback();
@@ -145,14 +150,21 @@ export default class SlDrawer extends LitElement {
return waitForEvent(this, 'sl-after-hide');
}
handleCloseClick() {
private requestClose() {
const slRequestClose = this.slRequestClose.emit({ cancelable: true });
if (slRequestClose.defaultPrevented) {
const animation = getAnimation(this, 'drawer.denyClose');
animateTo(this.panel, animation.keyframes, animation.options);
return;
}
this.hide();
}
handleKeyDown(event: KeyboardEvent) {
if (event.key === 'Escape') {
event.stopPropagation();
this.hide();
this.requestClose();
}
}
@@ -223,13 +235,6 @@ export default class SlDrawer extends LitElement {
}
}
handleOverlayClick() {
const slOverlayDismiss = this.slOverlayDismiss.emit({ cancelable: true });
if (!slOverlayDismiss.defaultPrevented) {
this.hide();
}
}
handleSlotChange() {
this.hasFooter = hasSlot(this, 'footer');
}
@@ -251,7 +256,7 @@ export default class SlDrawer extends LitElement {
})}
@keydown=${this.handleKeyDown}
>
<div part="overlay" class="drawer__overlay" @click=${this.handleOverlayClick} tabindex="-1"></div>
<div part="overlay" class="drawer__overlay" @click=${this.requestClose} tabindex="-1"></div>
<div
part="panel"
@@ -275,7 +280,7 @@ export default class SlDrawer extends LitElement {
class="drawer__close"
name="x"
library="system"
@click=${this.handleCloseClick}
@click=${this.requestClose}
></sl-icon-button>
</header>
`
@@ -362,6 +367,12 @@ setDefaultAnimation('drawer.hideStart', {
options: { duration: 250, easing: 'ease' }
});
// Deny close
setDefaultAnimation('drawer.denyClose', {
keyframes: [{ transform: 'scale(1)' }, { transform: 'scale(1.01)' }, { transform: 'scale(1)' }],
options: { duration: 250 }
});
// Overlay
setDefaultAnimation('drawer.overlay.show', {
keyframes: [{ opacity: 0 }, { opacity: 1 }],