Skip to content

Commit

Permalink
feat: implement scaleBeforeClose event in Modal (#430)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lalaluka authored Jul 6, 2021
1 parent 1ad87b9 commit bdc6786
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 19 deletions.
27 changes: 21 additions & 6 deletions packages/components/src/components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ import { animateTo, KEYFRAMES } from '../../utils/animate';

const supportsResizeObserver = 'ResizeObserver' in window;

type CloseEventTrigger = 'CLOSE_BUTTON' | 'ESCAPE_KEY' | 'BACKDROP';

export interface BeforeCloseEventDetail {
trigger: CloseEventTrigger;
}

/*
TODO
====
Expand Down Expand Up @@ -67,8 +73,12 @@ export class Modal {
/** Useful for toggling scroll-specific styles */
@State() hasScroll: boolean = false;

@Event() scaleOpen?: EventEmitter;
@Event() scaleClose?: EventEmitter;
/** Fires when the modal has been opened */
@Event() scaleOpen: EventEmitter<void>;
/** Event firing before an Modal Action is called. Propagation to closing the Event can be stoped. Possible actions: `buttonClose` `escapePressed` `backdrop` */
@Event() scaleBeforeClose: EventEmitter<BeforeCloseEventDetail>;
/** Fires when the modal has been closed */
@Event() scaleClose: EventEmitter<void>;

private closeButton: HTMLButtonElement | HTMLScaleButtonElement;
private modalContainer: HTMLElement;
Expand All @@ -84,7 +94,7 @@ export class Modal {
return;
}
if (event.key === 'Escape') {
this.opened = false;
this.emitBeforeClose('ESCAPE_KEY');
}
}

Expand All @@ -109,6 +119,12 @@ export class Modal {
}
}

emitBeforeClose(trigger: CloseEventTrigger) {
if (!this.scaleBeforeClose.emit({ trigger }).defaultPrevented) {
this.opened = false;
}
}

componentDidLoad() {
// Query all focusable elements and store them in `focusableElements`.
// Needed for the "focus trap" functionality.
Expand Down Expand Up @@ -204,7 +220,6 @@ export class Modal {
return (
<Host>
{this.styles && <style>{this.styles}</style>}

<div
ref={(el) => (this.modalContainer = el)}
class={this.getCssClassMap()}
Expand All @@ -213,7 +228,7 @@ export class Modal {
<div
class="modal__backdrop"
part="backdrop"
onClick={() => (this.opened = false)}
onClick={() => this.emitBeforeClose('BACKDROP')}
></div>
<div
data-focus-trap-edge
Expand All @@ -240,7 +255,7 @@ export class Modal {
ref={(el) => (this.closeButton = el)}
class="modal__close-button"
part="close-button"
onClick={() => (this.opened = false)}
onClick={() => this.emitBeforeClose('CLOSE_BUTTON')}
aria-label={this.closeButtonLabel}
>
<slot name="close-icon">
Expand Down
9 changes: 5 additions & 4 deletions packages/components/src/components/modal/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@

## Events

| Event | Description | Type |
| ------------ | ----------- | ------------------ |
| `scaleClose` | | `CustomEvent<any>` |
| `scaleOpen` | | `CustomEvent<any>` |
| Event | Description | Type |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| `scaleBeforeClose` | Event firing before an Modal Action is called. Propagation to closing the Event can be stoped. Possible actions: `buttonClose` `escapePressed` `backdrop` | `CustomEvent<BeforeCloseEventDetail>` |
| `scaleClose` | Fires when the modal has been closed | `CustomEvent<void>` |
| `scaleOpen` | Fires when the modal has been opened | `CustomEvent<void>` |


## Shadow Parts
Expand Down
43 changes: 43 additions & 0 deletions packages/components/src/html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,49 @@ <h3>Modal with header and buttons</h3>
});
</script>

<h3>Modal with scaleBeforeClose</h3>
<scale-button id="show-modal-clickoutside"> show modal </scale-button>
<scale-modal
id="modal-clickoutside"
opened="false"
close-click-outside="false"
>
<span slot="header">Header content</span> Click close to close Modal
</scale-modal>

<script>
const showModalclickoutside = document.querySelector(
'#show-modal-clickoutside'
);
const Modalclickoutside = document.getElementById('modal-clickoutside');
showModalclickoutside.addEventListener('click', () => {
Modalclickoutside.setAttribute('opened', 'true');
});

Modalclickoutside.addEventListener('scaleClose', () => {
Modalclickoutside.removeAttribute('opened');
});

Modalclickoutside.addEventListener('scaleBeforeClose', (event) => {
console.log(event);
if (event.detail.trigger === 'BACKDROP') {
event.preventDefault();
alert('Close by Backdrop prevented');
}
if (event.detail.trigger === 'ESCAPE_KEY') {
event.preventDefault();
alert('Close by Escape button prevented');
}
if (event.detail.trigger === 'CLOSE_BUTTON') {
alert('Close by buttonClose detected but not prevented');
}
});

document.getElementById('cancel-btn').addEventListener('click', () => {
Modalclickoutside.removeAttribute('opened');
});
</script>

<h3>Switch</h3>
<scale-switch label="Switch label"></scale-switch>
<h3>Switch disabled</h3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const Template = (args, context) => ({
}
},
methods: {
close() {
scaleClose() {
this.isOpen = false
}
},
Expand All @@ -70,7 +70,7 @@ export const Template = (args, context) => ({
:close-button-label="closeButtonLabel"
:align-actions="alignActions"
:styles="styles"
@close="close()"
@scaleClose="scaleClose()"
>
<template v-if="shortBody">
<p>Hello. Welcome. What a pleasure it is to have you.</p>
Expand All @@ -85,10 +85,10 @@ export const Template = (args, context) => ({
<p>Look, let's start with some tough love, alright? Ready for this? Here it goes: you two suck at peddling meth. Period. Good! 'Oh boo-hoo, I won't cook meth anymore!' You're a crybaby! Who needs you?! Hey, I'm unplugging the website, so no more money laundering! How do you like that?!</p>
</template>
<template #actions v-if="showActions">
<scale-button slot="action" variant="secondary" @click="close">
<scale-button slot="action" variant="secondary" @click="scaleClose">
Cancel
</scale-button>
<scale-button slot="action"@click="close">
<scale-button slot="action" @click="scaleClose">
Primary Action
</scale-button>
</template>
Expand Down
20 changes: 15 additions & 5 deletions packages/storybook-vue/stories/3_components/modal/ScaleModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
:close-button-label="closeButtonLabel"
:align-actions="alignActions"
:styles="styles"
@scaleClose="handler"
@scaleClose="scaleClose"
@scaleOpen="scaleOpen"
@scaleBeforeClose="scaleBeforeClose"
>
<slot name="close"></slot>
<slot></slot>
Expand All @@ -35,10 +37,18 @@ export default {
styles: { type: String },
},
methods: {
handler($event) {
scaleCloseAction($event);
this.$emit('close')
}
scaleOpen($event) {
action("scaleOpen");
this.$emit("scaleOpen", $event);
},
scaleBeforeClose($event) {
action("scaleBeforeClose");
this.$emit("scaleBeforeClose", $event);
},
scaleClose($event) {
action("scaleClose");
this.$emit("scaleClose", $event);
},
}
};
</script>

0 comments on commit bdc6786

Please sign in to comment.