Skip to content

Commit

Permalink
feat: add dialog (resolves #106) (#213)
Browse files Browse the repository at this point in the history
* Restore WIP code

* Restore dialog partial

* feat: add dialog (unstyled)

* fix: add inert polyfill in a Chromium-compatible way

* feat: add title/body support to dialog

* feat: responsive sizes
  • Loading branch information
Ned Zimmerman authored Feb 10, 2020
1 parent d32a330 commit 1b90b88
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 4 deletions.
2 changes: 0 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export default [
format: 'umd',
},
plugins: [babel()],
external: [ 'wicg-inert' ]
},

// CommonJS (for Node) and ES module (for bundlers) build.
Expand All @@ -21,6 +20,5 @@ export default [
{ file: pkg.main, format: 'cjs' },
{ file: pkg.module, format: 'es' },
],
external: [ 'wicg-inert' ]
},
];
119 changes: 119 additions & 0 deletions src/assets/scripts/Pinecone/Dialog/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/**
* Dialog Handler.
*/

/**
* Dialog class.
*/
class Dialog {
/**
* Constructor.
*
* @param {DomNode} btn
* @param {Object} options
*/
constructor( btn, options ) {
this.btn = btn;
this.config = {
...{
callback:
/**
* Callback for when one was not provided.
*/
() => {
console.error( 'No callback provided.' ); // eslint-disable-line
}
},
...options
};

this.invokeDialog = this.invokeDialog.bind( this );
this.handleClick = this.handleClick.bind( this );
this.addEventListeners();
}

/**
*
*
*/
handleClick() {
this.invokeDialog( this.config.callback );
}

/**
* Invoke dialog.
*
* @param {Function} callback
*/
invokeDialog( callback ) {
const elems = document.querySelectorAll( 'body > *' );
Array.prototype.forEach.call( elems, ( elem ) => {
elem.setAttribute( 'inert', 'inert' );
} );

const unique = +new Date();

const dialog = document.createElement( 'div' );
dialog.setAttribute( 'role', 'dialog' );
dialog.setAttribute( 'aria-labelledby', `q-${unique}` );
dialog.setAttribute( 'aria-describedby', `q-${unique + 1}` );
let innerHtml = `<h2 id="q-${unique}">${this.config.title}</h2>`;
if ( this.config.question ) {
innerHtml += `<p id="q-${unique + 1}">${this.config.question}</p>`;
}
innerHtml += `
<div class="buttons">
<button class="button button--secondary dismiss">${this.config.dismiss}</button>
<button class="button confirm">${this.config.confirm}</button>
</div>
`;
dialog.innerHTML = innerHtml;
const overlay = document.createElement( 'div' );
overlay.setAttribute( 'inert', 'inert' );
overlay.classList.add( 'overlay' );

/**
* Handle close event.
*/
const close = () => {
Array.prototype.forEach.call( elems, elem => {
if ( elem !== dialog ) {
elem.removeAttribute( 'inert' );
}
} );
dialog.parentNode.removeChild( dialog );
overlay.parentNode.removeChild( overlay );
trigger.focus();
};

const confirm = dialog.querySelector( '.confirm' );
const dismiss = dialog.querySelector( '.dismiss' );
const trigger = this.btn;

document.body.appendChild( overlay );
document.body.appendChild( dialog );

dismiss.focus();

confirm.onclick = () => {
close();
callback();
};
dismiss.onclick = () => close();
dialog.addEventListener( 'keydown', e => {
if ( 27 == e.keyCode ) {
e.preventDefault();
close();
}
} );
}

/**
* Add event listeners.
*/
addEventListeners() {
this.btn.addEventListener( 'click', this.handleClick, false );
}
}

export default Dialog;
3 changes: 2 additions & 1 deletion src/assets/scripts/Pinecone/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Accordion from './Accordion/index.js';
import Card from './Card/index.js';
import DeselectAll from './DeselectAll/index.js';
import Dialog from './Dialog/index.js';
import DisclosureButton from './DisclosureButton/index.js';
import FilterList from './FilterList/index.js';
import Icon from './Icon/index.js';
Expand All @@ -10,4 +11,4 @@ import NestedCheckbox from './NestedCheckbox/index.js';
import Notification from './Notification/index.js';
import SearchToggle from './SearchToggle/index.js';

export default { Accordion, Card, DeselectAll, DisclosureButton, FilterList, Icon, Menu, MenuButton, NestedCheckbox, Notification, SearchToggle };
export default { Accordion, Card, DeselectAll, Dialog, DisclosureButton, FilterList, Icon, Menu, MenuButton, NestedCheckbox, Notification, SearchToggle };
12 changes: 12 additions & 0 deletions src/assets/scripts/pinecone.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* global Pinecone */

import 'wicg-inert';

const menu = document.querySelector( '.menu' );
const menuToggle = document.querySelector( '.menu-toggle' );

Expand Down Expand Up @@ -99,3 +101,13 @@ const searchToggle = document.querySelector( '.search-toggle' );
if ( searchToggle ) {
new Pinecone.SearchToggle( searchToggle, searchToggle.nextElementSibling );
}

const dialogBtn = document.getElementById( 'invoke-dialog' );
if ( dialogBtn ) {
new Pinecone.Dialog( dialogBtn, {
title: 'Remove resource?',
question: 'Are you sure you want to remove this resource from your favorites?',
confirm: 'Yes, remove',
dismiss: 'No, don&rsquo;t remove'
} );
}
50 changes: 50 additions & 0 deletions src/assets/styles/components/_dialog.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
.button--invoke-dialog + * {
display: none;
}

[role="dialog"] {
background-color: $white;
border-radius: rem(3);
box-shadow: 0 rem(3) rem(6) rgba(0, 0, 0, 0.16);
height: auto;
left: $gutter;
padding: $gutter;
position: fixed;
top: 20vh;
width: calc(100% - 2 * #{$gutter});

.buttons {
margin-top: rem(16);
}

.buttons button {
max-width: 100%;
width: 100%;
}

.buttons button + button {
margin-top: rem(16);
}
}

.overlay {
background: $black;
height: 100%;
left: 0;
opacity: 0.7;
position: fixed;
top: 0;
width: 100%;
}

@include breakpoint-up(md) {
[role="dialog"] {
left: calc((100% - 32rem) / 2);
padding: rem(68) rem(92);
width: 32rem;

.buttons {
margin-top: $gutter;
}
}
}
1 change: 1 addition & 0 deletions src/assets/styles/pinecone.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
@import "components/disclosure-button";
@import "components/filter-sort";
@import "components/card";
@import "components/dialog";
@import "components/info-card";
@import "components/menu";
@import "components/menu--home";
Expand Down
10 changes: 10 additions & 0 deletions src/components/02-molecules/06-dialog/dialog.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
title: 'Dialog',
status: 'wip',
context: {
dialogTitle: 'Remove favorite',
dialogContent: 'Are your sure you want to remove this resource from your favorites?',
dialogConfirm: 'Yes, remove',
dialogCancel: 'No, don&rsquo;t remove'
}
};
2 changes: 2 additions & 0 deletions src/components/02-molecules/06-dialog/dialog.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% if not standAlone %}<div class="spacer"></div>{% endif %}
{% render '@button--borderless', {label: 'Remove favorite', id: 'invoke-dialog', icon: 'delete', iconPosition: 'start', standAlone: true}, true %}
1 change: 0 additions & 1 deletion src/components/_preview.njk
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
<div class="container">{% if _target.context.inFooter %}{{ yield | safe }}{% else %}{% render '@footer' %}{% endif %}</div>
</footer>
{% endif %}
<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?features=Element.prototype.inert"></script>
<script src="{{ '/scripts/pinecone.umd.js' | path }}"></script>
<script src="{{ '/scripts/pinecone.js' | path }}"></script>
</body>
Expand Down

0 comments on commit 1b90b88

Please sign in to comment.